linux gcc链接参数-L -rpath -rpath-link区别-程序员宅基地

技术标签: 搜索路径  链接  c++开发  动态库  so  rpath  

       找了一台ubuntu:

root@ubuntu:~/test$  cat /etc/issue
Ubuntu 20.04 LTS \n \l
root@ubuntu:~/test$  gcc -v
……
gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2) 

    测试源代码 world.c:

// world.c
void world(){

}

测试源代码 hello.c:

//hello.c

void world();

void hello(){
    world();
}

  测试源代码 main.c:

//main.c

void hello();

int main(){
    hello();
    return 0;
}

 main是主程序,hello和world是动态库,main直接依赖hello, hello依赖world,即main间接依赖world。

 写个简单makefile:

#makefile

main: main.c
        gcc -o $@ $<

hello: hello.c
        gcc -fPIC -shared -o [email protected] $<

world: world.c
        gcc -fPIC -shared -o [email protected] $<

先看看目录内容:

root@ubuntu:~/test$ ls -l
总用量 40
drwxrwxr-x  2 root  root   4096 7月  11 12:34 ./
drwxr-xr-x 21 root  root   4096 7月  11 12:32 ../
-rw-rw-r--  1 root  root     56 7月  11 10:26 hello.c
-rw-rw-r--  1 root  root     50 7月  11 10:27 main.c
-rw-rw-r--  1 root  root    129 7月  11 12:31 makefile
-rw-rw-r--  1 root  root     26 7月  11 10:23 world.c

接下来一步一步地尝试,先编译hello试试:

root@ubuntu:~/test$ make hello
gcc -fPIC -shared -o libhello.so hello.c
root@ubuntu:~/test$ ls -l
总用量 40
drwxrwxr-x  2 root  root   4096 7月  11 12:34 ./
drwxr-xr-x 21 root  root   4096 7月  11 12:32 ../
-rw-rw-r--  1 root  root     56 7月  11 10:26 hello.c
-rwxrwxr-x  1 root  root  15872 7月  11 12:32 libhello.so*
-rw-rw-r--  1 root  root     50 7月  11 10:27 main.c
-rw-rw-r--  1 root  root    129 7月  11 12:31 makefile
-rw-rw-r--  1 root  root     26 7月  11 10:23 world.c

居然成功生成动态库libhello.so,都没加-l -L这些参数,说明生成动态库的时候不是一定要去链接它的依赖库,即可以没有链接阶段。

再看看libhello.so的信息:

root@ubuntu:~/test$ ldd libhello.so 
	statically linked                                           #没有依赖,显示是静态链接的
root@ubuntu:~/test$ nm libhello.so 
0000000000004028 b completed.8059
                 w __cxa_finalize
0000000000001060 t deregister_tm_clones
00000000000010d0 t __do_global_dtors_aux
0000000000003e58 d __do_global_dtors_aux_fini_array_entry
0000000000004020 d __dso_handle
0000000000003e60 d _DYNAMIC
0000000000001130 t _fini
0000000000001110 t frame_dummy
0000000000003e50 d __frame_dummy_init_array_entry
00000000000020c0 r __FRAME_END__
0000000000004000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002000 r __GNU_EH_FRAME_HDR
0000000000001119 T hello
0000000000001000 t _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000001090 t register_tm_clones
0000000000004028 d __TMC_END__
                 U world                                      #有一个undefined的符号world

显然,它留了一个未定义的符号world等待去外部链接,跟静态库一样。把没有依赖的so认为是静态库,也行。

再编译world,这个没什么依赖,肯定成功:

root@ubuntu:~/test$ make world
gcc -fPIC -shared -o libworld.so world.c

最后编译主程序main:

root@ubuntu:~/test$ make main
gcc -o main main.c
/usr/bin/ld: /tmp/ccfAC3eh.o: in function `main':
main.c:(.text+0xe): undefined reference to `hello'
collect2: error: ld returned 1 exit status
make: *** [makefile:3:main] 错误 1

看出,编译可执行二进制程序的时候,必然有链接阶段,有符号hello找不到,链接失败。

