We are compiling a piece of software using generics where files are first made into object files, they are built like so:
arm-unknown-linux-gnu-gcc -c -O2 -Wstrict-prototypes -Wdeclaration-after-statement -fsigned-char -I/opt/tm-sdk/include -mlittle-endian -Wno-trigraphs -fno-strict-aliasing -fno-omit-frame-pointer -march=armv4 -mtune=arm9tdmi -Wall -Wextra -o src/flex.o src/flex.c
...
arm-unknown-linux-gnu-gcc -c -O2 -Wstrict-prototypes -Wdeclaration-after-statement -fsigned-char -I/opt/tm-sdk/include -mlittle-endian -Wno-trigraphs -fno-strict-aliasing -fno-omit-frame-pointer -march=armv4 -mtune=arm9tdmi -Wall -Wextra -o src/flexdb.o src/flexdb.c
Then they are linked with:
arm-unknown-linux-gnu-gcc -o flex src/flex.o src/flexdb.o src/flexio.o src/flexprotocol.o src/flexsettings.o src/flexstate.o -L/opt/tm-sdk/lib -ltag -lrt -ltmreader -lsqlite3 -lsha1
My questions is:
Do we need to include optimization and warning flags during linking? Would it do anything if -Wall, -Wextra, and -O2 were included when creating the flex binary from the object files?
Edit: Clarifying meaning based on feedback.
Do we need to include optimization and warning flags during this final stage of compilation?
Of course you don't need to include them for the link stage. You already know that, because you don't include them. But I think what you really want to know is ...
Would it do anything if -Wall, -Wextra, and -O2 were included when building the flex binary from object files.
All or almost all warnings are generated during the compilation stage. I don't off-hand know any exceptions, but it's conceivable that there are some. Thus, it's possible that passing warning-related flags during linking would trigger warnings that otherwise you would not receive. But that shouldn't affect the compiled binary in any way.
Optimization is different. There are optimizations that can be performed at link time, but that might not be performed at the default optimization level. Omitting optimization flags from the link command should not break your build, but including them may result in a binary that is faster and / or smaller.
Overall, I see no good reason to avoid passing the same warning and optimization flags during the link step that you do during the compilation steps. If you wish, it's not harmful to pass preprocessor-specific flags (e.g. -D) as well, as they'll just be ignored during linking. I presume that all this is managed by make, so it's not like you actually need to type out the options every time.
NO You're just calling the linker with the final call to gcc and -W and -O flags are for the compiler.
-Wall is primarily a preprocessor option, but there is also a reference for the libraries. See here
-Wextra appears to be strictly a c++ preprocessor option. See here
-O2 is a compiler optimization level setting. See here
So to answer your precise question, only -Wall would possibly help during your link step. The other two would not. You could test this by building with and without these options, seeing if any additional output is created in the case of warnings and if the code size or execution time differed between builds.
Related
A function, before being used, needs to be declared either in a included header or otherwise (though not a good practice). The header file describes the functions and variables that may be found in a library or an object file and the compiler can create (as of yet) unreferenced symbols to be resolved later whilst linking.
However, my compiler (gcc based toolchain called esp-open-sdk (xtensa CPU)) continues despite finding no reference to a function in the headers and only in the linking stage does the linker intimate of an `undefined reference to <-function-name->'.
Another strange behaviour is that the compiler says nothing if there is no return statement, and the function is not "void".
My question is: What is causing this behaviour? I think it's unlikely but is it some compiler flag?
My compiler flags are:
CFLAGS = -Os -g -O2 -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH
and the linker flags are:
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
Probably you use an old version of gcc. Before version 5.x, gcc defaults to a non-standard called "gnu90", which is a non-standard version of the obsolete C90 standard. There is no reason to ever use gnu90 unless you are maintaining some old Linux code. To avoid this, compile with:
-std=c11 -pedantic-errors
-std=c11 meaning you want the compiler to use the current C standard, without involving gnus or other strange animals. -pedantic-errors means that you want it to actually follow the standard and not just pretend to do it.
In order to get the warning for no return from functions, you need to use the option -Wreturn-type, which is included by using -Wall. Always compile with
-Wall -Wextra
Note that "Wall" does not stand for "all warnings", as it leads you to believe. Rather, -Wall means a fistful of warnings and -Wextra means a few warnings more.
In my makefile for a C project, I have set the CFLAGS variable as follows -
CFLAGS=-ansi -pedantic -Wall -Wextra -O2 -isystem $(SQLITEDIR)
I expected this variable to be used in the rule for building object files since the flags affect the compilation step
However, in the GNU make manual
https://www.gnu.org/software/make/manual/make.html#Using-Implicit
I see the following example -
foo : foo.o bar.o
cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
I think this is a rule for the linking step so I understand it why it include LDFLAGS, but what is the purpose CFLAGS here?
(I am guessing that you are using GNU make on some Linux system)
You are right in your use of CFLAGS (but I would add -g there). But I am not sure you need -isystem $(SQLITEDIR), it probably can be -I $(SQLITEDIR) instead. The -isystem directory option to GCC is rarely useful.
Read first the documentation about Invoking GCC, assuming you are using the GCC compiler. BTW, you could have CC= gcc in your Makefile. If your compiler is not GCC but something else (e.g. Clang/LLVM) read its documentation.
Then, run make -p to understand the builtin rules of your GNU make (there are many of them). You'll find out that many builtin rules are using CFLAGS etc. And that is why it is simpler to have a CFLAGS variable in your Makefile; if possible, take advantage of some builtin rules known to make.
BTW, you could avoid using any builtin rules and variables, but that is poor taste.
The POSIX standard defines some options understood by cc and by make (and some minimal rules for make). Both GCC and GNU make have much more. Read documentation of GNU make.
CFLAGS usually contain some (optimization or other) flags (e.g. -O or -g, or -pthread) which are also relevant at the linking step (assuming you link with gcc, which will invoke ld). That is why you usually link using gcc (as $(CC) in your recipe) with both LDFLAGS and CFLAGS.
You could use make --trace or even remake (as remake -x) to debug your Makefile.
I have some warning when compiling a piece of code using pthread_cleanup_push/pop with -O2 CFLAGS. Just by removing the O2 cflags in the Makefile make it compile without issue.
Is it forbidden to use gcc optimization with these pthread macros ? I was not able to find anything in man or documentation. By the way, is there any alternative to clean stuff at the end of a thread ? Also it is working perfectly with gcc arm. But not on x86 gcc.
Warning :
x/x.c:1292:2: warning: variable ‘__cancel_routine’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Wclobbered]
pthread_cleanup_push(x_cleanup, &fd);
My current CFLAGS option :
-W -Wall -Wformat -Wformat-security -Wextra -Wno-unused-result,
-Wextra -Wno-long-long -Wno-variadic-macros -Wno-missing-field-initializers
-std=gnu99 -O2
This issue has been reported several times now in GCC tracker (see here). I believe that this warns about real issue in pthread.h (see my comment). __cancel_routine is not marked as volatile so it's value is indeed undefined after return via longjmp which may cause arbitrary consequences.
The only solution is to remove the Werror until a fix ?
I'd rather go with -Wno-clobbered, to keep other warnings enabled.
Roll back on a previous version of gcc on x86 ?
You'll have to rollback to pre-2014 times which is quite a change... I think that if the code works for you, just disable -Wclobbered (with a descriptive comment).
But I did want to be sure that its was not a bigger issue which can cause unexpected behavior of my code or bugs.
Glibc code looks really suspicious. I'd wait for comments from GCC devs and if there is none, report this to Glibc developers.
If I call the GCC Linker with the option -nostdlib does this override any manual/explicit appendecis of standardlibs?
GCC is 4.8.1 from MinGW.
Example:
gcc -nostdlib [MyObjectsAndLibraries] -lmsvcrt -o Outfile
Since libmsvcrt is a standard library, will it be added to the link process or will it be ignored? I can't find any reliable data on this., this is why I would also appreciate some kind of source to this.
In this context, "standard libraries" means the libraries that gcc would implicitely link by default. Libraries explicitely mentioned on the command line will always be linked. In fact, gcc documentation at http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Link-Options.html#Link-Options even points out that unless you really know what you're doing you should add explicitely -lgcc when using -nostdlib, as the compiler may rely on some builtins defined in it:
In other words, when you specify -nostdlib or -nodefaultlibs you should usually specify -lgcc as well. This ensures that you have no unresolved references to internal GCC library subroutines.
Since I found this on Google,
#Virgile's answer is enough, but you may run into linker errors when you link with the style of command you gave. There is two steps to program building: compile and link. You can use GCC to do one or the other or both at the same time.
It is important to note the order of which you specify things. In your build, it may be problematic because your exe never gets linked with msvcrt or gcc. Including two libraries which have potentially the same symbols is also very bad.
Here is canonical build and link statements
gcc -g0 -O2 -Wall -nostdlib -c *.c
gcc -g0 -O2 -Wall -nostdlib -o a.exe *.o -lmsvcrt -lgcc
gcc -g0 -O2 -Wall -nostdlib -o a.exe *.c -lmsvcrt -lgcc
Here is a good reference
https://stackoverflow.com/a/18389266/2262111
If I want to minimize the time my c programs run, what optimization flags should I use (I want to keep it standard too)
Currently I'm using:
-Wall -Wextra -pedantic -ansi -O3
Should I also use
-std=c99
for example?
And is there I specific order I should put those flags on my makefile? Does it make any difference?
And also, is there any reason not to use all the optimization flags I can find? do they ever counter eachother or something like that?
I'd recommend compiling new code with -std=gnu11, or -std=c11 if needed. Silencing all -Wall warnings is usually a good idea, IIRC. -Wextra warns for some things you might not want to change.
A good way to check how something compiles is to look at the compiler asm output. http://gcc.godbolt.org/ formats the asm output nicely (stripping out the noise). Putting some key functions up there and looking at what different compiler versions do is useful if you understand asm at all.
Use a new compiler version. gcc and clang have both improved significantly in newer versions. gcc 5.3 and clang 3.8 are the current releases. gcc5 makes noticeably better code than gcc 4.9.3 in some cases.
If you only need the binary to run on your own machine, you should use -O3 -march=native.
If you need the binary to run on other machines, choose the baseline for instruction-set extensions with stuff like -mssse3 -mpopcnt. You can use -mtune=haswell to optimize for Haswell even while making code that still runs on older CPUs (as determined by -march).
If your program doesn't depend on strict FP rounding behaviour, use -ffast-math. If it does, you can usually still use -fno-math-errno and stuff like that, without enabling -funsafe-math-optimizations. Some FP code can get big speedups from fast-math, like auto-vectorization.
If you can usefully do a test-run of your program that exercises most of the code paths that need to be optimized for a real run, then use profile-directed optimization:
gcc -fprofile-generate -Wall -Wextra -std=gnu11 -O3 -ffast-math -march=native -fwhole-program *.c -o my_program
./my_program -option1 < test_input1
./my_program -option2 < test_input2
gcc -fprofile-use -Wall -Wextra -std=gnu11 -O3 -ffast-math -march=native -fwhole-program *.c -o my_program
-fprofile-use enables -funroll-loops, since it has enough information to decide when to actually unroll. Unrolling loops all over the place can make things worse. However, it's worth trying -funroll-loops to see if it helps.
If your test runs don't cover all the code paths, then some important ones will be marked as "cold" and optimized less.
-O3 enables auto-vectorization, which -O2 doesn't. This can give big speedups
-fwhole-program allows cross-file inlining, but only works when you put all the source files on one gcc command-line. -flto is another way to get the same effect. (Link-Time Optimization). clang supports -flto but not -fwhole-program.
-fomit-frame-pointer has been the default for a while now for x86-64, and more recently for x86 (32bit).
As well as gcc, try compiling your program with clang. Clang sometimes makes better code than gcc, sometimes worse. Try both and benchmark.
The flag -std=c99 does not change the optimization levels. It only changes what target language standard you want the compiler to confirm to.
You use -std=c99 when you want your program to be treated as a C99 program by the compiler.
The only flag that has to do with optimization among those you specified is -O3. Others serve for other purposes.
You may want to add -funroll-loops and -fomit-frame-pointer, but they should be already included in -O3.