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文件。

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

碰一碰发视频后端源码技术开发详解,支持OEM

一、引言 碰一碰发视频作为一种新颖的交互方式&#xff0c;在前端为用户带来便捷体验的同时&#xff0c;后端技术起着至关重要的支撑作用。后端负责管理视频资源、处理 NFC 标签信息与视频的关联逻辑、用户数据的存储与分析以及与前端的高效通信&#xff0c;确保整个系统稳定、…

HarmonyOS NEXT 实战之元服务:静态案例效果---本地特色景色

背景&#xff1a; 前几篇学习了元服务&#xff0c;后面几期就让我们开发简单的元服务吧&#xff0c;里面丰富的内容大家自己加&#xff0c;本期案例 仅供参考 先上本期效果图 &#xff0c;里面图片自行替换 效果图1完整代码案例如下&#xff1a; import { authentication } …

面试场景题系列:设计一致性哈希系统

为了实现横向扩展&#xff0c;在服务器之间高效和均匀地分配请求/数据是很重要的。一致性哈希是为了达成这个目标而被广泛使用的技术。首先&#xff0c;我们看一下什么是重新哈希问题。 1 重新哈希的问题 如果你有n个缓存服务器&#xff0c;常见的平衡负载的方法是使用如下哈希…

SqlSugar配置连接达梦数据库集群

安装达梦数据库时&#xff0c;会自动在当前操作系统中创建dm_svc.conf文件&#xff0c;可以在其中配置集群信息&#xff0c;不同操作系统下的文件位置如下图所示&#xff1a;   dm_svc.conf文件内的数据分为全局配置区域、服务配置区域&#xff0c;以参考文献1中的示例说明&…

scss配置全局变量报错[sass] Can‘t find stylesheet to import.

路径没有错误&#xff0c;使用别名即可 后又提示Deprecation Warning: Sass import rules are deprecated and will be removed in Dart Sass 3.0.0. 将import改为use 使用时在$前添加全局变量所在文件&#xff0c;即variable.

UGUI源码分析 --- UI的更新入口

首先所有的UI组件都是添加到画布&#xff08;Canvas&#xff09;显示的&#xff0c;所以首先要从Canvas入手&#xff0c;通过搜索脚本函数以及使用Profiler查看UI的函数的执行&#xff0c;定位到了willRenderCanvases函数 打开UI的文件夹&#xff0c; 通过搜索willRenderCanvas…

音视频入门知识(二)、图像篇

⭐二、图像篇 视频基本要素&#xff1a;宽、高、帧率、编码方式、码率、分辨率 ​ 其中码率的计算&#xff1a;码率(kbps)&#xff1d;文件大小(KB)&#xff0a;8&#xff0f;时间(秒)&#xff0c;即码率和视频文件大小成正比 YUV和RGB可相互转换 ★YUV&#xff08;原始数据&am…

电脑配置maven-3.6.1版本

不要使用太高的版本。 apache-maven-3.6.1-bin.zip 下载这个的maven压缩包 使用3.6.1版本。 解压缩放在本地软甲目录下面&#xff1a; 配置系统环境变量 在系统环境下面配置MAVEN_HOME 点击path 新增一条 在cmd中输入 mvn -v 检查maven的版本 配置阿里云镜像和本地的仓库 …

Python基础语法知识——数据类型的查询、数据类型转化

今天第一次学习python&#xff0c;之前学习过C&#xff0c;感觉学习起来还可以&#xff0c;就是刚用的时候有点手残&#xff0c;想的是python代码&#xff0c;结果写出来就是C,本人决定每天抽出时间写点。同时继续更新NX二次开发专栏学习&#xff0c;话不多说&#xff0c;晚上的…

Boost之log日志使用

不讲理论&#xff0c;直接上在程序中可用代码&#xff1a; 一、引入Boost模块 开发环境&#xff1a;Visual Studio 2017 Boost库版本&#xff1a;1.68.0 安装方式&#xff1a;Nuget 安装命令&#xff1a; #只安装下面几个即可 Install-package boost -version 1.68.0 Install…

C语言初阶习题【17】求N的阶乘( 递归和非递归实现)