好了,修改makefile,增加对hello的链接:

#makefile

main: main.c
        gcc -o $@ $< -lhello -L.    # -l指定依赖库名,-L指定依赖库首先搜索的目录

hello: hello.c
        gcc -fPIC -shared -o [email protected] $<

world: world.c
        gcc -fPIC -shared -o [email protected] $<

再次编译主程序main:

root@ubuntu:~/test$ make main
gcc -o main main.c -lhello -L.
/usr/bin/ld: ./libhello.so: undefined reference to `world'
collect2: error: ld returned 1 exit status
make: *** [makefile:3:main] 错误 1

这次提示找不到符号world了,意思是还得加-lworld:

#makefile

main: main.c
        gcc -o $@ $< -lhello -lworld -L. 

hello: hello.c
        gcc -fPIC -shared -o [email protected] $<

world: world.c
        gcc -fPIC -shared -o [email protected] $<

第3次编译主程序main:

root@ubuntu:~/test$ make main
gcc -o main main.c -lhello -lworld -L.
root@ubuntu:~/test$ ll
drwxrwxr-x  2 root  root   4096 7月  11 13:07 ./
drwxr-xr-x 21 root  root   4096 7月  11 13:07 ../
-rw-rw-r--  1 root  root     41 7月  11 12:47 hello.c
-rwxrwxr-x  1 root  root  15864 7月  11 12:48 libhello.so*
-rwxrwxr-x  1 root  root  15632 7月  11 12:53 libworld.so*
-rwxrwxr-x  1 root  root  16672 7月  11 13:07 main*
-rw-rw-r--  1 root  root     40 7月  11 12:48 main.c
-rw-rw-r--  1 root  root    149 7月  11 13:07 makefile
-rw-rw-r--  1 root  root     21 7月  11 12:47 world.c
root@ubuntu:~/test$ readelf -d main | grep NEEDED             #查看直接依赖库
 0x0000000000000001 (NEEDED)             共享库:[libhello.so]
 0x0000000000000001 (NEEDED)             共享库:[libworld.so]
 0x0000000000000001 (NEEDED)             共享库:[libc.so.6]


上图可以看到,main直接依赖hello和world库。

成功生成main,执行一下:

root@ubuntu:~/test$ ./main
./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

报错:找不到动态库libhello.so。libhello.so明明就在当前目录。

用ldd命令查看一下main的依赖,发现同时依赖hello和world,但都not found。

root@ubuntu:~/test$  ldd ./main
	linux-vdso.so.1 (0x00007ffec81da000)
	libhello.so => not found
	libworld.so => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcfb68ef000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fcfb6af9000)

这里就提一下linux中可执行程序加载动态库时搜索动态库的目录优先顺序,网上总结也很多:

1. 二进制程序被链接时由参数-rpath指定的运行时目录,多个则以冒号分隔。这个是被硬编码进二进制程序的,包括可执行程序和动态库,都可以有这个-rpath.

2.环境变量LD_LIBRARY_PATH指定的目录,多个则以冒号分隔。

3.系统里/etc/ld.so.conf文件里指定的目录。

4.系统里动态库加载器ld-linux.so(ldd命令实际调用的还是这个)默认的搜索目录/lib,usr/lib或者/lib64,/usr/lib64。

于是,可以通过设置环境变量的命令export LD_LIBRARY_PATH=.指定当前目录后再运行main,也可以把hello和world库拷贝到系统的库目录下再运行main。但这些方法不是此次测试的目标。此次要用第1种-rpath的方式。

修改makefile:

#makefile

main: main.c
        gcc -o $@ $< -lhello -lworld -L. -Wl,-rpath=.

hello: hello.c
        gcc -fPIC -shared -o [email protected] $<

world: world.c
        gcc -fPIC -shared -o [email protected] $<

删除之前生成的main文件,重新编译生成并运行:

root@ubuntu:~/test$ make main
gcc -o main main.c -lhello -lworld -L. -Wl,-rpath=.
root@ubuntu:~/test$ readelf -d main | grep runpath
 0x000000000000001d (RUNPATH)            Library runpath: [.]  #可见rpath被编码进二进制了
root@ubuntu:~/test$ ldd ./main
	linux-vdso.so.1 (0x00007ffd464dc000)
	libhello.so => ./libhello.so (0x00007f71df4d2000)
	libworld.so => ./libworld.so (0x00007f71df4cd000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f71df2ca000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f71df4de000)
root@ubuntu:~/test$ ./main
root@ubuntu:~/test$

没再报错,运行时能够在当前目录找到那两个库。

以上是在编译链接主程序的时候同时链接所有依赖库,包括从代码层面上说的直接依赖和间接依赖,实际上从链接层面上说两个库都成了直接依赖。

下面继续测试链接时的间接依赖,修改makefile,在编译hello的时候去链接world,编译main的时候不再显式链接world,看行不行:

#makefile

main: main.c
        gcc -o $@ $< -lhello -L. -Wl,-rpath=.

hello: hello.c
        gcc -fPIC -shared -o [email protected] $< -lworld -L.

world: world.c
        gcc -fPIC -shared -o [email protected] $<

clean:
        rm -f main libhello.so libworld.so
root@ubuntu:~/test$ make clean
rm -f main libhello.so libworld.so
root@ubuntu:~/test$ make world 
gcc -fPIC -shared -o libworld.so world.c
root@ubuntu:~/test$ make hello
gcc -fPIC -shared -o libhello.so hello.c -lworld -L.
root@ubuntu:~/test$ readelf -d libhello.so | grep NEEDED        #查看直接依赖库
 0x0000000000000001 (NEEDED)             共享库:[libworld.so]
root@ubuntu:~/test$ ldd libhello.so                             #寻找运行时所有依赖库
	linux-vdso.so.1 (0x00007ffe22ddb000)
	libworld.so => not found

以上可以看出,编译链接成功,hello库直接依赖world库,但是用ldd命令看出,运行时hello库找不到world库,这个还是可以指定-rpath解决,但先不管,直接编译主程序main,看main的rpath能不能连带找到world库。

root@ubuntu:~/test$ make main
gcc -o main main.c -lhello -L. -Wl,-rpath=.
root@ubuntu:~/test$ readelf -d main | grep NEEDED    #查看直接依赖库,不再直接依赖world
 0x0000000000000001 (NEEDED)             共享库:[libhello.so]
 0x0000000000000001 (NEEDED)             共享库:[libc.so.6]
root@ubuntu:~/test$ ldd main                         #寻找运行时所有依赖库,包括间接依赖
	linux-vdso.so.1 (0x00007ffd54b89000)
	libhello.so => ./libhello.so (0x00007f04b77c5000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f04b75c2000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f04b77d1000)
	libworld.so => not found
root@ubuntu:~/test$ ./main
./main: error while loading shared libraries: libworld.so: cannot open shared object file: No such file or directory

很遗憾,main运行时找不到world库。

那再试试在链接main的时候加上-lworld:

#makefile

main: main.c
        gcc -o $@ $< -lhello -lworld -L. -Wl,-rpath=.

hello: hello.c
        gcc -fPIC -shared -o [email protected] $< -lworld -L.

world: world.c
        gcc -fPIC -shared -o [email protected] $<

clean:
        rm -f main libhello.so libworld.so
root@ubuntu:~/test$ rm main
root@ubuntu:~/test$ make main
gcc -o main main.c -lhello -lworld -L. -Wl,-rpath=.
root@ubuntu:~/test$ readelf -d main | grep NEEDED    #查看直接依赖库,依然不直接依赖world
 0x0000000000000001 (NEEDED)             共享库:[libhello.so]
 0x0000000000000001 (NEEDED)             共享库:[libc.so.6]
root@ubuntu:~/test$ ldd main                        #寻找运行时所有依赖库,包括间接依赖
	linux-vdso.so.1 (0x00007ffd54b89000)
	libhello.so => ./libhello.so (0x00007f04b77c5000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f04b75c2000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f04b77d1000)
	libworld.so => not found
root@ubuntu:~/test$ ./main
./main: error while loading shared libraries: libworld.so: cannot open shared object file: No such file or directory

依然很遗憾,结局一样。说明在链接主程序时通过-l加上间接依赖库并不会将之改变成直接依赖库,除非main本就有亲自调用到world库的代码,有直接依赖关系。

显然,直接依赖world库的是hello库,而main只是间接依赖world库,所以在运行阶段main的rpath对world库不起作用,不能连带找到world库。也就是说,在运行阶段,rpath只对直接依赖库有作用,对间接依赖库没作用。要想通过rpath方式在运行时找到world库,只能hello库自己解决。

继续修改makefile,让hello库去解决world库的运行时目录:

#makefile

main: main.c
        gcc -o $@ $< -lhello -L. -Wl,-rpath=.

hello: hello.c
        gcc -fPIC -shared -o [email protected] $< -lworld -L. -Wl,-rpath=.

world: world.c
        gcc -fPIC -shared -o [email protected] $<

clean:
        rm -f main libhello.so libworld.so
root@ubuntu:~/test$ rm main libhello.so
root@ubuntu:~/test$ make hello
gcc -fPIC -shared -o [email protected] $< -lworld -L. -Wl,-rpath=.
root@ubuntu:~/test$ readelf -d libhello.so | grep NEEDED   #查看hello库的直接依赖库
 0x0000000000000001 (NEEDED)             共享库:[libworld.so]
root@ubuntu:~/test$ readelf -d libhello.so | grep runpath  #查看hello库rapth
 0x000000000000001d (RUNPATH)            Library runpath: [.]
root@ubuntu:~/test$ ldd libhello.so                        #hello库运行时寻找所有依赖库
	linux-vdso.so.1 (0x00007ffc820be000)
	libworld.so => ./libworld.so (0x00007f8dcfe9b000)
root@ubuntu:~/test$
root@ubuntu:~/test$ make main
gcc -o main main.c -lhello -L. -Wl,-rpath=.
root@ubuntu:~/test$ readelf -d main | grep NEEDED    #查看main的直接依赖库,不直接依赖world
 0x0000000000000001 (NEEDED)             共享库:[libhello.so]
 0x0000000000000001 (NEEDED)             共享库:[libc.so.6]
root@ubuntu:~/test$ ldd main                         #寻找运行时所有依赖库,包括间接依赖
	linux-vdso.so.1 (0x00007ffd54b89000)
	libhello.so => ./libhello.so (0x00007f04b77c5000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f04b75c2000)
	libworld.so => ./libworld.so (0x00007f31d1b6d000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f04b77d1000)
root@ubuntu:~/test$ ./main                            #运行成功
root@ubuntu:~/test$

更加证明,rpath只对直接依赖库有作用,主程序并不会在自己的rpath目录里去寻找间接依赖库。

以上说的基本是运行时对直接和间接依赖库的处理。那我又好奇,链接阶段是怎么处理间接依赖库的呢?删除间接依赖库后主程序main还能不能链接成功?下面继续测试:

root@ubuntu:~/test$ rm main libworld.so  #删除main和world库,保留hello库
root@ubuntu:~/test$ make main            #重新编译main
gcc -o main main.c -lhello -L. -Wl,-rpath=.
/usr/bin/ld: warning: libworld.so, needed by ./libhello.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: ./libhello.so: undefined reference to `world'
collect2: error: ld returned 1 exit status
make: *** [makefile:3:main] 错误 1

