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

Cmake 基础用法

# ==================================================
# CMake 学习项目 - 一个文件搞懂核心语法
# ==================================================
# 编译方法:
# cd code
# mkdir build; cd build
# cmake ..
# make
# ./hello

#

# cmake .. → 读取上一级(../)的 CMakeLists.txt,在当前目录生成 Makefile

# make → 读取当前目录的 Makefile,执行编译

# 关闭某个功能试试:
#cmake -DENABLE_LOG=OFF ..
# ==================================================

# ---- [知识点1] 项目声明 ----
cmake_minimum_required(VERSION 3.10) # 当前cmake 要求的最低 版本号
project(cmake_learn C) # 自定义项目名 + 源码后缀如果有C++ , C后面要加CPP

# ---- [知识点2] option: 开关选项(类比 Kconfig) ----
option(ENABLE_LOG "启用日志功能" ON) # 如果不指定默认cmake 变量开关的值,
option(ENABLE_MATH "启用数学模块" ON) #如果指定可以 cmake

# ---- [知识点3] set: 定义变量 ----
set(APP_VERSION "1.0.0")
message(STATUS "版本: ${APP_VERSION}")
message(STATUS "日志: ${ENABLE_LOG}")
message(STATUS "数学: ${ENABLE_MATH}")

# ---- [知识点4] 收集源文件 ----
# main.c 始终编译
set(SOURCES main.c)

# 根据 option 决定是否加入 utils.c(类比 obj-$(CONFIG_X) += xxx.o)
if(ENABLE_LOG)
list(APPEND SOURCES utils.c)
endif()

if(ENABLE_MATH)
list(APPEND SOURCES calc.c)
endif()

# ---- [知识点5] add_executable: 编译可执行文件 ----
add_executable(hello ${SOURCES})

# ---- [知识点6] target_compile_definitions: 添加宏定义 ----
target_compile_definitions(hello PRIVATE APP_VERSION="${APP_VERSION}")

if(ENABLE_LOG)
target_compile_definitions(hello PRIVATE HAS_LOG)
endif()

if(ENABLE_MATH)
target_compile_definitions(hello PRIVATE HAS_MATH)
endif()

# ---- [知识点7] target_compile_options: 编译选项 ----
target_compile_options(hello PRIVATE -Wall)

# ---- [知识点8] add_library: 静态库 ----
add_library(mylib STATIC sensor.c)
target_link_libraries(hello PRIVATE mylib)

--------------------------------------------------------------------------------------------------------

ubuntu@WIN-07G84A33SUO:/mnt/e/Qoder/Cmake/build$ cmake ..
-- The C compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- 版本: 1.0.0
-- 日志: ON
-- 数学: ON

-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/e/Qoder/Cmake/build

------------------------------------------------------------------------------------------

Scanning dependencies of target mylib
[ 16%] Building C object CMakeFiles/mylib.dir/sensor.c.o
[ 33%] Linking C static library libmylib.a
[ 33%] Built target mylib
Scanning dependencies of target hello
[ 50%] Building C object CMakeFiles/hello.dir/main.c.o
[ 66%] Building C object CMakeFiles/hello.dir/utils.c.o
[ 83%] Building C object CMakeFiles/hello.dir/calc.c.o
[100%] Linking C executable hello
[100%] Built target hello

------------------------------------------------------------------------------------------

CMake 帮你把这些参数自动分配给每个源文件,不用自己一个个写。

CMake 指令类比内核 Makefile
target_compile_definitions(hello PRIVATE HAS_LOG)ccflags-y += -DHAS_LOG
target_compile_options(hello PRIVATE -Wall)ccflags-y += -Wall
target_link_libraries(hello PRIVATE mylib)ldflags-y += -lmylib

核心理解

CMake 就是一个 Makefile 生成器

CMakeLists.txt (你写的)

│ cmake ..

Makefile + flags.make + link.txt (自动生成的)

│ make

hello (可执行文件)

你写的 CMakeLists.txt 是高层描述,cmake 翻译成底层 Makefile 规则。如果你手写 Makefile,就等于自己写C_FLAGS = -Wall -Dxxx这些;用 CMake 就是让它帮你自动生成,而且跨平台(Windows/Linux 都能生成对应的构建文件)。

-------------------------------------------------------------------------------------------------------------

实际编译命令

make 编译main.c时,实际执行的是:

gcc -Wall -DAPP_VERSION=\"1.0.0\" -DHAS_LOG -DHAS_MATH -c main.c -o main.o │ │ │ │ │ │ │ │ │ └─ 编译哪个文件 │ │ │ └─ C_DEFINES │ │ └─ C_DEFINES │ └─ C_FLAGS

