Linking partially static and partially dynamic in GCC - c

I'm trying to compile a very simple (as simple as hello world) C program using both dynamic and static linking with GCC. I want to know how to do this in general, so my minimal test example is simply trying to link libc as static and libm dynamically.
I've come across at least the following other questions regarding the same topic:
GCC: static linking only some libraries
Static link of shared library function in gcc
Some of the answers therein suggest things such as using -Wl,-Bstatic and -Wl,-Bdynamic to specify which libraries are respectively static and dynamic. Also suggested is among others simply specifying the full path of the static library to link against.
I've tried several of these suggestions, and variants thereof. I don't understand the error message it gives me. I know what PIE is, but I don't see how it relates to what I'm trying to do.
Here are some failed attempts:
$ gcc test.c /usr/lib64/libc.a
linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
urned 1 exit status
$ gcc test.c -Wl,-Bdynamic -lm -Wl,-Bstatic -lc
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bdynamic -lm -Wl,-Bstatic -lc test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bstatic -lc -Wl,-Bdynamic -lm test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
Compiling just with no arguments, and with -static work fine, but I need partial static compilation:
$ gcc test.c -lm
$ gcc -static test.c -lm
However, the following fails too:
$ gcc test.c /usr/lib64/libc.a /usr/lib64/libm.a
I've come across a similar error in this post:
C++ Statically linked shared library
However the answers do not seem to apply to my problem.
The program I'm trying to compile is simply (as test.c):
#include <stdio.h>
#include <math.h>
int main(int argc, char **argv)
{
int i = 0;
for(i = 0; i < 65535; i++) {
printf("%f\n", sinf(i));
printf("%f\n", cosf(i));
printf("%f\n", tanf(i));
printf("%f\n", sqrtf(i));
}
return 0;
}
EDIT: Please note that the program must be complex enough to actually require libm, otherwise linking attempts might give false positives if libm is not really needed. In my original test.c example, I used only sinf() to a constant value, which made the compiler optimize out the sinf() call completely.
I'm using:
$ gcc --version
gcc (Gentoo 4.7.3-r1 p1.4, pie-0.5.5) 4.7.3

The following worked for me
ln -s `gcc -print-file-name=libc.a`
gcc -static-libgcc -L. -lc test.c
Then ldd a.out gives:
not a dynamic executable
Edit:
The OP wants to link one library dynamically and another statically. He have the example of linking libc statically and libm dynamically. That particular case I have not been able to achieve. However, the opposite is possible i.e. linking libc dynamically and libm statically.
ln -s `gcc -print-file-name=libm.a`
gcc test.c -L. -lm
then ldd a.out gives
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x41960000)
/lib/ld-linux.so.2 (0x4193d000)
Note that the link order matters.e.g gcc -L. -lm test.c does not work.
This works with other libraries as well. For example gomp
gcc -fopenmp test.c
ldd shows libgomp.so.1. We can link it statically like this
ln -s `gcc -print-file-name=libgomp.a`
gcc -L. -fopenmp test.c
Now ldd a.out does not show libgomp.so.1. But in this case pthreads is still linked dynamically. To link pthreads statically requires that libc be linked statically as well.

Related

Cannot find -lCommunication collect2: error: ld returned 1 exit status

