失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Linux下C/C++程序编译链接加载过程中的常见问题及解决方法

Linux下C/C++程序编译链接加载过程中的常见问题及解决方法

时间:2019-03-06 03:41:39

相关推荐

Linux下C/C++程序编译链接加载过程中的常见问题及解决方法

Linux下C/C++程序编译链接加载过程中的常见问题及解决方法

1 头文件包含的问题

报错信息

该错误通常发生在编译时,常见报错信息如下:

run.cpp:2:10: fatal error: dlpack/dlpack.h: No such file or directory#include <dlpack/dlpack.h>^~~~~~~~~~~~~~~~~compilation terminated.

头文件包含的问题是新手常常会遇到的问题,在这里,我们要先搞懂 gcc 关于头文件搜索的相关过程、参数选项和环境变量,之后头文件包含的相关问题就迎刃而解了。

头文件的搜索顺序

我们先来看一下头文件的搜索顺序,我们知道,在 C/C++ 源文件中,包含头文件有两种形式,即分别是尖括号和双引号来包含:#inlcude <xxx>#include "xxx"

<>

对于尖括号包含的头文件,通常搜索顺序为:

搜索-I指定的目录搜索 gcc 环境变量C_INCLUDE_PATH(如果是C++程序,则为CPLUS_INCLUDE_PATH) 中指定的目录搜索 gcc 的默认目录:/usr/include/usr/local/include/usr/lib/gcc/x86_64-linux-gnu/7.5.0/include

“”

而对于双引号包含的头文件,我们很清楚,主要是为了当前工作目录下去搜索,这种情况的详细搜索顺序是这样的:

搜索当前目录搜索-I参数指定的目录搜索 gcc 环境变量C_INCLUDE_PATH(如果是C++程序,则为CPLUS_INCLUDE_PATH) 中指定的目录搜索 gcc 的默认目录:/usr/include/usr/local/include/usr/lib/gcc/x86_64-linux-gnu/7.5.0/include

可以看到,相对于<>的包含方式,""就是先多搜索了当前目录。

另外,要指出,编译器会按照上述顺序搜索头文件,一旦找到了就不会就绪往下进行了,也就是说,如果有同名的头文件,顺序靠后的搜索目录中的头文件会被靠前的屏蔽掉。

解决方法:编译参数选项和环境变量

通过上面介绍的与包含头文件相关的编译参数选项和环境变量我们也不难发现,当面对找不到头文件的错误时,有两种方式可以告诉编译器去找所需的头文件的目录:即通过编译参数选项或环境变量

编译参数选项-I参数指定编译器会去搜索的头文件包含目录。环境变量C_INCLUDE_PATHCPLUS_INCULDE_PATH分别指定C代码和C++代码需要去搜索的头文件包含目录。

注意这里不是由PATH环境变量指定的,PATH目录下都是一些可执行文件,他不是用来指定头文件的搜索目录的,

这里要说下 include 的默认目录,它也不是由$ATH环境变量指定的(也就是说在所有头文件包含的行为中,和PATH环境变量一毛钱关系没有),而是由g++的配置prefix指定的,可以通过gcc -v来查看:

Using built-in specs.COLLECT_GCC=gccCOLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapperOFFLOAD_TARGET_NAMES=nvptx-noneOFFLOAD_TARGET_DEFAULT=1Target: x86_64-linux-gnuConfigured with: ../src/configure -v --with-pkgversion='Ubuntu 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --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-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --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 --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnuThread model: posixgcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)

2 编译连接时的未定义引用的问题

报错信息

常见报错信息如下:

/tmp/ccWYumCZ.o: In function `main':run.cpp:(.text+0x8f): undefined reference to `tvm::runtime::Module::LoadFromFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'collect2: error: ld returned 1 exit status

编译链接时库搜索顺序

首先还是要明确在编译连接时的库的搜索顺序:

搜索-L+-l参数指定的搜索环境变量LIBRARY_PATH+ 参数-l指定的搜索默认目录中的/lib/usr/lib/usr/local/lib

解决方法:编译参数选项和环境变量

与上面头文件包含问题类似,解决方法还是靠添加编译参数选项和环境变量。这里需要注意的是:-L参数选项和LIBRARY_PATH环境变量都可以负责指定库的搜索目录,而-l参数选项是来指定搜索目录下的具体的库文件的名字。也就是说,-LLIBRARY_PATH二选一,再加上-l参数,才行。

比如我们在/home/song/tvm/build/目录下,有两个库文件libtvm.solibtvm_runtime.so,我们要用它们,有以下两种方法:

方法一:

export LIBRARY_PATH=/home/song/tvm/build/:$LIBRARY_PATHgcc main.cpp -ltvm -ltvm_runtime

方法二:

gcc main.cpp -L/home/song/tvm/build/ -ltvm -ltvm_runtime

可参考:gcc参数 -i, -L, -l, -include

3 运行时链接库的问题

报错信息

该问题发生在运行时,即我们已经得到可执行文件a.out了,但是在运行时却报错类似:

./a.out: error while loading shared libraries: libtvm.so: cannot open shared object file: No such file or directory

我们还可以借助工具ldd来查看a.out需要运行时链接的库是否都可用:

ldd a.out# 输出:linux-vdso.so.1 (0x00007ffc0ebca000)libtvm.so => not foundlibstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f1b829b7000)libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1b8279f000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1b823ae000)libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1b8000)/lib64/ld-linux-x86-64.so.2 (0x00007f1b82f45000)

可以看到,确实如同报错信息提示的那样,libtvm.so它是找不到的。

运行时链接库的搜索顺序

我们还是先来看一下运行时链接库的搜索顺序:

编译目标代码时指定的动态库搜索路径

环境变量LD_LIBRARY_PATH指定的动态库搜索路径

配置文件/etc/ld.so.conf中指定的动态库搜索路径

默认的动态库搜索路径

/lib

/lib64

/usr/lib

应注意动态库搜寻路径并不包括当前文件夹,所以当即使可执行文件和其所需的so文件在同一文件夹,也会出现找不到so的问题,就像#include <xxxx>也不搜索当前目录

解决方法:编译选项参数、环境变量、配置文件、软链接

这里编译选项参数和环境变量的方法与上面类似,这里就不再赘述了,说说配置文件和软链接的方法:

修改/etc/ld.so.conf文件

/etc/ld.so.conf文件中添加运行时库的路径。然后执行ldconfig命令。

或者在/etc/ld.so.conf.d目录下添加一个新建的.conf新文件,然后在文件中输入新的路径,然后再执行ldconfig命令:

vim /etc/ld.so.conf.d/MyLibrary.conf# 加上自己需要的搜索路径sudo ldconfig

添加运行时库的软链接

可以用ln命令来创建运行时库的软链接,并把软链接放在系统默认路径下,然后程序链接时只需链接动态库的软链接就行。这样做的好处是当动态库升级时,只需替换掉原来的老软链接就行,无需修改编译命令。其实上面的问题2 也可以考虑用这种方法。

Ref:

/s/blog_7195909a0100zi7i.html

/Damocles_shi/article/details/104085803

如果觉得《Linux下C/C++程序编译链接加载过程中的常见问题及解决方法》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。