CMakeLists.txt 语法解释

一、一个典型CMakeLists.txt都包含哪些部分?

👉 标准结构如下:

1. 基本信息
cmake_minimum_required(...)
project(...)

完整示例(推荐):

project(SoC_Sim

VERSION 1.0

DESCRIPTION "SystemC SoC Simulation Platform"

LANGUAGES CXX

)

2. 全局配置

set(...)

option(...)

3. 依赖查找

find_package(...)

include_directories(...)

link_directories(...)

target_include_directories(...)

4. 源码组织

add_library(...)

add_executable(...)

5. 链接关系

target_link_libraries(...)

6. 编译选项

target_compile_options(...)

target_compile_definitions(...)

7. 子模块

add_subdirectory(...)

8. 安装/导出(可选)

install(...)

二、逐块解释


1️⃣ 基本信息(必须有)

cmake_minimum_required(VERSION 3.16)

project(SoC_Sim)

👉 作用:

cmake_minimum_required(VERSION <min>[...<policy_max>]):

"这个工程至少需要这个版本的 CMake 才能正确构建"。

project(<name>

VERSION \

DESCRIPTION \

LANGUAGES \...\]) 整个工程的"身份信息 + 语言环境 + 编译器初始化" #### 2️⃣ 全局配置(控制工程行为) set(CMAKE_CXX_STANDARD 17) **1. `set(...)` ------ 定义变量(最基础)** *** ** * ** *** 基本语法 set(\<变量名\> \<值\>) 例如: set(CMAKE_CXX_STANDARD 17) set(SYSTEMC_HOME "C:/systemc") *** ** * ** *** 常见用法 ✅ 字符串 / 路径 set(SYSTEMC_HOME "C:/msys64/home/systemc") ✅ 列表(非常常用) set(SRC main.cpp ddr_ctrl.cpp noc.cpp ) 👉 等价于一个"数组" ✅ 布尔变量 set(DEBUG ON) set(USE_DDR OFF) 👉 但注意:这只是普通变量,不是用户可配置项 ✅ 缓存变量(重要) set(SYSTEMC_HOME "C:/systemc" CACHE PATH "SystemC install path") 👉 特点: * 会出现在 `cmake-gui` * 用户可以修改 * 会写入缓存(CMakeCache.txt) 变量使用方式 ${SYSTEMC_HOME} 作用域(重点) 子目录可以访问父目录变量 但不会反向传递(默认) 👉 类似 RTL 层级作用域 **2. `option(...)` ------ 开关变量(给用户用)** *** ** * ** *** 基本语法 ``` option(<变量名> "说明" [默认值]) ``` 例如: ``` option(ENABLE_TRACE "Enable waveform tracing" ON) ``` 它在干什么? 👉 定义一个: > **用户可以控制的 ON/OFF 开关** 使用方式 ``` if(ENABLE_TRACE) message("Trace enabled") endif() ``` 用户如何修改? ``` cmake -G Ninja .. -DENABLE_TRACE=OFF ``` 👉 或 GUI 工具里勾选 #### 3️⃣ 依赖管理(重点) **方法1:手动路径(你现在用)** ``` include_directories(${SYSTEMC_HOME}/include) ``` **语法:**include_directories(\ \ ...) 例如: include_directories(${SYSTEMC_HOME}/include) 它在干什么? 👉 本质: > **告诉编译器去哪里找头文件** link_directories(${SYSTEMC_HOME}/lib-linux64) **语法:**link_directories(\ \ ...) 例如: link_directories(${SYSTEMC_HOME}/lib-linux64) 它在干什么? 👉 本质: > **告诉链接器去哪里找库文件(.so / .a)** **方法2:自动查找(更专业)** find_package(SystemC REQUIRED) **语法:**find_package(\ \[REQUIRED\] \[VERSION x.x\] \[COMPONENTS ...\]) 例如: find_package(SystemC REQUIRED) **它在干什么?** 👉 本质: > **在系统中查找某个库,并加载它的配置(头文件、库、编译选项)** *** ** * ** *** **成功后会得到什么?** 通常会生成: SystemC_INCLUDE_DIRS SystemC_LIBRARIES 或者更现代: SystemC::systemc (推荐) *** ** * ** *** **推荐写法(现代 CMake)** find_package(SystemC REQUIRED) target_link_libraries(sim SystemC::systemc ) 👉 自动完成: * include path * link library * compile options *** ** * ** *** **如果找不到怎么办?** 你可以指定路径: cmake -DCMAKE_PREFIX_PATH=/path/to/systemc .. *** ** * ** *** **工程意义(非常重要)** 👉 `find_package` 是: > **唯一"可扩展 + 可复用 + 工业标准"的依赖管理方式** 👉 推荐以后用这个(更工程化) #### 4️⃣ 源码组织(核心) **可执行程序:** ``` add_executable(sim main.cpp) ``` **基本语法:** add_executable(\ \[sources...\]) *** ** * ** *** **示例:** add_executable(sim tb_top.cpp) 👉 生成: sim.exe / sim **特点:** * 必须有入口函数(`main` / `sc_main`) * 是最终运行程序 **库(推荐!):** **基本语法:** add_library(\ \[STATIC \| SHARED \| MODULE \| INTERFACE\] \[sources...\]) **各参数解释:** 🔹 `` 库名(target 名) add_library(memory ...) 👉 后面用: target_link_libraries(sim memory) *** ** * ** *** 🔹 类型(4种) *** ** * ** *** ✅ 1. STATIC(默认最常用) add_library(memory STATIC ddr_ctrl.cpp bank.cpp) 👉 生成: libmemory.a (Linux) memory.lib (Windows) 特点: * 编译进最终程序 * 不依赖运行时库 *** ** * ** *** ✅ 2. SHARED(动态库) add_library(noc SHARED router.cpp) 👉 生成: libnoc.so / noc.dll 特点: * 运行时加载 * 可替换 ✅ 3. MODULE(插件) add_library(plugin MODULE plugin.cpp) 👉 不会被自动链接 👉 用于 dlopen 这类场景 ✅ 4. INTERFACE(重点🔥) add_library(soc_core INTERFACE) 👉 特点: * ❌ 不生成任何库文件 * ✅ 只传递依赖关系 🔹 `[sources...]` add_library(memory ddr_ctrl.cpp bank.cpp ) 👉 可以为空(INTERFACE 时) add_library(core fifo.cpp noc.cpp ddr_ctrl.cpp ) 👉 类比: * library = 模块(IP) * executable = 仿真顶层 #### 5️⃣ 链接关系(必须理解) ``` target_link_libraries(sim core systemc m ) ``` 👉 表示: * sim 依赖 core * 依赖 SystemC库 **基本语法:** target_link_libraries(\ \[PRIVATE \| PUBLIC \| INTERFACE

