Part 2: Automatic Recording of Dependencies on Header Files
Part 3: CFLAGS and friends, config.sh, compile.do
Part 4: CFLAGS and friends, env/VAR, default.run.do
Part 5: Auto-update BUILDDATE in version.h
Part 6: The yacc/bison problem: one call produces two artifacts
Part 7: Test: Generator for N source files
My code featured in this series can be found at
https://git.sr.ht/~ew/ew.redo/
Of course I was wondering, how to deal with our old friends like CFLAGS and their kin. Looking into the documentation and projects using redo, I came up with two possible solutions --- there are more, of course.
Our friends the make variables convert to shell variables and are living in a shell script named config.sh
# config.sh --- define/set used variables CC="gcc" CFLAGS="-O2 -g -Wpedantic -Wall"
This file is being sourced (evaluated) in order to make their values known before calling gcc. So we change default.o.do accordingly:
# default.o.do redo-ifchange config.sh $2.c source ./config.sh ${CC} ${CFLAGS} -MMD -MF $2.d -o $3 -c $2.c read DEPS <$2.d redo-ifchange ${DEPS#*:}
Calling redo in verbose mode will show, that config.sh is indeed sourced.
shell$ redo clean ; redo -xx all redo clean (0.002s) + redo-ifchange hello + OBJS='hello.o resources.o' + redo-ifchange hello.o resources.o + redo-ifchange config.sh hello.c + redo-ifchange config.sh resources.c + source ./config.sh ++ CC=gcc ++ CFLAGS='-O3 -g -Wpedantic -Wall' + gcc -O3 -g -Wpedantic -Wall -MMD -MF hello.d -o .redo.hello.o.2613144615.3 -c hello.c + read DEPS + redo-ifchange hello.c resources.h + source ./config.sh ++ CC=gcc ++ CFLAGS='-O3 -g -Wpedantic -Wall' + gcc -O3 -g -Wpedantic -Wall -MMD -MF resources.d -o .redo.resources.o.1407379196.3 -c resources.c + read DEPS + redo-ifchange resources.c redo . . hello.o (default.o.do) (0.045s) redo . . resources.o (default.o.do) (0.049s) + gcc -o .redo.hello.309219992.3 hello.o resources.o redo . hello (0.084s) redo all (0.097s) shell$ grep CFLAGS config.sh CFLAGS="-O3 -g -Wpedantic -Wall" shell$ # edit config.sh shell$ grep CFLAGS config.sh CFLAGS="-O2 -g -Wpedantic -Wall" shell$ redo -xx all + redo-ifchange hello + OBJS='hello.o resources.o' + redo-ifchange hello.o resources.o + redo-ifchange config.sh hello.c + redo-ifchange config.sh resources.c + source ./config.sh ++ CC=gcc ++ CFLAGS='-O2 -g -Wpedantic -Wall' + gcc -O2 -g -Wpedantic -Wall -MMD -MF hello.d -o .redo.hello.o.2777614334.3 -c hello.c + read DEPS + redo-ifchange hello.c resources.h + source ./config.sh ++ CC=gcc ++ CFLAGS='-O2 -g -Wpedantic -Wall' + gcc -O2 -g -Wpedantic -Wall -MMD -MF resources.d -o .redo.resources.o.3139069011.3 -c resources.c + read DEPS + redo-ifchange resources.c redo . . hello.o (default.o.do) (0.048s) redo . . resources.o (default.o.do) (0.053s) + gcc -o .redo.hello.2275538568.3 hello.o resources.o redo . hello (0.087s) redo all (0.099s) shell$ redo -xx all + redo-ifchange hello redo all (0.004s) shell$
While this works, it is fairly obvious that "source config.sh" is being run every single time, the commands in default.o.do are executed. And it might not work with every shell or environment, even if source is replaced by a dot '.'.
In order to avoid, that CFLAGS and friends are evaluated more often than absolutely needed, one can produce a compile script from a template. There are variables in the template, and they are expanded to create the script only once per build. The script itself does not have variables any more. So this is the plan:
# compile.do redo-ifchange config.sh . ./config.sh touch $3 && chmod ug+x $3 && \ cat <<EOF > $3 ${CC} ${CFLAGS} -c -MMD -MF \$2.d -o \$3 \$2.c read DEPS < \$2.d redo-ifchange \${DEPS#*:} EOF
This is a short, but not a particularly nice script. You must watch the quoting at all times. The output of this script is captured as compile.
shell$ redo -xx compile + redo-ifchange config.sh + . ./config.sh ++ CC=gcc ++ CFLAGS='-O2 -g -Wpedantic -Wall' + touch .redo.compile.3766532193.3 + chmod ug+x .redo.compile.3766532193.3 + cat redo compile (0.012s) shell$ cat compile gcc -O2 -g -Wpedantic -Wall -c -MMD -MF $2.d -o $3 $2.c read DEPS < $2.d redo-ifchange ${DEPS#*:}
So one more change is needed, call the freshly generated script in default.o.do:
# default.o.do -*-shell-script-*- # - all magic commands are hidden in generated script ./compile via ./compile.do redo-ifchange compile $2.c ./compile $1 $2 $3
Calling redo to build everything from scratch works as expected:
shell$ redo clean; redo -xx all redo clean (0.002s) + redo-ifchange hello + OBJS='hello.o resources.o' + redo-ifchange hello.o resources.o + redo-ifchange compile hello.c + redo-ifchange compile resources.c + redo-ifchange config.sh + . ./config.sh ++ CC=gcc ++ CFLAGS='-O2 -g -Wpedantic -Wall' + touch .redo.compile.1615745472.3 + chmod ug+x .redo.compile.1615745472.3 + cat redo . . . compile (0.007s) + ./compile hello.o hello .redo.hello.o.2194970874.3 + ./compile resources.o resources .redo.resources.o.3986075340.3 redo . . hello.o (default.o.do) (0.062s) redo . . resources.o (default.o.do) (0.067s) + gcc -o .redo.hello.2517927474.3 hello.o resources.o redo . hello (0.103s) redo all (0.115s) shell$ ./hello Hello, world!