当前位置: 首页 > news >正文

Makefile与CMake

一、Makefile 核心内容

1. Makefile 基础结构与工作原理
  • 三要素
    • 目标(Target):要生成的文件或执行的操作(如可执行文件、清理操作)。
    • 依赖(Dependency):生成目标所需的文件或其他目标。
    • 命令(Command):生成目标的具体指令(需以Tab 键开头)。
  • 工作原理
    Make 通过检查依赖文件的修改时间,仅重新编译更新过的文件,提高编译效率。例如:
    simple: main.o foo.o    # 目标:simple,依赖:main.o和foo.ogcc -o simple main.o foo.o  # 命令
    main.o: main.c          # 子目标:main.o依赖main.cgcc -c main.c -o main.o
    
2. 关键特性与语法
  • 伪对象(.PHONY)
    避免 Make 将目标视为同名文件,强制执行命令。例如:

    .PHONY: clean
    clean:rm simple main.o foo.o
    
     
    • 若不声明.PHONY,当目录存在clean文件时,make clean会认为目标已更新,不执行删除命令。
  • 变量与自动变量

    • 自定义变量:用于存储重复内容(如编译器、文件列表),例:
      CC = gcc
      SRCS = main.c foo.c
      OBJS = $(SRCS:.c=.o)  # 将.c替换为.o
      
    • 自动变量
      • $@:当前目标名(如simple)。
      • $^:所有依赖文件(如main.o foo.o)。
      • $<:第一个依赖文件(如main.c)。
      $(EXE): $(OBJS)$(CC) -o $@ $^  # 等价于gcc -o simple main.o foo.o
      
  • 函数与第三方库依赖

    • wildcard:获取指定模式的文件列表,例:SRCS = $(wildcard *.c)
    • patsubst:字符串替换,例:OBJS = $(patsubst %.c, %.o, $(SRCS))
    • 第三方库链接:通过-I指定头文件路径,-L指定库路径,-l指定库名,例:

      makefile

      CFLAGS += -I./include
      LDFLAGS += -L./lib -lpthread
      
3. 实战范例
  • 简单示例

    all: test@echo "hello all"
    test:@echo "hello test"
    
     
    • make默认执行第一个目标(all),依赖test,因此先执行test再执行all
  • 复杂编译流程
    通过变量和自动变量简化多文件编译,例:

    CC = gcc
    SRCS = main.c foo.c
    OBJS = $(SRCS:.c=.o)
    EXE = simple$(EXE): $(OBJS)$(CC) -o $@ $^%.o: %.c$(CC) -c $< -o $@
    

二、CMake 核心内容

1. CMake 概述
  • 定位:跨平台构建工具,通过编写CMakeLists.txt生成 Makefile 或其他项目文件(如 VS 工程),简化多平台编译配置。
  • 优势:相比 Makefile,语法更简洁,支持模块化设计,适合大型项目。
2. 基础语法与流程
  • 核心命令
    • cmake_minimum_required:指定 CMake 最低版本。
    • project:定义项目名称和语言(如CCXX)。
    • add_executable:添加可执行文件,关联源文件。
    • add_library:生成库文件(SHARED动态库,STATIC静态库)。
    • target_link_libraries:链接库文件到可执行文件。
  • 编译流程
    1. 在项目根目录创建CMakeLists.txt
    2. 创建build目录,进入后执行cmake ..生成 Makefile。
    3. 执行make编译。
3. 实战场景
  • 单文件编译

    cmake_minimum_required(VERSION 2.8)
    project(0voice)
    set(SRC_LIST main.c)
    add_executable(0voice ${SRC_LIST})
    
  • 多目录与库管理

    • 子目录编译为库
      # 根目录CMakeLists.txt
      add_subdirectory(src/dir1)  # 添加子目录
      add_subdirectory(src/dir2)
      add_executable(main main.c)
      target_link_libraries(main dir1 dir2)  # 链接库
      
       
      # src/dir1/CMakeLists.txt
      add_library(dir1 SHARED dir1.c)  # 生成动态库
      
    • 强制使用静态库
      target_link_libraries(main libdir1.a)  # 指定静态库文件名
      
  • 安装与编译选项

    • 指定安装路径
      cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..  # 安装到/usr/local
      make install  # 安装库、头文件等到目标路径
      
    • Debug/Release 模式
      if(${CMAKE_BUILD_TYPE} MATCHES "Release")set(CMAKE_CXX_FLAGS "-O3 -Wall")  #  Release优化
      else()set(CMAKE_CXX_FLAGS "-O0 -g")     # Debug调试符号
      endif()
      
特性MakefileCMake
学习难度较高(语法灵活但复杂)较低(模块化命令,易上手)
跨平台支持依赖平台特定语法(如 GNU Make)原生支持多平台(生成对应平台构建文件)
大型项目管理手动维护依赖关系,易出错支持子目录、库管理,自动处理依赖
适用场景简单项目或需要精细控制编译流程的场景复杂多模块项目、跨平台开发

建议

  • 小型项目或需要深入理解编译原理时,使用 Makefile。
  • 中大型项目或跨平台开发时,优先选择 CMake,搭配make执行编译。

三、Makefile和CMake的具体案例

案例 1:Makefile 跨目录编译

项目结构
project_make/
├── include/           # 头文件目录
│   └── utils.h
├── src/               # 源文件目录
│   ├── main.c
│   └── utils/
│       └── util.c
├── build/             # 输出目录(存放目标文件和可执行文件)
└── Makefile

