linux 编译指定库、头文件的路径问题

本文介绍了如何解决编程中常见的链接错误,如undefined reference to错误,并详细解释了如何使用-l和-L参数指定链接库,以及-I参数指定头文件路径。此外还介绍了如何设定相关环境变量以及创建和使用静态链接库。

1. 为什么会出现undefined reference to 'xxxxx'错误?

首先这是链接错误,不是编译错误,也就是说如果只有这个错误,说明你的程序源码本身没有问题,是你用编译器编译时参数用得不对,你没有指定链接程序要用到得库,比如你的程序里用到了一些数学函数,那么你就要在编译参数里指定程序要链接数学库,方法是在编译命令行里加入-lm。

2.-l参数和-L参数

-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了。

-L参数跟着的是库文件所在的目录名。再比如我们把libtest.so放在/aaa/bbb/ccc目录下,那链接参数就是-L/aaa/bbb/ccc -ltest另外,大部分libxxxx.so只是一个链接

3. -include-I参数

-include用来包含头文件,但一般情况下包含头文件都在源码里用#include xxxxxx实现,-include参数很少用。-I参数是用来指定头文件目录,/usr/include目录一般是不用指定的,gcc知道去那里找,但是如果头文件不在/usr/include里我们就要用-I参数指定了,比如头文件放在/myinclude目录里,那编译命令行就要加上-I/myinclude参数了,如果不加你会得到一个"xxxx.h: No such file or directory"的错误。-I参数可以用相对路径,比如头文件在当前目录,可以用-I.来指定

4.几个相关的环境变量

PKG_CONFIG_PATH:用来指定pkg-config用到的pc文件的路径,默认是            /usr/lib/pkgconfig,pc文件是文本文件,扩展名是.pc,里面定义开发包的安装路径,Libs参数和Cflags参数等等。

CC:用来指定c编译器。

CXX:用来指定cxx编译器。

LIBS:跟上面的--libs作用差不多。

CFLAGS:跟上面的--cflags作用差不多。

CC,CXX,LIBS,CFLAGS手动编译时一般用不上,在做configure时有时用到,一般情况下不用管。

环境变量设定方法:export ENV_NAME=xxxxxxxxxxxxxxxxx

==============================================================================

[相关介绍]

应用程序(Applications)

应用程序通常都有固定的文件夹,系统通用程序放在/usr/bin,日后系统管理员在本地计算机安装的程序通常放在/usr/local/bin或者/opt文件夹下。除了系统程序外,大部分个人用到的程序都放在/usr /local下,所以保持/usr的整洁十分重要。当升级或者重装系统的时候,只要把/usr/local的程序备份一下就可以了。


一些其他的程序有自己特定的文件夹,比如X Window系统,通常安装在/usr/X11中,或者/usr/X11R6。GNU的编译器GCC,通常放置在/usr/bin或者/usr/local/bin中,不同的Linux版本可能位置稍有不同。


头文件(Head Files)

在C语言和其他语言中,头文件声明了系统函数和库函数,并且定义了一些常量。对于C语言,头文件基本上散落于/usr/include和它的子文件夹下。其他的编程语言的库函数分布在编译器定义的地方,比如在一些Linux版本中,X Window系统库函数分布在/usr/include/X11,GNU C++的库函数分布在/usr/include/g++。这些系统库函数的位置对于编译器来说都是“标准位置”,即编译器能够自动搜寻这些位置。


如果想引用位于标准位置之外的头文件,我们需要在调用编译器的时候加上-I标志,来显式的说明头文件所在文件夹。比如,

        $ gcc -I/usr/openwin/include hello.c

会告诉编译器除了标准位置外,还要去/usr/openwin/include看看有没有所需的头文件。详细情况见编译器的使用手册(man gcc)。


库函数(Library Files)

库函数就是函数的仓库,它们都经过编译,重用性不错。通常,库函数相互合作,来完成特定的任务。比如操控屏幕的库函数(cursers和ncursers库函数),数据库读取库函数(dbm库函数)等。


系统调用的标准库函数一般位于/lib以及/usr/lib。C编译器(精确点说,连接器)需要知道库函数的位置。默认情况下,它只搜索标准C库函数。


