编译方法(gcc,Makefile,CMake)

本文详细介绍了C++程序的编译过程,包括预处理、编译、汇编和链接四个步骤,并通过gcc和g++命令演示了多源文件的编译。接着,讲解了如何生成静态库和动态库文件,以及它们的区别。文章还对比了Makefile和CMake两种构建工具,强调了CMake的易用性和可移植性。最后,提供了单目录和多目录源文件的CMake构建实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

编译分四步
预处理:将不同文件中的源程序聚合到一起,并进行宏替换
编译:将高级语言(X=2)翻译成汇编语言或机器语言的过程
汇编:将汇编语言(MOV X,2)翻译成机器语言的过程
链接:将多个可重定位(内存的起始地址不固定)的机器代码文件链接到一起,解决外部内存地址问题


gcc

# gcc -E test.c -o test.i
-E 让编译器只对输入文件进行预处理

# gcc -S test.i -o test.s
-S 产生汇编语言文件,扩展名是.s

# gcc -c test.s -o test.o
-c 将汇编语言转化为机器语言

# gcc test.o -o test
-o 为产生的可执行文件指定文件名,若不加-o 则默认文件名为a.out

简单点一步到位
# gcc -c test.c -o test
直接生成一个test可执行程序
通过./test调用该程序

处理多源文件目录

(以下的树结构是通过tree命令实现的)
在这里插入图片描述
先给代码,可以自己动手试试

main.cc

#include <iostream>
#include "swap.h"
using namespace std;
int main()
{
        int a=1,b=10;
        cout<<"交换前"<<"a = "<<a<<" "<<"b = "<<b<<endl;
        swap(a,b);
        cout<<"交换后"<<"a = "<<a<<" "<<"b = "<<b<<endl;
        return 0;
}

swap.cc

#include "swap.h"
void swap(int &a,int &b)
{
        int tmp=a;
        a=b;
        b=tmp;
}

swap.h

#ifndef SWAP_H__
#define SWAP_H__
void swap(int&,int&);
#endif

命令行输入

I后面的参数是目录,因为源代码中我使用的是#include"swap.h"
需要指定目录才能让编译器找到头文件
# g++ main.cc src/swap.cc -Iinclude -o main

-I指定头文件路径。编译得到一个名字为main的可执行程序,输入./main运行结果如下。
在这里插入图片描述

生成静(动)态库文件进行编译

库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。unix系统的静态库文件和动态库文件后缀分别是.a和.so;windows静态库文件就是.lib文件,动态库文件就是.dll文件。
两种库的区别在于静态库被调用时直接加载到内存,而动态库再是在需要的时候加载到内存,不使用的时候再从内存释放。

静态库
(以下案例参照第一幅树状图)

//静态库在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中
# cd Test/src

//第一步生成.o汇编文件,
# g++ -c swap.cc -I../include

//第二步生成静态库libswap.a,静态库的命名 libxxx.a
# ar rs libswap.a swap.o

//回到Test目录
# cd ..

//第三步链接生成可执行文件
#-l 指定链接时需要的库,刚刚生成的libswap.a,swap是库名
#-L 链接src目录下的库文件
#-I 链接include目录下的头文件
# g++ main.cc -lswap -Lsrc -Iinclude -o static_main

生成静态库文件后能够直接运行

动态库

# cd Test/src
//第一步生成.o文件
#-fpic 创建与地址无关的编译程序(加上就完事了)
# g++ -c swap.cc -fpic -I../include

//第二步生成动库文件libswap.so
#-shared 表示生成的是动态库
# g++ -shared -o libswap.so swap.o

# cd ..

//第三步链接生成可执行文件
# g++ main.cc -lswap -Lsrc -Iinclude -o dynamic_main

最后命令行输入来运行,指定库文件搜索路径
# LD_LIBRARY_PATH=src ./dynamic_main

Makefile

直接看陈皓写的把,我写的不好
https://blog.csdn.net/haoel/article/details/2886

CMake

基本语法

项目构建工具cmake是makefile的上层工具,目的是为了产生可移植的makefile,并简化自己动手写makefile时的巨大工作量。
和makefile类似,要创建一个CMakeLists.txt

#基本语法:指令(参数 参数;参数)
#参数之间是空格或分号
#指令用大小写都行

#cmake最低版本需求,不加入此行会受到警告信息
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)

#添加编译参数
ADD_COMPILE_OPTIONS(-phread -wall)

ADD_SUBDIRECTORY(src)#指明本项目包含一个子目录src

#生成库文件
#${SRC},这个命令的是对SRC这个变量取值
ADD_LIBRARY ( Test ${SRC})

#把当前目录(.)下所有源代码文件和头文件加入变量SRC_LIST
AUX_SOURCE_DIRECTORY(. SRC_LIST)

#编译SRC_LIST变量代表的所有源文件生成可执行程序 main
ADD_EXECUTABLE(main ${SRC_LIST})

#添加头文件搜索路径,相当于于指定g++编译器的参数-I
#dir是路径(绝对路径和相对路径都可)
INCLUDE_DIRECTORIES(dir);

