g++链接及动态库和静态库浅析
文章目录
- 制作动态库
- 第一个问题
- 第二个问题
- 为什么没用-I(大写的i)也可以?
制作动态库
- myprint.h文件
和#pragma once void myprint();
myprint.cc 文件#include <stdio.h> #include "myprint.h" void myprint() { printf("myprint\n"); }
- 使用命令制作动态库
[test_so_a] :) mkdir so [test_so_a] :) g++ -fPIC -o myprint.o -c myprint.cc [test_so_a] :) g++ -shared -o libmyprint.so myprint.o [test_so_a] :) mv libmyprint.so so/ [test_so_a] :) ls -al ./so/ total 24 drwxrwxr-x 2 pengchen pengchen 4096 Mar 13 19:06 . drwxrwxr-x 3 pengchen pengchen 4096 Mar 13 19:06 .. -rwxrwxr-x 1 pengchen pengchen 16208 Mar 13 19:06 libmyprint.so [test_so_a] :)
- 使用动态库main.cc
生成可执行文件指令#include "myprint.h" int main() { myprint(); }
这里几个问题?[test_so_a] :) g++ -E main.cc -o main_dynamic.i [test_so_a] :) g++ -S main_dynamic.i -o main_dynamic.s [test_so_a] :) g++ -c main_dynamic.s -o main_dynamic.o [test_so_a] :) g++ -o main_dynamic main_dynamic.o -L ./so/ -lmyprint [test_so_a] :) echo $LD_LIBRARY_PATH [test_so_a] :) ./main_dynamic ./main_dynamic: error while loading shared libraries: libmyprint.so: cannot open shared object file: No such file or directory [test_so_a] :( export LD_LIBRARY_PATH=./so/:${LD_LIBRARY_PATH} [test_so_a] :) ./main_dynamic myprint [test_so_a] :)
- 为什么在链接阶段需要添加-L(大些L)和-l(小写L,与大写的i意思完全不同)选项?
- 环境变量LD_LIBRARY_PATH的作用?
- 为什么没用-I(大写的i)也可以?
第一个问题
-
为什么需要-L以“编译和链接阶段,指定链接器应该搜索哪些目录以找到库文件。”?反正动态库又不放到可执行文件里面?LD_LIBRARY_PATH不就行了?
-L 选项在编译和链接阶段起到了关键作用,确保了链接器能正确解析符号、生成符号表和依赖信息。虽然动态库本身不嵌入到可执行文件中,但这些步骤对于生成一个能够正确运行的可执行文件是不可或缺的。而 LD_LIBRARY_PATH 则是在运行时阶段工作的,保证程序在执行时能找到这些库。两者的作用和使用阶段不同,不能互相替代。
- 验证是否具有”正确解析符号“ 功能
发现不管是在目标文件还是可执行文件,myprint()都是未解析的符号错误(undefined reference),GPT说对于动态库是正常的。那拿静态库试一下[test_so_a] :) nm -AC main_dynamic.o main_dynamic.o: U _GLOBAL_OFFSET_TABLE_ main_dynamic.o:0000000000000000 T main main_dynamic.o: U myprint() [test_so_a] :) nm -AC main_dynamic main_dynamic:0000000000004010 B __bss_start main_dynamic:0000000000004010 b completed.8061 main_dynamic: w __cxa_finalize@@GLIBC_2.2.5 main_dynamic:0000000000004000 D __data_start main_dynamic:0000000000004000 W data_start main_dynamic:0000000000001090 t deregister_tm_clones main_dynamic:0000000000001100 t __do_global_dtors_aux main_dynamic:0000000000003db0 d __do_global_dtors_aux_fini_array_entry main_dynamic:0000000000004008 D __dso_handle main_dynamic:0000000000003db8 d _DYNAMIC main_dynamic:0000000000004010 D _edata main_dynamic:0000000000004018 B _end main_dynamic:00000000000011d8 T _fini main_dynamic:0000000000001140 t frame_dummy main_dynamic:0000000000003da8 d __frame_dummy_init_array_entry main_dynamic:000000000000214c r __FRAME_END__ main_dynamic:0000000000003fb8 d _GLOBAL_OFFSET_TABLE_ main_dynamic: w __gmon_start__ main_dynamic:0000000000002004 r __GNU_EH_FRAME_HDR main_dynamic:0000000000001000 t _init main_dynamic:0000000000003db0 d __init_array_end main_dynamic:0000000000003da8 d __init_array_start main_dynamic:0000000000002000 R _IO_stdin_used main_dynamic: w _ITM_deregisterTMCloneTable main_dynamic: w _ITM_registerTMCloneTable main_dynamic:00000000000011d0 T __libc_csu_fini main_dynamic:0000000000001160 T __libc_csu_init main_dynamic: U __libc_start_main@@GLIBC_2.2.5 main_dynamic:0000000000001149 T main main_dynamic:00000000000010c0 t register_tm_clones main_dynamic:0000000000001060 T _start main_dynamic:0000000000004010 D __TMC_END__ main_dynamic: U myprint()
发现[test_so_a] :) g++ -c myprint.cc -o myprint.o [test_so_a] :) ar rcs ./a/libmyprint.a myprint.o [test_so_a] :) g++ -o main_static -L ./a/ -lmyprint /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start': (.text+0x24): undefined reference to `main' collect2: error: ld returned 1 exit status [test_so_a] :( g++ -o main_static main_static.o -L ./a/ -lmyprint [test_so_a] :) ./main_static myprint [test_so_a] :) nm -AC main_static.o main_static.o: U _GLOBAL_OFFSET_TABLE_ main_static.o:0000000000000000 T main main_static.o: U myprint() [test_so_a] :) nm -AC main_static main_static:0000000000004010 B __bss_start main_static:0000000000004010 b completed.8061 main_static: w __cxa_finalize@@GLIBC_2.2.5 main_static:0000000000004000 D __data_start main_static:0000000000004000 W data_start main_static:0000000000001090 t deregister_tm_clones main_static:0000000000001100 t __do_global_dtors_aux main_static:0000000000003dc0 d __do_global_dtors_aux_fini_array_entry main_static:0000000000004008 D __dso_handle main_static:0000000000003dc8 d _DYNAMIC main_static:0000000000004010 D _edata main_static:0000000000004018 B _end main_static:00000000000011f8 T _fini main_static:0000000000001140 t frame_dummy main_static:0000000000003db8 d __frame_dummy_init_array_entry main_static:000000000000217c r __FRAME_END__ main_static:0000000000003fb8 d _GLOBAL_OFFSET_TABLE_ main_static: w __gmon_start__ main_static:000000000000200c r __GNU_EH_FRAME_HDR main_static:0000000000001000 t _init main_static:0000000000003dc0 d __init_array_end main_static:0000000000003db8 d __init_array_start main_static:0000000000002000 R _IO_stdin_used main_static: w _ITM_deregisterTMCloneTable main_static: w _ITM_registerTMCloneTable main_static:00000000000011f0 T __libc_csu_fini main_static:0000000000001180 T __libc_csu_init main_static: U __libc_start_main@@GLIBC_2.2.5 main_static:0000000000001149 T main main_static: U puts@@GLIBC_2.2.5 main_static:00000000000010c0 t register_tm_clones main_static:0000000000001060 T _start main_static:0000000000004010 D __TMC_END__ main_static:000000000000115d T myprint() [test_so_a] :)
main_static:000000000000115d T myprint()
。 - 生成符号表
其实上述已经为可执行文件main_dynamic和main_static生成了带有myprint的符号表,毕竟没有-L都无法生成文件。故不表。 - 查看是否生成依赖信息
[test_so_a] :( g++ -o main_dynamic main_dynamic.o /usr/bin/ld: main_dynamic.o: in function `main': main.cc:(.text+0x9): undefined reference to `myprint()' collect2: error: ld returned 1 exit status [test_so_a] :( g++ -o main_dynamic main_dynamic.o -L ./so -lmyprint [test_so_a] :) ldd main_dynamic linux-vdso.so.1 (0x00007ffdb0769000) libmyprint.so => ./so/libmyprint.so (0x00007f0a63c44000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0a63a47000) /lib64/ld-linux-x86-64.so.2 (0x00007f0a63c50000) [test_so_a] :)
- 验证是否具有”正确解析符号“ 功能
第二个问题
- 环境变量LD_LIBRARY_PATH的作用?
为可执行程序指定在运行时加载自定义动态库的搜索路径。对于标准库,其标准搜索路径是(这里不确定是不是这个命令):
这里[test_so_a] :) ldconfig -v 2>/dev/null | grep -v ^$'\t' /usr/lib/x86_64-linux-gnu/libfakeroot: /usr/local/lib: /lib/x86_64-linux-gnu: /lib: [test_so_a] :) cpp -v /dev/null -o /dev/null Using built-in specs. COLLECT_GCC=cpp OFFLOAD_TARGET_NAMES=nvptx-none:hsa OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.4.0-1ubuntu1~20.04.2' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-9QDOt0/gcc-9-9.4.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2) COLLECT_GCC_OPTIONS='-E' '-v' '-o' '/dev/null' '-mtune=generic' '-march=x86-64' /usr/lib/gcc/x86_64-linux-gnu/9/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu /dev/null -o /dev/null -mtune=generic -march=x86-64 -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /usr/lib/gcc/x86_64-linux-gnu/9/include /usr/local/include /usr/include/x86_64-linux-gnu /usr/include End of search list. COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-E' '-v' '-o' '/dev/null' '-mtune=generic' '-march=x86-64' [test_so_a] :)
参考https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dynamic_or_shared.html[test_so_a] :) echo $LD_LIBRARY_PATH [test_so_a] :) ./main_dynamic ./main_dynamic: error while loading shared libraries: libmyprint.so: cannot open shared object file: No such file or directory [test_so_a] :( export LD_LIBRARY_PATH=./so/:${LD_LIBRARY_PATH} [test_so_a] :) ./main_dynamic myprint [test_so_a] :)
https://www.zhihu.com/question/537366949
为什么没用-I(大写的i)也可以?
- 参考
You can specify any number or combination of these options on the command line to search for header files in several directories. The lookup order is as follows:
For the quote form of the include directive, the directory of the current file is searched first.
For the quote form of the include directive, the directories specified by -iquote options are searched in left-to-right order, as they appear on the command line.
Directories specified with -I options are scanned in left-to-right order.
Directories specified with -isystem options are scanned in left-to-right order.
Standard system directories are scanned.
Directories specified with -idirafter options are scanned in left-to-right order.
参考
https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html