失败了,找不到间接依赖的world库了。这里至少可以得出一个结论:链接阶段也必须要找到间接依赖库才行。那到底是怎么找的呢?

 这里也顺便提一下链接器寻找依赖库的目录顺序:

1. 首先是在编译链接时-L等参数显式指定的目录里找,为什么说“-L等”,那说明不止-L,还有其它,上图已经提示了用rpath或者rpath-link,后面再讨论。
2. 系统环境变量 LIBRARY_PATH指定的目录。
3. 编译器安装时自身配置的搜索目录,可用命令gcc --print-search-dir | grep libraries 查看,链接时会以-L参数形式隐式地传递给链接器ld。

4. 链接器ld安装时自身配置的搜索目录,可用命令ld -verbose | grep SEARCH_DIR 可查看。

当然,上面后三种指定目录不在此讨论之列,这里只讨论第一种编译链接时显式指定的链接目录。

回到上面链接时找不到world库的问题,上面已经说过,-l -L并不能改变间接依赖库成为直接依赖库,所以在主程序main链接时找不到间接依赖库world自然就不会是-l -L这两参数的原因。

修改makefile, 将world库生成在./lib目录下:

#makefile

main: main.c
        gcc -o $@ $< -lhello -L. -Wl,-rpath=.

hello: hello.c
        gcc -fPIC -shared -o [email protected] $< -lworld -L./lib -Wl,-rpath=.

