Ding Zhiyu Week 2 Study Report: Deep Dive into CMakeLists for Medium-Large Projects
Author: Ding Zhiyu, Date: 2024.1.28 ]
Main Content
Common CMake Syntax for Medium-Large Projects (Quick Reference)
Basic Project Settings
-
Specify minimum CMake version requirement:
cmake_minimum_required(VERSION 3.12.0 FATAL_ERROR) -
Project declaration:
project(roms VERSION 3.9 LANGUAGES Fortran) -
Set variables and CMake module path:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") -
Set build type:
set(CMAKE_BUILD_TYPE Release)
Compiler and Linker Configuration
-
Add compiler options:
add_compile_options(-Wall -Wextra) -
Set target-specific compile definitions:
target_compile_definitions(roms_executable PRIVATE -DUSE_NETCDF4) -
Set target-specific compile options:
target_compile_options(roms_executable PRIVATE -O2) -
Set target-specific link options:
target_link_options(roms_executable PRIVATE -L/path/to/lib)
Environment Detection and Conditional Branching
- Check environment variables:
if(DEFINED ENV{ECBUILD_MODULE_PATH})
# 做一些特定于ecbuild的配置
endif()
Including Other Scripts and Modules
-
Include custom CMake scripts:
include(roms_functions) -
Find and link dependency libraries:
find_package(NetCDF REQUIRED COMPONENTS Fortran)
Source Code and Resource Management
-
Add subdirectory:
add_subdirectory(src) -
Specify header file and library directories:
include_directories(${NetCDF_INCLUDE_DIRS})
link_directories(${NetCDF_LIBRARY_DIRS}) -
Set source file properties:
set_property(SOURCE file.F90 PROPERTY COMPILE_FLAGS "-special-flag") -
Auto-generate source code:
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated_source.f90
COMMAND generate_source_script
DEPENDS script_input.dat
) -
Handle files and directories:
file(GLOB MY_SOURCES "src/*.cpp")
file(COPY ${CMAKE_SOURCE_DIR}/data/ DESTINATION ${CMAKE_BINARY_DIR}/data)
Target Definition and Linking
-
Create object library:
add_library(Objects OBJECT ${All_f90s}) -
Create static and shared libraries:
add_library(ROMS_static STATIC $<TARGET_OBJECTS:Objects>)
add_library(ROMS_shared SHARED $<TARGET_OBJECTS:Objects>) -
Build executable:
add_executable(roms_executable ${master_f90})
target_link_libraries(roms_executable ${NetCDF_LIBRARIES})
Installation and Testing
-
Install targets and files:
install(TARGETS roms_executable DESTINATION bin)
install(FILES readme.txt DESTINATION share/doc)
install(DIRECTORY docs/ DESTINATION share/doc) -
Enable and add tests:
enable_testing()
add_test(NAME MyTest COMMAND TestExecutable)
Packaging and Project Export
-
Set up CPack packaging:
set(CPACK_PACKAGE_NAME "MyApp")
include(CPack) -
Export and install targets:
export(TARGETS roms_executable FILE ROMSExecutableTargets.cmake)
install(EXPORT ROMSExecutableTargets FILE ROMSExecutableTargets.cmake DESTINATION lib/cmake/ROMS)
Custom Build Steps and Cleanup
-
Add custom build commands and targets:
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!") -
Provide toggle options:
option(USE_MY_LIB "Use the provided library" ON) -
Set CMake policies:
cmake_policy(SET CMP0074 NEW)
CMakeLists Analysis Practice
For the example project, see the 示例项目cmakelists+详细注释.txt file in the folder
Analysis of Example Project CMakeLists Overall Structure and Approach
-
Basic configuration:
- Set the minimum required CMake version.
- Define module paths for searching custom CMake modules.
- Check whether running under the ecbuild build system, and adjust subsequent configuration accordingly.
-
Project definition:
- Use the
project()command to define a project named "roms", specifying the version number and the primary programming language as Fortran. - Under the ecbuild environment, enable Fortran and set related build options.
- Use the
-
ROMS-related CMake file inclusion:
- Include a series of custom CMake functions, compiler flags, and configuration files.
-
Dependency management:
- Detect the NetCDF library location based on environment variables and link it.
- If under the ecbuild environment, use ecbuild's built-in MPI detection functionality and add MPI Fortran library linking.
- Based on SCORPIO's enabled status, add the corresponding header file directories.
-
ROMS source code organization:
- Add each subdirectory as a sub-build directory. These subdirectories contain the core components, drivers, and various functional modules of ROMS.
- Set common include and link directories.
- Collect all source files into a list, and based on options like ADJOINT, REPRESENTER, TANGENT, decide whether to include source files from corresponding subdirectories.
-
ROMS-specific rules:
- Set special preprocessor definitions and compile flags for specific source files.
- For files that exceed standard Fortran line length limits, set free-format compilation flags.
-
Clean up dependencies:
- Use a Perl script to clean up CMake-generated dependency information files to ensure correct dependencies.
- Create a custom target "fix" and make the Objects target depend on it.
-
Object library creation:
- Use the
preprocess_fortranfunction to process source code, generate .f90 files, and compile them as an OBJECT library target "Objects". - Based on the LIBSHARED and LIBSTATIC options, generate shared libraries (ROMS_shared) and static libraries (ROMS_static) respectively, and install them.
- Use the
-
Build executable:
- When ROMS_EXECUTABLE is enabled, build the executable from the master.F file in the Master subdirectory.
- Set appropriate link directories and libraries, including NetCDF, ARPACK (if needed), and SCORPIO (if parallel I/O is enabled).
- Link the Objects target, ROMS library, and other dependencies into the final executable, and install to the appropriate location.
Example Project CMakeLists + Detailed Comments
See the 示例项目cmakelists+详细注释.txt file in the folder