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>...\):

"这个工程至少需要这个版本的 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(<dir1> <dir2> ...)

例如:

include_directories(${SYSTEMC_HOME}/include)

它在干什么?

👉 本质:

告诉编译器去哪里找头文件

link_directories(${SYSTEMC_HOME}/lib-linux64)

**语法:**link_directories(<dir1> <dir2> ...)

例如:

link_directories(${SYSTEMC_HOME}/lib-linux64)

它在干什么?

👉 本质:

告诉链接器去哪里找库文件(.so / .a)

方法2:自动查找(更专业)

find_package(SystemC REQUIRED)

**语法:**find_package(<PackageName> 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(<name> sources...)


示例:

add_executable(sim tb_top.cpp)

👉 生成:

sim.exe / sim

特点:

  • 必须有入口函数(main / sc_main

  • 是最终运行程序

库(推荐!):

基本语法:

add_library(<name> STATIC \| SHARED \| MODULE \| INTERFACE sources...)

各参数解释:

🔹 <name>

库名(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(<target>

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/

相关推荐
Irissgwe6 天前
二、Linux基础开发工具(2)
linux·makefile·gcc·g++·
量子炒饭大师10 天前
【Linux系统编程】——【自动化构建-make/Makefile】拒绝手动编译!构建你的赛博代码加工厂,重塑逻辑矩阵效率极限
linux·运维·自动化·makefile·make·自动化构建
yuanyuan2o220 天前
从最小项目开始的 CMake 教程
c语言·开发语言·arm开发·c++·makefile·make·cmake
李日灐1 个月前
< 6 > Linux 自动化构建工具:makefile 详解 + 进度条实战小项目
linux·运维·服务器·后端·自动化·进度条·makefile
送外卖的CV工程师1 个月前
STM32+Makefile编译+OpenOCD 烧录调试
stm32·单片机·嵌入式硬件·makefile·调试·烧录·openocd
zhang-ge1 个月前
Makefile调试技巧:打印信息与变量调试
makefile
送外卖的CV工程师1 个月前
STM32 CubeMX Makefile 工程编译 入门指南
stm32·单片机·嵌入式硬件·学习·makefile·stm32cubemx
H Journey2 个月前
C++之 CMake、CMakeLists.txt、Makefile
开发语言·c++·makefile·cmake
【骠姚校尉】2 个月前
Makefile核心教程(六) --- 一文吃透 Makefile 通配符
linux·makefile·通配符·核心教程
星光20252 个月前
Makefile语法
makefile