kmcmake-Generated Root CMakeLists.txt: Project Build Workflow & Structure
The root CMakeLists.txt (auto-generated by kmcmake) is the central control hub for your project’s
build process. It follows a strict, phase-based workflow that aligns with CMake’s native logic while encapsulating
kmcmake’s "convention over configuration" philosophy. Every section serves a clear purpose—from initializing the project
to exporting targets for external use—with minimal manual edits required.
Core Workflow: 5 Key Phases
The file is structured in sequential phases, ensuring dependencies are resolved, configurations are applied, and builds are executed in the correct order. Below is a detailed breakdown of each phase, mapped directly to the generated code.
Phase 1: Project Initialization & Metadata Setup
Goal: Configure basic CMake project settings, versioning, and top-level flags.
This phase runs first to establish foundational project properties (no kmcmake-specific logic yet—pure CMake).
# Phase 1: Project Initialization
cmake_minimum_required(VERSION 3.31) # kmcmake template minimum required CMake version
project(myproject CXX) # Project name + language (C++ only)
# Flag: Mark if this is the top-level project (vs. included as a dependency)
option(${PROJECT_NAME}_IS_TOP_PROJECT "Whether myproject is the top-level project" ON)
get_property(not_top DIRECTORY PROPERTY PARENT_DIRECTORY)
if (not_top)
set(${PROJECT_NAME}_IS_TOP_PROJECT OFF)
endif ()
# Project metadata (semantic versioning + description)
set(PROJECT_DESCRIPTION "Hercules is an ahead of time compiler for a subset of the Python language framework.")
set(PROJECT_VERSION_MAJOR 0)
set(PROJECT_VERSION_MINOR 0)
set(PROJECT_VERSION_PATCH 5)
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
# Export version metadata as project-specific variables (for external use)
set(${PROJECT_NAME}_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(${PROJECT_NAME}_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(${PROJECT_NAME}_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set(${PROJECT_NAME}_VERSION ${PROJECT_VERSION})
# Uppercase project name (used for macros in version.h.in)
string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UP)
# Flag: Enable Python extension build (off by default)
option(PYTHON_EXTENSION "Build as a Python shared library" OFF)
# kmcmake framework version (for compatibility checks)
set(KMCMAKE_VERSION 1.0.0)
Key Notes:
PROJECT_NAMEand version variables are used consistently across kmcmake (e.g., inversion.h.in,myproject_config.cmake.in).${PROJECT_NAME}_IS_TOP_PROJECTensures correct behavior if your project is included as a dependency in another CMake project.
Phase 2: kmcmake Framework Integration
Goal: Import kmcmake’s core modules and tools—enabling kmcmake’s macros (e.g., kmcmake_cc_library) and utilities.
This phase connects your project to kmcmake’s framework without modifying kmcmake’s source code.
# Phase 2: kmcmake Framework Integration
# Add kmcmake's core module paths to CMake's module search list
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/kmcmake)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/kmcmake/tools)
# Add your project's custom cmake/ directory to the module path (for user configs)
list(APPEND CMAKE_MODULE_PATH ${${PROJECT_NAME}_SOURCE_DIR}/cmake)
# Include kmcmake's core module (initializes macros, utilities, and default settings)
include(kmcmake_module)
Key Notes:
CMAKE_MODULE_PATHtells CMake where to find kmcmake’s macros (e.g.,kmcmake_cc_library.cmake) and your custom configs (e.g.,myproject_deps.cmake).include(kmcmake_module)is mandatory—it activates kmcmake’s core functionality (no manual setup needed).
Phase 3: User-Specific Configuration Import
Goal: Load your project’s custom settings (dependencies, C++ flags, test configs) from the cmake/ directory.
This phase is where you inject project-specific logic—kmcmake generated placeholders for your customizations.
# Phase 3: User-Specific Configuration
##################################################################
# Your cmake directory (${PROJECT_SOURCE_DIR}/cmake) — add custom logic here
#################################################################
include(myproject_user_option OPTIONAL) # Optional user override entrypoint (loaded first)
include(myproject_deps) # Load external dependencies (e.g., gflags, spdlog)
include(myproject_cxx_config) # Load C++ compile flags (presets + custom tweaks)
include(myproject_test) # Load test configuration (e.g., Google Test setup)
# Generate version.h from template (uses metadata from Phase 1)
string(TOUPPER ${CMAKE_BUILD_TYPE} UPPERCASE_BUILD_TYPE)
configure_file(
${PROJECT_SOURCE_DIR}/myproject/version.h.in # Input template
${PROJECT_SOURCE_DIR}/myproject/version.h # Output generated file
@ONLY # Replace @PLACEHOLDER@ values
)
Key Notes:
myproject_user_option.cmakeis the recommended place for user-local option overrides (for example:KMCMAKE_RUNTIME_SIMD_LEVEL, test/benchmark toggles, custom flags).- The three
include()calls load your custom configs (fromcmake/), which we covered in earlier chapters. configure_file()generatesversion.h(the metadata bridge) using variables from Phase 1 (e.g.,PROJECT_VERSION) and build context (e.g.,CMAKE_BUILD_TYPE).
Phase 4: Build Execution (Core Logic)
Goal: Trigger builds for core code, tests, benchmarks, and examples—conditioned on kmcmake flags.
This phase executes the actual build logic, with kmcmake’s flags controlling which components are built.
# Phase 4: Build Execution
# Build core business logic (myproject/ directory: libraries/binaries via kmcmake macros)
add_subdirectory(myproject)
####################################################################
# Auto-generated build rules — edit with caution
####################################################################
# Build tests (if KMCMAKE_BUILD_TEST is enabled)
if (KMCMAKE_BUILD_TEST)
add_subdirectory(tests)
endif ()
# Build benchmarks (if KMCMAKE_BUILD_BENCHMARK is enabled)
if (KMCMAKE_BUILD_BENCHMARK)
add_subdirectory(benchmark)
endif ()
# Build examples (if KMCMAKE_BUILD_EXAMPLES is enabled)
if (KMCMAKE_BUILD_EXAMPLES)
add_subdirectory(examples)
endif ()
Key Notes:
add_subdirectory(myproject)is mandatory—it processesmyproject/CMakeLists.txt, where you define your core libraries/binaries with kmcmake macros.- Conditional flags (e.g.,
KMCMAKE_BUILD_TEST) are kmcmake-provided—enable them via the command line (e.g.,cmake -DKMCMAKE_BUILD_TEST=ON ..).
Phase 5: Target Export & Packaging (Top-Level Only)
Goal: Export your project’s targets, headers, and config files for external use—only runs if this is the top-level project and not a Python extension.
This phase makes your project reusable by other CMake projects (via find_package()).
# Phase 5: Target Export & Packaging (skip if building Python extension)
if(NOT PYTHON_EXTENSION)
##############################################
# Install headers to standard include directory
#############################################
install(DIRECTORY ${PROJECT_NAME}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING
PATTERN "*.inc"
PATTERN "*.h"
PATTERN "*.hpp"
)
# Configure export paths (standard CMake layout)
set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(namespace "${PROJECT_NAME}::")
# Generate ConfigVersion.cmake (supports version constraints)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${version_config}" COMPATIBILITY SameMajorVersion
)
# Generate Config.cmake from your template (myproject_config.cmake.in)
configure_package_config_file(
"cmake/myproject_config.cmake.in"
"${project_config}"
INSTALL_DESTINATION "${config_install_dir}"
)
# Install export files (for find_package())
install(
FILES "${project_config}" "${version_config}"
DESTINATION "${config_install_dir}"
)
install(
EXPORT "${TARGETS_EXPORT_NAME}"
NAMESPACE "${namespace}"
DESTINATION "${config_install_dir}"
)
# Generate and install pkg-config file (for non-CMake projects)
configure_file(
${PROJECT_SOURCE_DIR}/kmcmake/package/pkg_dump_template.pc.in
${PROJECT_BINARY_DIR}/package/${PROJECT_NAME}.pc
)
install(
FILES ${PROJECT_BINARY_DIR}/package/${PROJECT_NAME}.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
# Uncomment to enable CPack (RPM/DEB/archive packaging)
# include(myproject_cpack_config)
endif()
# kmcmake build completion message
kmcmake_print("myproject cmake build system is created by kmcmake package manager tools")
kmcmake_print("kmcmake: https://github.com/kumose/kmcmake")
kmcmake_print("tools: https://github.com/kumose/kmdo")
kmcmake_print("docs: https://pub.kumose.cc/kmdo")
Key Notes:
- Header Installation: Copies your project’s headers (
.h/.hpp/.inc) to the system’s standard include directory (e.g.,/usr/local/include). - CMake Export: Generates
myprojectConfig.cmake,myprojectConfigVersion.cmake, andmyprojectTargets.cmake—enabling external projects to usefind_package(myproject). - pkg-config Support: Generates a
.pcfile for non-CMake projects (e.g., projects usingmake/autotools). - CPack Integration: Uncomment
include(myproject_cpack_config)to enable cross-platform packaging (RPM/DEB/ZIP).
Critical Best Practices for the Root CMakeLists.txt
-
Minimize Manual Edits:
kmcmake generates most of this file—only modify sections marked with# Your cmake directory ...(Phase 3) or uncomment optional features (e.g., CPack). Edits to other phases may break kmcmake compatibility. -
Use kmcmake Flags for Conditional Builds:
Control tests/benchmarks/examples via kmcmake’s built-in flags (set via command line orCMakePresets.json):# Enable tests and examples
cmake -DKMCMAKE_BUILD_TEST=ON -DKMCMAKE_BUILD_EXAMPLES=ON .. -
Preserve Standard Layout:
kmcmake follows CMake’s standard install layout (e.g.,lib/cmake/${PROJECT_NAME}for configs,include/for headers). Do not change these paths—they ensure compatibility with external projects. -
Versioning Consistency:
UpdatePROJECT_VERSION_MAJOR/MINOR/PATCHhere—this value propagates toversion.h,myproject_config.cmake, andpkg-configfiles.
Key Design Philosophy
The root CMakeLists.txt embodies kmcmake’s core principles:
- Phase-Based Order: Ensures dependencies are resolved before builds, and exports happen after builds—avoiding "chicken-and-egg" errors.
- Separation of Concerns: User-specific logic (Phase 3) is isolated from framework integration (Phase 2) and export logic (Phase 5)—easy to maintain.
- Standard Compliance: Follows CMake’s native conventions (e.g.,
write_basic_package_version_file,install(EXPORT)) so your project works with existing CMake ecosystems. - Zero Boilerplate: kmcmake generates all the repetitive logic (e.g., export path configuration, pkg-config setup) —you focus on your core code.
This file is the "backbone" of your kmcmake project—connecting your code to kmcmake’s framework, handling configurations, and enabling reusability. With minimal manual intervention, it delivers a production-grade build system that scales from small libraries to large multi-component projects.