代码文件内容
  1. include/utils.h(头文件)
 
#ifndef UTILS_H
#define UTILS_Hint add(int a, int b);#endif
 
  1. src/utils/util.c(功能实现)
#include "utils.h"int add(int a, int b) {return a + b;
}
 
  1. src/main.c(主函数)
#include <stdio.h>
#include "utils.h"int main() {int sum = add(3, 5);printf("3 + 5 = %d\n", sum);return 0;
}
Makefile 实现
# 变量定义
CC = gcc
CFLAGS = -Wall -I./include  # -I 指定头文件路径
SRCS = $(wildcard src/*.c src/utils/*.c)  # 匹配所有源文件
OBJS = $(patsubst %.c, build/%.o, $(SRCS))  # 目标文件路径(build目录下保持原目录结构)
EXE = build/app  # 最终可执行文件路径# 生成可执行文件(默认目标)
all: $(EXE)# 链接目标文件生成可执行文件
$(EXE): $(OBJS)@mkdir -p $(dir $@)  # 创建输出目录(若不存在)$(CC) $^ -o $@# 模式规则:编译 .c 文件为 .o(保持目录结构)
build/%.o: %.c@mkdir -p $(dir $@)  # 创建目标文件所在目录(如 build/src/utils/)$(CC) $(CFLAGS) -c $< -o $@# 清理生成文件
.PHONY: clean
clean:rm -rf build/
操作说明
  1. 执行 make,会自动:
    • 在 build 目录下生成 src/main.osrc/utils/util.o 目标文件。
    • 链接生成可执行文件 build/app
  2. 运行 ./build/app,输出 3 + 5 = 8

案例 2:CMake 跨目录编译

项目结构
project_cmake/
├── include/           # 头文件目录
│   └── utils.h
├── src/               # 源文件目录
│   ├── main.c
│   └── utils/
│       ├── util.c
│       └── CMakeLists.txt  # 子目录 CMake 配置
├── build/             # 编译目录(手动创建)
└── CMakeLists.txt     # 根目录 CMake 配置
代码文件内容

头文件 include/utils.hsrc/utils/util.csrc/main.c 与 Makefile 案例完全相同。

CMake 配置文件
  1. 根目录 CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)# 指定 C 标准(可选)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)# 包含头文件目录(全局生效)
include_directories(include)# 添加子目录(会执行 src/utils/CMakeLists.txt)
add_subdirectory(src/utils)# 定义主程序源文件(仅主函数)
set(MAIN_SRC src/main.c)# 生成可执行文件(链接子目录生成的库)
add_executable(app ${MAIN_SRC})
target_link_libraries(app utils)  # 链接子目录生成的库
 
  1. 子目录 src/utils/CMakeLists.txt
# 定义当前目录的源文件(仅功能实现)
set(UTIL_SRC util.c)# 生成静态库(库名:utils)
add_library(utils STATIC ${UTIL_SRC})# 可选:设置库的输出目录(例如放到 build/lib)
set_target_properties(utils PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
操作说明
  1. 进入 build 目录(需手动创建):
    mkdir build && cd build
    
  2. 执行 cmake .. 生成构建文件(会自动处理跨目录依赖)。
  3. 执行 make 编译,生成:
    • 静态库 build/lib/libutils.a(子目录生成)。
    • 可执行文件 build/app(根目录生成)。
  4. 运行 ./app,输出 3 + 5 = 8

0voice · GitHub 

相关文章:

  • 登录接口中图片验证码Tesseract-OCR识别Java脚本
  • 优化算法加速深度学习模型训练
  • IEEE出版|连续多年稳定检索|第三届信号处理与智能计算国际学术会议(SPIC2025)
  • CentOS7 OpenSSL升级1.1.1w
  • Vue中的自定义指令适用于哪些场景
  • 报销单业务笔记
  • 题解:P12207 [蓝桥杯 2023 国 Python B] 划分
  • 贝叶斯优化Transformer融合支持向量机多变量回归预测,附相关性气泡图、散点密度图,Matlab实现
  • 深入探索向量数据库:构建智能应用的新基础
  • vue3搭建脚手架前的前置知识
  • psycopg_pool.PoolTimeout: couldn‘t get a connection after 120.00 sec异常
  • 技术文档:变频器干扰问题与解决方案
  • 使用 QGIS 插件 OpenTopography DEM Downloader 下载高程数据(申请key教程)
  • 压电陶瓷极化-佰力博与您探讨极化工艺的重要性及极化方法。
  • Open CASCADE学习|容器及其使用
  • 2024 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(省赛)解题报告 | 珂学家
  • Zabbix Agent的区别与选择!
  • 鸿蒙OSUniApp制作自定义的下拉菜单组件(鸿蒙系统适配版)#三方框架 #Uniapp
  • 阿里巴巴 1688 数据接口开发指南:构建自动化商品详情采集系统
  • 【RabbitMQ】实现RPC通信的完整指南
  • 定制基因编辑疗法治愈罕见遗传病患儿
  • 一图读懂丨创新创业人才最高补贴500万元!临港新片区发布创客新政“十二条”
  • 音乐节困于流量
  • 贝壳一季度收入增长42%:二手房市场活跃度维持在高位
  • 美联储主席:供应冲击或更频繁,将重新评估货币政策方法中的通胀和就业因素
  • 刘强东坐镇京东一线:管理层培训1800人次,最注重用户体验