I am getting a really odd error from GCC 4.8.1 with inline functions.
I have two near-identical inline functions defined in header files (debug.h and error.h) in src/include/, with the only difference being what they print - one prefixes DEBUG: to the message, and the other %s: error: %s (program name, error message). When defining the functions both inline, and compiling a debug build (so it sets the macro DEBUG=1), I get lots of undefined reference errors:
src/main_debug.o
gcc -osrc/main_debug.o src/main.c -c -Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g -DCC="\"gcc\"" -DCFLAGS="\"-Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g\"" -DDEBUG=1 -DBTCWATCH_VERSION="\"0.0.1\""
src/lib/btcapi_debug.o
gcc -osrc/lib/btcapi_debug.o src/lib/btcapi.c -c -Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g -DCC="\"gcc\"" -DCFLAGS="\"-Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g\"" -DDEBUG=1
src/lib/libbtcapi_debug.a
ar rc src/lib/libbtcapi_debug.a src/lib/btcapi_debug.o
ranlib src/lib/libbtcapi_debug.a
src/lib/cmdlineutils_debug.o
gcc -o src/lib/cmdlineutils_debug.o src/lib/cmdlineutils.c -c -Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g -DCC="\"gcc\"" -DCFLAGS="\"-Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g\"" -DDEBUG=1
src/lib/libcmdlineutils_debug.a
ar rc src/lib/libcmdlineutils_debug.a src/lib/cmdlineutils_debug.o
ranlib src/lib/libcmdlineutils_debug.a
debug
gcc -obtcwatch-debug src/main_debug.o -Lsrc/lib/ -lbtcapi_debug -lcmdlineutils_debug -lcurl -ljansson
src/main_debug.o: In function `main':
/home/marcoms/btcwatch/src/main.c:148: undefined reference to `debug'
src/main_debug.o:/home/marcoms/btcwatch/src/main.c:185: more undefined references to `debug' follow
collect2: error: ld returned 1 exit status
make: *** [debug] Error 1
But changing debug()'s definition to static inline removes the errors. But I have never received any errors from error()'s definition, although its defenition is inline, and not static inline.
The definitions are all in headers (i.e. not prototyped)
According to the manual, passing -std=gnu11 enables C99 instead of GNU inline semantics.
This means inline, static inline and extern inline all behave differently. In particular, inline expects an external definition in a separate translation unit (which you can provide without duplicating the definition - see this answer).
Related
I created the following makefile:
assembler: main.o first_pass.o second_pass.o helpers.o data_array.o symbol_table.o
gcc -Wall -ansi -pedantic main.o first_pass.o second_pass.o helpers.o data_array.o symbol_table.o -o assembler
main.o: main.c header.h
gcc -Wall -ansi -pedantic main.c -o main.o
first_pass.o: first_pass.c header.h
gcc -Wall -ansi -pedantic first_pass.c -o first_pass.o
second_pass.o: second_pass.c header.h
gcc -Wall -ansi -pedantic second_pass.c -o second_pass.o
helpers.o: helpers.c header.h data.h
gcc -Wall -ansi -pedantic helpers.c -o helpers.o
data_array.o: data_array.c header.h data.h
gcc -Wall -ansi -pedantic data_array.c -o data_array.o
symbol_table.o: symbol_table.c header.h data.h
gcc -Wall -ansi -pedantic symbol_table.c -o symbol_table.o
In my 'main.c' file I have #include "header.h". Where in 'header.h' I have the declarations of all the functions.
But I receive the following error:
gcc -Wall -ansi -pedantic main.c -o main.o
/tmp/cc3dP7hx.o: In function `main':
main.c:(.text+0x257): undefined reference to `first_pass`
main.c:(.text+0x2e4): undefined reference to `second_pass'
main.c:(.text+0x37f): undefined reference to build_obj_file
main.c:(.text+0x3a9): undefined reference to build_ent_file
main.c:(.text+0x427): undefined reference to free_all_data
main.c:(.text+0x436): undefined reference to free_all_symbols
main.c:(.text+0x44d): undefined reference to free_all_words
collect2: error: ld returned 1 exit status
makefile:4: recipe for target 'main.o' failed
make: *** [main.o] Error 1
The problem is that your command doesn't create object files, but attempt to build executable programs:
gcc -Wall -ansi -pedantic main.c -o main.o
You need the -c option to create object files:
gcc -Wall -pedantic main.c -c -o main.o
A better idea would be to rely on the make implicit rules so you don't have to explicitly list all commands:
CC = gcc
LD = gcc
CFLAGS = -Wall -pedantic
LDFLAGS =
assembler: main.o first_pass.o second_pass.o helpers.o data_array.o symbol_table.o
You might want to add rules for the header-file dependencies, or figure out some way to auto-generate them (it's possible). Other than that the above Makefile should be enough to build all object files and then link them together into the assembler executable program.
Note that I have removed the -ansi flag, as it's mostly obsolete these days.
I am currently attempting problem set 4 (speller) from the CS50 course. It is the first problem set where we have multiple header files and multiple source files, so they gave us a Makefile to use, to compile each .c file into .o, then link the .o files to form the compiled binary.
This is the makefile
speller:
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o speller.o speller.c
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o dictionary.o dictionary.c
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -o speller speller.o dictionary.o
Output of ls:
dictionaries dictionary.h keys speller speller.o dictionary.c dictionary.o Makefile speller.c texts
When I run make for the first time, it compiles speller no problems. However, when I make changes in dictionary.c and save it (In particular, I purposely screwed up all my printf() calls to printasdasdsa() yeah you get it) and I run make, it keeps saying make: 'speller' is up to date, and just refuses to rebuild even though I made changes to dictionary.c's source.
Any idea what's wrong with the way I'm building speller? Is there something wrong with my makefile?
I know that there's a way to force make to rebuild by passing the "-B" flag, but is it convention to always do it that way whenever you make a change in your code?
This is the task: https://docs.cs50.net/2019/x/psets/4/speller/hashtable/speller.html
Make only rebuilds a target if the target does not exist, or the target is older than one of its dependencies. In your case you have a target speller, with no dependencies. The first time you run it, make checks, and doesn't find it, so it builds it. The next time you build, it checks, the file exists, and since it does not have any dependencies, it does not rebuild. You would want to do something like:
speller: speller.c dictionary.c
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o speller.o speller.c
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o dictionary.o dictionary.c
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -o speller speller.o dictionary.o
Or, better yet:
speller: speller.o dictionary.o
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -o speller speller.o dictionary.o
speller.o: speller.c
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o speller.o speller.c
dictionary.o: dictionary.c
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o dictionary.o dictionary.c
Which would not rebuild the .o files unless the .c files changed, and would not rebuild the app unless one of the .o files was rebuilt. Note that neither of these two handle any header files. If your .c files include any local headers, those need to be added to the dependencies as well.
#HardcoreHenry explains make's behavior very well in his answer (do not accept this one over that). I want to point out, however, that make has a fair amount of built-in smarts about building software, to the extent that it can do relatively simple builds without any Makefile at all. Moreover, when you do write a Makefile, it is usually considered good style to minimize repetition.
Thus, I'd suggest this as an even better alternative:
CC = clang
CFLAGS = -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 \
-Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare \
-Wno-unused-parameter -Wno-unused-variable -Wshadow
speller: speller.o dictionary.o
$(CC) -o $# $(CFLAGS) speller.o dictionary.o
That relies on make knowing how to build object files from C source files (which it does) and using the C compiler and and flags specified by the CC and CFLAGS variables when it does so (which it will). It also uses the special variable $#, which, in a rule's recipe, expands to the name of the rule's target. Some versions of make offer even a bit more opportunity to DRY this out.
Among other things, note how the compiler and build flags are specified once each, and near the top. Now if you ever want to change those, you can do it in one easy-to-find place.
You need to add dependencies. When using GNU make, you can skip the .o step for small projects and compile the program as a whole
speller: speller.c dictionary.c
${CLANG} ${CFLAGS} ${LDFLAGS} $(filter %.c,$^) -o $# ${LIBS}
I can successfully compile Nginx with the following variables in the makefile
CC = clang-6.0
CFLAGS = -pipe -O -Wall -Wextra -Wpointer-arith -Wconditional-uninitialized -Wno-unused-parameter -Werror -g
When attempting to use -fsanitize=fuzzer or -fsanitize=fuzzer-no-link and changing my Makefile to:
CFLAGS = -pipe -fsantizer=fuzzer-no-link -O -Wall -Wextra -Wpointer-arith -Wconditional-uninitialized -Wno-unused-parameter -Werror -g
I get numerous undefined references to __sancov_lowest_stack and to __sanitizer_cov_trace_const_cmp8
How would I fix this? Which libraries am I missing?
You have to add sanitizer flags like -fsanitize=fuzzer to your CFLAGS and your LDFLAGS.
If they aren't passed to the linker but just to the compiler you get tons of undefined symbol errors for sanitizer runtime library functions (like the one you quoted in your question).
Note that when using -fsanitizer=fuzzer it makes sense to combine it with the Adress Sanitizer (i.e. -fsanitizer=fuzzer,address).
Also, with libFuzzer, you have to provide your own fuzzer callback function LLVMFuzzerTestOneInput() and omit a main() function.
You need to link against honggfuzz/libhfuzz/libhfuzz.a.
For some reason, when calling certain functions for which I have not included the appropriate header file, I do not always get a compile-time "function is not declared / defined" error. It's a real source of headaches. Most recently, calling glfwGetTime() returned zero when the header was not included, but correct values when it was, wasting a lot of debugging time.
I've noticed that when compiling same code under Linux / native GCC, these tend to be caught.
Here are my compiler options:
CFLAGS = -I$(LIBDIR) $(INCLUDES) -std=c11 -m$(BITS) -fms-extensions -fopenmp -Wall -Wextra -Wimplicit-function-declaration -Werror -Wmissing-prototypes -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wlogical-op -Wcast-align -Wconversion -Wpedantic -Wfloat-equal -w -O0 -MMD
Any ideas why these aren't being caught at compile? P.S. This is NOT related to printf().
I am getting a really odd error from GCC 4.8.1 with inline functions.
I have two near-identical inline functions defined in header files (debug.h and error.h) in src/include/, with the only difference being what they print - one prefixes DEBUG: to the message, and the other %s: error: %s (program name, error message). When defining the functions both inline, and compiling a debug build (so it sets the macro DEBUG=1), I get lots of undefined reference errors:
src/main_debug.o
gcc -osrc/main_debug.o src/main.c -c -Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g -DCC="\"gcc\"" -DCFLAGS="\"-Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g\"" -DDEBUG=1 -DBTCWATCH_VERSION="\"0.0.1\""
src/lib/btcapi_debug.o
gcc -osrc/lib/btcapi_debug.o src/lib/btcapi.c -c -Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g -DCC="\"gcc\"" -DCFLAGS="\"-Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g\"" -DDEBUG=1
src/lib/libbtcapi_debug.a
ar rc src/lib/libbtcapi_debug.a src/lib/btcapi_debug.o
ranlib src/lib/libbtcapi_debug.a
src/lib/cmdlineutils_debug.o
gcc -o src/lib/cmdlineutils_debug.o src/lib/cmdlineutils.c -c -Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g -DCC="\"gcc\"" -DCFLAGS="\"-Wall -Wextra -Wpedantic -std=gnu11 -march=native -Og -g\"" -DDEBUG=1
src/lib/libcmdlineutils_debug.a
ar rc src/lib/libcmdlineutils_debug.a src/lib/cmdlineutils_debug.o
ranlib src/lib/libcmdlineutils_debug.a
debug
gcc -obtcwatch-debug src/main_debug.o -Lsrc/lib/ -lbtcapi_debug -lcmdlineutils_debug -lcurl -ljansson
src/main_debug.o: In function `main':
/home/marcoms/btcwatch/src/main.c:148: undefined reference to `debug'
src/main_debug.o:/home/marcoms/btcwatch/src/main.c:185: more undefined references to `debug' follow
collect2: error: ld returned 1 exit status
make: *** [debug] Error 1
But changing debug()'s definition to static inline removes the errors. But I have never received any errors from error()'s definition, although its defenition is inline, and not static inline.
The definitions are all in headers (i.e. not prototyped)
According to the manual, passing -std=gnu11 enables C99 instead of GNU inline semantics.
This means inline, static inline and extern inline all behave differently. In particular, inline expects an external definition in a separate translation unit (which you can provide without duplicating the definition - see this answer).