I do not know gcc and c well. In my /home/pi/Desktop/intern/adis16227_generic directory I have following 5 files.
ADIS16227.c
ADIS16227.h
Communication.c
Communication.h
main.c
main.c
#include<stdio.h>
#include "Communication.h" // Communication definitions.
int main() {
printf("hello!!\n");
unsigned char status = 0;
status = SPI_Init(0, 1000000, 1, 1);
printf("%u", status);
return 0;
}
Run command:
$ sudo gcc -L /home/pi/Desktop/intern/adis16227_generic main.c -lCommunication
Error:
/usr/bin/ld: cannot find -lCommunication
collect2: error: ld returned 1 exit status
Question:
What I am missing here?
What do I need to run the code?
-l is for libraries, and you never built a library from your Communication.c. The simplest solution is just add Communication.c to your compiler command line.
For larger projects, compile each translation unit separately with the -c switch like this:
gcc -c -Wall -Wextra -pedantic -omain.o main.c
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
and so on ... (as a suggestion, I added some common warning options here, they help you spot errors)
The resulting .o files are object code. That's already compiled machine code, but with meta-information needed for a linker to link it with other object code into a complete executable.
Then link them all with one command:
gcc -oprogram main.o Communication.o
If you actually want a library from -- say -- Communication.c and ADIS16227.c, you could compile both to object code:
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
gcc -c -Wall -Wextra -pedantic --oADIS16227.o ADIS16227.c
and then use ar to create a static library from them:
ar rcs libCommunication.a Communication.o ADIS16227.o
Then your initial compiler command would work (with the -lCommunication switch).
Final piece of advice: Never compile as root. This is completely unnecessary. So remove your sudo here.
those options:
-L /home/pi/Desktop/intern/adis16227_generic -lCommunication
suggest that the linker should find libCommunication.a (or .so) in the /home/pi/Desktop/intern/adis16227_generic directory.
But there are only sources in this directory. The linker won't build the sources of your "Communication" library for you.
So you could build the library and link with it:
gcc -c ADIS16227.c Communication.c
ar r libCommunication.a ADIS16227.o Communication.o
but maybe the fastest & quickest way to achieve a successful build would be:
sudo gcc -o main *.c
so it compiles all the files of the directory into the executable called main
Of course, it makes compilation times longer, but maybe it's not noticeable.
First move into the /home/pi/Desktop/intern/adis16227_generic directory:
cd /home/pi/Desktop/intern/adis16227_generic
Then, compile the source:
gcc ADIS16227.c Communication.c main.c -I .
You can now run your compiled program (called by default a.out):
./a.out
You have to compile separatedly files and then compile main with related obj file.
gcc -c Communication.c Communication.h
gcc main.c Communication.o -o main

Undefined reference error but symbol existing in the library

I get an undefined reference error for the example below. I have seen lots of questions that relate to this issue but believe I gave a stripped, reproducible, conceptual example as opposed specific issues in other questions,
dynlib.h:
void printMe_dyn();
dynlib.c:
#include <stdio.h>
#include "dynlib.h"
void printMe_dyn() {
printf("I am execuded from a dynamic lib");
}
myapp.c:
#include <stdio.h>
#include "dynlib.h"
int main()
{
printMe_dyn();
return 0;
}
Build steps:
gcc -Wall -fpic -c dynlib.c
gcc -shared -o libdynlib.so dynlib.o
gcc -Wall -L. -ldynlib myapp.c -o myapp
Error:
/tmp/ccwb6Fnv.o: In function `main':
myapp.c:(.text+0xa): undefined reference to `printMe_dyn'
collect2: error: ld returned 1 exit status
Proof that the symbol is in the library:
nm libdynlib.so | grep printMe_dyn
00000000000006e0 T printMe_dyn
Am I using the correct compiler flags for building the dynamic
library?
Is the proof I've presented really an unambiguous proof?
What other approach could be taken to diagnose the issue?
The order of appearance of libraries matter.
To quote the online gcc manual
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.
You should be changing your compilation statement to
gcc -o myapp -Wall -L. myapp.c -ldynlib
to tell gcc to search for the symbols used in (compiled) myapp.c to be present in dynlib.
Just as additional notice. The same behavior one may obtain when the library has been built by gcc and linked to the c++ project. Like follows:
gcc -Wall -fpic -c dynlib.c
gcc -shared -o libdynlib.so dynlib.o
g++ -o myapp -Wall -L. myapp.cpp -ldynlib
In such case the reason is name-mangling used by g++. To have it turned off one must wrap C-function prototypes by extern "C" within C-library. For example like follows:
dynlib.h:
#ifdef __cplusplus
extern "C"{
#endif
void printMe_dyn();
#ifdef __cplusplus
}
#endif
The order of libraries in linker command line matters. Fix:
gcc -o myapp -Wall -L. myapp.c -ldynlib

