Ex29 Linking failure

So I got the original ex29 — where Zed shows us each individual step of the compilation process — working. I’m trying to tackle the extra credit now, where we use the skeleton directory. I copied libex29.c and ex29.c in the directories specified and changed the TARGET variable to build/libex29.a. Then I ran make and got a bunch of linking errors. Looking in the Makefile, I found that the LIBS variable is never used, which explains those. Where do I put it so that the linker does its job? I tried putting it in various positions among the CFLAGS, to no success.

Hmm for the linker I think I got a few of those variables wrong as they changed over time:

https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html

That should be base environment variables, then:

http://man7.org/linux/man-pages/man8/ld.so.8.html

Controls others, but this is in a Makefile so:

https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html

I believe you want either LDLIBS, LDFLAGS. Let me know if that’s what you’re looking for.

Ah, LDLIBS did the trick. LDFLAGS, however, failed with the same linker errors as LIBS. Now it just fails because I have to fill out the tests

Still, I see that LDLIBS is never explicitly used. Is that just one of those implied dependencies you mentioned in the Ex2 video?

Yes, Make tries to figure a lot of this out for you automatically, and I remember that you set LIBS but I think either I remembered wrong or it changed. Probably a combination of them.

I have a basic understanding of *nix shell scripting, but how does this line of runtests.sh work:

if $VALGRIND ./$i 2>> tests/tests.log

I know that

./$i 2>> tests/tests.log

will run each executable in tests/ whose filename ends in _tests and redirect error messages to the log file, but how does this line constitute a valid test for the if statement?

Valgrind “returns” an exit code which you can test for truth or falsity.

@florian is close, but it’s doing one more thing. If you have the VALGRIND variable set, then $VALGRIND gets replaced by the executable for valgrind, otherwise it’s empty. The if will then fail for a valgrind fail, or a test fail, and only run valgrind if you set it.

Now, the part I’m not clear on is whether this is parsed as:

if $VALGRIND
then
    ./$i 2>> tests/tests.log
fi

Or, I think it’s actually this (which is why it works):

if $VALGRIND ./$i
then
    # empty
fi 2>> tests/tests.log

I wrote that so long ago I actually don’t remember, but I’m pretty sure it’s #2.

A free service run by Zed A. Shaw for learncodethehardway.org.