再谈 GCC库的搜索路径问题

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

你可能感兴趣的:(再谈 GCC库的搜索路径问题)