昨天编译linux kernel 的代码,刚开始提示 找不到 -lncurses, 安装了 ncurses之后,还是提示找不到。找了半天,才发现Makefile文件里面某个地方给 GCC加了个选项 -m32, 而用的系统是 x86-64的,所以安装的 ncurses肯定能搜到,但是被跳过了。
有下面的文件:
1. ctest1.c
void ctest1(int *i) { *i=5; }
void ctest2(int *i) { *i=100; }
#include <stdio.h> void ctest1(int *); void ctest2(int *); int main() { int x; ctest1(&x); printf("Valx=%d\n",x); return 0; }
cc -Wall -c ctest1.c ctest2.c
ar -cvq libctest.a ctest1.o ctest2.o
$ cc prog.c -lctest /usr/bin/ld: cannot find -lctest collect2: ld returned 1 exit status那么, gcc 默认会去搜索哪些目录呢?
可以在上面的命令 加选项 -v 来看:
#include "..." search starts here: #include <...> search starts here: /usr/lib/gcc/i686-linux-gnu/4.6/include /usr/local/include /usr/lib/gcc/i686-linux-gnu/4.6/include-fixed /usr/include/i386-linux-gnu /usr/include End of search list. GNU C (Ubuntu/Linaro 4.6.3-1ubuntu5) version 4.6.3 (i686-linux-gnu) compiled by GNU C version 4.6.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9 GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: 09c248eab598b9e2acb117da4cdbd785 COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=i686' as --32 -o /tmp/ccZAn7G7.o /tmp/ccNuit3w.s COMPILER_PATH=/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/:/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/:/usr/lib/gcc/i686-linux-gnu/4.6/../../../../lib/:/lib/i386-linux-gnu/:/lib/../lib/:/usr/lib/i386-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/i686-linux-gnu/4.6/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=i686' /usr/lib/gcc/i686-linux-gnu/4.6/collect2 --sysroot=/ --build-id --no-add-needed --as-needed --eh-frame-hdr -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 -z relro /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crti.o /usr/lib/gcc/i686-linux-gnu/4.6/crtbegin.o -L/usr/lib/gcc/i686-linux-gnu/4.6 -L/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu -L/usr/lib/gcc/i686-linux-gnu/4.6/../../../../lib -L/lib/i386-linux-gnu -L/lib/../lib -L/usr/lib/i386-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/i686-linux-gnu/4.6/../../.. /tmp/ccZAn7G7.o -lctest -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i686-linux-gnu/4.6/crtend.o /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crtn.o /usr/bin/ld: cannot find -lctest collect2: ld returned 1 exit status可见,默认,先搜查的是 COMPILER_PATH, 然后是 LIBRARY_PATH.
然后,加上 当前路径:
$ cc prog.c -L. -lctest -v
#include "..." search starts here: #include <...> search starts here: /usr/lib/gcc/i686-linux-gnu/4.6/include /usr/local/include /usr/lib/gcc/i686-linux-gnu/4.6/include-fixed /usr/include/i386-linux-gnu /usr/include End of search list. GNU C (Ubuntu/Linaro 4.6.3-1ubuntu5) version 4.6.3 (i686-linux-gnu) compiled by GNU C version 4.6.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9 GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: 09c248eab598b9e2acb117da4cdbd785 COLLECT_GCC_OPTIONS='-L.' '-v' '-mtune=generic' '-march=i686' as --32 -o /tmp/ccWa3nUL.o /tmp/cca6Y5Wi.s COMPILER_PATH=/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/:/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/:/usr/lib/gcc/i686-linux-gnu/4.6/../../../../lib/ :/lib/i386-linux-gnu/:/lib/../lib/:/usr/lib/i386-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/i686-linux-gnu/4.6/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-L.' '-v' '-mtune=generic' '-march=i686' /usr/lib/gcc/i686-linux-gnu/4.6/collect2 --sysroot=/ --build-id --no-add-needed --as-needed --eh-frame-hdr -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 -z relro /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crti.o /usr/lib/gcc/i686-linux-gnu/4.6/crtbegin.o -L. -L/usr/lib/gcc/i686-linux-gnu/4.6 -L/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu -L/usr/lib/gcc/i686-linux-gnu/4.6/../../../../lib -L/lib/i386-linux-gnu -L/lib/../lib -L/usr/lib/i386-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/i686-linux-gnu/4.6/../../.. /tmp/ccWa3nUL.o -lctest -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i686-linux-gnu/4.6/crtend.o /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crtn.o可见,此时, -L后面的当前目录被放到了所有搜索路径的前面;换句话说, -L.指定的目录被优先搜索。
然后,编译动态库:
$ gcc -Wall -c -fpic ctest*.c
gcc -shared -Wl,-soname,libctest.so.1 -o libctest.so.1.0 ctest*.o然后link这个动态库:
~$ gcc -Wall prog.c -lctest -o prog /usr/bin/ld: cannot find -lctest collect2: ld returned 1 exit status在/etc/ld.so.conf.d 下增加个文件 mylib.conf, 并把刚才那个动态库的目录放进去:
$ cat mylib.conf /home/charles然后执行 sudo ldconfig.之后,再确认:
$ sudo ldconfig -p | grep "libctest" libctest.so.1 (libc6) => /home/charles/libctest.so.1
$ ls ~/libctest* -l -rw-rw-r-- 1 charles charles 1942 Nov 9 01:37 /home/charles/libctest.a lrwxrwxrwx 1 root root 15 Nov 9 08:17 /home/charles/libctest.so.1 -> libctest.so.1.0 -rwxrwxr-x 1 charles charles 6704 Nov 9 08:12 /home/charles/libctest.so.1.0再执行:
$ gcc -Wall prog.c -lctest -o prog /usr/bin/ld: cannot find -lctest collect2: ld returned 1 exit status还是找不到库。
原因是, gcc会去查找 名字为 libctest.so 和 libctest.a的库。 lddconfig 指定的/home/charles下面没有 libctest.so; 因为 lddconfig指定的库只对动态库有效,
所以 libctest.a也找不到。
ln -sf libctest.so.1 libctest.so
$ ls ~/libctest* -l -rw-rw-r-- 1 charles charles 1942 Nov 9 01:37 /home/charles/libctest.a lrwxrwxrwx 1 charles charles 13 Nov 9 08:44 /home/charles/libctest.so -> libctest.so.1 lrwxrwxrwx 1 root root 15 Nov 9 08:17 /home/charles/libctest.so.1 -> libctest.so.1.0 -rwxrwxr-x 1 charles charles 6704 Nov 9 08:12 /home/charles/libctest.so.1.0
需要重新执行 ldconfig:
~$ sudo ldconfig
~$ sudo ldconfig -p | grep libctest libctest.so.1 (libc6) => /home/charles/libctest.so.1 libctest.so (libc6) => /home/charles/libctest.so再执行:
$ gcc -Wall prog.c -lctest -o prog /usr/bin/ld: cannot find -lctest collect2: ld returned 1 exit status还是找不到。
原因是,ldconfig配置的路径是用来在运行时搜索的。
$ gcc -Wall prog.c -L. -lctest -o prog charles@taotao:~$ ./prog Valx=5此时运行也没有问题,原因是已经在 ldconfig里设置好了动态库的位置。
动态库运行时的搜索路径:
1)LD_LIBRARY_PATH里列出的路径
2) /etc/ld.so.cache 里保存的路径
3) /lib
4)/usr/lib
------------------------------------------------------------------------
1. 动态库不同版本的链接,有两种方法:
ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so.1 ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so或者级联的形式:
ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so.1 ln -sf /opt/lib/libctest.so.1 /opt/lib/libctest.so
2. 可以用 gcc -print-file-name=libfilename 确认一个库是不是在link时能被搜索到(不用额外设置):
$ gcc -print-file-name=libncurses.a /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/libncurses.a charles@taotao:~$ gcc -print-file-name=libncurses.so /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/libncurses.so
如果能输出完整的路径,那说明这个库已经包含在gcc的链接和运行时的搜索路径里面了。
3. 下面的命令把动态库直接写到了二进制文件里面:
gcc -Wl,-R/home/charles -L. prog.c -o prog -lctest
$ readelf -d prog | grep charles 0x0000000f (RPATH) Library rpath: [/home/charles]因此,不需要设置运行时的路径,直接就可以运行。
2.参考:
http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html