05月03, 2016

程序编译时头文件、链接库文件目录的一些问题

这是一篇从主博客转移而来的文章。

本文本来是写在Ubuntu 14.04 LTS下配置MPICH、NetCDF、ifort环境这篇文章中的,后来考虑到篇幅太长,因此单独把它拿出来了。

以*nix为例,程序编译时,经常会使用到-I-L-l这三个参数,举例如下:

-I/home/fz/mpich/include
-L/usr/local/lib
-lmpi
  • -I+路径表示编译该程序时第一个寻找头文件的目录,之后是/usr/include/usr/local/include(与lib不同,/usr/local/include一般是默认路径,而/usr/local/lib一般需要自己添加)。
  • -L+路径表示编译该程序时第一个寻找库文件的目录,之后是/lib/usr/lib。用户常用库路径/usr/local/lib一般需要自己添加。
  • -l+库名称表示编译该程序时使用的动态链接库文件名称,例如-lmpi表示使用libmpi.so这一动态链接库。如果在该参数前使用-Bstatic参数,即-Bstatic -lmpi,则表示使用的是静态链接库,即libmpi.a。不加的话则默认是动态的,也就是-Bdynamic。也就是说,编译器会先去找so动态链接库,如果找不到则再去找a静态链接库,若还是找不到则报错。

我们知道,若想让一个程序运行时去调用某个动态链接库,则程序编译时需要使用-l参数指定动态链接库。

这里有两个问题:

1、编译器从哪去找名为libmpi.so的动态链接库文件?

2、程序运行时从哪去找名为libmpi.so的动态链接库文件?

首先,编译器、程序运行都会从默认库文件路径里去找,也就是/lib/usr/lib,但是如果不在这两个目录之中怎么办呢?

答案是:

1、编译器可以使用-L参数指定寻找动态链接库文件的路径。

2、想要程序运行时从某个目录寻找动态链接库文件,那就需要修改LD_LIBRARY_PATH这个环境变量的值了,例如这篇文章中配置NetCDF-C的过程。

不过,既然可以通过环境变量指定程序运行时调用的动态链接库路径,那么能否指定程序编译时所用的动态链接库路径,这样就无需使用-L参数了?

当然可以!使用LIBRARY_PATH环境变量即可!

另外,既然程序编译、运行时所有的动态链接库路径都可以用环境变量指定,那么程序编译时使用的头文件能否用环境变量指定呢?

其实也是可以的,不过不同编译器可能会使用不同的环境变量,例如GCC使用的是C_INCLUDE_PATHCPLUS_INCLUDE_PATHOBJC_INCLUDE_PATH

总结一下上面所说的几点:

  • 程序编译时所用的动态链接库路径,需要使用-L参数来指定。不过,也可以在LIBRARY_PATH环境变量中添加,从而无需使用-L参数手动指定。但是-l一直都是需要的,它用来告诉编译器该程序会调用哪个动态(静态)链接库。
  • 程序运行时所用的动态链接库路径,需要在LD_LIBRARY_PATH环境变量中添加。
  • 程序编译时所用的头文件路径,也可以在对应的环境变量中添加,而无需使用-I参数手动指定。不过不同编译器使用的环境变量可能会不一样。

最后要提一点:如果在编译时链接了so动态链接库,程序想要运行,就得使用LD_LIBRARY_PATH指定动态链接库所在目录。因为动态链接库的特性就是在运行时才载入,如果不指定它的路径,那么程序肯定就找不到相关函数和变量,没法运行。那既然只在运行时才需要它的内容,为什么编译的时候也需要链接它呢?这是为了让编译器知道它需要哪些so文件以及在其中可以找到哪些函数和变量,这样当程序运行的时候,就会将它需要的so文件载入,不然程序怎么知道它要载入哪些动态链接库文件呢?而且这样做的话如果找不到某个库,也可以提示出具体缺少哪个so文件。

本文链接:https://debug.fanzheng.org/post/about-header-and-link-when-compiling.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。