#添加库文件的搜索路径,相当于g++的参数-L
LINK_DIRECTORIES(dir)

#指定项目名称
PROJECT(HELLO) 

#定义src变量,值为hello1.c、hello2.c
SET(src hello1.c hello2.c)

#指明可执行文件 main需要连接一个名为Test的链接库
#类似g++ -l参数
TARGET_LINK_LIBRARIES( main Test )

编译流程

1、编写CMakeLists.txt
2、执行命令cmake生成一个makefile文件
3、执行命令make

两种构建方式

在正式开始写CMakeLists.txt之前,介绍一下两种构建方式
1、内部构建
cmake在当前目录会产生其他文件,而且这些文件我们不需要,就显得很杂乱,所以不推荐使用

2、外部构建(一般使用这个)
这个是通过mkdir 一个 build 目录,(名字自拟,常使用的是build),与内部构建不同的是,外部构建会把生成的文件都放在build目录下,所以推荐使用这个。

实例编译

单目录源文件内部构建编译

在这里插入图片描述
三步走战略:
第一步:编写CMakeLists.txt
如果用g++来编译:g++ HelloWorld.cc -o HelloWorld

#必须的这一步 设置可接受的最低版本号
#版本号的可以通过cmake --version命令查看
cmake_minimum_required(VERSION 3.0)

#设置项目名称
project(HELLOWORLD)
#项目名称应该要和add_executable的第一个参数名相同,大小写无所谓

#g++ HelloWorld.cc -o HelloWorld
add_executable(HelloWorld HelloWorld.cc)

第二步:执行cmake .
注意这个cmake后的点,表示CMakeLists.txt是在当前目录下
在这里插入图片描述
现在我们得到了一个我们需要的Makefile文件和其他我们不需要的东西,所以采用外部构建的方式是非常有必要的。

第三步
执行make
在这里插入图片描述
bingo,已经成功生成了一个HelloWorld可执行程序了。

多目录源文件外部构建编译

在这里插入图片描述
第一步:写CMakeLists.txt
如果用g++来编译:g++ main.cc src/swap.cc -Iinclude -o main

cmake_minimum_required(VERSION 3.0)

project(SWAP)

#g++ -Iinclude
//#include_directories(include),下面是绝对路径,这是相对路径,都是可以的
include_directories(${CMAKE_SOURCE_DIR}/include)

#g++ main.cc src/swap.cc -o main
add_executable(swap main.cc src/swap.cc)

第二步:cmake
mkdir build,在build目录下执行cmake(后面两个.),因为CMakeLists.txt在上一级目录。
在这里插入图片描述
第三步:make
在这里插入图片描述
基本的Cmake使用方法就介绍到这,可能以后会补充。

### MakefileCMake的区别 #### Makefile概述 Makefile是一种用于定义编译规则的文件,主要用于GNU Make工具。它通过一系列依赖关系来描述如何构建目标文件以及这些目标之间的相互依赖性[^1]。 - **语法结构简单**:基于简单的命令行指令组合而成。 - **灵活性高**:可以直接编写复杂的shell脚本逻辑。 - **维护成本较高**:随着项目规模增大,管理多个平台下的不同编译选项变得困难。 ```makefile # Example Makefile content CC=gcc CFLAGS=-Wall -g OBJS=main.o foo.o bar.o program: $(OBJS) $(CC) $(CFLAGS) -o program $(OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ ``` #### CMake概述 CMake是一个跨平台的自动化构建系统生成器,能够为不同的编译环境创建相应的本地化配置文件(如Unix Makefiles、Ninja scripts等)。其核心优势在于提供了高层次抽象接口简化了多平台支持过程中的复杂度处理[^2]。 - **易于移植性强**:一次编写`CMakeLists.txt`即可适用于多种操作系统和编译器组合。 - **内置模块丰富**:提供大量预定义宏函数帮助开发者快速完成常见任务设置。 - **版本兼容机制完善**:允许指定最低支持版本号以确保旧版特性仍能正常工作。 ```cmake # Example CMakeLists.txt content cmake_minimum_required(VERSION 3.0) project(MyProject) set(CMAKE_CXX_STANDARD 17) add_executable(program main.cpp foo.cpp bar.cpp) target_compile_options(program PRIVATE -Wall -Wextra -pedantic-errors) ``` ### 构建系统的差异对比 | 特征 | Makefile | CMake | | --- | --- | --- | | 平台适应性 | 需要针对特定OS定制 | 自动适配各主流开发环境 | | 学习曲线 | 较低;适合熟悉Shell编程者 | 初期可能稍显陡峭但长期有益于大型工程 | | 维护难度 | 大型项目下容易混乱 | 更加清晰有序利于团队协作 | ### 总结 对于小型个人项目而言,直接采用Makefile可能是最便捷的选择之一。然而,在面对更庞大且涉及多平台部署需求的应用场景时,则推荐优先考虑使用功能更为强大的CMake作为首选方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值