库函数文件通常开头字母是lib。后面的部分标示库函数的用途(比如C库函数用c标识, 数学库函数用m标示),小数点后的后缀表明库函数的类型:

  • .a 指静态链接库
  • .so 指动态链接库

去/usr/lib看一下,你会发现,库函数都有动态和静态两个版本。

查看动态库函数工具: ldd  *.so

与头文件一样,库函数通常放在标准位置,但我们也可以通过-L标识符,来添加新的搜索文件夹,-l指定特定的库函数文件。比如

        $ gcc -o x11fred -L/usr/openwin/lib x11fred.c -lX11

上述命令就会在编译期间,链接位于/usr/openwin/lib文件夹下的libX11函数库,编译生成x11fred。

静态链接库(Static Libraries)

最简单的函数库就是一些函数的简单集合。调用库函数中的函数时,需要在调用函数中include定义库函数的头文件。我们用-l选项添加标准函数库之外的函数库。

静态函数库,也称为archives ,通常以后缀.a结尾。


我们也可以创建维护自己的静态链接库函数。下面就介绍一下:

我们创建的库函数包括两个函数,然后在后面的实例中调用其中之一。两个库函数名字分别是fred和bill,仅仅是输出字符串。

  1. 首先,我们分别编写两个源文件(fred.c和bill.c),源文件如下:
  1. /* fred.c */ 
  2. #include <stdio.h> 
  3. void fred(int arg) 
  4. printf(“fred: you passed %d\n”, arg); 
  5. /* bill.c */ 
  6. #include <stdio.h> 
  7. void bill(char *arg) 
  8. printf(“bill: you passed %s\n”, arg); 
/* fred.c */ #include <stdio.h> void fred(int arg) { printf(“fred: you passed %d\n”, arg); } /* bill.c */ #include <stdio.h> void bill(char *arg) { printf(“bill: you passed %s\n”, arg); }

    2. 接下来,我们将这两个源文件编译为两个独立的目标文件。这里要用到GCC的-c选项。命令如下所示:

        $ gcc -c fred.c bill.c

        $ ls *.o

        bill.o fred.o

    3. 然后,写一个调用bill的测试函数,在此之前,最好为库函数建立一个头文件。头文件中有对库函数的声明。如果其他函数要调用库函数,必须在其代码中包含头文件。也可以在fred.c 和bill.c中包含该头文件,有利于编译器发现错误。头文件lib.h的内容如下所示:

  1. /*
  2. This is lib.h. It declares the functions fred and bill for users
  3. */ 
  4. void bill(char *); 
  5. void fred(int); 
/* This is lib.h. It declares the functions fred and bill for users */ void bill(char *); void fred(int);

    4. 测试函数program.c比较简单,代码如下:

  1. #include “lib.h” 
  2. int main() 
  3.     bill(“Hello World”); 
  4.     exit(0); 
#include “lib.h” int main() { bill(“Hello World”); exit(0); }

    5. 现在我们可以编译测试一下程序了:

        $ gcc -c program.c

        $ gcc -o program program.o bill.o

        $ ./program

        bill: we passed Hello World

    6. 接下来,我们要创建一个函数库。利用ar函数建立归档文件(archive),然后将目标文件加入其中。

        $ ar crv libfoo.a bill.o fred.o

        a - bill.o

        a - fred.o

    7. 现在可以使用函数库中的函数了。我们用-l指定函数库的名字。因为该函数库没有在标准文件夹中,我们还需要用-L将当前文件夹"."添加到搜索路径中。编译命令如下所示:

        $ gcc -o program program.o -L. -lfoo

共享链接库(Shared Libraries)

静态链接库的一个缺点是,如果我们同时运行了许多程序,并且它们使用了同一个库函数,这样,在内存中会大量拷贝同一库函数。这样,就会浪费很多珍贵的内存和存储空间。使用了共享链接库的Linux就可以避免这个问题。

共享函数库和静态函数在同一个地方,只是后缀有所不同。比如,在一个典型的Linux系统,标准的共享数序函数库是/usr/lib/libm.so。

