背景:
初学者经常搞不清楚,一个main.cpp文件,调用了某库(可能静态也可动态)中的函数,如何将它跑起来。
编译:
g++ -c main.cpp main.cpp:3:26: fatal error: leveldb/db.h: No such file or directory #include "leveldb/db.h" ^ compilation terminated.
缺少头文件,加上再编译(编译只与头文件有关,不需要关注库):
g++ -c main.cpp -I/home/ww/2.src/leveldb/include
OK,生成main.o
链接:
- 先考虑链接静态库的情况(同时存在动态和静态库的情况下,默认使用静态库)。
g++ -o main main.o -L/home/ww/2.src/leveldb/out-static -lleveldb -lpthread
OK,执行正常。
- 如果是动态库的链接,链接方法是一样:
g++ -o main main.o -L/home/ww/2.src/leveldb/out-shared -lleveldb -lpthread
但这个可执行文件是跑不了的:
ldd main
linux-vdso.so.1 (0x00007fffd58f2000)
libleveldb.so.1 => not found
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fbb4a509000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fbb4a1fe000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fbb49efd000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fbb49ce7000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbb4993c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fbb4a726000)
./main
./main: error while loading shared libraries: libleveldb.so.1: cannot open shared object file: No such file or directory
因为动态库不仅在编译(具体来看是链接)时要被搜索,在二进制文件加载和执行时也要搜索。上面的例子仅指定了链接时的搜索。
看下文档对于动态库的说明:
linux程序跑时,program loader会自动被加载并跑起来(即上面加红的
/lib64/ld-linux-x86-64.so.2 (0x00007ff40629d000) )。它作用是找到当前程序依赖的各个库文件,并加载它们。
loader找到动态库文件有几种方法:
- ldconfig
这是最正式的方法,正式发布都应该使用这种方法。
默认的loader搜索动态库的路径在 /etc/ld.so.conf定义。
如:
ww@iZj6c1oc6sq0uze89upki0Z:/etc/ld.so.conf.d$ cat * /usr/lib/x86_64-linux-gnu/libfakeroot # libc default configuration /usr/local/lib # Multiarch support /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu
因此,需要将动态库放到对应的地点,并对应修改或增加.conf文件。
之后,需要调用ldconfig。它的作用是建立起加载所需要的符号缓存。这里不做示例。
- prelaod
这种方式适用于需要部分替换已有库文件中的一些方法。当然也能作为加载路径使用。具体使用是使用LD_PRELOAD环境变量:
LD_PRELOAD=/home/ww/2.src/leveldb/out-shared/libleveldb.so ./main Open db OK
- LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/home/ww/2.src/leveldb/out-shared:${LD_LIBRARY_PATH} ldd main linux-vdso.so.1 (0x00007ffe239f5000) libleveldb.so.1 => /home/ww/2.src/leveldb/out-shared/libleveldb.so.1 (0x00007ff405fe6000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff405dc9000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff405abe000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff4057bd000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff4055a7000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff4051fc000) /lib64/ld-linux-x86-64.so.2 (0x00007ff40629d000)
调试时用此方法比较方便,正式场合也可用。但它有一些潜在的问题:
- 由于安全原因,在使用setuid的情况下不会生效。具体见参考文献。
- 直接使用loader指定路径调用
/lib64/ld-linux-x86-64.so.2 --library-path /home/ww/2.src/leveldb/out-shared ./main Open db OK
调试使用。
参考:
【1】http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
【2】http://xahlee.info/UnixResource_dir/_/ldpath.html