逐个解释

变量gcc 参数作用具体效果
C_FLAGS-Wall-Wall开启所有常见警告有潜在问题代码时打印警告,不中断编译
C_DEFINES-DAPP_VERSION=\"1.0.0\"-D定义宏,传值C 代码里APP_VERSION变成"1.0.0"
C_DEFINES-DHAS_LOG-D定义宏,只定义C 代码里#ifdef HAS_LOG为真
C_DEFINES-DHAS_MATH-D定义宏,只定义C 代码里#ifdef HAS_MATH为真
C_INCLUDES(空)-I指定头文件搜索路径当前为空,用默认路径

实际效果对比

-Wall的作用:

// 没有 -Wall:编译通过,不提示

// 有 -Wall:编译时会打印警告

int x;

printf("%d", x); // 警告:变量 x 未初始化就使用了

-D有值 vs 无值的区别:

// -DAPP_VERSION=\"1.0.0\" → 有值,可以当字符串用

printf("版本: %s\n", APP_VERSION); // 输出:版本: 1.0.0

// -DHAS_LOG → 无值,只表示"已定义"

#ifdef HAS_LOG

log_print("日志已启用"); // 这段代码会被编译

#endif

-I头文件路径(当前为空):

# 如果有这一行: target_include_directories(hello PRIVATE /opt/mylib/include)
# C_INCLUDES 就会变成: C_INCLUDES = -I/opt/mylib/include

这样#include "xxx.h"时,gcc 会去那个目录找头文件。你现在项目头文件都在同目录,所以不需要。

----------------------------------------------------------------

最终可以执行

ubuntu@WIN-07G84A33SUO:/mnt/e/Qoder/Cmake/build$./hello
=== CMake 学习 Demo (v1.0.0) ===
[LOG] 日志功能已启用
add(3, 5) = 8
mul(4, 7) = 28
温度: 25.6 C (来自静态库 mylib)

http://www.jsqmd.com/news/1079089/

相关文章:

  • DMX 报 Agent RPC error (-1): com.kingbase8.utiL.KSQLException: ERROR: relation “sys _database“ does n
  • 跨越语言的二进制光纤(下篇):gRPC 微服务重构与 HTTP/2 多路复用深度拆解
  • 锌离子Zn2+响应水凝胶的结构与响应机制
  • Shopee虾皮API|根据ItemID获取商品详情 完整对接教程
  • Sunshine游戏串流完全指南:打造个人专属云游戏服务器终极教程
  • iPad 为什么不建议用丢失模式催收,而应优先使用“收租模式”
  • 036、SPIR-V Dialect:GPU Shader与Vulkan生态
  • 一眸科技:探索情感认知智能,构筑有温度的AI
  • 如何用Python工具为Beyond Compare 5生成有效授权密钥?3种方法全解析
  • 用心做事,方知生活真味
  • 如何写一个正确的二分查找?
  • LordOfTheRoot靶场渗透实战:从信息收集到权限提升的完整路径解析
  • 把卖点翻译成购买理由:食品品牌增长链路的结构化方法
  • 35-页面模板组织与前后端协作方式:平台如何把模块能力落到可维护页面
  • 2026软考系规备考:金钟老师是谁?为什么他适合带零基础?
  • CryptoHack Writeup——Modular Exponentiation:理解RSA中的模幂运算
  • 从OWASP Juice Shop二星挑战掌握Web安全核心漏洞实战技巧
  • N_m3u8DL-RE:跨平台流媒体下载工具,支持点播和直播
  • 从SEO到GEO:当7亿人开始问AI“哪家靠谱”,你的品牌还在搜索结果里“隐身”吗?
  • JUI引擎 DeviceContext + 交换链方案技术复盘
  • 沃虎VOOHU BMS隔离变压器应用方案:储能与电池管理系统的高压隔离采样选型
  • 分类变量编码实战:从数据类型诊断到生产级Pipeline
  • 5~60V 恒流驱动HI7002替代惠海 H5116 聚能芯半导体智芯电子一级代理
  • 郎月婷张天阳李卿主演,软科幻悬疑剧《幻世》6月25日登陆优酷
  • PostgreSQL 一键批量修复所有表序列值
  • 一键激活IDEA
  • springboot+langchain4j 实战 Day15——打造一个“生产“级 Agent 服务:单个 Agent 同时持有多个 Tool,LLM 自主判断调用哪个
  • KMS智能激活脚本:5分钟彻底解决Windows和Office激活难题
  • Selenium自动化测试:从元素定位到健壮交互的完整指南
  • Mac NTFS读写终极解决方案:Free-NTFS-for-Mac免费完整指南