昨天编译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
~$ 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