Who are you?

Linux环境变量及编译器库路径

这篇文档主要对Linux下常见的环境变量做个大致的介绍,同时对gcc和gfortran的编译器库路径设置进行一个简单的学习。

<!—more—>

Linux环境变量

分类

  1. 根据生命周期可分
    • 永久环境变量:修改配置文件生效
    • 临时环境变量:利用export命令,仅在当前客户端下生效,关闭后失效
  2. 根据作用域可分
    • 系统环境变量:对所有用户有效
    • 用户环境变量:仅对特定用户有效

修改方式

  1. vim /etc/profile:永久,系统
  2. vim ~/.bashrc:永久,用户
  3. export 变量名=变量值:临时(在当前终端输入)

注意:在文件中修改时需要export 变量名=变量值,保存退出后需要source /etc/profile或是source ~/.bashrc才能生效

常见变量

  1. PATH:【一般用于添加可执行文件的路径】决定了shell将到哪些目录中寻找命令或程序,PATH的值是一系列目录,当运行一个程序时,Linux在这些目录下进行搜寻编译链接。定义格式:

    1
    export PATH=$PATH:<PATH 1>:<PATH 2>:<PATH 3>:------:<PATH N>
  2. HOME:指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)。

  3. HISTSIZE:指保存历史命令记录的条数。

  4. LOGNAME:指当前用户的登录名。

  5. HOSTNAME:指主机的名称,许多应用程序如果要用到主机名的话,通常是从这个环境变量中来取得的

  6. SHELL:指当前用户用的是哪种Shell。

  7. LANG/LANGUGE:和语言相关的环境变量,使用多种语言的用户可以修改此环境变量。

  8. MAIL:指当前用户的邮件存放目录。

注意:上述变量的名字并不固定,如HOSTNAME在某些Linux系统中可能设置成HOST

变量操作

  1. echo 显示某个环境变量值 echo $PATH
  2. export 设置一个新的环境变量 export HELLO="hello" (可以无引号)
  3. env 显示所有环境变量
  4. set 显示本地定义的shell变量
  5. unset 清除环境变量 unset HELLO
  6. readonly 设置只读环境变量 readonly HELLO

参考:

GCC编译器常用环境变量

编译阶段

  1. C_INCLUDE_PATH:gcc编译时查找头文件的目录

  2. CPLUS_INCLUDE_PATH:g++编译C++文件时查找头文件的目录

  3. LIBRARY_PATH:gcc和g++在编译的链接(link)阶段查找库文件的目录列表,在编译的时候需要指明所链接的库名,对于libxyz.a库,使用-lxyz指明即可

    • 我们也可以在编译的时候用-L直接指定库文件目录,然后再使用-lxyz来实现库文件的链接
    • 在这里库文件可以是静态的(static),也可以是动态的(shared)。
      • 对于静态库文件,其代码在编译链接后会复制到程序中去,因此程序在运行的时候不必再次搜寻相应的库文件
      • 对于动态库文件,在程序运行时需要动态链接到程序上,因此需要指定LD_LIBRARY_PATH路径
  4. gcc编译、链接生成可执行文件时,动态库的搜索路径顺序如下:

    1
    2
    3
    4
    # 不会递归在子目录下搜索
    1、gcc编译、链接命令中的-L选项;
    2、gcc的环境变量的LIBRARY_PATH(多个路径用冒号分割);
    3、gcc默认动态库目录:/lib:/usr/lib:usr/lib64:/usr/local/lib。