1.题目 2.分析 非递归 需要用到循环&#xff0c;n个数就是循环n次&#xff0c;每次和之前的乘起来 例如 5的阶乘 就是 5*4 *3 *2 *1 循环1到5 。需要一个变量来接收每次的结果 注意这个地方是乘&#xff0c;所以要从1 开始&#xff0c;sum 也需要是1而不是0 for(i 1&#xf…

云效流水线自动化部署web静态网站

云效流水线部署静态网站 背景新建流水线配置流水线运行流水线总结 背景 配置流水线以前&#xff0c;每次更新导航网站都要登进去宝塔后台&#xff0c;删掉旧的目录和文件&#xff0c;再上传最新的文件&#xff0c;太麻烦啦 网上的博客基本都是分享vue项目&#xff0c;这一篇是…

【开源项目】数字孪生化工厂—开源工程及源码

飞渡科技数字孪生化工厂管理平台&#xff0c;基于自研孪生引擎&#xff0c;将物联网IOT、人工智能、大数据、云计算等技术应用于化工厂&#xff0c;为化工厂提供实时数据分析、工艺优化、设备运维等功能&#xff0c;助力提高生产效率以及提供安全保障。 通过可视化点位标注各厂…

SpringCloud整合skywalking实现链路追踪和日志采集

1.部署skywalking https://blog.csdn.net/qq_40942490/article/details/144701194 2.添加依赖 <!-- 日志采集 --><dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-logback-1.x</artifactId><version&g…

Linux下Nvidia显卡GPU开启驱动持久化

GPU开启驱动持久化的原因 GPU 驱动一直处于加载状态&#xff0c; 减少运行程序时驱动加载的延迟。不开启该模式时&#xff0c;在程序每次调用完 GPU 后&#xff0c; GPU 驱动都会被卸载&#xff0c;下次调用时再重新加载&#xff0c; 驱动频繁卸载加载&#xff0c; GPU 频繁被…

图像处理-Ch4-频率域处理

Ch4 频率域处理(Image Enhancement in Frequency Domain) FT &#xff1a;将信号表示成各种频率的正弦信号的线性组合。 频谱&#xff1a; ∣ F ( u , v ) ∣ [ R 2 ( u , v ) I 2 ( u , v ) ] 1 2 |F(u, v)| \left[ R^2(u, v) I^2(u, v) \right]^{\frac{1}{2}} ∣F(u,v)…

虚拟化 | Proxmox VE 8.x 开源的虚拟化平台快速上手指南

[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ] 0x00 简介说明 前言简述 描述:作为一个爱折腾的IT打工佬,时刻以学习各类新技术新知识为目标,这不正好有一台部署了VMware vSphere ESXi 虚拟化环境的服务器,由于正好安装其系统的磁盘有坏道,经常导致使用 ESXi 异…

rocketmq-push模式-消费侧重平衡-类流程图分析

1、观察consumer线程 使用arthas分析 MQClientFactoryScheduledThread 定时任务线程 定时任务线程&#xff0c;包含如下任务&#xff1a; 每2分钟更新nameServer列表 每30秒更新topic的路由信息 每30秒检查broker的存活&#xff0c;发送心跳请求 每5秒持久化消费队列的offset…

使用亚马逊针对 PyTorch 和 MinIO 的 S3 连接器实现可迭代式数据集

2023 年 11 月&#xff0c;Amazon 宣布推出适用于 PyTorch 的 S3 连接器。适用于 PyTorch 的 Amazon S3 连接器提供了专为 S3 对象存储构建的 PyTorch 数据集基元&#xff08;数据集和数据加载器&#xff09;的实现。它支持用于随机数据访问模式的地图样式数据集和用于流式处理…

[2003].第2-01节:关系型数据库表及SQL简介

所有博客大纲 后端学习大纲 MySQL学习大纲 1.数据库表介绍&#xff1a; 1.1.表、记录、字段 1.E-R&#xff08;entity-relationship&#xff0c;实体-联系&#xff09;模型中有三个主要概念是&#xff1a; 实体集 、 属性 、 联系集2.一个实体集&#xff08;class&#xff09…