2022-12-19

Tools: redo (part 3) CFLAGS and friends, config.sh, compile.do

=> #software

Content

=> Part 0: Intro
=> Part 1: Hello, world!
=> 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/

Part 3: How about CFLAGS and friends? config.sh and compile.do

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.

config.sh

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$

config.sh and compile.do

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 < $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!

=> Home

Proxy Information
Original URL
gemini://ew.srht.site/en/2022/20221219-redo-3.gmi
Status Code
Success (20)
Meta
text/gemini
Capsule Response Time
153.782208 milliseconds
Gemini-to-HTML Time
0.891988 milliseconds

This content has been proxied by September (ba2dc).