运行阶段

  1. LD_LIBRARY_PATH:程序运行时查找动态链接库(.so文件)的目录列表。

  2. LD_PRELOAD:【不常见,优先加载指定的共享库】在LD_PRELOAD(参考man ld.so的LD_PRELOAD部分)中定义的动态链接库会在其他动态链接库之前被加载,因此会覆盖其他链接库里定义的同名符号(函数变量等)。需要注意的是,在C++中覆盖C函数库中的函数时,应使用extern "C"阻止Name Mangling

    Tips:

    • 对于Debian系统,若是修改LD_LIBRARY_PATH无效,则可修改/etc/ld.so.conf或/etc/ld.so.conf.d/*.conf,将库目录作为一行加入以上的conf文件中,然后运行ldconfig命令即可。
    • 修改/etc/ld.so.conf文件进行搜索路径的设置方式对于程序连接时的库(包括共享库和静态库) 的定位已经足够了,但是对于使用了共享库的程序的执行还是不够的。这是因为为了加快程序执行时对共享库的定位速度,避免使用搜索路径查找共享库的低效率, 所以是直接读取库列表文件 /etc/ld.so.cache ,从中进行搜索的。/etc/ld.so.cache 是一个非文本的数据文件,不能直接编辑,它是根据 /etc/ld.so.conf 中设置的搜索路径由 /sbin/ldconfig 命令将这些搜索路径下的共享库文件集中在一起而生成的(ldconfig 命令要以 root 权限执行)。因此,为了保证程序执行时对库的定位,在 /etc/ld.so.conf 中进行了库搜索路径的设置之后,还必须要运行 /sbin/ldconfig 命令更新 /etc/ld.so.cache 文件之后才可以。ldconfig ,简单的说,它的作用就是将/etc/ld.so.conf列出的路径下的库文件缓存到/etc/ld.so.cache 以供使用。
  3. 可执行文件运行时动态库搜索路径

    1
    2
    3
    4
    5
    6
    7
    1、编译目标代码时指定的动态库搜索路径:用选项-Wl,rpath和include指定的动态库的搜索路径,比如gcc -Wl,-rpath,include -L. -ldltest hello.c,在执行文件时会搜索路径`./include`;
    2、环境变量LD_LIBRARY_PATH(多个路径用冒号分割);
    3、在 /etc/ld.so.conf.d/ 目录下的配置文件指定的动态库绝对路径(通过ldconfig生效,一般是非root用户时使用);
    4、gcc默认动态库目录:/lib:/usr/lib:usr/lib64:/usr/local/lib等。
    # 默认的动态库搜索路径可以通过ld --verbose命令查看
    # 查看某个程序需要的动态链接库可通过 ldd 来实现l

Gfortran编译器常用环境变量

【必须了解的一点】在 GCC 4.0 之前,g77 是 GCC 的一部分;此后,gfortran 是 GCC 的一部分。g95 是一个基于 GCC 的 Fortran 编译器,它不是 GCC 的一部分。

像 g++ 一样,gfortran 也只是设置过 Fortran 程序所需基本环境的 gcc 的一个前端。如下的Fortran例子我们可以通过下面 gcc 的命令来编译:

1
2
3
$ gfortran helloworld.f -o helloworld
# 等价于
$ gcc helloworld.f -o helloworld -lgfortran -lgfortranbegin

注意:

  • 库文件libgfortranbegin.a (通过命令行选项-lgfortranbegin被调用) 包含运行和终止一个 Fortran 程序所必须的开始和退出代码。库文件libgfortran.a 包含 Fortran 底层的输入输出等所需要的运行函数。当运行 gfortran 时,会自动链接这两个库

  • 当我们运行 gfortran 时,实际上运行并不是这个编译器,而是编译器驱动器。该驱动器解析命令行中所给出的选项,然后才调用真正的编译器,汇编器和链接器。默认情况下,编译器驱动器根据命令行中给定的文件的后缀决定它自己下一步的动作:一个名为 foo.c 将传递给 C 编译器,而名为 foo.f95 的文件将传递给 Fortran 95 的编译器,等等。

  • 理解了这一点,我们就可以知道gcc helloworld.f将自动调用 fortran 的编译器。只不过我们要为链接器指定必要的库。

    理解了这一点,我们可以知道 gfortran helloworld.c 可以编译一个 c 程序,gfortran helloworld.cpp -lstdc++编译的是一个 C++ 程序。

综上:

  • Gfortran所用的环境变量与gcc是一样的,其余不同的环境变量在以后遇到后再添加

参考: