This question already has answers here:
Use both static and dynamically linked libraries in gcc
(3 answers)
Closed 5 years ago.
First of all I would like to give some background information to avoid the XY Problem.
I am trying to compile a c++ program using makefiles and g++. I also have to build any dependencies statically into the program, but not the 'system libraries' (libz.so, libdl.so, libstdc++.so, libm.so, libpthread.so, libc.so and libgcc.so).
To achieve this I specify -static as linker flag, then all dependencies that have to be statically linked and then I use the -Wl, -Bdynamic option, that should tell the linker to link every library, after this option, to be linked in dynamically including the 'system libraries' because they get linked last.(please correct me if I am wrong.)
LDFLAGS += -Lpath/to/dependencies
# These libs should be linked statically
LDFLAGS += -static
LDFLAGS += -llib1
LDFLAGS += -llib2
LDFLAGS += -llib3
# Libs after this should be linked dynamically.
LDFLAGS += -Wl, -Bdynamic
LDFLAGS += -lz # If i dont specify these three libraries (z, pthread, dl)
LDFLAGS += -lpthread # I get undefined reference errors
LDFLAGS += -ldl
When I call make, the program compiles and links just fine, but when I try to execute it I get the error: bash: ./program: No such file or directory.
But the file DOES exist.
When I remove the -static flag from the linker, the program can be excecuted just fine, but the dependencies are linked dynamically, which is not what I want :(.
So when I call file on the program, that was made with the -static flag, I get this:
program: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), dynamically linked, interpreter /usr/lib/libc.so.1, for GNU/Linux 4.9.0, not stripped
The problem seems to be that the interpreter is set to /usr/lib/libc.so.1 and not to /lib/ld-linux.so.2 as it should usually be. At least it is, when I compile without the -static option.
What I found out is that the 'interpreter' is in reality the shared library loader and from what I read, I now assume that the bash tells me it can not find the program because the library loader is just wrong (Even though I don't quite understand the details of this).
So basically my question is: Why does the library loader get set to libc.so when I specify the -static option to the linker and how can I tell the linker to use the correct library loader when -static is specified?
Your error is mixing -static and -Bdynamic as both compiler and linker flags. Don't do that. If you use -Wl, gcc just blindly pass these flags to the linker, but if you don't, it rearranges the entire link line. (check what it does with gcc -v).
The mix creates an inconsistent and erroneous link command. I have no idea why gcc doesn't at least warn about that, but it doesn't, and silently sets the dynamic loader to a non-existent file.
You want to use -Wl,-Bstatic and -Wl,-Bdynamic consistently throughout. Not -Bstatic and -Bdynamic, as gcc logic is different from that of ld.
This will create a correct dynamically linked executable with some static libs linked in.
Related
How do I get my 'make' process to show me the actual search paths and libraries found with the linker?
I have link errors for symbols I know are in libraries I am trying to use ( verified using objdump ). What I don't know is if the linker is finding the correct libraries. It should be, since all of the libraries I am using are in one directory and some of them ARE being found and used.
So I would like to get diagnostic output showing what library search paths were used, and what libraries ( with paths ) that were actually found and used by the linker.
I tried make -n and got
g++ -g -Wall -DLINUX -I../../../Common/include -I../../../Common/libs/liblua/src main.o IDUpdater.o version.o -L../../../Common/libs -lapp -lserver -lthreading -lnet -lmsgqueue -lcpp -lisam -lisamcore -ldb -ldbisam -ldbsql -Wl,--whole-archive -Wl,--no-whole-archive -o foo
I know libisam.a ,libdbisam.a and others are found and used, but libmsgqueue.a is not. These libraries are all in ../../..'Common/libs/.
Does the gcc's option -static affect only one library that follows immediately or does it affect all libraries provided on command line?
g++ -static -lutils1 -lutils2
GGC's -static linkage option prevents linkage with shared libraries. So
all libraries that the linkage requires must be static. The
linker must be able to find a static library to resolve all -lname options that
are passed, as well as static versions of all default libraries that GCC silently
appends to the linkage.
That is the intended use of the -static option, although it is possible to make it more flexible.
GCC's -static option works simply by causing GCC to pass the option -static|-Bstatic to the linker (ld), at
a position in the generated ld commandline that precedes all the libraries in
the linkage.
The linker's -static option has a different meaning from GCC's. From the ld manual:
-Bstatic
-dn
-non_shared
-static
Do not link against shared libraries. This is only meaningful on platforms for which shared libraries are supported.
he different variants of this option are for compatibility with various systems.
You may use this option multiple times on the command line: it affects library searching for -l options which follow it.
(My emphasis)
So the linker's -static|-Bstatic option means: Do not link any shared libraries until further notice. At a later
point in the ld commandline you may cancel the effect of -static|-BStatic with the option -Bdynamic, which
will allow dynamic libraries to be linked again, from that point on, until further notice.
Unlike the linker, GCC has no option that cancels the effect of its -static option. However, GCC allows you to pass abitrary options through to ld, via -Wl,<ld-options>.
So you can in fact cancel GCC's -static option at a later point in the commandline like this:
gcc -static -o prog main.o -lfoo -lbar -Wl,-Bdynamic -lgum ...
This will generate a linkage commandline in which -lfoo and -lbar must be resolved to
static libraries but -lgum and any subsequent library can be resolved to
a shared library or a static library, as usual. Though if you wanted to "turn on/turn off"
dynamic linkage like this at different points in the commandline, it would be more
natural not to use GCC's -static option and instead write the equivalent:
gcc -o prog main.o -Wl,-Bstatic -lfoo -lbar -Wl,-Bdynamic -lgum ...
For example, consider that I wrote a Fortran program in one computer and want to run it on another computer which may not have required libraries and/or has a different compiler (or even better, no Fortran compiler at all). Is it possible to create an executable with all its dependencies?
I am using gfortran (7.2.1) in Fedora 26 and sometimes use LAPACK routines in my code.
Using -static option with the program
program main
write (*,*) 'Hello'
end
I get the output
gfortran -static a.f90
/usr/bin/ld: cannot find -lm
/usr/bin/ld: cannot find -lm
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
There is no error with gfortran -static-libgfortran a.f90
In Fedora, gcc does not ship by default with static libraries.
You need to install the package glibc-static for the -static option to work, as hinted in this related question.
Note that -static-libgfortran will only do static linking of the libgfortran library and that you must have static versions of your dependencies as well.
The best option is to use Alpine Linux that uses musl libc. I highly recommend using the docker image (only 5 Mb).
I compiling my code, but failed.
# g++ -g test.cpp -o test -lboost_filesystem
/tmp/cc5yybJZ.o(.text+0xb0): In function `__static_initialization_and_destruction_0':
/usr/local/include/boost/system/error_code.hpp:214: undefined reference to `boost::system::generic_category()'
/tmp/cc5yybJZ.o(.text+0xbc):/usr/local/include/boost/system/error_code.hpp:215: undefined reference to `boost::system::generic_category()'
/tmp/cc5yybJZ.o(.text+0xc8):/usr/local/include/boost/system/error_code.hpp:216: undefined reference to `boost::system::system_category()'
/tmp/cc5yybJZ.o(.gnu.linkonce.t._ZN5boost10filesystem9file_sizeERKNS0_4pathE+0x19): In function `boost::filesystem::file_size(boost::filesystem::path const&)':
/usr/local/include/boost/filesystem/operations.hpp:447: undefined reference to `boost::filesystem::detail::file_size(boost::filesystem::path const&, boost::system::error_code*)'
collect2: error: ld returned 1 exit status
but it was success when I compile with -L/usr/local/lib
g++ -g test.cpp -o test -lboost_filesystem -L/usr/local/lib
and the /usr/local/lib has already configured in /etc/ld.so.conf
# cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
/usr/lib64
/usr/local/lib
/usr/local/mpc/lib
/usr/local/mpfc/lib
What's the reason?
What's the different between -L/libpath and /etc/ld.so.conf configure the libpath?
/etc/ld.so.conf is used by the dynamic linker (see manpage ld.so(8)) to figure out which paths to search for your library file. This happens at runtime.
You still need to pass -L/usr/local/lib to gcc, which will pass it on to ld (see manpage ld(1)). This happens at compile time.
Why doesn't gcc or ld just look up the paths in /etc/ld.so.conf automatically? I'd guess a few possible reasons: (1) having more automatic behavior like this makes the system more complex and trickier to understand; (2) gcc runs on systems with different dynamic linkers (or none at all); (3) maybe that behavior is not what you wanted, and then you'd need some extra way to turn it off.
In any case, on most Linux systems, you would just have a package manager that puts the libraries in the right place (typically /usr/lib), so this is usually a non-issue. Otherwise, it's customary to just define your own CFLAGS variable to include the necessary -L... directives.
It's also possible to configure gcc to automatically pass various -L... directives (among other things) by modifying the spec file.
/etc/ld.so.conf is a runtime thing - it allows Linux to find the shared libraries your executables need to run.
You can augment /etc/ld.so.conf by defining $LD_LIBRARY_PATH in your environment.
"-L", on the other hand, is entirely for linking your program. It's an "ld" thing. Specifying "-L" in your g++ command should fix your link error.
You can use the "ldd" command to see what shared libraries a binary needs, and where in the environment it expects to find them.
This question already has answers here:
How to link to a shared library without lib* prefix in a different directory? [duplicate]
(2 answers)
Closed 2 years ago.
I compiled a few libraries using Eclipse-CDT on windows. However, when I tried to compile them under linux gcc keeps giving me the error /usr/bin/ld: cannot find -lrequestedLib. I'm using the exact same build settings between the two environments (namely I made sure to add the directories that contain the libraries i need to link to). I'm sure the system has read access rights to the files as well. I'm not sure what to make of this. Please help.
Edit: These are the commands that ecplise runs to build the library:
gcc -I/home/me/lib/ -O3 -Wall -c -fmessage-length=0 -olibToMake.o ../libToMake.c
gcc -L/home/me/lib/ -shared -olibToMake.so libToMake.o -lrequestedLib
Edit 2: The command that renders the error is the second of the two, resulting in the /usr/bin/ld: cannot find -lrequestedLib being output.
Edit 3: I've confirmed that requestedLib.so is a x86_64 binary.
If you don't want to pass -L command line options to gcc(1), be sure to add the path containing the libraries to /etc/ld.so.conf or /etc/ld.so.cond.d/<something>.
Once you've installed your libraries you also need to run ldconfig(8) by hand. (Most new users forget this step because typical package managers take care of this for you when installing new libraries.)
gcc -I/home/me/lib/ -O3 -Wall -c -fmessage-length=0 -olibToMake.o ../libToMake.c
gcc -L/home/me/lib/ -shared -olibToMake.so libToMake.o -lrequestedLib
When building 64-bit shared libraries on x86_64, the -fPIC flag is usually required, or you get a recompile with -fPIC error at shared library link time.
Since you didn't use -fPIC, yet your link succeeded, you are likely using (non-default) gcc that targets i*86 (that is, produces 32-bit output). You can confirm that by running file libToMake.so.
You didn't show that command that actually fails (the one that produces cannot find -lrequestedLib error). I am guessing that that command is using a different gcc (default one?), that targets x86_64. If it looks something like
gcc main.c -L/home/me/lib -lrequestedLib
that command will ignore /home/me/lib/librequestedLib.so (because you can't link together 32-bit and 64-bit code), and will continue searching for librequestedLib elsewhere. When it can't find a 64-bit version of librequestedLib, it will produce the error message you are gettiing.