Linux源码安装过程中大多会用到configure程序,它是一个script,执行时可以传入必要参数告知配置项目。

configure程序会根据传入的配置项目检查程序编译时所依赖的环境以及对程序编译安装进行配置,最终生成编译所需的Makefile文件供程序make命令读入使用,进而调用相关编译程式(通常调用编译程序都是gcc)来编译最终的二进制程序。而configure脚本在检查相应依赖环境时(例:所依赖软件的版本、相应库版本等),通常会通过pkg-config的工具来检测相应依赖环境,以及生成一些 bin/sbin等程序。

Linux的环境变量,一般在 /etc/profile 里配置,主要环境变量包含:

PATH、HISTSIZE、PKG_CONFIG_PATH

LIBRARY_PATH、LD_LIBRARY_PATH:使用 -L 指定包含lib/lib64 库文件路径搜索

C_INCLUDE_PATH、CPLUS_INCLUDE_PATH、CPATH:使用 -I 指定包含C/C++头文件路径搜索

 

米扑博客配置在 /etc/profile 文件里的环境变量(部分)

1、PATH

PATH是配置二进制 sbin、bin目录

示例:

## PATH放末尾, 让/usr/local/和自定义安装命令优先
export PATH=/usr/local/bin:$PATH

## sqlite3, pcre2, apr, apr-iconv, apr-util, openssl
export SQLITE_ROOT=/usr/local/sqlite3
export PATH=${SQLITE_ROOT}/bin:$PATH

export PCRE_ROOT=/usr/local/pcre2
export PATH=${PCRE_ROOT}/bin:$PATH

export APR_ROOT=/usr/local/apr
export PATH=${APR_ROOT}/bin:$PATH

export APR_ICONV_ROOT=/usr/local/apr-iconv
export PATH=${APR_ICONV_ROOT}/bin:$PATH

export APR_UTIL_ROOT=/usr/local/apr-util
export PATH=${APR_UTIL_ROOT}/bin:$PATH

export OPENSSL_ROOT=/usr/local/openssl
export PATH=${OPENSSL_ROOT}/bin:$PATH


export ImageMagick_ROOT=/usr/local/ImageMagick
export PATH=${ImageMagick_ROOT}/bin:$PATH

export libgd_ROOT=/usr/local/libgd
export PATH=${libgd_ROOT}/bin:$PATH

export libiconv_ROOT=/usr/local/libiconv
export PATH=${libiconv_ROOT}/bin:$PATH

export libevent_ROOT=/usr/local/libevent
export PATH=${libevent_ROOT}/bin:$PATH

export libmemcached_ROOT=/usr/local/libmemcached
export PATH=${libmemcached_ROOT}/bin:$PATH


## memcached
export MEMCACHED_ROOT=/usr/local/memcached
export PATH=${MEMCACHED_ROOT}/bin:$PATH

export REDIS_ROOT=/usr/local/redis
export PATH=${REDIS_ROOT}/bin:$PATH


## php, php-fpm
export PHP_ROOT=/usr/local/php
export PATH=$PHP_ROOT/bin:$PHP_ROOT/sbin:$PATH

## nginx
export NGINX_ROOT=/usr/local/nginx
export PATH=$NGINX_ROOT/sbin:$PATH


## 打印出环境变量
# echo $PATH
/usr/local/nginx/sbin:/usr/local/php/bin:/usr/local/php/sbin:/usr/local/redis/bin:/usr/local/memcached/bin:/usr/local/libmemcached/bin:/usr/local/libevent/bin:/usr/local/libiconv/bin:/usr/local/libgd/bin:/usr/local/ImageMagick/bin:/usr/local/openssl/bin:/usr/local/apr-util/bin:/usr/local/apr-iconv/bin:/usr/local/apr/bin:/usr/local/pcre2/bin:/usr/local/sqlite3/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin

 

2、LIBRARY_PATH、LD_LIBRARY_PATH

2.1 对于库文件的搜索路径:

LIBRARY_PATH=<your lib path>;
export LIBRARY_PATH

2.2 对于链接程序ld使用的库文件搜索路径:

LD_LIBRARY_PATH=<your ldlib path>;
export LD_LIBRARY_PATH

LIBRARY_PATH is used by gcc before compilation to search for directories containing libraries that need to be linked to your program.

LD_LIBRARY_PATH is used by your program to search for directories containing the libraries after it has been successfully compiled and linked.

