Single-command compile and link fails, separate steps work - linker

While I was trying to solve a linker problem with g++, I found that trying to compile link a simple one-file program in one command was failing, due to undefined symbols.
g++ -lEGL -lGLESv2 -o test test.cpp
However, if I compiled test.cpp separately, and then linked as a second step, everything works OK.
g++ -c test.cpp
g++ -o test test.o -lGL -lGLESv2
What's the difference between the first command and the others, and why would one way fail and the other way work? I'm guessing it's something to do with the order of linking, but I get the feeling that this is a little buggy.

When you compile and link in one go, as per:
g++ -lEGL -lGLESv2 -o test test.cpp
g++ obeys as if you did:
g++ -c -o deleteme.o test.cpp
g++ -lEGL -lGLESv2 -o test deleteme.o
rm deleteme.o
(If you run the command with the -v (verbose) option and scrutinize the
goobledegook carefully, you'll be able to spot the distinct invocations
of the compiler, assembler, and linker, with temporary files passed between).
So now do you see what's wrong? It's library search order. In the linkage:
g++ -lEGL -lGLESv2 -o test deleteme.o
You are telling the linker to search libEGL and libGLESv2 for unresolved symbols
before reading the object file, deleteme.o that requires symbols from them, so those symbols
will go unresolved. In your second linkage:
g++ -o test test.o -lGL -lGLESv2
You've got the linkage order right. There's nothing buggy here. From man ld
The linker will search an archive only once, at the location where
it is specified on the command line. If the archive defines a
symbol which was undefined in some object which appeared before the
archive on the command line, the linker will include the
appropriate file(s) from the archive. However, an undefined symbol
in an object appearing later on the command line will not cause the
linker to search the archive again.

Related

C Link External Library in Makefile

I am having issues linking a library (termbox) when compiling. I get the error:
make: *** No rule to make target `termbox.h', needed by `test.o'. Stop.
Makefile:
edit: test.o
gcc -Wall -o edit test.o
test.o: test.c termbox/src/termbox.h
gcc -Wall -c test.c -ltermbox/src
Include:
#include "termbox/src/termbox.h"
I have also tried using the compiled library but ran into similar issues. Do I have to use some sort of combination of specifying the header file and the location of the compiled library?
The directory of my termbox folder is in the same directory as test.c.
Thanks!
You have managed to compile and include the header file for the library, but you did not yet tell the compiler where the code (definitions) are - i.e. you did not tell it to link in the library yet.
You will need to do that next, this is done in a similar way to telling the linker what files to link, but with some extra syntax. It appears to be a static library (.a suffix) so you can link like this:
test.o: test.c termbox/src/termbox.h
gcc -Wall -c test.c -Itermbox/src -Lsrc -ltermbox
Where -L... specifies where libraries can be found and -l... specifies the library name to link to minus the lib prefix and the .a or .so suffix. Also note that order is important, so leave the library linkage at the end.
More on library linking order here
UPDATE
Sorry I added the linking to the wrong line! - here is the updated answer:
# The linker stage
edit: test.o
gcc -Wall -o edit test.o -Lsrc -ltermbox
# Compile stage
test.o: test.c termbox/src/termbox.h
gcc -Wall -c test.c -ltermbox/src

gcc in Windows cannot compile C program written for Unix/Linux

I am a Unix/Linux newbie who is trying to run a shell script written by a person who left no documentation and has since demised. This script contains line:
./search $opt1 $arg1 < $poly 2>&1 | tee $output
Which is trying to get the file $poly and call program ./search and divert the output to $output.
When I get to this line, I am given message: ./search: cannot execute binary file: Exec format error
search is a C program called from the script and is in the same folder as various other C programs to do with this project. Script and C programs were developed and originally executed on a Unix/Linux box which is no longer available, so I have been asked to try to resurrect this project but under Windows using gcc in NetBeans and cygwin.
The message : ./search: cannot execute binary file: Exec format error is most likely to do with the fact there is no executable file for search. When I try to build the C programs I get the following output:
C:\cygwin64\bin\make.exe -f Makefile
gcc -ansi -g -c cbuild.c
gcc -ansi -g -c complex.c
gcc -ansi -g -c mylib.c
gcc -ansi -g -c poly.c
gcc -ansi -g -c real.c
gcc -ansi -g -c zero.c
gcc -lgmp -lm -lrt -o cbuild cbuild.o complex.o mylib.o poly.o real.o zero.o
real.o: In function `rabs':
/cygdrive/c/../progs/real.c:9: undefined reference to `__imp___gmpf_abs'
/cygdrive/c/../progs/real.c:9:(.text+0x1e): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `__imp___gmpf_abs'
real.o: In function `radd':
I assume that R_X86_64_PC32 refers to the environment I am using. I am using a 64 bit version of Netbeans with gcc 5.4.0 in a 64 bit version of cygwin on Windows 10.
Can anyone advise what I must to to resolve this so that I can build the C programs?
The problem is this:
gcc -lgmp -lm -lrt -o cbuild cbuild.o complex.o mylib.o poly.o real.o zero.o
By default, the linker will link libraries and objects in the order specified on the command line, and, when linking a library, will only include symbols needed by things before it on the command line. Since -lgmp is first, there are (as yet) no outstanding symbols (except main), so nothing is included from the library. When later objects need the symbols from it, they won't see them.
Change the order to
gcc -o cbuild cbuild.o complex.o mylib.o poly.o real.o zero.o -lgmp -lm -lrt
and it should work. Alternately, use the -Wl,--as_needed linker option to get the linker to remember earlier libraries and relink them if more symbols from them are referenced by later object files (requires a recent version of the GNU linker -- I have no idea if it works with cygwin).
This kind of misordering is usually a symptom of a broken Makefile. The normal Makefile structure has a bunch of variables that are set to control the default rules that know how to compile source files and link object files. The two variables relevant for linking are LDFLAGS and LDLIBS, and the difference is that LDFLAGS comes before all the object files on the command line and LDLIBS comes after all the object files.
So in order to make things work, you need to ensure that all of the -l options and other libraries are in LDLIBS:
LDLIBS = -lgmp -lrt -lm
and NOT in LDFLAGS

How to compile an executable using clang and safe-stack flag

I am trying to compile a simple hello-world executable using clang-3.7 (also tried 3.8 (dev)) with -fsanitize=safe-stack flag. As explained here (http://clang.llvm.org/docs/SafeStack.html), I need to pass this flag to compiler and linker.
"To enable SafeStack, just pass -fsanitize=safe-stack flag to both compile and link command lines."
I tried the following command to compile an executable:
clang-3.7 -fsanitize=safe-stack -o a.out -Wl,-fsanitize=safe-stack test.c
But the linker tells me, that i need to compile it as a shared library (-shared), if I pass the -f flag to the linker.
/usr/bin/ld: -f may not be used without -shared
How can I compile an executable using the -fsanitize=safe-stack flag?
By "pass it to both the compile and link command lines" the documentation means to pass it both when you're compiling, and when you're linking. It does not mean to use -Wl, which passes it straight through to the linker - -f means something entirely unrelated to the linker.
In this case,
clang-3.7 -fsanitize=safe-stack -o a.out test.c
is sufficient. If you were using separate command executions to compile and link, you would need to pass it on both:
clang-3.7 -fsanitize=safe-stack -c -o test.o test.c
clang-3.7 -fsanitize=safe-stack -o a.out test.o

Error "undefined reference" while linking in MinGW

I have got the object-file from source code using MinGW.
But on linking:
ld -o test.exe test.o
I get errors, for example the following:
undefined reference to printf
First, why are you using ld directly?
The following is an excerpt from the "GCC and Make" tutorial found at http://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html.
Compile and Link Separately
The above command compile the source file into object file and link with other object files (system library) into executable in one step. You may separate compile and link in two steps as follows:
// Compile-only with -c option
> g++ -c -Wall -g Hello.cpp
// Link object file(s) into an executable
> g++ -g -o Hello.exe Hello.o
Note g++ (you can substitute gcc if you are using C and not C++) is used both for compiling and linking. ld is not used at all.
The benefit of using g++ or gcc to link is that it will link with default libraries, such as the one you need to link with for printf, automatically.
To link with other libraries, you specify the library name with the -l parameter, as in -lmylib.
We can view commands ran by compiler via command
c99 -v test.o
We'll get some text. All after string which contains "COLLECT_CGG_OPTIONS" will be arguments of ld.
But size of executable file is much more then size of file got by previous way.

Why am I getting a gcc "undefined reference" error trying to create shared objects?

Why am I getting an "undefined reference" error using gcc?
I am trying to create a shared object (.so) that exports one function, "external()". I then try to link against the .so but get "undefined reference 'external'". What am I doing wrong here?
File: external.c
int external() {
return 5;
}
File: program.c
int external();
int main(char** argv, int* argc) {
return external();
}
Commands:
$ gcc -fPIC -c external.c
$ gcc -shared -o libexternal.so external.o
$ gcc -L. -lexternal -o program program.c
/tmp/cc3MmhAE.o: In function `main':
program.c:(.text+0x7): undefined reference to `external'
collect2: ld returned 1 exit status
I can even run nm and see that the .so is defining 'external':
Command:
$ nm libexternal.so | grep external
0000040c T external
What am I missing here?
Recent versions of gcc/ld default to linking with --as-needed.
This means if you write -lexternal before the C file the library will automatically get excluded (the order matters when testing if things are "needed" like this)
You can fix this with either of:
gcc -L. -o program program.c -lexternal
gcc -L. -Wl,--no-as-needed -lexternal -o program program.c
The latter of which passes --no-as-needed to the linker, which would cause the library to still be linked, even if you didn't call external() from it.
Note: -Wl,--no-as-needed isn't applied globally to everything that's linked, it's only applied to things that follow it in the command line order. So -lexternal -Wl,--no-as-needed also wouldn't work. This does mean that you can mix and match behaviours though, for example gcc -L. -Wl,--no-as-needed -lexternal -Wl,--as-needed -o program program.c -lmightneed would always link against external, but only link against mightneed if one or both of program.c/libexternal.so caused it to be needed.

Resources