c++编译过程初识

编译过程

预处理:主要是执行一些预处理指令,主要是#开头的代码,如#include 的头文件、#define 定义的宏常量、#ifdef #ifndef #endif等条件编译的代码,具体包括查找头文件、进行宏替换、根据条件编译等操作。

g++ -E example.cpp -o example.i

编译:进行词法分析、语法分析、语义分析、代码优化等,将.i文件转换为汇编代码文件,即.s文件。

g++ -S example.i -o example.s

汇编:这一阶段不同平台(Windows、Linux)的汇编器将汇编代码翻译为二进制的机器码,可被计算机识别并执行。windows上是.obj文件,linux上是.o文件。

g++ -c example.s -o example.o

链接:将.o或.obj文件和所需的库文件组合生成最终的可执行文件。

静态链接:程序编译时,将所需的库文件直接嵌入到最终的可执行文件中,使程序在运行时不再依赖外部库文件,启动速度快,但占内存,且库文件更新需重新编译。

动态链接:程序运行时,将程序所需的库文件加载到内存中,供程序调用。节省磁盘空间,且只需要更新库文件,但外部依赖可能导致较多的环境问题。

一个C++程序可以同时包含动态链接和静态链接的部分。

g++ example.o -o exec # 或者exec.exe文件

静态链接库

windows上.lib文件,linux上.a文件。

cpp 复制代码
// test.h
#include<iostream>
using namespace std;

int cacl(int a, int b);

// test.cpp
#include "test.h"

int cacl(int a, int b){
    cout << "这是库文件内容" << endl;
    return a>b?a:b;
}

// main.cpp
#include "test.h"

int main(){
    int a = cacl(4, 5);
    cout << "这是main函数内容" << "  最大值是" << a << endl;
}
cpp 复制代码
静态库生成:
    1、g++ -c test.cpp test.o  // 生成.o文件
    2、ar rsc libxxx.a *.o   // ar打包工具,rsc打包参数,生成.a文件
    3、将.a文件和头文件发给客户使用即可
静态库使用
    1、.a文件、头文件、测试程序(main.cpp)放一起
    2、g++ main.cpp -o main -L./ -lxxx    
        // main是生成的可执行程序。 -L指定库文件路径, -l指定库文件名称(掐头去尾中间的名称)

动态链接库

windows上.dll文件, linux上.so文件。windows上用不同编译工具生成的动态库文件会有不同。动态库有执行权限,静态库没有执行权限;

在C++中加载动态链接库主要有两种方式:隐式加载(静态加载)和显式加载(动态加载)。上述main函数中的直接使用的方式就属于静态加载。动态加载需要用到LoadLibrary函数。

test.h test.cpp main.cpp内容同上,生成动态链接库是直接使用gcc命令并且添加-fPIC(-fpic)以及-shared参数,具体如下:

cpp 复制代码
动态库生成
    g++ -c  -fpic test.cpp -o test.o  // -fpic生成对位置没有要求的.o文件
    g++ -shared test.o -o libcacl.so  // -shared生成动态库
    发布动态库和头文件:提供 xxx.h和 xxx.so
动态库使用
    g++ main.cpp -L ./ -l cacl -o app  //编译测试程序

当生成可执行程序后,通过./app执行,会报错:./app: error while loading shared libraries: libcacl.so: cannot open shared object file: No such file or directory,这是因为找不到共享库文件,还需进行以下设置:

方案1、修改LD_LIBRARY_PATH环境变量,将动态库地址添加到变量里

vi ~/.bashrc,然后source生效

方案2、修改/etc/ld.so.conf文件

sudo /etc/ld.so.conf --添加动态库路径到此文件中

sudo ldconfig --更新/etc/ld.so.conf中的数据到/etc/ld.so.cache中

方案3、拷贝或创建软链接到/lib或/urs/lib目录

库拷贝

sudo cp libcalc.so /usr/lib

创建软链接(推荐这种方式)

sudo ln -s libcalc.so /usr/lib/libcalc.so

方案4、可执行文件内部的DT_RPATH段 --无法操作这种方案

通过以上几种方案后,无论我们把app移动到任何目录下,都可以./app执行啦~~

启动可执行程序前,可以通过一个命令检测程序能不能找到需要的动态库,这个命令是ldd

例如: ldd app,如果没有找到就会显示not found

makefile初识

以上编译时都需要执行g++命令,如果项目比较大的话,这种方式是比较麻烦的,这时候就需要makefile文件了,它是定义一系列的编译规则的文件,一旦定义好,只需要执行一个make命令,整个工程完全自动编译。

一个最简单的示例:

cpp 复制代码
/*target: dependencies
    command1
    command2
    ...
*/


test:
	g++ test.cpp main.cpp -o test

.PHONY:clean
clean:
	rm test

test就是目标文件,执行make命令时会执行"g++ test.cpp main.cpp -o test";

.PHONY是伪目标,为了防止有clean的同名文件。clean就是伪目标,执行make clean时会执行"rm test"的命令。

下面看一个优化后的makefile文件:

cpp 复制代码
# 自定义变量
target = test
src = $(wildcard *.cpp)  # wildcard函数,查找所有的cpp文件

$(target):
	$(CXX) $(src) -o $@   # CXX是预定义变量,$@是自动变量

.PHONY:clean
clean:
	-rm test

makefile提供了预定义变量、自动变量,还支持自定义变量,附上两张图片,忘了之前在哪看到的了,如有侵权删。需要注意,自动变量只能在command中使用。

除了wildcard函数外,还有patsubst函数:(这两个函数比较常用)

cpp 复制代码
patsubst : $(patsubst %.cpp, %.o $(src))
// 将src中的.cpp后缀文件改为.o后缀,这个只是makefile里的替换,并不会真的改磁盘里的文件。
// .o文件是汇编后的文件,是编译时的依赖,只是上面我们没有指定依赖,所以没用到

make执行时,会进行时间戳比较,目标文件和依赖的时间戳比较,若是目标文件比依赖靠后,那make执行会提示"已是最新"。

CMakeLists初识

CMakeLists.txt文件用来描述项目的结构和依赖关系,然后生成适合不同构建系统的项目文件,如Makefile、Visual Studio项目文件、Xcode项目文件等。所以,如果我们不想写makefile文件,就可通过CMakeLists文件来生成。

.

├── build

├── CMakeLists.txt

├── include

│ └── test.h

├── main.cpp

└── src

└── test.cpp

下面我们通过编写CMakeLists文件,来编译代码

cpp 复制代码
# cmake最低版本号
cmake_minimum_required(VERSION 3.0)
# 设置项目名称
project(cacl)

# 添加头文件路径
include_directories(./include)
# 添加可执行目标
add_executable(main main.cpp)

# 生成库文件
add_library(test SHARED src/test.cpp)
# 添加动态链接库
target_link_libraries(main test)

然后cd build目录,执行cmake ..,就会生成makefile文件,然后再执行make命令,就能得到可执行程序。以上编译过程实现了将test.cpp内容编译为so共享库,然后链接到main执行程序。

qmake初识

qmake是Qt官方提供的构建工具,专门用于构建Qt项目。它使用.pro文件来描述项目的结构和依赖关系,然后生成Makefile文件。

小节

以上知识点都比较浅显,目前我也是在学习c++的路上,希望与大家共勉~

参考链接

由浅入深,教你使用Makefile编译C++文件_c++ makefile-CSDN博客

c++ CMakeLists.txt详解_cmake --install build --strip-CSDN博客

相关推荐
梅茜Mercy7 分钟前
C++:入门详解(关于C与C++基本差别)
java·c语言·c++
cskywit7 分钟前
OpenManus介绍及本地部署体验
开发语言·php
張萠飛13 分钟前
Apache Doris中都用了哪些开发语言,编译过程中用到了哪些编译器,以及用到了哪些成熟的技术框架
开发语言·apache
功德+n15 分钟前
Apache POI详解
java·开发语言·maven·apache
f狐0狸x38 分钟前
【蓝桥杯每日一题】3.8
数据结构·c++·算法·蓝桥杯
牵牛老人39 分钟前
C++设计模式-工厂模式:从原理、适用场景、使用方法,常见问题和解决方案深度解析
开发语言·c++·设计模式
阿巴~阿巴~1 小时前
动态规划填表技巧:固定最后一个数 vs 固定倒数第二个数
c++·算法·动态规划
无难事者若执1 小时前
python LLM工具包
开发语言·python
h39741 小时前
Windows软件插件-视频渲染器
c++·windows·音视频
rkmhr_sef2 小时前
QoS质量配置
开发语言·智能路由器·php