EDIT:As pointed below, your libraries can be static or shared(静态库和共享库). If it is static then the code is copied over into your program and you don't need to search for the library after your program is compiled and linked. If your library is shared then it needs to be dynamically linked to your program and that's when LD_LIBRARY_PATH comes into play.

示例1:/etc/profile 配置

## 配置lib/lib64 环境变量, 以找到xx.so链接库
# 也可配置 echo "/usr/local/openssl/lib64" > /etc/ld.so.conf.d/openssl.conf && ldconfig -v 
export LD_LIBRARY_PATH=/usr/lib:/usr/lib64:${LD_LIBRARY_PATH}
export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64:${LD_LIBRARY_PATH}

export OPENSSL_ROOT=/usr/local/openssl
export LD_LIBRARY_PATH=${OPENSSL_ROOT}/lib:${OPENSSL_ROOT}/lib64:${LD_LIBRARY_PATH}

## 打印lib/lib64 环境变量
# echo $LIBRARY_PATH

# echo $LD_LIBRARY_PATH
/usr/local/openssl/lib:/usr/local/openssl/lib64:/usr/local/lib:/usr/local/lib64:/usr/lib:/usr/lib64:

注意:末尾冒号:之后为空,说明 LD_LIBRARY_PATH 初始值为空,改进方案:设置环境变量前可先判空

 

示例2:/etc/ld.so.conf 配置

库文件在连接(静态库和共享库)和运行(仅限于使用共享库的程序)时被使用,其搜索路径是在系统中进行设置的。一般Linux系统把/lib和/usr/lib两个目录作为默认的库搜索路径,所以使用这两个目录中的库是不需要进行设置搜索路径即可直接使用。对于处于默认库搜索路径之外的库,需要将库的位置添加到 库的搜索路径之中。

设置库文件的搜索路径有下列两种方式,可任选其一使用:

1)在环境变量 LD_LIBRARY_PATH 中指明库的搜索路径,即示例1:/etc/profile 配置
2)在/etc/ld.so.conf 文件中添加库的搜索路径。下面详细介绍

将自己可能存放库文件的路径都加入到/etc/ld.so.conf中是简单、明了、清晰的,添加方法也极其简单,将库文件的绝对路径直接写进去就OK了,一行一个。例如:

vim /etc/ld.so.conf