<lib1> <lib2> ...

)

真正关键:三种作用域(核心🔥)


PRIVATE

target_link_libraries(memory PRIVATE systemc)

👉 含义:

memory 自己用 systemc,但不会传递给别人


PUBLIC

target_link_libraries(memory PUBLIC systemc)

👉 含义:

memory 用 systemc,并且依赖它的人也必须用


INTERFACE

target_link_libraries(soc_core INTERFACE memory)

👉 含义:

自己不用,但使用它的人必须用

推荐写法(标准):

memory模块

add_library(memory ddr_ctrl.cpp)

target_link_libraries(memory

PUBLIC systemc

)

noc模块

add_library(noc router.cpp)

target_link_libraries(noc

PUBLIC systemc

)

聚合

add_library(soc_core INTERFACE)

target_link_libraries(soc_core

INTERFACE memory noc

)

仿真顶层

add_executable(sim tb_top.cpp)

target_link_libraries(sim

soc_core

m

)


依赖传播结果:

sim

└── soc_core

├── memory

│ └── systemc

└── noc

└── systemc

👉 sim 自动拥有:

  • systemc
  • memory
  • noc

常见错误


❌ 1. 全用 PRIVATE

复制代码
target_link_libraries(memory PRIVATE systemc)

👉 结果:

复制代码
sim 找不到 systemc ❌

❌ 2. 不用 INTERFACE 聚合

target_link_libraries(sim memory noc systemc)

👉 问题:

  • sim 依赖过多
  • 层次混乱

❌ 3. 顺序错误(老编译器)

target_link_libraries(sim systemc memory) ❌

👉 有些平台会炸


6️⃣ 编译选项(调试/优化)

复制代码
target_compile_options(sim PRIVATE -O2 -Wall)

语法:

target_compile_options(<target>

PRIVATE \| PUBLIC \| INTERFACE

<options...>

)


它在干什么?

👉 本质:

给编译器加参数(类似 g++ 后面的 -O2 -Wall)


示例

target_compile_options(sim PRIVATE -O2 -Wall)

👉 等价:

g++ -O2 -Wall ...


常见选项

target_compile_options(sim PRIVATE

-O2 # 优化

-g # 调试信息

-Wall # 警告

-Wextra

)


作用域(和 link 一样🔥)


PRIVATE

target_compile_options(memory PRIVATE -O2)

👉 只影响 memory 自己


PUBLIC

target_compile_options(memory PUBLIC -O2)

👉 memory 和依赖它的模块都会用


INTERFACE

复制代码

target_compile_options(soc_core INTERFACE -O2)

👉 自己不用,但下游会用

7️⃣ 宏定义(非常有用)

语法:

target_compile_definitions(<target>

PRIVATE \| PUBLIC \| INTERFACE

<definitions...>

)

复制代码
target_compile_definitions(sim PRIVATE DEBUG=1)

👉 类似 RTL:

`define DEBUG

结合 option 使用(工程级)


示例:

cmake:

option(ENABLE_TRACE "Enable waveform" ON)

if(ENABLE_TRACE)

target_compile_definitions(sim PRIVATE ENABLE_TRACE)

endif()

c++:

#ifdef ENABLE_TRACE

dump_wave();

#endif


8️⃣ 子目录(大项目必备)

add_subdirectory(src)

add_subdirectory(tb)

add_subdirectory(noc)

👉 用于:

  • 分模块管理

  • 团队协作

  • 👉 add_subdirectory(...) 的本质是:
    "把子目录的 CMakeLists.txt 纳入当前工程,并参与构建"


    基本语法

    复制代码
    add_subdirectory(<source_dir> [binary_dir] [EXCLUDE_FROM_ALL])

    参数解释

    🔹 <source_dir>(必须)

    复制代码
    add_subdirectory(src)

    👉 表示:

    复制代码
    进入 src/ 目录,执行里面的 CMakeLists.txt

    🔹 [binary_dir](可选)

    复制代码
    add_subdirectory(src build_src)

    👉 指定这个子目录的构建输出目录

    👉 很少用,一般不用写


    🔹 [EXCLUDE_FROM_ALL](高级)

    add_subdirectory(test EXCLUDE_FROM_ALL)

    👉 表示:

    默认不参与构建(除非被依赖)

它到底干了什么?

当你写:

add_subdirectory(src)

👉 实际发生:

  • 进入 src/CMakeLists.txt
  • 执行里面所有 add_library / add_executable
  • 把这些 target 注册到整个工程

9️⃣ 安装(一般后期才用)

install(TARGETS sim DESTINATION bin)

👉 install(...) 解决的是:"别人怎么用你的工程"


先给一句本质:

👉 install(...) 的本质是:
"定义构建完成后,文件要被拷贝到哪里、以什么结构对外发布"


基本语法(常见形式):

install(TARGETS ...)

install(FILES ...)

install(DIRECTORY ...)

install(EXPORT ...)

👉 这四个就是你 90% 会用到的


最核心:install(TARGETS ...)


语法

install(TARGETS <targets...>

RUNTIME DESTINATION <dir> # 可执行文件

LIBRARY DESTINATION <dir> # 动态库

ARCHIVE DESTINATION <dir> # 静态库

)


示例

add_executable(sim tb_top.cpp)

install(TARGETS sim

RUNTIME DESTINATION bin

)

👉 安装后:

install_prefix/

└── bin/

└── sim


库安装

add_library(memory STATIC ddr_ctrl.cpp)

install(TARGETS memory

ARCHIVE DESTINATION lib

)

👉 生成:

lib/libmemory.a


安装头文件(非常重要)


install(FILES ...)

install(FILES

include/ddr_ctrl.h

DESTINATION include

)


install(DIRECTORY ...)(推荐)

install(DIRECTORY include/

DESTINATION include

)

👉 会保留目录结构


安装完整工程结构(标准做法)


推荐结构

install(TARGETS memory noc

ARCHIVE DESTINATION lib

LIBRARY DESTINATION lib

)

install(DIRECTORY include/

DESTINATION include

)

👉 安装后:

install_prefix/

├── lib/

│ ├── libmemory.a

│ └── libnoc.a

└── include/

├── ddr_ctrl.h

└── noc.h


install(EXPORT ...)(高级🔥)

👉 这是配合 find_package 的关键


语法

install(EXPORT <export_name>

DESTINATION lib/cmake/<PackageName>

)


示例

install(TARGETS memory noc

EXPORT SoCTargets

)

install(EXPORT SoCTargets

DESTINATION lib/cmake/SoC

)


👉 作用:

生成:

SoCTargets.cmake

👉 这样别人可以:

find_package(SoC)

target_link_libraries(app SoC::memory)


安装路径控制


默认路径

cmake --install .

👉 默认安装到:

/usr/local


自定义路径

cmake -DCMAKE_INSTALL_PREFIX=./install ..

cmake --build .

cmake --install .

👉 安装到:

./install/

相关推荐
一只自律的鸡1 个月前
【MakeFile】基础培训2
makefile
tod1132 个月前
Makefile进阶(上)
linux·运维·服务器·windows·makefile·进程
一个平凡而乐于分享的小比特2 个月前
Makefile 源码编译系统详解
linux·makefile
一个平凡而乐于分享的小比特2 个月前
Autoconf:Linux自动生成Makefile的详解
makefile·cmake·autoconf
一个平凡而乐于分享的小比特3 个月前
Linux内核构建三剑客:Kconfig、.config与Makefile关系详解
linux·makefile·kconfig·.config
ベadvance courageouslyミ3 个月前
项目一(线程邮箱)
c语言·线程·makefile·进程间通信·线程邮箱
熊猫钓鱼>_>3 个月前
Makefile应用场景实践日志:构建高效C/C++项目工作流
c语言·c++·bug·mfc·makefile·编译·kmp
___波子 Pro Max.3 个月前
Makefile设置DEBUG宏定义方法总结
makefile·make
乖乖是干饭王3 个月前
Linux 内核 Kbuild 中的 ld 调用机制
linux·c·makefile