No undefined references when compiling shared library

Im wondering why Im getting no undefined references when compiling as a shared library using -shared as an option for gcc. Consider the following case:
#include <confuse.h>
int
main(int argc, char **argv)
{
cfg_opt_t opts[1];
cfg_t *cfg = cfg_init(opts, CFGF_NOCASE);
return 0;
}
libconfuse is needed here in order to run the program properly. If im compiling it as a "normal" application without specifying that libconfuse is needed (-lconfuse) im getting the following (from my perspective regular) error:
$ gcc -Wall -Wno-unused-variable test.c -o test
/tmp/ccTVz6an.o: In function `main':
test.c:(.text+0x20): undefined reference to `cfg_init'
collect2: error: ld returned 1 exit status
If im compiling the same code as a shared library im not getting any error message regarding the library:
$ gcc -Wall -Wno-unused-variable test.c -o test.so -shared
$ echo $?
0
Can someone please bring light into darkness?
You are compiling a (shared) library, not a program, and libraries are expected not to be complete, so undefined references do not prevent the shared library from building.
Yes, it may sound a bit surprising, particularly if you come from a OS (Windows?) where the shared libraries are always fully linked, but that's how ELF works.
If you want to ensure that all your references are are resolved when building a shared library you can use the linker option --no-undefined:
gcc -Wall -Wno-unused-variable test.c -o test.so -shared -Wl,--no-undefined
Note that libraries used to resolve references when linking a shared library will be added to the header of that library, as NEEDED entries, and then linked automatically when using that library. See objdump -p for details.
With shared libraries (not static ones), you could link a library libA.so into your other library libB.so.
So you could compile your shared library as:
gcc -Wall -Wno-unused-variable -fPIC test.c \
-o libmytest.so -shared -lconfuse
Later you would link that library to some main.c with
gcc -Wall main.c -lmytest -L. -o myprog
or you could load it at runtime, using dlopen(3) on ./libmytest.so (read the man page about why ./ is significant to dlopen)
Simple explanations are in the Program Library HowTo. But Drepper's paper: How to Write Shared Libraries is the best reference.
And it is permitted for a shared library (or even a static one) to have undefined references, since quite often the user of that library would explicitly link the lower level libraries needed by it.

Linking Math Library in GCC 4.6.1 (Ubuntu 11.10)

I find a problem in the linking process of my application. I did not have the same with gcc 4.5. It tries to link math library with the following command.
gcc -Wall -Wno-unused -MD -o mems_seektest mems_seektest.o -lm -L. -g -DASSERTS -I../src// -I../ -I../src//src -DDEBUG -lmems_internals
and report following error massages:
undefined reference to `sqrt'
Any idea ?
recent gcc/ld uses the --as-needed linker flag as default. Practically, that means libraries have to be specified in the reverse order of dependencies on the command line. If the mems_internals library needs the sqrt function your -lm after -lmems_internals.
gcc -Wall -Wno-unused -MD -o mems_seektest mems_seektest.o -L. -g -DASSERTS -I../src// -I../ -I../src//src -DDEBUG -lmems_internals -lm
I've had the same problem with gcc 4.6.1, even with only one library. This doesn't work:
$ gcc -lm eg.o -o eg
eg.o: In function `foo':
/home/nick/tmp/eg.c:5: undefined reference to `sqrt'
collect2: ld returned 1 exit status
But this does:
$ gcc eg.o -o eg -lm
I hit this because I was using "LDFLAGS=-lm" in my Makefile. Works fine if you use "LDLIBS=-lm" instead.
You didn't tell us what -lmems_internals is, but maybe the unresolved symbol comes from there. The order of the -l options is generally important to the linker, you should always put system libraries last.
You can check where the unresolved symbol comes from by using something like
nm yourLibrary | grep sqrt
if there is a U in front of sqrt the symbol is undefined.
I'd say the linker is using the wrong libm.

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