A colleague recently asked me whether or not I would recommend using CMake for a project that needed to target multiple architectures. While I appreciate that his instinct was not to reach for Autotools, I think CMake falls firmly in the same category as Autotools (though, to be fair, you're only introducing one new problem rather than four).
As an example, I present a complete Makefile to build cat on every platform for which Debian packages a GCC cross compiler. I know, cat is not a particularly interesting program, but the focus is on the Makefile.
.POSIX:
ARCHES= \
aarch64-linux-gnu \
arm-linux-gnueabi \
arm-linux-gnueabihf \
i686-linux-gnu \
mips-linux-gnu \
mips64el-linux-gnuabi64 \
mipsel-linux-gnu \
powerpc-linux-gnu \
powerpc64le-linux-gnu \
s390x-linux-gnu \
x86_64-linux-gnu
CC=$(ARCH)-gcc
all:
for i in $(ARCHES); do make ARCH=$$i $$i; done
$(ARCH): $(ARCH)/cat
$(ARCH)/cat: $(ARCH)/cat.o
$(CC) $(LDFLAGS) -s -o $@ $(ARCH)/cat.o
$(ARCH)/cat.o: cat.c
mkdir -p $(ARCH)
$(CC) $(CFLAGS) -c cat.c -o $@
This will cause make
to loop through all the available architectures, outputting object files and linked binaries into a directory named for the target.
There's really no magic involved, though I understand that specifying a target that includes a macro name might seem so. Basically, the default target (all
) executes a loop through the list of targets in $(ARCHES)
, setting ARCH
to that target and building that same target (e.g. make ARCH=aarch64-linux-gnu aarch64-linux-gnu
). This causes the $(ARCH)
macro in each of the other targets to be replaced (in this case with aarch64-linux-gnu
). The substitution also happens in the prerequisites and rules. So, on the first iteration, the child make
process seems something more like (unchanged portions omitted for clarity):
.POSIX:
CC=aarch64-linux-gnu-gcc
aarch64-linux-gnu: aarch64-linux-gnu/cat
aarch64-linux-gnu/cat: aarch64-linux-gnu/cat.o
$(CC) $(LDFLAGS) -s -o $@ aarch64-linux-gnu/cat.o
aarch64-linux-gnu/cat.o: cat.c
mkdir -p aarch64-linux-gnu
$(CC) $(CFLAGS) -c cat.c -o $@
This continues for each of the other architectures listed under ARCHES
.
If you prefer to use Clang to GCC (and I won't blame you if you do), just change the CC
macro:
CC=clang -triple $(ARCH)
Copyright © 2019 Jakob Kaivo <jakob@kaivo.net>