Linux下C++程序的编译链接与运行

C++ 程序的编译链接有时候会很复杂,特别是各种链接错误,这里我总结一下相关的知识点。

编译

编译是将源文件转化为目标文件的过程。一个源文件(.cpp)对应一个目标文件(.o)。

g++在默认情况下是直接将编译和链接一起做了,产生最终的可执行文件,过程中产生的.o文件会被删除。如果只编译不链接,可以加上-c参数。编译单个文件的一个作用是可以在整个程序没有完成的情况下,检查当前文件有没有编译错误。

g++ -c main.cpp	#生成main.o
g++ -c test.cpp	#生成test.o

如果源文件中引用了第三方的头文件,则需要指明头文件的搜索路径。

g++对头文件的搜索顺序是:

  1. 源文件所在目录,必须是#include "header.h"形式,如果是#include <header.h>则不会搜索本地目录
  2. -I参数指定的目录,多个-I按出现的顺序搜索
  3. 环境变量CPLUS_INCLUDE_PATH(C语言是C_INCLUDE_PATH)指定的目录,: 分割多个路径
  4. 标准系统目录,包括操作系统头文件和编译器自带的头文件。可以使用g++ -xc++ -E -v -命令查看当前search path

链接

将目标文件(.o)和库文件合并生成最终的可执行文件。

g++ main.o test.o

如果用到了第三方的库,则需要用参数-l指定库名。这里的库包括动态链接库和静态链接库,优先查找动态库,没有则找静态库。例如,-lopenssl,则查找的库文件为libopenssl.so和libopenssl.a,搜索的路径如下:

  1. -Llibpath参数指定的库路径
  2. 环境变量LIBRARY_PATH指定的目录,: 分割多个路径
  3. 系统默认的库目录,/lib、/lib64、/usr/lib、/usr/lib64

运行

运行时主要涉及到动态链接库的搜索,运行时对动态链接库的搜索顺序如下:

  1. 在编译目标代码时所传递的动态库搜索路径(注意,这里指的是通过-Wl,rpath=<path1>:<path2>-R选项传递的运行时动态库搜索路径,而不是通过-L选项传递的)
  2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径
  3. 配置文件/etc/ld.so.conf中所指定的动态库搜索路径(更改/etc/ld.so.conf之后,一定要执行命令ldconfig,该命令会将/etc/ld.so.conf文件中所有路径下的库载入内存)
  4. 系统默认的库目录,/lib、/lib64、/usr/lib、/usr/lib64

-Wl,rpath

加上-Wl,-rpath选项的作用就是指定程序运行时的库搜索目录。例如,将当前路径加入程序运行时的库搜索目录:

g++ -Wl,-rpath=`pwd` main.o -L. -ladd -o app

pkg-config

pkg-config在编译应用程序和库的时候作为一个工具来使用,可以帮助你插入正确的编译选项。

例如,程序中使用了openssl这个库,又不知道头文件和库文件目录在哪,就可以这样用:

gcc -o test test.c `pkg-config --libs --cflags openssl`

--cflags一般用于指定头文件,--libs一般用于指定库文件。

pkg-config是需要配置的。一个.pc文件,包含了库的信息,放置在pkg-config的搜索路径下,默认的路径是/usr/lib64/pkgconfig/,还可以通过PKG_CONFIG_PATH环境变量来指定pkg-config还应该在哪些地方去寻找.pc文件。