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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值