跳到主要内容

丁致宇第二周学习报告 深入中大型项目的Cmakelists

​ 作者:丁致宇,时间:2024.1.28 ]

正文

中大型项目常用cmake语法(查找表)

项目基本设置

  1. 指定CMake最低版本要求

    cmake_minimum_required(VERSION 3.12.0 FATAL_ERROR)
  2. 项目声明

    project(roms VERSION 3.9 LANGUAGES Fortran)
  3. 设置变量和CMake模块路径

    set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
  4. 设置构建类型

    set(CMAKE_BUILD_TYPE Release)

编译器和链接器配置

  1. 添加编译器选项

    add_compile_options(-Wall -Wextra)
  2. 设置目标特定的编译定义

    target_compile_definitions(roms_executable PRIVATE -DUSE_NETCDF4)
  3. 设置目标特定的编译选项

    target_compile_options(roms_executable PRIVATE -O2)
  4. 设置目标特定的链接选项

    target_link_options(roms_executable PRIVATE -L/path/to/lib)

环境检测与条件分支

  1. 检查环境变量
    if(DEFINED ENV{ECBUILD_MODULE_PATH})
    # 做一些特定于ecbuild的配置
    endif()

包含其他脚本和模块

  1. 包含自定义CMake脚本

    include(roms_functions)
  2. 查找并链接依赖库

    find_package(NetCDF REQUIRED COMPONENTS Fortran)

源代码和资源管理

  1. 添加子目录

    add_subdirectory(src)
  2. 指定头文件和库目录

    include_directories(${NetCDF_INCLUDE_DIRS})
    link_directories(${NetCDF_LIBRARY_DIRS})
  3. 设置源文件属性

    set_property(SOURCE file.F90 PROPERTY COMPILE_FLAGS "-special-flag")
  4. 自动生成源码

    add_custom_command(
    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated_source.f90
    COMMAND generate_source_script
    DEPENDS script_input.dat
    )
  5. 处理文件和目录

    file(GLOB MY_SOURCES "src/*.cpp")
    file(COPY ${CMAKE_SOURCE_DIR}/data/ DESTINATION ${CMAKE_BINARY_DIR}/data)

目标定义和链接

  1. 创建对象库

    add_library(Objects OBJECT ${All_f90s})
  2. 创建静态库和共享库

    add_library(ROMS_static STATIC $<TARGET_OBJECTS:Objects>)
    add_library(ROMS_shared SHARED $<TARGET_OBJECTS:Objects>)
  3. 构建可执行文件

    add_executable(roms_executable ${master_f90})
    target_link_libraries(roms_executable ${NetCDF_LIBRARIES})

安装和测试

  1. 安装目标和文件

    install(TARGETS roms_executable DESTINATION bin)
    install(FILES readme.txt DESTINATION share/doc)
    install(DIRECTORY docs/ DESTINATION share/doc)
  2. 启用和添加测试

    enable_testing()
    add_test(NAME MyTest COMMAND TestExecutable)

打包和项目导出

  1. 设置CPack打包

    set(CPACK_PACKAGE_NAME "MyApp")
    include(CPack)
  2. 导出和安装目标

    export(TARGETS roms_executable FILE ROMSExecutableTargets.cmake)
    install(EXPORT ROMSExecutableTargets FILE ROMSExecutableTargets.cmake DESTINATION lib/cmake/ROMS)

自定义构建步骤和清理

  1. 添加自定义构建命令和目标

    add_custom_target(clean-all COMMAND ${CMAKE_MAKE_PROGRAM} clean)
    add_custom_command(TARGET roms_executable POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Build complete!")
  2. 提供开关选项

    option(USE_MY_LIB "Use the provided library" ON)
  3. 设置CMake策略

    cmake_policy(SET CMP0074 NEW)

Cmakelists解读实践

示例项目见文件夹内的 示例项目cmakelists+详细注释.txt文件

分析示例项目cmakelists整体结构与思路

  1. 基本配置

    • 设置最小所需的CMake版本。
    • 定义模块路径,用于搜索自定义的CMake模块。
    • 检查是否在ecbuild构建系统下运行,根据此条件调整后续配置。
  2. 项目定义

    • 使用project()命令定义名为“roms”的项目,指定版本号及主要编程语言为Fortran。
    • 在ecbuild环境下,启用Fortran并设置相关构建选项。
  3. ROMS相关的CMake文件引入

    • 引入一系列自定义的CMake函数、编译器标志和配置文件。
  4. 依赖管理

    • 根据环境变量检测NetCDF库的位置并进行链接。
    • 如果在ecbuild环境下,使用ecbuild自带的MPI查找功能,并添加MPI Fortran库链接。
    • 根据SCORPIO的开启状态,添加相应的头文件目录。
  5. ROMS源码组织

    • 添加各个子目录作为子构建目录,这些子目录包含了ROMS的核心组件、驱动程序以及各种功能模块。
    • 设置公共的包含目录和链接目录。
    • 收集所有源文件到一个列表中,并根据ADJOINT、REPRESENTER、TANGENT等选项决定是否包含相应子目录的源文件。
  6. ROMS特定规则

    • 为特定源文件设置特殊的预处理器定义和编译标志。
    • 针对某些需要超过标准Fortran行长度限制的文件,设置自由格式编译标志。
  7. 清理依赖关系

    • 通过Perl脚本清理CMake生成的依赖信息文件,确保正确的依赖关系。
    • 创建一个自定义目标“fix”,并在Objects目标上依赖它。
  8. 对象库创建

    • 使用preprocess_fortran函数处理源代码,生成.f90文件,并将它们作为一个OBJECT库目标“Objects”。
    • 根据LIBSHARED和LIBSTATIC选项分别生成动态库(ROMS_shared)和静态库(ROMS_static),并安装。
  9. 构建可执行文件

    • 当ROMS_EXECUTABLE被启用时,从Master子目录中的master.F文件构建可执行文件。
    • 设置合适的链接目录与链接库,包括NetCDF、ARPACK(如果需要)以及SCORPIO(如果开启了并行I/O)。
    • 将Objects目标、ROMS库以及其他依赖项链接到最终的可执行文件中,并安装至合适位置。

示例项目cmakelists+详细注释

见文件夹内的 示例项目cmakelists+详细注释.txt文件