☀️

Hi Folks.

一、简单配置

  1. 列出所有 .c 文件, 头文件 h 放在根目录无需列出
    cmakeminimumrequired(VERSION 3.5.0)
    project(c-ascii-roguelite VERSION 0.1.0 LANGUAGES C)
    
    # 列出所有 .c 源文件(用空格分隔) add_executable(c-ascii-roguelite main.c player.c map.c )
  2. file(GLOB) 自动收集源文件
    cmakeminimumrequired(VERSION 3.5.0)
    project(c-ascii-roguelite VERSION 0.1.0 LANGUAGES C)
    
    # 自动收集 src 目录下所有 .c 文件(假设所有 .c 都在 src 文件夹) file(GLOB SOURCES "src/*.c") # SOURCES 变量会包含所有匹配的文件
    add_executable(c-ascii-roguelite ${SOURCES})

二、头文件路径处理(不在根目录)

cmakeminimumrequired(VERSION 3.5.0)
project(c-ascii-roguelite VERSION 0.1.0 LANGUAGES C)

add_executable(c-ascii-roguelite main.c player.c map.c )
# 指定头文件所在目录(让编译器能找到 #include "player.h") targetincludedirectories(c-ascii-roguelite PRIVATE ${CMAKECURRENTSOURCE_DIR}/include # 假设头文件在 include 文件夹 )

三、添加自定义命令

执行顺序

  1. file(GLOB) 在配置阶段获取 *.c 的文件,存入 SOURCES 变量
  2. list(APPEND) 手动添加动态生成文件
  3. adddependencies 构建主目标 c-ascii-roguelite 前先完成 generatemap;必须在 add_executable 后,确保依赖关系能关联到已定义的主目标

构建产物

  1. 动态生成的源码:参与编译,需加入 SOURCES,参考 object.c
  2. 辅助构建产物:不参与编译,仅生成文件,参考 map.png
    cmakeminimumrequired(VERSION 3.5.0)
    project(c-ascii-roguelite VERSION 0.1.0 LANGUAGES C)
    
    set(CMAKECSTANDARD 11) set(CMAKECSTANDARD_REQUIRED ON)

    addcustomcommand( OUTPUT ${CMAKESOURCEDIR}/object.h COMMAND awk -v pass=h -f ${CMAKESOURCEDIR}/object.awk ${CMAKESOURCEDIR}/object.txt > ${CMAKESOURCEDIR}/object.h DEPENDS ${CMAKESOURCEDIR}/object.awk ${CMAKESOURCEDIR}/object.txt COMMENT "Generating object.h" )
    addcustomcommand( OUTPUT ${CMAKESOURCEDIR}/object.c COMMAND awk -v pass=c1 -f ${CMAKESOURCEDIR}/object.awk ${CMAKESOURCEDIR}/object.txt > ${CMAKESOURCEDIR}/object.c COMMAND awk -v pass=c2 -f ${CMAKESOURCEDIR}/object.awk ${CMAKESOURCEDIR}/object.txt >> ${CMAKESOURCEDIR}/object.c DEPENDS ${CMAKESOURCEDIR}/object.awk ${CMAKESOURCEDIR}/object.txt ${CMAKESOURCEDIR}/object.h COMMENT "Generating object.c" )
    addcustomcommand( OUTPUT ${CMAKESOURCEDIR}/map.gv # 生成的 map.gv 放在构建目录 COMMAND awk -f ${CMAKESOURCEDIR}/map.awk ${CMAKESOURCEDIR}/object.txt > ${CMAKESOURCEDIR}/map.gv DEPENDS ${CMAKESOURCEDIR}/map.awk # 依赖的 awk 脚本(源目录) ${CMAKESOURCEDIR}/object.txt # 依赖的输入文件(源目录) COMMENT "Generating map.gv using map.awk" )
    # 生成 map.png(依赖 map.gv 和 dot 工具) addcustomcommand( OUTPUT ${CMAKESOURCEDIR}/map.png # 生成的 map.png 放在构建目录 COMMAND dot -Tpng -o ${CMAKESOURCEDIR}/map.png ${CMAKESOURCEDIR}/map.gv DEPENDS ${CMAKESOURCEDIR}/map.gv # 依赖前面生成的 map.gv COMMENT "Generating map.png using dot" )
    addcustomtarget( generate_map DEPENDS ${CMAKESOURCEDIR}/map.gv ${CMAKESOURCEDIR}/map.png ${CMAKESOURCEDIR}/object.c COMMENT "Generating map.gv and map.png" )
    file(GLOB SOURCES "*.c") list(APPEND SOURCES object.c)
    add_executable(c-ascii-roguelite ${SOURCES}) adddependencies(c-ascii-roguelite generatemap)

四、多目录复杂构建

list(APPEND)追加

file(GLOB SOURCES "${SRC_DIR}/*.c")

file(GLOB SRCUTILFILES "${SRCUTILDIR}/*.c")
# 将util目录的源文件和生成的object.c加入项目(核心修改:追加SRCUTILFILES) list(APPEND SOURCES ${SRCUTILFILES} # 新增:加入util目录的tokenize.c ${GEN_DIR}/object.c )
# 可执行文件 add_executable(c-mud-adventure ${SOURCES})

file(GLOB)普通合并

file(GLOB) 是直接覆盖,错误使用:

file(GLOB SOURCES "${SRC_DIR}/*.c")
file(GLOB SOURCES "${GEN_DIR}/object.c")

正确使用:

file(GLOB SOURCES "${SRC_DIR}/*.c")

file(GLOB SRCUTILFILES "${SRCUTILDIR}/*.c")
# 合并所有源文件(核心修改:直接合并SRCUTILFILES) set(SOURCES ${SOURCES} ${SRCUTILFILES} ${GEN_DIR}/object.c )
# 可执行文件 add_executable(c-mud-adventure ${SOURCES})

file(GLOB_RECURSE)递归合并(推荐)

file(GLOB_RECURSE) 是递归匹配指定目录

file(GLOBRECURSE SRCROOTFILES "${SRCDIR}/*.c")

# 3. 合并所有源文件 set(SOURCES ${SRCROOTFILES} ${GEN_DIR}/object.c
# 可执行文件 add_executable(c-mud-adventure ${SOURCES})

五、指定 C 语言标准

# 显式指定 C 标准为 C11
set(CMAKECSTANDARD 11)
# 强制要求编译器支持该标准(避免降级)
set(CMAKECSTANDARD_REQUIRED ON)