当一个程序使用共享函数库时,在连接阶段并不把函数代码连接进来,而只是链接函数的一个引用。当最终的函数导入内存开始真正执行时,函数引用被解析,共享函数库的代码才真正导入到内存中。这样,共享链接库的函数就可以被许多程序同时共享,并且只需存储一次就可以了。共享函数库的另一个优点是,它可以独立更新,与调用它的函数毫不影响。

<think> 首先,用户的问题是:“我想查找在configure中指定系统头文件路径的方法。请问在configure中指定系统头文件路径的方法”。用户提到了之前的引用,但这些只是上下文,我需要基于系统指令和用户需求回答。 系统指令要求: - 所有行内数学表达式使用$...$。 - 独立公式使用$$...$$。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾添加引用标识。 - 结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 用户提供的引用是关于Linux头文件文件搜索路径的,特别是涉及configure脚本和pkg-config的使用。这些引用来自[^1]、[^2]、[^3]、[^4]。 用户的核心需求是:在configure脚本中指定系统头文件路径的方法。 我需要结合引用中的信息来回答问题。关键点: - pkg-config:用于在编译时传递头文件路径。configure脚本使用pkg-config来查找的存在和获取编译选项(如cflags和libs)。 - 环境变量:如PKG_CONFIG_PATH,用于指定pkg-config搜索.pc文件的路径。 - 系统路径:如/etc/ld.so.conf用于指定动态搜索路径,ldconfig用于更新缓存。 - configure脚本本身可能有选项来指定路径。 在configure脚本中指定头文件路径的常见方法: 1. **使用环境变量**:如CFLAGS用于指定编译器标志(包括头文件路径),LDFLAGS用于指定链接器标志(包括路径)。 2. **使用pkg-config**:通过设置PKG_CONFIG_PATH环境变量,指向包含.pc文件的目录。 3. **configure选项**:许多configure脚本提供--with-<package>-include和--with-<package>-lib选项来指定特定头文件路径。 4. **直接指定路径**:在运行configure时,可以通过CFLAGS和LDFLAGS指定路径,例如CFLAGS="-I/path/to/headers" LDFLAGS="-L/path/to/libs" ./configure。 从引用中: - 引用[^1]提到pkg-config用于查找和传递路径。 - 引用[^2]说明configure时pkg-config搜索.pc文件。 - 引用[^3]讨论动态搜索路径通过/etc/ld.so.conf。 - 引用[^4]描述动态搜索顺序。 对于configure脚本,焦点应放在编译时的路径指定,而不是运行时的动态路径。 回答结构: 1. **介绍方法**:清晰列出在configure中指定头文件路径的方法。 2. **逐步解释**:帮助用户理解如何操作。 3. **添加引用**:在相关内容末尾添加引用标识。 4. **生成相关问题**:在最后添加相关问题。 确保回答真实可靠:基于标准Linux编译实践。 最终回答用中文。 生成相关问题: - 例如: - 如何设置永久性的搜索路径? - pkg-config是如何工作的? - configure脚本的其他常见选项有哪些? 回答提纲: 1. 开头简述方法。 2. 详细解释每个方法: - 使用环境变量(CFLAGS, LDFLAGS)。 - 使用pkg-config和PKG_CONFIG_PATH。 - 使用configure脚本的特定选项。 3. 引用相关部分。 4. 结尾生成相关问题。 </think> ### 在configure中指定系统头文件路径的方法 在Linux环境下,`configure`脚本用于自动检测和配置软件编译环境。当需要指定系统头文件(如`.h`文件)和文件(如`.so`或`.a`文件)的路径时,可以通过以下几种方法实现。这些方法基于编译路径的设置,确保编译器能够正确找到依赖项。以下是逐步说明: #### 1. **使用环境变量指定路径** - **头文件路径**:通过设置 `CFLAGS`(C编译器标志)或 `CXXFLAGS`(C++编译器标志)变量,使用 `-I` 选项添加头文件目录。 - 例如,指定头文件路径 `/usr/local/include`: ```bash export CFLAGS="-I/usr/local/include" ./configure ``` - 如果需要添加多个路径,使用空格分隔:`CFLAGS="-I/path1 -I/path2"`。 - 这个方法适用于编译器在预处理阶段搜索头文件[^2]。 - **文件路径**:通过设置 `LDFLAGS`(链接器标志)变量,使用 `-L` 选项添加文件目录。 - 例如,指定文件路径 `/usr/local/lib`: ```bash export LDFLAGS="-L/usr/local/lib" ./configure ``` - 同时,可能需要设置 `LIBS` 变量来指定具体名(如 `-lmylib`): ```bash export LIBS="-lmylib" ./configure ``` - 这确保链接器在编译时能找到所需的[^1][^3]。 #### 2. **使用 `pkg-config` 工具自动管理路径** - **配置 `PKG_CONFIG_PATH`**:`pkg-config` 通过读取 `.pc` 文件(存储的元数据)来获取头文件路径。在运行 `configure` 前,设置 `PKG_CONFIG_PATH` 环境变量,指向包含这些 `.pc` 文件的目录。 - 例如,如果的 `.pc` 文件在 `/usr/local/lib/pkgconfig`: ```bash export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH" ./configure ``` - `configure` 脚本会自动调用 `pkg-config` 查询 `cflags`(头文件路径)和 `libs`(文件路径),无需手动指定 `CFLAGS` 或 `LDFLAGS`[^1][^2]。 - **测试 `pkg-config`**:运行 `pkg-config --cflags <名>` 或 `pkg-config --libs <名>` 验证路径是否正确,例如: ```bash pkg-config --cflags glib-2.0 # 输出头文件路径 pkg-config --libs glib-2.0 # 输出文件路径 ``` #### 3. **使用 `configure` 脚本本身的选项** - 许多 `configure` 脚本提供内置选项来直接指定路径: - **特定路径**:使用 `--with-<名>-include` 和 `--with-<名>-lib` 选项。 - 例如,指定 OpenSSL 的头文件路径: ```bash ./configure --with-openssl-include=/opt/openssl/include --with-openssl-lib=/opt/openssl/lib ``` - **通用路径**:使用 `--includedir` 和 `--libdir` 选项指定默认安装路径(但通常在编译依赖项时用于最终安装目录)。 - 例如: ```bash ./configure --includedir=/custom/include --libdir=/custom/lib ``` - 这些选项在脚本的 `--help` 中可查看:`./configure --help | grep include`[^2]。 #### 4. **永久性系统路径配置(辅助方法)** - 如果路径需要长期有效(不仅限于 `configure`),可以修改系统配置文件: - **动态路径**:编辑 `/etc/ld.so.conf` 添加目录,然后运行 `sudo ldconfig` 更新缓存。例如: ```bash echo "/usr/local/lib" | sudo tee -a /etc/ld.so.conf sudo ldconfig ``` - 这影响运行时搜索,但间接支持编译时链接[^3][^4]。 - **头文件路径**:将目录添加到编译器默认搜索路径(如 `/usr/include`),但不推荐修改系统目录,优先使用 `CFLAGS`。 ### 最佳实践和注意事项 - **组合使用**:通常结合环境变量和 `pkg-config`。例如,先设置 `PKG_CONFIG_PATH`,再运行 `configure`。 - **验证路径**:在 `configure` 后检查 `config.log` 文件,确认路径是否被正确识别。 - **常见问题**:如果路径包含空格,使用引号包裹(如 `CFLAGS="-I'/path with spaces'"`)。 - **引用说明**:`pkg-config` 依赖于 `.pc` 文件的正确性,每个文件定义了的名称、路径编译选项(如 `glib-2.0.pc`)[^1][^2]。动态搜索顺序可通过实验确定(如删除并测试执行文件)[^4],但运行时路径不影响 `configure` 的编译时检测。 通过以上方法,您可以灵活地在 `configure` 脚本中指定头文件路径,适应不同编译需求。 相关问题: 1. 如何创建自定义的pkg-config .pc文件? 2. 在Linux中,如何永久设置环境变量如 PKG_CONFIG_PATH? 3. configure脚本失败时,如何调试头文件缺失问题
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值