Bootstrap

C++编译连接问题总结(cmake库连接设置、环境变量设置与查看、C++静态库与动态库、软连接与硬链接)

一、静态库与动态库

1.1 静态库与动态库

1.1.1 编译过程

预编译 -->  编译 -->  汇编 --> 链接

  • 预编译,即预处理,主要处理在源代码文件中以“#”开始的预编译指令,如宏展开、处理条件编译指令、处理#include指令等。
  • 编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析以及优化后生成相应的汇编代码文件。
  • 汇编是将汇编代码转变成二进制文件。
  • 链接将二进制文件链接成一个可执行的命令,主要是把分散的数据和代码收集并合成一个单一的可加载并可执行的的文件。链接可以发生在代码静态编译、程序被加载时以及程序执行时。链接过程的主要工作是符号解析和重定位。

1.1.2 静态库

库是一组目标文件的包,就是一些最常用的代码编译成目标文件后打包存放。

库一般分为两种:静态库(.a 、.lib)动态库(.so 、.dll )所谓静态、动态是指链接过程。

静态库:在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

静态库的特点:

  • 静态库对函数库的链接是放在编译时期完成的。
  • 程序在运行时与函数库再无瓜葛,移植方便。
  • 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件

静态库命令规则:

Linux静态库命名规范,必须是"lib[your_library_name].a":lib为前缀,中间是静态库名,扩展名为.a。

1.2.3 动态库

动态库

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。

动态库特点:

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期。
  • 可以实现进程之间的资源共享。(因此动态库也称为共享库)
  • 将一些程序升级变得简单。

动态库特点:

动态链接库的名字形式为 libxxx.so,前缀是lib,后缀名为“.so”。

为什么编译出来的动态库,都是 lib*.so.0.0.0
然后建立一个连接,给lib*.so.0
再建一个连接,给lib*.so

这样做的目的是什么呢??

版本问题啊,一般so后的数字都是版本号。建链接后就可以在程序中使用一个统一的动态库名称。

1.3.4 软连接和硬链接

inode叫做索引节点号,这是Linux文件系统管理文件的方式。在建立文件系统时,会建立一个索引节点表,里面包含一定数量的索引节点。每当建立一个文件时,就会为他分配一个索引节点号,相当于文件的地址。

为解决文件的共享使用,Linux 系统引入了两种链接:硬链接 (hard link) 与软链接(又称符号链接,即 soft link 或 symbolic link)。链接为 Linux 系统解决了文件的共享使用,还带来了隐藏文件路径、增加权限安全及节省存储等好处。若一个 inode 号对应多个文件名,则称这些文件为硬链接。换言之,硬链接就是同一个文件使用了多个别名。

(1)硬链接是通过索引节点进行的链接。在Linux中,多个文件指向同一个索引节点是允许的,像这样的链接就是硬链接。硬链接只能在同一文件系统中的文件之间进行链接,不能对目录进行创建。

硬链接是指通过索引节点来进行链接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都会给它分配一个编号,这个编号被称为索引节点编号号(Inode Index)或者Inode,它是文件或者目录在一个文件系统中的唯一标识,文件的实际数据放置在数据区域(data block),它存储着文件重要参数信息,也就是元数据 (metadata),比如创建时间、修改时间、文件大小、属主、归属的用户组、读写权限、数据所在block号等。

 在Linux系统中,多个文件名指向同一索引节点(Inode)是正常且允许的。一般这种链接就称为硬链接。硬链接的作用之一是允许一个文件拥有多个有效路径名,这样用户就可以建立硬链接到重要的文件,以防止“误删”源数据(很多硬件,如netapp存储中的快照功能就应用了这个原理,增加一个快照就多了一个硬链接。 

不过硬链接只能在同一文件系统中的文件之间进行链接,不能对目录进行创建。之所以文件建立了硬链接就会防止数据误删,是因为文件系统的原理是,只要文件的索引节点还有一个以上的链接(仅删除了该文件的指向),只删除其中一个链接并不影响索引节点本身和其他的链接(数据的实体并未删除),只有当最后一个链接被删除后,此时如果有新数据要存储到磁盘上,被删除的文件的数据块及目录的链接才会被释放,空间被新数据暂用覆盖。

硬链接的应用:

当你希望有一个文件能实时同步修改的内容的时候 ,你可以尝试硬链接,为什么可以做到同步更新呢?当你对文件写操作的时候,在内核层面操作的是inode ,以为硬链接的inode 相同,所以会同步更新。cp就比较单纯了,肯定是两个inode,占用两倍的空间。大家可以根据需求自行选择要用硬链接还是cp。

// 不能为不存在的文件创建硬链接
[root@P1QMSPGPM01 file-loader]# ln test1.sh tmp.sh
ln: accessing `test1.sh': No such file or directory
 
 文件有相同的 inode 号以及 data block 
[root@P1QMSPGPM01 file-loader]# ln test.sh tmp.sh|ll -il
142171 -rwxr-xr-x 2 root root     2317 Mar 12 11:03 test.sh
142171 -rwxr-xr-x 2 root root     2317 Mar 12 11:03 tmp.sh
 
// 不能交叉文件系统
[root@P1QMSPGPM01 file-loader]# ln /dev/sda1 /opt/servers/file-loader/a.txt 
ln: creating hard link `/opt/servers/file-loader/a.txt' => `/dev/sda1': Invalid cross-device link
 
//不能为目录创建
[root@P1QMSPGPM01 file-loader]# ln deploy/ backup/
ln: `deploy/': hard link not allowed for directory

(2)软连接:软链接(也叫符号链接)与硬链接不同,文件用户数据块中存放的内容是另一文件的路径名的指向。软链接就是一个普通文件,只是数据块内容有点特殊。软链接可对文件或目录创建。软链接有着自己的 inode 号以及用户数据块。因此软链接的创建与使用没有类似硬链接的诸多限制

删除软链接并不影响被指向的文件,但若被指向的原文件被删除,则相关软连接就变成了死链接。

查看链接文件

 上图文件列表中第一列权限位标识第一个字符显示的是文件类型,-为一般文件,d为目录,而l显示的就是链接文件

软连接和硬链接的特点:

软链接:

  • 1.软链接是存放另一个文件的路径的形式存在。
  • 2.软链接可以 跨文件系统 ,硬链接不可以。
  • 3.软链接可以对一个不存在的文件名进行链接,硬链接必须要有源文件。
  • 4.软链接可以对目录进行链接。

硬链接:

  • 1. 硬链接,以文件副本的形式存在。但不占用实际空间。
  • 2. 不允许给目录创建硬链接。
  • 3. 硬链接只有在同一个文件系统中才能创建。
  • 4. 删除其中一个硬链接文件并不影响其他有相同 inode 号的文件。 

不论是硬链接或软链接都不会将原本的档案复制一份,只会占用非常少量的磁碟空间。

  • 删除源文件,软链接会失效,硬链接不会;
  • 软链接 可以为文件和目录(允许不存在)创建链接,硬链接 只可以为文件创建链接;
  • 软链接 可以跨文件系统,硬链接 必须是同一个文件系统;
  • 软链接的文件权限 可以和源文件不一样,硬链接的文件权限 一定和源文件一样;

创建链接:

linux系统可以用ln命令来创建链接文件。

ln命令格式: 

ln [参数] [源文件或目录] [目标文件或目录]

主要参数:

  • -i 交互模式,文件存在则提示用户是否覆盖。
  • -s 软链接(符号链接)。
  • -d 允许超级用户制作目录的硬链接。
  • -b 删除,覆盖以前建立的链接
  1. 软链接 (符号链接) ln -s   source  target 
  2. 硬链接 (实体链接)ln       source  target

应用举例:

touch infile  # 创建源文件
ln infile infile_hard_file  #创建硬链接
ll # 查看硬链接

 输出结果如下:

-rw-r--r-- 2 root root   0 6月  30 08:34 infile
-rw-r--r-- 2 root root   0 6月  30 08:34 infile_hard_file
-rw-r--r-- 1 root root 122 6月  30 08:13 test.txt
 编辑源文件 infile 的内容:可以看到源文件与硬链接的存储大小变化一致。

-rw-r--r-- 2 root root  86 6月  30 08:34 infile
-rw-r--r-- 2 root root  86 6月  30 08:34 infile_hard_file
-rw-r--r-- 1 root root 122 6月  30 08:13 test.txt

创建软连接

ln -s infile infile_soft_file  #创建软连接
ll

输出结果如下:

-rw-r--r-- 2 root root  86 6月  30 08:34 infile
-rw-r--r-- 2 root root  86 6月  30 08:34 infile_hard_file
lrwxrwxrwx 1 root root   6 6月  30 08:38 infile_soft_file -> infile
-rw-r--r-- 1 root root 122 6月  30 08:13 test.txt
 

通过查看 inode 号对比

ls -li

 1068224 -rw-r--r-- 2 root root  86 6月  30 08:34 infile
1068224 -rw-r--r-- 2 root root  86 6月  30 08:34 infile_hard_file

1068226 lrwxrwxrwx 1 root root   6 6月  30 08:38 infile_soft_file -> infile
1068225 -rw-r--r-- 1 root root 122 6月  30 08:13 test.txt
可知硬链接与源文件的 inode号相同,软连接的inode号不同。

删除软连接:使用rm指令

(1)先查看软连接,如删除 mylink

$ ls -l
total 4708
-rw-rw-r-- 1 abhishek abhishek 4794657 Sep 27 20:36 export.json
-rw-rw-r-- 1 abhishek abhishek     311 Sep 22 12:19 line.txt
lrwxrwxrwx 1 abhishek abhishek      26 Oct 17 11:24 mylink -> ./Documents/sample-mark.md

(2)删除

$ rm mylink  
$ ls -l

二、环境变量的查看与设置

一般是指操作系统中指定操作系统运行环境的一些参数。它相当于一个指针,想要查看变量的值,需要加上“$”。

2.1 显示环境变量

export命令显示当前系统定义的所有环境变量
echo $PATH命令输出当前的PATH环境变量的值
/home/uusama/bin:/home/uusama/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
其中PATH变量定义了运行命令的查找路径,以冒号:分割不同的路径,使用export定义的时候可加双引号也可不加。

2.2 配置环境变量

方法一:

export命令直接修改PATH的值,配置MySQL进入环境变量的方法:

export PATH=/home/uusama/mysql/bin:$PATH
 
# 或者把PATH放在前面
export PATH=$PATH:/home/uusama/mysql/bin
生效时间:立即生效
生效期限:当前终端有效,窗口关闭后无效
生效范围:仅对当前用户有效
配置的环境变量中不要忘了加上原来的配置,即$PATH部分,避免覆盖原来配置

方法二:

通过修改用户目录下的~/.bashrc文件进行配置
vim ~/.bashrc
 
# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin
生效时间:使用相同的用户打开新的终端时生效,或者手动source ~/.bashrc生效
生效期限:永久有效
生效范围:仅对当前用户有效
如果有后续的环境变量加载文件覆盖了PATH定义,则可能不生效

方法三:

vim ~/.bash_profile
和修改~/.bashrc文件类似,也是要在文件最后加上新的路径即可:

vim ~/.bash_profile
 
# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin
vim ~/.bash_profile
和修改~/.bashrc文件类似,也是要在文件最后加上新的路径即可:

vim ~/.bash_profile
 
# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin
生效时间:使用相同的用户打开新的终端时生效,或者手动source ~/.bash_profile生效
生效期限:永久有效
生效范围:仅对当前用户有效
如果没有~/.bash_profile文件,则可以编辑~/.profile文件或者新建一个

方法四:

该方法是修改系统配置,需要管理员权限(如root)或者对该文件的写入权限:

# 如果/etc/bashrc文件不可编辑,需要修改为可编辑
chmod -v u+w /etc/bashrc
 
vim /etc/bashrc
 
# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin
生效时间:新开终端生效,或者手动source /etc/bashrc生效
生效期限:永久有效
生效范围:对所有用户有效

三、cmake 中编译、连接、环境目录的设置

cmake 文件中

3.1 set_target_properties 设置库目录

功能:设置可执行程序编译时,所需要的库目录,及可执行程序在运行时所需库目录

语法:

set_target_properties(target1 target2 ...
                      PROPERTIES prop1 value1
                      prop2 value2 ...)

参数:

举例: 

set_target_properties(
    进程名
    PROPERTIES
    LINK_FLAGS -Wl,-rpath=/lib,-rpath-link=/lib,-L/static/lib,
)

-rpath= ,程序执行时搜索动态库的路径;(多个用“:”分割)

-rpath-link=,程序编译连接时搜索动态库的路径;(多个用“:”分割)

-L,程序编译连接时搜索静态态库的路径;(多个用“,”分割)

 设置构建目标时的属性值

set_target_properties( test
PROPERTIES
LINK_FLAGS -Wl,-rpath=/usr/local/lib:/usr/local/3_lib, 
-rpath-link=${PROJECT_SOURCE_DIR}/project/lib:${PROJECT_SOURCE_DIR}/project/3_lib,
-L${PROJECT_SOURCE_DIR}/project/static/3_lib,-L${PROJECT_SOURCE_DIR}/project/static/lib
)

第二种设置动态库目录的方法:使用 link_directories

语法:

set(LIB_DIR
   {PROJECT_SOURCE_DIR}/project/lib
   ${PROJECT_SOURCE_DIR}/project/3_lib
)
MESSAGE(STATUS "Lib目录: ${LIB_DIR}")
link_directories(${LIB_DIR})

 3.2  target_link_libraries 设置连接库名

 target_link_libraries

 指定链接目标文件时需要链接的外部库,相同于gcc参数-l

 “-I”(大写i),“-L”(大写l),“-l”(小写l)

gcc -o hello hello.c -I /home/hello/include -L /home/hello/lib -lworld

  •  “-I”(大写i): 寻找头文件的目录       -I /home/hello/include表示将/home/hello/include目录作为第一个寻找头文件的目录,寻找的顺序是:/home/hello/include-->/usr/include-->/usr/local/include 
  • “-L”(大写l) 寻找库文件的目录  -L /home/hello/lib表示将/home/hello/lib目录作为第一个寻找库文件的目录,寻找的顺序是:/home/hello/lib-->/lib-->/usr/lib-->/usr/local/lib
  • “-l”(小写l)  -lworld表示在上面的lib的路径中寻找libworld.so动态库文件(如果gcc编译选项中加入了“-static”表示寻找libworld.a静态库文件),程序链接的库名是world

 语法说明:

    target_link_libraries (目标名称
        PUBLIC 
               静态库名.a  
               -l动态库名
    )

如:

    target_link_libraries (test
        PUBLIC 
           test.a  
           -lboost_system
           -lboost_atomic
    )

3.3 使用cmake 构建静态库与动态库

(1)添加目录

(2) include目录 编写头文库 hello.h

#ifndef HELLO_H
#define HELLO_H
#include <iostream>

void HelloFunc();

#endif

(3)src 目录编写源文件 hello.ccp

#include "hello.h"

void HelloFunc(){
    std::cout << "Hello My Linux !" << std::endl;
}

(4)编写CMakeLists.txt

# 设置CMake最低版本
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

# 设置目标链接库文件的存放位置
SET(LIBRARY_OUTPUT_PATH "${PROJECT_BINARY_DIR}/lib")

# 添加源文件目录
AUX_SOURCE_DIRECTORY(${PROJECT_SOURCE_DIR}/src DIR_SRCS)

# 添加头文件目录
INCLUDE_DIRECTORIES("${PROJECT_SOURCE_DIR}/include")

# 生成动态库
ADD_LIBRARY(hello SHARED ${DIR_SRCS})

# 生成静态库
ADD_LIBRARY(hello_static STATIC ${DIR_SRCS})

(3) 进入build 目录,执行 cmake .. ,后执行make

若生成的库同时依赖其他库:

3.3 使用3.2中构建的动态库

(1)创建工程目录如下

(2)将3.2 中头文件与动态库文件  放入hello_lib 目录

 (3)编写主函数 main.cpp

#include <iostream>
#include <hello.h>
int main()
{
 HelloFunc();
 return 0;
}

(4)编写CMakeLists.txt


# 设置CMake最低版本
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

# 工程的名称
project(main)

#添加头文件目录
INCLUDE_DIRECTORIES(/home/herry/cmake_test/test_lib_main/hello_lib/include)

#添加库文件目录
link_directories(/home/herry/cmake_test/test_lib_main/hello_lib/lib)


# 添加需要构建的可执行文件
add_executable(${PROJECT_NAME} main.cpp)

#设置需要连设置库文件
target_link_libraries(${PROJECT_NAME} hello.so

(5)进入 build ,执行 cmake ../   ,执行make  

3.4 使用静态库

参考文献:

【1】Linux环境变量文件加载详解:Linux环境变量配置 | 《Linux就该这么学》

【2】C++静态库与动态库(比较透彻):C++静态库与动态库(比较透彻)_千么漾漾的博客-CSDN博客_c++ 静态库和动态库

【3】linux环境变量是什么意思: linux环境变量是什么意思-linux运维-PHP中文网

【4】【Linux】Linux系统硬链接和软链接【Linux】Linux系统硬链接和软链接 - songguojun - 博客园

【5】 set_target_propertiesset_target_properties — CMake 3.0.2 Documentation

【6】HelloWorld CMake CMake中构建静态库与动态库及其使用(转)HelloWorld CMake CMake中构建静态库与动态库及其使用 - 莫水千流 - 博客园

【7】CMake应用:CMakeLists.txt完全指南:CMake应用:CMakeLists.txt完全指南 - 知乎

【8】gcc -I -L -l区别:gcc -I -L -l区别_一路奔跑94的博客-CSDN博客

【9】CMake 在Linux上编译生成动态库和静态库:CMake 在Linux上编译生成动态库和静态库_斧冰-CSDN博客

【10】linux下生成动态链接库并使用(使用cmake):https://lightsail.blog.csdn.net/article/details/68941252?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control

【11】 Linux 软连接和硬链接_MyySophia的博客-CSDN博客_linux软连接和硬连接

;