# cat /etc/ld.so.conf
include ld.so.conf.d/*.conf

/usr/local/lib64
/usr/local/lib
/usr/lib
/usr/lib64

配置单个程序库文件:1)新建文件,2)写入lib库路径,例如:

vim /etc/ld.so.conf.d/openssl.conf

# cat /etc/ld.so.conf.d/openssl.conf 
/usr/local/openssl/lib64

最后执行命令,使其生效:

ldconfig -v

库搜索路径的设置有两种方式:在环境变量LD_LIBRARY_PATH中设置以及在/etc/ld.so.conf文件中设置。其中,第二种设置方式需要root权限,以改变/etc/ld.so.conf文件并执行/sbin/ldconfig命令,使配置生效

 

3、C_INCLUDE_PATH、CPLUS_INCLUDE_PATH、CPATH

C_INCLUDE_PATH、CPLUS_INCLUDE_PATH、CPATH常被用于在全局性地添加预处理C/C++时的包含目录,其中:

C_INCLUDE_PATH仅对预处理C有效,被 C header 包含

CPLUS_INCLUDE_PATH仅对预处理C++有效,被C++ header 包含

CPATH对所有语言均有效

常用的容易出错的设置方法是在~/.bashrc等文件中简单地使用递归式赋值:

export C_INCLUDE_PATH=$C_INCLUDE_PATH:/somewhere/include

这条语句的命令会将C_INCLUDE_PATH赋值为它原本的值之后再附加上:/somewhere/include而组成的值。

例如,如果原本$C_INCLUDE_PATH的值为/previous/include,那么执行过这一条shell语句后,$C_INCLUDE_PATH的值就会变为/previous/include:/somewhere/include,而如果原本没有定义过环境变量C_INCLUDE_PATH或定义了但值为空,那么$C_INCLUDE_PATH的值就会变为:/somewhere/include

可为什么说这样写是容易出错的呢?

在Linux中是使用冒号:分隔两个目录的(Windows下常用分号;),使用这条语句期望达成的效果应该是添加/somewhere/include到预处理C时的包含目录。

GCC的官方文档影响GCC的环境变量中有这样一句:

In all these variables, an empty element instructs the compiler to search its current working directory. Empty elements can appear at the beginning or end of a path. For instance, if the value of CPATH is :/special/include, that has the same effect as -I. -I/special/include.

意思是:在所有这些变量中,一个空的元素会指示编译器搜索当前工作目录。空的元素可以出现在一个路径的开头或结尾。例如,如果CPATH的值是:/special/include,这将会等效于-I. -I/special/include.

因此在之前的例子中,只想在预处理搜索路径中添加一个/somewhere/include,期望的C_INCLUDE_PATH的值是/somewhere/include,但实际上C_INCLUDE_PATH却被赋值为了:/somewhere/include,开头的冒号之前虽然为空,却会为预处理搜索路径添加上当前工作目录,也即Linux中的.,且优先级是所有目录中最高的!

而这往往并不是我们想要的结果,这会导致预处理的包含目录随着当前工作目录的改变而改变,如果当前工作目录中恰好有一个与源代码中包含的文件同名的文件,则会导致不可预期的错误。

不巧的是,VSCode在自动生成的tasks.json中,默认的tasks.options.cwd恰好是/usr/bin,因此一旦错误地设置了C_INCLUDE_PATH的值,同时/usr/bin中恰好有一个同名的文件(要知道这里的文件大多都是可执行程序),那么在编译C程序时,就会错把这个同名文件当作源代码文件包含进来,接下来就可以欣赏海量的编译错误了。譬如目前最受欢迎的Linux发行版Manjaro,在安装好后的/usr/bin中就会有一个名为array的可执行程序,与C++的<array>重名。

正确方法:

首先明确一点,这几个预处理包含目录的环境变量(C_INCLUDE_PATH、CPLUS_INCLUDE_PATH、CPATH)并不是Linux操作系统的一部分,因此一般情况下Linux是不会设置这些环境变量的,其值都为空。

所以在对某一个环境变量第一次设置时,应该直接将其赋值为所需的目录,在之后的设置中再使用递归式的赋值;或者直接一次性将所有目录用:分隔开并一次性一起赋值;或者索性不使用这些环境变量,而是在编译时使用-I参数来添加包含目录

其他:

查看gcc预处理C时的的搜索目录:echo | gcc -x c -v -E -

查看gcc预处理C++时的的搜索目录:echo | gcc -x c++ -v -E -

查看clang预处理C++时的搜索目录:echo | clang -x c++ -v -E -

当前工作目录 cwd : current working directory

打印当前工作目录 pwd : print name of current/working directory

示例:

# echo $C_INCLUDE_PATH

# echo $CPLUS_INCLUDE_PATH

# echo $CPATH

说明:以上环境变量值都为空,说明没设置其值!

 

4、PKG_CONFIG_PATH

pkg-config 是一个用于管理和检索库的配置信息的工具,它使得编译软件项目更加容易。

当编写一个程序并依赖于其他库时,需告诉编译器如何找到这些库的头文件和链接文件:

  1. 包名称:库的名称,例如,libpng、libjpeg、libcurl 等。
  2. 包的版本:库的版本号,不同版本的库可能有不同的特性和API。
  3. 头文件路径:包含库的头文件(.h 文件)的目录路径。
  4. 库文件路径:包含库文件(.so、.a 文件等)的目录路径。
  5. 编译器和链接器选项:告诉编译器和链接器如何使用这些库。

pkg-config 工具通过提供一个方便的方式来获取这些信息,使得开发者不再需要手动设置这些路径和选项。它可以查找系统中已经安装的库,并为你提供正确的编译和链接选项。

pkg-config 就是用来解决编译连接不统一问题的一个管理工具。它的基本思想:pkg-config是通过库提供的一个.pc文件获得库的各种必要信息的,包括版本信息、编译和连接需要的参数等。需要的时候可以通过pkg-config提供的参数(--cflags, --libs),将所需信息提取出来供编译和连接使用。这样,不管库文件安装在哪,通过库对应的.pc文件就可以准确定位,可以使用相同的编译和连接命令,使得编译和连接界面统一。pkg-config 提供的主要功能有:

1)检查库的版本号。如果所需库的版本不满足要求,打印出错误信息,避免连接错误版本的库文件。
2)获得编译预处理参数,如宏定义,头文件的路径。
3)获得编译参数,如库及其依赖的其他库的位置,文件名及其他一些连接参数。
4)自动加入所依赖的其他库的设置。

示例:查看libwebp.pc文件内容,包含了 cflags、libs

# cat /usr/lib64/pkgconfig/libwebp.pc    
prefix=/usr
exec_prefix=/usr
libdir=/usr/lib64
includedir=/usr/include

Name: libwebp
Description: Library for the WebP graphics format
Version: 0.3.0
Cflags: -I${includedir}
Libs: -L${libdir} -lwebp
Libs.private: -lm -pthread

说明:使用 pkg-config 的 --cflags 参数给出在编译时所需要的选项,而 --libs 参数给出连接时选项

例如,假设一个 sample.c 的程序用到了 Glib 库,就可以这样编译:

$ gcc -c `pkg-config --cflags glib-2.0` sample.c

然后这样连接:

$ gcc sample.o -o sample `pkg-config --libs glib-2.0`

或者上面两步合并为以下一步:

$ gcc sample.c -o sample `pkg-config --cflags --libs glib-2.0`

可以看到,由于使用了pkg-config工具来获得库的选项,所以不论库安装在什么目录下,都可以使用相同的编译和连接命令,带来了编译和连接界面的统一。使用pkg-config工具提取库的编译和连接参数有两个基本的前提:

1)库本身在安装的时候必须提供一个相应的.pc文件,不这样做的库说明不支持pkg-config工具的使用。

2)pkg-config必须知道要到哪里去寻找此.pc 文件。

 

PKG_CONFIG_PATH 变量

在某些情况下,系统中可能存在多个版本的同一个库,或者库安装在非标准的路径下。为了确保 pkg-config 能够正确地找到所需的库,可以使用 PKG_CONFIG_PATH 环境变量来指定额外的库搜索路径。

PKG_CONFIG_PATH 是一个包含多个目录路径的环境变量,用于告诉 pkg-config 工具在哪些路径下查找库的 .pc 文件(.pc 文件包含了库的配置信息)。这样,开发者可以控制 pkg-config 的搜索路径,以便找到特定版本的库或非标准路径下的库。环境变量PKG_CONFIG_PATH是用来设置.pc文件的搜索路径的,pkg-config按照设置路径的先后顺序进行搜索,直到找到指定的.pc 文件为止。这样,库的头文件的搜索路径的设置实际上就变成了对.pc文件搜索路径的设置。

例如,如果你的项目依赖于一个位于 /path/to/custom/lib 目录下的自定义库,并且该库没有被系统默认搜索到,你可以通过设置 PKG_CONFIG_PATH 变量来让 pkg-config 找到这个库的配置文件。

在 Linux/Unix 系统上,可以像这样设置 PKG_CONFIG_PATH:

## 配置pkgconfig 环境变量, 以找到xx.so链接库
# php install: ./configure --prefix=/usr/local/php ....
export PKG_CONFIG_PATH="/usr/lib64/pkgconfig":$PKG_CONFIG_PATH
export PKG_CONFIG_PATH="/usr/share/pkgconfig":$PKG_CONFIG_PATH
export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig":$PKG_CONFIG_PATH
export PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig":$PKG_CONFIG_PATH

## 打印出变量值
# echo $PKG_CONFIG_PATH
/usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig:/usr/share/pkgconfig:/usr/lib64/pkgconfig:

说明:以上配置的 /usr/lib64/pkgconfig/ 目录下,就存在很多 xx.pc 文件:

# ls -l /usr/lib64/pkgconfig
total 488
-rw-r--r-- 1 root root  253 Sep 30  2020 com_err.pc
-rw-r--r-- 1 root root  231 Sep 30  2020 e2p.pc
-rw-r--r-- 1 root root  208 Oct  6  2022 expat.pc
-rw-r--r-- 1 root root  229 Sep 30  2020 ext2fs.pc
-rw-r--r-- 1 root root  415 Oct 31  2018 fontconfig.pc
-rw-r--r-- 1 root root  225 Oct 31  2018 fontutil.pc
-rw-r--r-- 1 root root  321 Sep  7  2017 form.pc
-rw-r--r-- 1 root root  324 Sep  7  2017 formw.pc
-rw-r--r-- 1 root root  316 Nov  6  2020 freetype2.pc
-rw-r--r-- 1 root root  439 Jun 10  2021 gio-2.0.pc
-rw-r--r-- 1 root root  269 Jun 10  2021 gio-unix-2.0.pc
-rw-r--r-- 1 root root  373 Jun 10  2021 glib-2.0.pc
-rw-r--r-- 1 root root  287 Jun 10  2021 gmodule-2.0.pc
-rw-r--r-- 1 root root  287 Jun 10  2021 gmodule-export-2.0.pc
-rw-r--r-- 1 root root  266 Jun 10  2021 gmodule-no-export-2.0.pc
-rw-r--r-- 1 root root  297 Mar 21  2023 libcrypto.pc
-rw-r--r-- 1 root root 2677 Dec 14  2023 libcurl.pc
-rw-r--r-- 1 root root  344 Jun 14  2014 libevent_openssl.pc
-rw-r--r-- 1 root root  304 Jun 14  2014 libevent.pc
-rw-r--r-- 1 root root  349 Jun 14  2014 libevent_pthreads.pc
-rw-r--r-- 1 root root  270 Oct  1  2020 libexslt.pc
-rw-r--r-- 1 root root  799 Nov 22  2015 libidn.pc
-rw-r--r-- 1 root root  224 Aug  9  2019 libjpeg.pc
-rw-r--r-- 1 root root  382 Jun 15  2022 liblzma.pc
-rw-r--r-- 1 root root  473 May 27 02:19 libmariadb.pc
-rw-r--r-- 1 root root  312 Aug  2  2017 libpcre16.pc
-rw-r--r-- 1 root root  312 Aug  2  2017 libpcre32.pc
-rw-r--r-- 1 root root  245 Aug  2  2017 libpcrecpp.pc
-rw-r--r-- 1 root root  307 Aug  2  2017 libpcre.pc
-rw-r--r-- 1 root root  287 Aug  2  2017 libpcreposix.pc
-rw-r--r-- 1 root root  226 Oct 13  2020 libpng15.pc
lrwxrwxrwx 1 root root   11 Jun 29 09:56 libpng.pc -> libpng15.pc
-rw-r--r-- 1 root root  245 Feb 24  2022 libsasl2.pc
-rw-r--r-- 1 root root  283 Apr  1  2020 libselinux.pc
-rw-r--r-- 1 root root  241 Oct 31  2018 libsepol.pc
-rw-r--r-- 1 root root  338 Mar 21  2023 libssl.pc
-rw-r--r-- 1 root root 1078 Aug  2  2017 libtasn1.pc
-rw-r--r-- 1 root root  235 Oct 13  2020 libtiff-4.pc
-rw-r--r-- 1 root root  236 Sep  8  2017 libtomcrypt.pc
-rw-r--r-- 1 root root  219 Jun 10  2014 libverto.pc
-rw-r--r-- 1 root root  256 May  5  2023 libwebpmux.pc
-rw-r--r-- 1 root root  228 May  5  2023 libwebp.pc
-rw-r--r-- 1 root root  243 Oct 22  2021 libxml-2.0.pc
-rw-r--r-- 1 root root  236 Oct  1  2020 libxslt.pc
-rw-r--r-- 1 root root  285 Jun 10  2014 libzip.pc
-rw-r--r-- 1 root root  671 Jan 13  2024 MagickCore-6.Q16.pc
-rw-r--r-- 1 root root  671 Jan 13  2024 MagickCore.pc
-rw-r--r-- 1 root root  648 Jan 13  2024 MagickWand-6.Q16.pc
-rw-r--r-- 1 root root  648 Jan 13  2024 MagickWand.pc
-rw-r--r-- 1 root root  793 May 27 02:19 mariadb.pc

测试是否添加成功:

# 执行命令在PKG_CONFIG_PATH环境变量路径里,找到libwebp.pc文件
# pkg-config --libs libwebp
-lwebp

 

5、HISTSIZE

命令的历史个数配置,一般自定义配置为有操作者、日期格式的,方便查阅:

vim /etc/profile

## history config, history log: /root/.bash_history and /home/mimvp/.bash_history 
#export HISTTIMEFORMAT="%F %T  "
#export HISTTIMEFORMAT="[%Y-%m-%d %H:%M:%S] "
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S  `who am i | awk '{print $1,$5}'` "
export HISTSIZE=5000

 

 

参考推荐:

Linux动态链接库.so文件的创建与使用

CentOS 搭建 SVN Server

LNMP(CentOS+Nginx+Mysql+PHP)服务器环境配置

CentOS “/lib64/libc.so.6: version `GLIBC_2.14′ not found”系统glibc版本太低