diff --git a/Makefile b/Makefile index 638597a..5225696 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,43 @@ -CC = gcc -CFLAGS = -Wall -Wextra -O2 -std=c99 -march=native $(shell pkg-config --cflags libcurl json-c readline) -LDLIBS = $(shell pkg-config --libs libcurl json-c readline) +# Makefile for Solo-C. +# +# Written for the POSIX make utility (IEEE Std 1003.1, XCU make) and a POSIX +# shell (/bin/sh), so it works with any conforming make and no GNU-only +# features. Deliberately avoided: +# +# $(shell ...) not POSIX - pkg-config is run by the recipe shell +# ?= not POSIX - defaults are plain "=" and are overridden on +# the command line, e.g. make CC=clang CFLAGS=-O1 +# .PHONY not POSIX - see the FORCE target at the bottom +# target-specific variables, ifeq, wildcard, -include, ... all non-POSIX +# +# Rule syntax used here: recipe lines start with a TAB, macros are written +# $(NAME) (POSIX also accepts ${NAME}), and the only automatic macro used is +# $@, the name of the target. Prerequisite names are written out: $< is POSIX +# for inference rules only, and "$< is the first prerequisite" in a plain rule +# is a GNU extension that even BusyBox make lacks. + +SHELL = /bin/sh + +# Standard macros. POSIX defaults CC to c99; Solo-C uses the system compiler +# driver "cc" instead, which is the compiler a platform actually ships +# (gcc, clang, musl-gcc, ...). Every macro here can be overridden from the +# command line: make CC=clang, make CFLAGS=-O1, make LDLIBS=-lcurl. +CC = cc +CFLAGS = -Wall -Wextra -O2 -std=c99 -march=native +LDFLAGS = +LDLIBS = +LINT = lint +LINTFLAGS = +LINTLIBS = -lc + +# Link-time discovery of the shared dependencies. POSIX make cannot run +# commands while reading a makefile, so the flags are collected by the shell +# that runs the recipe instead of by $(shell ...) while parsing. +PKG_CONFIG = pkg-config +PKGS = libcurl json-c readline +# $$(...) survives expansion of the macro and reaches the shell as $(...). +PKG_CFLAGS = $$($(PKG_CONFIG) --cflags $(PKGS)) +PKG_LIBS = $$($(PKG_CONFIG) --libs $(PKGS)) # Fully static binary. # @@ -21,41 +58,52 @@ LDLIBS = $(shell pkg-config --libs libcurl json-c readline) # # Archive order matters: libcurl.a pulls in ares_* symbols, so libcares.a has to # come after it on the link line. -CURL_STATIC ?= static-deps/libcurl.a -CARES_STATIC ?= static-deps/libcares.a +CURL_STATIC = static-deps/libcurl.a +CARES_STATIC = static-deps/libcares.a STATIC_LIBS = $(CURL_STATIC) $(CARES_STATIC) -lssl -lcrypto -lz -lidn2 -lunistring \ -lreadline -lncursesw -ljson-c -lm -ldl -pthread solo: main.c - $(CC) $(CFLAGS) -o solo main.c $(LDLIBS) - strip solo + $(CC) $(CFLAGS) $(PKG_CFLAGS) $(LDFLAGS) -o $@ main.c $(PKG_LIBS) $(LDLIBS) + strip $@ +# Writes solo-static, not a file called "static", so $@ is not used here. static: main.c @for f in $(CURL_STATIC) $(CARES_STATIC); do \ test -f $$f || { echo "missing $$f - run: make static-deps"; exit 1; }; \ done - $(CC) $(CFLAGS) -fno-lto -static -o solo-static main.c $(STATIC_LIBS) + $(CC) $(CFLAGS) $(LDFLAGS) -fno-lto -static -o solo-static main.c $(STATIC_LIBS) $(LDLIBS) strip solo-static -static-deps: +static-deps: FORCE sh ./mkstaticdeps.sh # Rebuild both archives from scratch, ignoring what is already there. -static-deps-force: +static-deps-force: FORCE FORCE=1 sh ./mkstaticdeps.sh -PREFIX ?= /usr/local +# Install paths. DESTDIR and PREFIX may be set on the command line: +# make install DESTDIR=/tmp/pkg PREFIX=/usr +PREFIX = /usr/local BINDIR = $(PREFIX)/bin -INSTALL ?= install +INSTALL = install -install: solo +install: solo FORCE $(INSTALL) -d $(DESTDIR)$(BINDIR) $(INSTALL) -m 755 solo $(DESTDIR)$(BINDIR)/solo -uninstall: +uninstall: FORCE rm -f $(DESTDIR)$(BINDIR)/solo $(DESTDIR)$(BINDIR)/solo-static -clean: +clean: FORCE rm -f solo solo-static -.PHONY: clean static static-deps static-deps-force install uninstall +# POSIX lint target: runs the lint tool named by the LINT macro. +lint: main.c FORCE + $(LINT) $(LINTFLAGS) $(LINTLIBS) main.c + +# POSIX make has no .PHONY special target. Any target that depends on FORCE is +# always out of date, because FORCE never creates a file, so its recipe always +# runs. Keep this target last: the first target in the file is the default goal. +FORCE: + @: