c++编译过程初识

news2025/1/1 15:23:59

编译过程

预处理:主要是执行一些预处理指令,主要是#开头的代码,如#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文件。

// 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;
}

 

静态库生成:
    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参数,具体如下:

动态库生成
    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命令,整个工程完全自动编译。

一个最简单的示例:

/*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文件:

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

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

.PHONY:clean
clean:
	-rm test

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

 

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

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文件,来编译代码

# 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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2267222.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JS中的闭包和上下文

变量提升 和 函数提升 这里要提到一个提升的概念&#xff0c;即在JS中&#xff0c;在解析代码之前还有一个预处理的过程&#xff0c;这个过程中会把部分变量和函数声明提前到代码的最顶部&#xff0c; 会在其他所有代码之前执行。虽然当我们按照规范&#xff08;严格模式或者T…

GitLab 将停止为中国区用户提供服务,60天迁移期如何应对? | LeetTalk Daily

“LeetTalk Daily”&#xff0c;每日科技前沿&#xff0c;由LeetTools AI精心筛选&#xff0c;为您带来最新鲜、最具洞察力的科技新闻。 GitLab作为一个广受欢迎的开源代码托管平台&#xff0c;近期宣布将停止服务中国大陆、澳门和香港地区的用户提供服务。根据官方通知&#x…

【2024年最新】BilibiliB站视频动态评论爬虫

废话不多说&#xff0c;直接先放git仓库&#xff1a;GitHub - linyuye/Bilibili_crawler: bilibili爬虫&#xff0c;基于selenium获取oid与cookie&#xff0c;request获取api内容 〇&#xff1a;概念简述 oid&#xff1a;视频/动态的uuid&#xff0c;b站对于发布内容的通用唯…

汽车IVI中控开发入门及进阶(46):FFmpeg

概述: FFmpeg 是领先的多媒体框架,能够解码、编码、 转码、复用、解复用、流、过滤和播放 几乎所有人类和机器创建的东西。它支持最模糊的古老格式,直到最前沿。无论它们是由某个标准委员会、社区还是公司设计的。它还具有高度的可移植性:FFmpeg 在各种构建环境、机器架构…

计算属性 简写和 完整写法

计算属性渲染不加上括号 methods方法和computed属性区别&#xff1a; computed只计算一次&#xff0c;然后缓存&#xff0c;后续直接拿出来使用&#xff0c;而methods每次使用每次计算&#xff0c;不会缓存 计算属性完整写法&#xff1a; 既获取又设置 slice 截取 成绩案例 …

WebRTC Simulcast 大小流介绍与优化实践

Simulcast 是 WebRTC 中的一种标准化技术 &#xff0c;简称大小流。通过 Simulcast&#xff0c;客户端可以同时发送同一视频的多个版本。每个版本都以不同的分辨率和帧率独立编码&#xff0c;带宽较多的拉流端可以接收较高质量的视频流&#xff0c;带宽有限的拉流端则可以接收较…

kong网关使用pre-function插件,改写接口的返回数据

一、背景 kong作为api网关&#xff0c;除了反向代理后端服务外&#xff0c;还可对接口进行预处理。 比如本文提及的一个小功能&#xff0c;根据http header某个字段的值&#xff0c;等于多少的时候&#xff0c;返回一个固定的报文。 使用到的kong插件是pre-function。 除了上…

轮播图带详情插件、uniApp插件

超级好用的轮播图 介绍访问地址参数介绍使用方法&#xff08;简单使用&#xff0c;参数结构点击链接查看详情&#xff09;图片展示 介绍 带有底部物品介绍以及价格的轮播图组件&#xff0c;持续维护&#xff0c;uniApp插件&#xff0c;直接下载填充数据就可以在项目里面使用 …

Vite内网ip访问,两种配置方式和修改端口号教程

目录 问题 两种解决方式 结果 总结 preview.host preview.port 问题 使用vite运行项目的时候&#xff0c;控制台会只出现127.0.0.1&#xff08;localhost&#xff09;本地地址访问项目。不可以通过公司内网ip访问&#xff0c;其他团队成员无法访问&#xff0c;这是因为没…

老旧小区用电安全保护装置#限流式防火保护器参数介绍#

摘要 随着居民住宅区用电负荷的增加&#xff0c;用电安全问题日益突出&#xff0c;火灾隐患频繁发生。防火限流式保护器作为一种新型电气安全设备&#xff0c;能够有效预防因电气故障引发的火灾事故。本文介绍了防火限流式保护器的工作原理、技术特点及其在居民住宅区用电系统…

Ftrans数据摆渡系统 搭建安全便捷跨网文件传输通道

一、专业数据摆渡系统对企业的意义 专业的数据摆渡系统对企业具有重要意义&#xff0c;主要体现在以下几个方面‌&#xff1a; 1、‌数据安全性‌&#xff1a;数据摆渡系统通过加密传输、访问控制和审计日志等功能&#xff0c;确保数据在传输和存储过程中的安全性。 2、‌高…

LabVIEW生物医学信号虚拟实验平台

介绍了一款基于LabVIEW的多功能生物医学信号处理实验平台的设计和实现。平台通过实践活动加强学生对理论的理解和应用能力&#xff0c;特别是在心电图(ECG)和脑电图(EEG)的信号处理方面。实验平台包括信号的滤波、特征提取和频谱分析等功能&#xff0c;能直观体验和掌握生物医学…

大数据实验三

Python and anaconda 实验三数据预处理和轨迹聚类参考地址&#xff1a; https://www.hifleet.com/wp/communities/data/hangyundashujujishukechengshiyanzhinanshujuyuchulijiguijijuleichixugengxinzhong#post-2212https://www.hifleet.com/wp/communities/data/hangyundas…

【python因果库实战14】因果生存分析3

标准化生存分析 参见《因果推断》一书第17.5节&#xff08;“参数化的g公式”&#xff09;。 在参数化标准化中&#xff0c;也称为“参数化g公式”&#xff0c;时间步k处的生存率是对协变量X水平和处理分配a条件下的条件生存率的加权平均&#xff0c;权重为每个分层中个体的比…

云边端一体化架构

云边端一体化架构是一种将云计算、边缘计算和终端设备相结合的分布式计算模型。该架构旨在通过优化资源分配和数据处理流程&#xff0c;提供更高效、更低延迟的服务体验。 下面是对这个架构的简要说明&#xff1a; 01云计算&#xff08;Cloud Computing&#xff09; — 作为中心…

C/C++ 数据结构与算法【哈夫曼树】 哈夫曼树详细解析【日常学习,考研必备】带图+详细代码

哈夫曼树&#xff08;最优二叉树&#xff09; 1&#xff09;基础概念 **路径&#xff1a;**从树中一个结点到另一个结点之间的分支构成这两个结点间的路径。 **结点的路径长度&#xff1a;**两结点间路径上的分支数。 **树的路径长度&#xff1a;**从树根到每一个结点的路径…

2、C#基于.net framework的应用开发实战编程 - 设计(二、三) - 编程手把手系列文章...

二、设计&#xff1b; 二&#xff0e;三、构建数据库&#xff1b; 此例子使用的是SQLite数据库&#xff0c;所以数据库工具用的SQLiteStudio x64&#xff0c;这个是SQLite专用的数据库设计管理工具&#xff0c;其它的数据库管理工具比如DBeaver的使用请见实战工具系列文章。 1、…

Edge SCDN酷盾安全重塑高效安全内容分发新生态

在数字化浪潮不断推进的今天&#xff0c;互联网内容的分发效率与安全性已成为企业业务发展的关键要素。酷盾安全推出的Edge Secure Content Delivery Network&#xff08;Edge SCDN&#xff09;&#xff0c;不仅集成了分布式DDoS防护、CC防护、WAF防护及BOT行为智能分析等安全加…

JAVA HTTP压缩数据

/*** 压缩数据包** param code* param data* param resp* throws IOException*/protected void writeZipResult(int code, Object data, HttpServletResponse resp) throws IOException {resp.setHeader("Content-Encoding", "gzip");// write到客户端resp…

工厂+策略模式之最佳实践(疾病报卡维护模块API设计)

目录 &#x1f4bb;业务场景 &#x1f527;应用技术 ⚙概要流程 ❗开发注意 服务类上标注了 自定义注解 却无法直接利用getDeclaredAnnotation 获取 *Spring代理机制 代理机制的工作原理 代理的工作机制 代理的使用场景 已获取EmrXXXServiceImpl 的Class&#xff0c;如…