What is the way to print the search paths that in looked by ld in the order it searches.
You can do this by executing the following command:
ld --verbose | grep SEARCH_DIR | tr -s ' ;' \\012
gcc passes a few extra -L paths to the linker, which you can list with the following command:
gcc -print-search-dirs | sed '/^lib/b 1;d;:1;s,/[^/.][^/]*/\.\./,/,;t 1;s,:[^=]*=,:;,;s,;,; ,g' | tr \; \\012
The answers suggesting to use ld.so.conf and ldconfig are not correct because they refer to the paths searched by the runtime dynamic linker (i.e. whenever a program is executed), which is not the same as the path searched by ld (i.e. whenever a program is linked).
On Linux, you can use ldconfig, which maintains the ld.so configuration and cache, to print out the directories search by ld.so with
ldconfig -v 2>/dev/null | grep -v ^$'\t'
ldconfig -v prints out the directories search by the linker (without a leading tab) and the shared libraries found in those directories (with a leading tab); the grep gets the directories. On my machine, this line prints out
/usr/lib64/atlas:
/usr/lib/llvm:
/usr/lib64/llvm:
/usr/lib64/mysql:
/usr/lib64/nvidia:
/usr/lib64/tracker-0.12:
/usr/lib/wine:
/usr/lib64/wine:
/usr/lib64/xulrunner-2:
/lib:
/lib64:
/usr/lib:
/usr/lib64:
/usr/lib64/nvidia/tls: (hwcap: 0x8000000000000000)
/lib/i686: (hwcap: 0x0008000000000000)
/lib64/tls: (hwcap: 0x8000000000000000)
/usr/lib/sse2: (hwcap: 0x0000000004000000)
/usr/lib64/tls: (hwcap: 0x8000000000000000)
/usr/lib64/sse2: (hwcap: 0x0000000004000000)
The first paths, without hwcap in the line, are either built-in or read from /etc/ld.so.conf.
The linker can then search additional directories under the basic library search path, with names like sse2 corresponding to additional CPU capabilities.
These paths, with hwcap in the line, can contain additional libraries tailored for these CPU capabilities.
One final note: using -p instead of -v above searches the ld.so cache instead.
I'm not sure that there is any option for simply printing the full effective search path.
But: the search path consists of directories specified by -L options on the command line, followed by directories added to the search path by SEARCH_DIR("...") directives in the linker script(s). So you can work it out if you can see both of those, which you can do as follows:
If you're invoking ld directly:
The -L options are whatever you've said they are.
To see the linker script, add the --verbose option. Look for the SEARCH_DIR("...") directives, usually near the top of the output. (Note that these are not necessarily the same for every invocation of ld -- the linker has a number of different built-in default linker scripts, and chooses between them based on various other linker options.)
If you're linking via gcc:
You can pass the -v option to gcc so that it shows you how it invokes the linker. In fact, it normally does not invoke ld directly, but indirectly via a tool called collect2 (which lives in one of its internal directories), which in turn invokes ld. That will show you what -L options are being used.
You can add -Wl,--verbose to the gcc options to make it pass --verbose through to the linker, to see the linker script as described above.
The most compatible command I've found for gcc and clang on Linux (thanks to armando.sano):
$ gcc -m64 -Xlinker --verbose 2>/dev/null | grep SEARCH | sed 's/SEARCH_DIR("=\?\([^"]\+\)"); */\1\n/g' | grep -vE '^$'
if you give -m32, it will output the correct library directories.
Examples on my machine:
for g++ -m64:
/usr/x86_64-linux-gnu/lib64
/usr/i686-linux-gnu/lib64
/usr/local/lib/x86_64-linux-gnu
/usr/local/lib64
/lib/x86_64-linux-gnu
/lib64
/usr/lib/x86_64-linux-gnu
/usr/lib64
/usr/local/lib
/lib
/usr/lib
for g++ -m32:
/usr/i686-linux-gnu/lib32
/usr/local/lib32
/lib32
/usr/lib32
/usr/local/lib/i386-linux-gnu
/usr/local/lib
/lib/i386-linux-gnu
/lib
/usr/lib/i386-linux-gnu
/usr/lib
The question is tagged Linux, but maybe this works as well under Linux?
gcc -Xlinker -v
Under Mac OS X, this prints:
#(#)PROGRAM:ld PROJECT:ld64-224.1
configured to support archs: armv6 armv7 armv7s arm64 i386 x86_64 armv6m armv7m armv7em
Library search paths:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/lib
Framework search paths:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/
[...]
The -Xlinker option of gcc above just passes -v to ld. However:
ld -v
doesn't print the search path.
Mac version: $ ld -v 2, don't know how to get detailed paths.
output
Library search paths:
/usr/lib
/usr/local/lib
Framework search paths:
/Library/Frameworks/
/System/Library/Frameworks/
Related
I am new to linux programming and learning it from The Linux Programming Interface by Michael Kerrisk.
I have to compile my first program that has dependencies.
Directory structure:
--linux-programs
|--seek_io.c
|--lib
|--tlpi_hdr.h
|--error_functions.h
|--error_functions.c
|--get_num.h
|--ename.c.inc
I want to compile seek_io.c program with dependencies in the lib directory, so that I can see how the program works.
I tried a few things, absolutely clueless on how they work following this stackoverflow answer. I get all sorts of errors as I am an absolute beginner to Linux programming, not to programming, linux OS and C.
Trials:
gcc -I ./lib/ -c ./lib/error_functions.c and then gcc -o seek_io.c ./error_function.o gives error:
/usr/lib/gcc/x86_64-linux-gnu/crt1.o: In function _start:
(.text+0x20): undefined reference to main
collect2: error: ld returned 1 exit status
After this run, on ls I find that my seek_io.c is not listed.
Basically the author of the book says for tlpi_hdr.h file:
This header file includes various other header files used by many of the example programs, defines a Boolean data type, and defines macros for calculating the minimum and maximum of two numeric values. Using this header file allows us to make the example programs a bit shorter.
Link to codes for files mentioned above:
tlpi_hdr.h
error_functions.h
error_functions.c
get_num.h
get_num.c
seek_io.c
The problem is with your second gcc command, where you're using the -o file to specify the output file where to store the resulting executable file, but passing it the name of the C source file seek_io.c instead...
gcc -o seek_io.c ./error_function.o
This means link file error_function.o and store the executable in seek_io.c. This fails because there is no main function, which is needed for a standalone executable, so your C source file is not overwritten by the failing link command.
You can fix this easily by passing the -o option a proper output file name, which in the case (of this link command) should be the name of the executable that you want to create, such as seek_io:
gcc -o seek_io seek_io.c ./error_function.o
(But this will fail without a -I ./lib/, since seek_io.c includes tlpi_hdr.h which is in that directory. If you add it to that command, it should work.)
You can also decide to split the compile and link steps in two separate steps (the command above will both compile seek_io.c into an object file and then link the two object files into an executable) with:
$ gcc -I ./lib/ -c ./lib/error_functions.c
$ gcc -I ./lib/ -c seek_io.c
$ gcc -o seek_io seek_io.o error_function.o
One final nitpick is that for the -I flag to specify the directories where to search for the include files, the more common usage has no space between the flag itself and the directory name, so you'll most commonly see -I./lib or even -Ilib.
$ gcc -Ilib -c ./lib/error_functions.c
$ gcc -Ilib -c seek_io.c
$ gcc -o seek_io seek_io.o error_function.o
Linux separates the linker-time search path and run-time search path.
For the run-time search path, I found the rule for ld.so in its man page (8 ld.so):
DT_RPATH
environment LD_LIBRARY_PATH
DT_RUNPATH
ld.so.cache
/lib, /usr/lib
But for linker-time search path, no luck for ld :(
Man page for ld (1 ld) says, besides -L option:
The default set of paths searched (without being specified with -L) depends on which emulation mode ld is using, and in some cases also on how it was configured.
The paths can also be specified in a link script with the "SEARCH_DIR" command. Directories specified this way are searched at the point in which the linker script appears in the command line.
Does the "default set of paths" depending on emulation mode mean "SEARCH_DIR"?
misssprite, to look for the linker search path for specific ELF emulation just run ld -m<emulation> --verbose | grep SEARCH_DIR
Speaking about the ld itself, the library path search order is the following:
Directories specified via -L command line flags
Directories in the LIBRARY_PATH environment variable
SEARCH_DIR variables in the linker script.
You can look what directories are specified in the default linker script by running ld --verbose | grep SEARCH_DIR. Note that = in the SEARCH_DIR values will be replaced by the value of --sysroot option if you specify it.
Usually ld is not invoked directly, but via compiler driver which passes several -L options to the linker. In the case of gcc or clang you can print the additional library search directories added by a compiler by invoking it with -print-search-dirs option. Also note that if you specify some machine-specific compiler flags (like e.g -m32 as misssprite mentioned) than the linker may use different linker script according to the chosen ELF emulation. In the case of gcc you can use -dumpspecs option to look how different compiler flags affect the linker invocation. But IMHO the simplest way to look for the linker command line is to compile and link a simple program with -v specified.
misssprite, there is no search for ld.so or ld-linux.so in the binutils's ld linker.
When dynamic program is build with gcc, it uses option -dynamic-linker of ld (collect2) program: http://man7.org/linux/man-pages/man1/ld.1.html
-Ifile, --dynamic-linker=file
Set the name of the dynamic linker. This is only meaningful when
generating dynamically linked ELF executables. The default
dynamic linker is normally correct; don't use this unless you
know what you are doing.")
Usually used as runtime loader for ELF, the "ld-linux.so" is registered as interpreter in the dynamic ELF file, program header INTERP (.interp), check output readelf -l ./dynamic_application. This field is for full path, as I understand.
When there is no gcc (directly called 'ld' program) or no this option was given, ld uses hardcoded string of full path to ld.so; and this default is incorrect for most OS, including Linux:
https://github.com/bneumeier/binutils/blob/db980de65ca9f296aae8db4d13ee884f0c18ac8a/bfd/elf64-x86-64.c#L510
/* The name of the dynamic interpreter. This is put in the .interp
section. */
#define ELF64_DYNAMIC_INTERPRETER "/lib/ld64.so.1"
#define ELF32_DYNAMIC_INTERPRETER "/lib/ldx32.so.1"
https://github.com/bneumeier/binutils/blob/db980de65ca9f296aae8db4d13ee884f0c18ac8a/gold/x86_64.cc#L816
template<>
const Target::Target_info Target_x86_64<64>::x86_64_info =
...
"/lib/ld64.so.1", // program interpreter
const Target::Target_info Target_x86_64<32>::x86_64_info =
...
"/libx32/ldx32.so.1", // program interpreter
Correct dynamic linker/loader path is hardcoded in machine spec files of gcc, grep output of gcc -dumpspecs command for ld-linux for -dynamic-linker option value.
I am trying to build a simple executable that uses boost_serialization and boost_iostreams.
#include <fstream>
#include <iostream>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/device/file.hpp>
int main()
{
using namespace boost::iostreams;
filtering_ostream os;
os.push(boost::iostreams::gzip_compressor());
os.push(boost::iostreams::file_sink("emptyGzipBug.txt.gz"));
}
Unfortunately the system I am working with has a very outdated version of boost_serialization in /usr/lib/, and I have no way to change that.
I am fairly certain when I build the example using
g++ -o main main.cpp -lboost_serialization -lboost_iostreams
that the linker errors result because gcc uses the system version of boost_serialization rather than my locally installed version. Setting LIBRARY_PATH and LD_LIBRARY_PATH to /home/andrew/install/lib doesnt work. When i build using
g++ -o main main.cpp -L/home/andrew/install/lib -lboost_serialization -lboost_iostreams
then everything works.
My questions are:
How can I get gcc to tell me the filenames of the libraries its using?
Is it possible to setup the environment so that I dont have to specify the absolute path to my local boost on the command line of gcc.
PS After typing the below info, I thought I'd be kind and add what you need for your specific case:
g++ -Wl,-rpath,/home/andrew/install/lib -o main main.cpp -I/home/andrew/install/include -L/home/andrew/install/lib -lboost_serialization -lboost_iostreams
gcc itself doesn't care about the libraries. The linker does ;).
Even though the linker needs to find the shared libraries so it can resolve
symbols, it doesn't store the path of those libraries in the executable normally.
So, for a start, lets find out what is actually in the binary after you linked it:
$ readelf -d main | grep 'libboost'
0x0000000000000001 (NEEDED) Shared library: [libboost_serialization.so.1.54.0]
0x0000000000000001 (NEEDED) Shared library: [libboost_iostreams.so.1.54.0]
Just the names thus.
The libraries that are actually used are detemined by /lib/ld-linux.so.*
at run time:
$ ldd main | grep libboost
libboost_serialization.so.1.54.0 => /usr/lib/x86_64-linux-gnu/libboost_serialization.so.1.54.0 (0x00007fd8fa920000)
libboost_iostreams.so.1.54.0 => /usr/lib/x86_64-linux-gnu/libboost_iostreams.so.1.54.0 (0x00007fd8fa700000)
The path is found by looking in /etc/ld.so.cache (which is normally
compiled by running ldconfig). You can print its contents with:
ldconfig -p | grep libboost_iostreams
libboost_iostreams.so.1.54.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libboost_iostreams.so.1.54.0
libboost_iostreams.so.1.49.0 (libc6,x86-64) => /usr/lib/libboost_iostreams.so.1.49.0
libboost_iostreams.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libboost_iostreams.so
but since that is only the cached result of a previous look up,
you are more interested in the output of:
$ ldconfig -v 2>/dev/null | egrep '^[^[:space:]]|libboost_iostreams'
/lib/i386-linux-gnu:
/usr/lib/i386-linux-gnu:
/usr/local/lib:
/lib/x86_64-linux-gnu:
/usr/lib/x86_64-linux-gnu:
libboost_iostreams.so.1.54.0 -> libboost_iostreams.so.1.54.0
/lib32:
/usr/lib32:
/lib:
/usr/lib:
libboost_iostreams.so.1.49.0 -> libboost_iostreams.so.1.49.0
which shows the paths that it looked in before finding a result.
Note if you are linking a 64bit program and it would find a 32bit
library first (or visa versa) then that would be skipped as being
incompatible. Otherwise, the first one found is used.
The paths used to search are specified in /etc/ld.so.conf which is
read (usually at boot time, or after installing something new)
when running ldconfig as root.
However, precedence take paths specified as a colon separated list
of paths in the environment variable LD_LIBRARY_PATH.
For example, if I'd do:
$ export LD_LIBRARY_PATH=/tmp
$ cp /usr/lib/libboost_iostreams.so.1.49.0 /tmp/libboost_iostreams.so.1.54.0
$ ldd main | grep libboost_iostreams
libboost_iostreams.so.1.54.0 => /tmp/libboost_iostreams.so.1.54.0 (0x00007f621add8000)
then it finds 'libboost_iostreams.so.1.54.0' in /tmp (even though it was a libboost_iostreams.so.1.49.0).
Note that you CAN hardcode a path in your executable by passing -rpath to
the linker:
$ unset LD_LIBRARY_PATH
$ g++ -Wl,-rpath,/tmp -o main main.cpp -lboost_serialization -lboost_iostreams
$ ldd main | grep libboost_iostreams
libboost_iostreams.so.1.54.0 => /tmp/libboost_iostreams.so.1.54.0 (0x00007fbd8bcd8000)
which can be made visible with
$ readelf -d main | grep RPATH
0x000000000000000f (RPATH) Library rpath: [/tmp]
Note that LD_LIBRARY_PATH even takes precedence over -rpath, unless
you also passed -Wl,--disable-new-dtags, along with the -rpath and provided that you are linking an executable and your linker supports
this flag.
You can show the search paths that gcc uses during compile(link) time with the -print-search-dirs command line option:
$ g++ -print-search-dirs | grep libraries
libraries: =/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/lib/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/lib/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/:/lib/x86_64-linux-gnu/4.7/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/4.7/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../:/lib/:/usr/lib/
This can be influenced by adding -L command line options. If a library can't be found in a path specified with the -L option then it looks in paths found through the environment variable GCC_EXEC_PREFIX (see the man page for that) and if that fails it uses the environment variable LIBRARY_PATH.
When you run g++ with the -v option, it will print the LIBRARY_PATH used.
LIBRARY_PATH=/tmp/lib g++ -v -o main main.cpp -lboost_serialization -lboost_iostreams 2>&1 | grep LIBRARY_PATH
LIBRARY_PATH=/tmp/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/tmp/lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../:/lib/:/usr/lib/
Finally, note that especially for boost (but in general) you should
use header files that match the correct version! So, if the library that you
link with at run time is version xyz you should have used an -I command line option to get g++ to find the corresponding header files, or things might not link or worse, result in unexplainable crashes.
-nodefaultlibs
Do not use the standard system libraries when linking. Only the
libraries you specify are passed to the linker, and options
specifying linkage of the system libraries, such as
-static-libgcc or -shared-libgcc, are ignored. The standard
startup files are used normally, unless -nostartfiles is used.
The compiler may generate calls to "memcmp", "memset", "memcpy"
and "memmove". These entries are usually resolved by entries in
libc. These entry points should be supplied through some other
mechanism when this option is specified.
Haven't used it myself but it sounds exactly like what was asked for.
Note: Full working example now below. Original question follows:
I'm having problems using ld's -rpath parameter with $ORIGIN.
As I couldn't find a complete example, I thought I'd try to write one myself, so that I and others can use it later. Once I get it working I'll tidy it up.
I asked about this before, but I think my post was a bit confusing.
The example project builds one shared library and one executable that links to said library.
It's very small (3 files, 22 lines incl buildscript).
You can download the project from here
File structure (before building):
project/
src/
foo.cpp
main.cpp
make.sh
project/src/foo.cpp
int foo()
{ return 3; }
project/src/main.cpp
int foo();
#include <iostream>
int main()
{
std::cout << foo() << std::endl;
return 0;
}
project/make.sh
# Make directories:
mkdir -p -v obj
mkdir -p -v lib
mkdir -p -v run
# Build the library:
g++ -c -o obj/foo.o src/foo.cpp -fPIC
g++ -shared -o lib/foo.sh obj/foo.o
# Build the executable:
g++ -c -o obj/main.o src/main.cpp
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../../lib' -Llib -l:foo.sh
From the project directory, run make.sh (make sure it's executable).
File structure (after building):
project/
src/
foo.cpp
main.cpp
obj/
foo.o
main.o
lib/
foo.so
run/
main.run
make.sh
run/main.run should now load lib/foo.sh on execution, from anywhere.
Problems
Currently, this only partly works.
The files compile and link OK, but it fails to link when run from any directory except project (which is the point of the exercise).
Inspecting main.run with readelf -d shows:
0x0000000000000001 (NEEDED) Shared library: [lib/foo.sh]
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../../lib]
Which looks close (I'd rather have [foo.sh] than [lib/foo.sh] but I'll fix that later).
AFAICT the $ORIGIN in -Wl,-rpath,'$ORIGIN/../../lib' means project/run/main.run so this rpath should become project/lib.
I have tried $ORIGIN/.., $ORIGIN/../lib, $ORIGIN/../.., $ORIGIN/../../lib to no avail.
Note: I'm using -l: which requires the complete library filename (amongst other reasons, it's easier to script with variables when all functions take the same name format).
Does anyone know why this isn't working?
Or alternately, does anyone have or know of a complete working example?
(I'd rather have [foo.sh] than [lib/foo.sh] but I'll fix that later).
There's most of your problem: the / in the name stops the dynamic linker from doing the rpath magic.
(Your rpath is wrong too. Think about it: from the shell, if you were currently in the directory where your executable is, how would you get to the directory where your library is? Here, you'd need to cd ../lib. So your rpath should be $ORIGIN/../lib.)
If you built your object as libfoo.so and linked with -Llib -lfoo, the linker would work out what you were intending, and do the right thing. But if you're going to use unusual naming conventions, you'll have to help it out:
Change the link line for the library to explicitly set the SONAME for your library to just foo.sh:
g++ -shared -Wl,-soname,foo.sh -o lib/foo.sh obj/foo.o
Fix the rpath:
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib' -Llib -l:foo.sh
It's useful to run ldd main/main.run to see what's going on. In your original failing case, you'll see something like:
lib/foo.sh (0xNNNNNNNN)
(the lack of any => /some/resolved/path showing that it's not done any path resolution). In the fixed case, you'll see something like:
foo.sh => /your/path/to/run/../lib/foo.sh (0xNNNNNNNN)
This is a example of relative-path linking (with ld) by using $ORIGIN in an rpath.
rpath is a path (or set of paths) embedded in binary files (shared libraries (.so) and executables).
These paths are the foremost search paths for the shared libraries the binary must be linked with at runtime.
$ORIGIN is a potential start directory for an rpath path.
It resolves to the directory containing the executing file. (eg: $ORIGIN/lib)
The example project builds one shared library and one executable that links to said library using rpath and $ORIGIN.
You can download the project from here.
File structure (before building):
project/
src/
foo.cpp
main.cpp
make.sh
project/src/foo.cpp
int foo()
{ return 3; }
project/src/main.cpp
int foo();
#include <iostream>
int main()
{
std::cout << foo() << std::endl;
return 0;
}
project/make.sh
# Make directories:
mkdir -p -v obj
mkdir -p -v lib/dir
mkdir -p -v run
# Build the library:
g++ -c -o obj/foo.o src/foo.cpp -fPIC
g++ -shared -o lib/dir/foo.so -Wl,-soname,foo.so obj/foo.o
# Build the executable:
g++ -c -o obj/main.o src/main.cpp
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Llib/dir -l:foo.so
From the project directory, run make.sh (if it won't run, ensure make.sh has execute permissions).
If all went OK, main.run should now load lib/dir/foo.so on execution, regardless of the absolute path to project (you can move it to anywhere), and regardless of the current working directory (you can run it from anywhere).
Notes:
-fPIC instructs the compiler to build relocatable object files (object files build into shared libraries must be relocatable).
-Wl,-soname,<NAME> embeds <NAME> into the generated library. This should match the name you supply for the -l or -l: options when linking to this library.
-Wl,-rpath,'<PATH>' embeds <PATH> into the generated library as a runtime library search path (or rpath - see above).
-L adds a path to the build-time library search path list. (Note: rpath is irrelevant at build-time, -L is irrelevant at runtime).
-l: adds the filename (without path) of a library to link against. (Similar to -l, except -l: requires the complete filename.
File structure (after building):
project/
src/
foo.cpp
main.cpp
obj/
foo.o
main.o
lib/
dir/
foo.so
run/
main.run
make.sh
Note: I'm using -l: which requires the complete library filename (amongst other reasons, it's easier to script with variables when all functions take the same name format).
It is more common to use -l, whereby -l<NAME> denotes lib.so.
Limitations
As far as I'm aware (correct me if I'm wrong) there's no way to add a library inside a subdirectory within a search path (except for adding that directory as a sub-path). This is true for both build-time (-L) and run-time (-rpath) search paths.
So if you have two libraries with the same name but different locations, you won't be able to link them both. (I hope I'm wrong or that this gets fixed).
I'm having difficulty with the linker when it comes to compiling a sample program that uses the POSIX aio library (e.g. aio_read(), aio_write(), etc) on Linux.
I'm running Ubuntu with a 2.6 kernel, and have used the apt-get utility to install libaio. But even though I'm linking with the aio library, the compiler still gives me linker errors.
root#ubuntu:/home# g++ -L /usr/lib/libaio.a aio.cc -oaio
/tmp/cc5OE58r.o: In function `main':
aio.cc:(.text+0x156): undefined reference to `aio_read'
aio.cc:(.text+0x17b): undefined reference to `aio_error'
aio.cc:(.text+0x191): undefined reference to `aio_return'
collect2: ld returned 1 exit status
Where are all these aio_x functions actually defined, if not in the library libaio.a?
I also had issues linking against libaio in spite of the aio package being correctly installed and the -lrt flag being present.
It turned out that placing -l flags later (for example, last) in the gcc command invocation sometimes fixes this issue. I stumbled upon this solution here on Stack Overflow.
I stopped doing this:
gcc -Wall -Werror -g -o myExe -lrt myExe.c
And started doing this:
gcc -Wall -Werror -g -o myExe myExe.c -lrt
EDIT: according the the man page, libaio.so is not the correct library to link to:
man aio_read
SYNOPSIS
#include <aio.h>
int aio_read(struct aiocb *aiocbp);
Link with -lrt.
so you should link with this:
g++ -lrt aio.cc -o aio
The way libraries work with gcc is like this:
-L adds directory dir to the list of directories to be searched for -l.
-l adds a library itself, if the file is named libsomename.so, you just use "-lsomename"
Does -L specify the search path and -l specifies the actual library?
You want -laio in order to link to libaio. The argument of -o is what you want the compiled executable to be called.
Try:
sudo apt-get install libaio-dev
Then make sure you specify -laio on the link line.
Okay, Evan Teran is correct - it worked when I linked with -lrt. It seems the aio_x functions are defined in a general POSIX extension library.
Thanks, Evan.