再谈 GCC库的搜索路径问题
来源:互联网 发布:苹果刷机 for mac 编辑:程序博客网 时间:2024/04/28 20:03
昨天编译Linux kernel 的代码,刚开始提示 找不到 -lncurses, 安装了 ncurses之后,还是提示找不到。找了半天,才发现Makefile文件里面某个地方给 GCC加了个选项 -m32, 而用的系统是 x86-64的,所以安装的 ncurses肯定能搜到,但是被跳过了。
有下面的文件:
1. ctest1.c
- void ctest1(int *i)
- {
- *i=5;
- }
2. ctest2.c- void ctest2(int *i)
- {
- *i=100;
- }
3. prog.c- #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
然后,link库到可执行文件:- $ 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
这个时候已经自动生了一个文件 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 -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