world: world.c
        mkdir -p ./lib
        gcc -fPIC -shared -o ./lib/[email protected] $^

clean:
        rm -f main libhello.so libworld.so ./lib/libworld.so

先删除之前生成的主程序和所有库文件:

root@ubuntu:~/test$ make clean
rm -f main libhello.so libworld.so ./lib/libworld.so
root@ubuntu:~/test$ ll
总用量 24
drwxrwxr-x  2 root  root  4096 7月  11 16:07 ./
drwxr-xr-x 21 root  root  4096 7月  11 16:07 ../
-rw-rw-r--  1 root  root    41 7月  11 12:47 hello.c
-rw-rw-r--  1 root  root    40 7月  11 12:48 main.c
-rw-rw-r--  1 root  root   265 7月  11 16:07 makefile
-rw-rw-r--  1 root  root    21 7月  11 12:47 world.c

再重新编译:

root@ubuntu:~/test$ make world 
mkdir -p ./lib
gcc -fPIC -shared -o ./lib/libworld.so world.c
root@ubuntu:~/test$
root@ubuntu:~/test$ make hello
gcc -fPIC -shared -o libhello.so hello.c -lworld -L./lib -Wl,-rpath=.
root@ubuntu:~/test$
root@ubuntu:~/test$ make main
gcc -o main main.c -lhello -L. -Wl,-rpath=.
/usr/bin/ld: warning: libworld.so, needed by ./libhello.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: ./libhello.so: undefined reference to `world'
collect2: error: ld returned 1 exit status
make: *** [makefile:3:main] 错误 1

world库生成在./lib目录,hello库通过-L./lib找到world库链接成功并生成在当前目录,而主程序main通过-L.在当前目录里找到hello

库进行链接却报找不到world库。提示很清楚,尝试用-rpath或者-rpath-link。

先尝试在main的链接时rpath增加一个目录./lib:

#makefile

main: main.c
        gcc -o $@ $< -lhello -L. -Wl,-rpath=.:./lib

hello: hello.c
        gcc -fPIC -shared -o [email protected] $< -lworld -L./lib -Wl,-rpath=.

world: world.c
        mkdir -p ./lib
        gcc -fPIC -shared -o ./lib/[email protected] $^

clean:
        rm -f main libhello.so libworld.so ./lib/libworld.so

再重新编译main:

root@ubuntu:~/test$ rm main
root@ubuntu:~/test$ make main
gcc -o main main.c -lhello -L. -Wl,-rpath=.:./lib
root@ubuntu:~/test$ readelf -d main | grep runpath
 0x000000000000001d (RUNPATH)            Library runpath: [.:./lib]
root@ubuntu:~/test$ ./main
./main: error while loading shared libraries: libworld.so: cannot open shared object file: No such file or directory
root@ubuntu:~/test$

上图看出,链接成功了,说明在链接时,链接器会到rapth指定的目录里寻找间接依赖库。

但是运行失败,找不到world库,之前说过,运行时只在rpath里搜索直接依赖库而不搜索间接依赖库。world库的运行时搜索目录由hello库的rpath指定。

再尝试在main的链接时rpath-link指定为./lib:

#makefile

main: main.c
        gcc -o $@ $< -lhello -L. -Wl,-rpath=.,-rpath-link=./lib

hello: hello.c
        gcc -fPIC -shared -o [email protected] $< -lworld -L./lib -Wl,-rpath=.

world: world.c
        mkdir -p ./lib
        gcc -fPIC -shared -o ./lib/[email protected] $^

clean:
        rm -f main libhello.so libworld.so ./lib/libworld.so

重新编译main:

root@ubuntu:~/test$ make main
gcc -o main main.c -lhello -L. -Wl,-rpath=.,-rpath-link=./lib
root@ubuntu:~/test$ readelf -d main | grep runpath
 0x000000000000001d (RUNPATH)            Library runpath: [.]   #这里没有rpath-link指定的目录
root@ubuntu:~/test$ ./main
./main: error while loading shared libraries: libworld.so: cannot open shared object file: No such file or directory
root@ubuntu:~/test$

然后是链接成功,运行时失败,主程序的runpath里也没有./lib。

可见,rpath-link和rpath都可以用于指定间接依赖库的搜索目录,但rpath还指定了运行时直接依赖库的搜索目录。显然rpath的作用包含了rpath-link的作用,rpath目录在链接阶段间接依赖库的搜索目录,在运行阶段直接依赖库的搜索目录。

那么,rpath-link和rpath在链接阶段还能指定直接依赖库的搜索目录吗?下面把main链接参数改一下,去掉-L.,在rpath和rpath-link里都指定当前目录:

#makefile

main: main.c
        gcc -o $@ $< -lhello -Wl,-rpath=.,-rpath-link=.:./lib

hello: hello.c
        gcc -fPIC -shared -o [email protected] $< -lworld -L./lib -Wl,-rpath=.

world: world.c
        mkdir -p ./lib
        gcc -fPIC -shared -o ./lib/[email protected] $^

clean:
        rm -f main libhello.so libworld.so ./lib/libworld.so

重新编译main:

root@ubuntu:~/test$ rm main
root@ubuntu:~/test$ make main
gcc -o main main.c -lhello -Wl,-rpath=.,-rpath-link=.:./lib
/usr/bin/ld: 找不到 -lhello
collect2: error: ld returned 1 exit status
make: *** [makefile:3:main] 错误 1

遗憾,虽然hello库在当前目录,链接器还是找不到hello库,说明rpath-link和rpath在链接阶段确实不能用来搜索直接依赖库。

验证最后一个问题,直接依赖库的rapth的另一个作用。

修改makefile,main的rpath改为当前目录,把hello库的rpath改成./lib,再重新编译hello和main,最后运行main:

#makefile

main: main.c
        gcc -o $@ $< -lhello -L. -Wl,-rpath=.

hello: hello.c
        gcc -fPIC -shared -o [email protected] $< -lworld -L./lib -Wl,-rpath=./lib

world: world.c
        mkdir -p ./lib
        gcc -fPIC -shared -o ./lib/[email protected] $^

clean:
        rm -f main libhello.so libworld.so ./lib/libworld.so
root@ubuntu:~/test$ rm main libhello.so
root@ubuntu:~/test$ make hello
gcc -fPIC -shared -o libhello.so hello.c -lworld -L./lib -Wl,-rpath=./lib
root@ubuntu:~/test$ make main 
root@ubuntu:~/test$ ./main
root@ubuntu:~/test$

上图可见main的链接和运行都成功了,显然,由于world库是在./lib目录下,在主程序main链接阶段,通过主程序的rpath是找不到world库,唯一的可能性就是通过直接依赖库hello的rpath指定的目录找到了间接依赖库world。也就是说,直接依赖库的rpath目录也被用来搜索间接依赖库了。

综上,进行总结:

1.  编译生成动态库A时,并不是一定要去链接它的代码层面上的依赖库B,它们可以一起成其它使用者比如main的直接依赖库,这个时候A、B库在依赖关系树上是同层次的;当然也可以在在编译动态库A先链接好B,形成A依赖B的关系,而其它使用者比如main使用它们时,只须链接动态库A,形成main直接依赖A,A直接依赖B,main间接依赖B。这里就有了直接依赖和间接依赖的概念。注:main不一定是一个有main函数的可执行程序,也可以是一个动态库。

2. 链接器ld(gcc\g++在链接阶段调用ld)的-L指定的是链接阶段时的直接依赖库的搜索目录。

3. rpath-link指定了链接阶段所有间接依赖库的搜索目录,由于它没有被硬编码写进生成目标,所以只临时用于当前编译链接目标。比如main->A->B->C,其中->表示依赖关系,在编译链接A时,指定了rpath-link目录,而后编译链接main时,编译链接A时指定的rpath-link不复存在。

4. rpath指定了链接阶段间接依赖库的搜索目录,也指定了运行阶段直接依赖库的搜索目录。rpath被硬编码进了当前生成目标文件中,在依赖关系树上一直存在。当前生成目标main的直接依赖库A里的rapth也是A的直接依赖库B的链接阶段和运行阶段时的索目录之一。

5. 在依赖关系树上,如果各个库的rpath设置得不一样,或者没有设置,在链接阶段还好,通过rpath或者rpath-link统一指定就行,但运行阶段就麻烦了,要想最后整体打包发布,最好就是靠环境变量LD_LIBRARY_PATH或者/etc/ld.so.conf配置的方式了。

最后画个图再说一下rpath:

图中箭头表示依赖关系。

在编译链接A1时,直接依赖库B1只能放在A1的-L指定的./lib1目录中;在编译链接A2时,直接依赖库B2只能放在A2的-L指定的./lib2目录中。

在编译链接main时,直接依赖库A1和A2只能放在main的-L指定的./lib目录中;而间接依赖库B1既可以放在A1的rpath指定的./lib1中,也可以放在main的rpath指定的./lib中;同理,B2既可以在./lib2中,也可以在./lib中。当然了,B1放./lib2或者B2放./lib1中是找不到的。

在main运行时,直接依赖库A1和A2只能放在main的rpath指定的./lib目录中,间接依赖库B1只能放在A1的rpath指定的./lib1目录中,同理B2只能放在./lib2中。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sdghchj/article/details/107282085

智能推荐

ffmpeg音视频处理流程核心技术_视频效果演示系统的核心技术-程序员宅基地

文章浏览阅读712次。视频播放器原理 什么是ffmpeg? ffmpeg 音视频编/解码 流程图 ffmpeg 常用 struct AVFormatContext AVStream AVCodecContext AVCodec AVPacket AVFrame ffmpeg 常用Api av_register_all() avformat_alloc_output_context2() avio_open()..._视频效果演示系统的核心技术

Java List集合多种情况处理方法_java list reduce-程序员宅基地

文章浏览阅读449次。Java List集合多种情况处理方法:List集合交集、并集、差集、去重、与数组互转、删除、排序等操作_java list reduce

【UML】软件需求说明书_uml需求文档访客管家-程序员宅基地

文章浏览阅读2.3k次,点赞77次,收藏80次。需求:指人对客观事务需要的表现,体现为愿望、意向和兴趣,因而成为行动的一种直接原因。软件需求(IEEE软件工程标准词汇表):(1)用户解决问题或达到目标所需的条件或能力。(2)系统或系统部件要满足合同、标准、规范或者其他正式规定文档所需具有条 件或能力。(3)对(1)或(2)中的一个条件或一种能力的一种文档化表述。用例:定义 1 用例是对一个活动者使用一个系统的一项功能时进行交互过程中的一个文字描述序列。_uml需求文档访客管家

linux笔记-根文件系统及文件管理命令详解_根文件系统文本登陆-程序员宅基地

文章浏览阅读574次。第三章、Linux根文件系统及文件管理命令详解02_03_Linux根文件系统详解文件系统:rootfs: 根文件系统 FHS:Filesystem Hierarchy Standard(文件系统目录标准)的缩写,多数Linux版本采用这种文件组织形式,类似于Windows操作系统中c盘的文件目录,FHS采用树形结构组织文件。FHS定_根文件系统文本登陆

马克 · 扎克伯格期望的元宇宙到底会是什么样子?_马克扎克伯格博客-程序员宅基地

文章浏览阅读358次。马克 · 扎克伯格期望的元宇宙到底会是什么样子?_马克扎克伯格博客

使用Python开发游戏运行脚本(二)实现模拟点击_大漠窗口绑定成功按键-程序员宅基地

文章浏览阅读1.4w次,点赞8次,收藏78次。本文接上一篇文章 使用Python开发游戏运行脚本(一)成功调用大漠插件上一篇我们已经简单实现了python调用大漠插件并输出版本号的功能,接下来我们要做的就是通过大漠插件模拟鼠标点击和键盘文字输入。 由于近年来最热门的游戏基本都是手游,所以我们也会以手游为例来进行游戏脚本的开发。大漠插件是一款针对Windows平台的鼠标键盘模拟+图文查找库,这样我们要想实现手游脚本开发的第一步,就是下载Android模拟器,然后在对安卓模拟器进行鼠标和键盘的模拟,以此来实现自动化游戏脚本。一、Android模拟器的_大漠窗口绑定成功按键

随便推点

Canvas实现黑客帝国字符雨_canvas画字符雨-程序员宅基地

文章浏览阅读1k次。 利用Canvas的fillText(),隔一定时间在画布上作画&lt;!DOCTYPE html&gt;&lt;head&gt; &lt;meta charset="utf-8"&gt; &lt;meta name="viewport" content="width=device-width,initial-scale=1.0"&gt; &_canvas画字符雨

微信公众号跳转微信小程序,自定义微信跳转标签_opentaglist-程序员宅基地

文章浏览阅读1.1k次。微信公众号跳转微信小程序,自定义微信跳转标签_opentaglist

数据恢复技术与LVM数据恢复方法_vgreduce --removemissing恢复-程序员宅基地

文章浏览阅读4.3k次。数据恢复技术与LVM数据恢复方法 1摘要 随着计算机网络应用的发展,数据存储的安全性变的越来越重要。在常见的基于RAID和LVM的环境下面,当出现硬盘故障或者错误操作导致数据丢失的情况下,采用适当的数据恢复策略可以在很大程度上提供数据恢复的成功概率。本文研究了几种情况下的数据恢复技术和方法,为数据恢复和数据安全的预防提供了指导。 2数据恢复需求 2.1Linux IO存储栈 图(1)Linux IO 存储..._vgreduce --removemissing恢复

程序员如何年薪百万?深度学习必读书籍!_年薪百万的程序员看什么书-程序员宅基地

文章浏览阅读307次。深度学习程序员想年薪百万,基础必须打牢,所以推荐重点书籍Deep Learning花书Deep Learning with PythonDeep Learning for Computer Vision with PythonScikit-Learn与TensorFLow机器学习实用指南深度学习实践Tensorflow机器学习指南..._年薪百万的程序员看什么书

Window系统下C/C++程序毫秒和微秒级程序运行时间的获取方法_large_integer nfreq, t1, t2;-程序员宅基地

文章浏览阅读1.3k次。一、使用clock()函数,获取毫秒级(ms)时间[1]#include &lt;time.h&gt;//clock()头文件clock_t start = clock();{statement section}//测试代码段clock_t end = clock();printf("the running time is :%fs\n", (double)(end -s..._large_integer nfreq, t1, t2;

IntelliJ IDEA 使用教程-- 从入门到上瘾(配套视频教程)_idea使用视频教程-程序员宅基地

文章浏览阅读6.8k次,点赞3次,收藏31次。 前言: 至于用哪个开发工具本文暂且不做任何讨论, 今天着重讲解IntelliJ IDEA这款开发工具的使用 前言:IntelliJ IDEA如果说IntelliJ IDEA是一款现代化智能开发工具的话,Eclipse则称得上是石器时代的东西了。其实笔者也是一枚从Eclipse转IDEA的探索者,随着近期的不断开发实践和调试,逐步..._idea使用视频教程

推荐文章

热门文章

相关标签