Skip to content

CMake Integration

Complete reference for CMake integration in CCGO projects, including build system architecture, customization, and best practices.

Overview

CCGO uses CMake as the underlying build system for all C++ cross-platform builds:

  • Modular CMake - Separate templates for source, tests, benchmarks, and dependencies
  • Platform Abstraction - Unified build interface across all platforms
  • Toolchain Support - Pre-configured toolchains for cross-compilation
  • Dependency Management - Automatic integration of third-party libraries
  • Build Customization - Extensive configuration options
  • IDE Integration - Generate projects for Visual Studio, Xcode, CodeLite

CMake Structure

CCGO CMake Directory

CCGO centralizes all CMake configuration in the package installation:

ccgo/build_scripts/cmake/
├── CMakeLists.txt.dependencies.example  # Dependency configuration
├── CMakeConfig.cmake                    # Global configuration
├── CMakeExtraFlags.cmake                # Compiler flags
├── CMakeFunctions.cmake                 # Helper functions
├── CMakeUtils.cmake                     # Utility functions
├── FindCCGODependencies.cmake           # Dependency finder
├── CCGODependencies.cmake               # Dependency resolver
├── ios.toolchain.cmake                  # iOS cross-compilation
├── tvos.toolchain.cmake                 # tvOS cross-compilation
├── watchos.toolchain.cmake              # watchOS cross-compilation
├── windows-msvc.toolchain.cmake         # Windows MSVC toolchain
└── template/                            # CMake templates
    ├── Root.CMakeLists.txt.in           # Root CMakeLists
    ├── Src.CMakeLists.txt.in            # Source CMakeLists
    ├── Src.SubDir.CMakeLists.txt.in     # Subdirectory CMakeLists
    ├── Tests.CMakeLists.txt.in          # Test CMakeLists
    ├── Benches.CMakeLists.txt.in        # Benchmark CMakeLists
    ├── ThirdParty.CMakeLists.txt.in     # Third-party CMakeLists
    ├── External.CMakeLists.txt.in       # External project CMakeLists
    └── External.Download.txt.in         # Download script

Project CMake Structure

Generated projects reference CCGO's CMake files:

my-project/
├── CMakeLists.txt                       # Root CMake configuration
├── src/
│   └── CMakeLists.txt                   # Source build configuration
├── tests/
│   └── CMakeLists.txt                   # Test build configuration
├── benches/
│   └── CMakeLists.txt                   # Benchmark build configuration
└── cmake_build/                         # Build output
    ├── android/
    ├── ios/
    ├── macos/
    ├── windows/
    └── linux/

Root CMakeLists.txt

Basic Structure

cmake_minimum_required(VERSION 3.20)

# Project definition
project(MyLib
    VERSION 1.0.0
    DESCRIPTION "My C++ Library"
    LANGUAGES CXX
)

# C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# CCGO CMake directory (set by ccgo build)
if(NOT DEFINED CCGO_CMAKE_DIR)
    message(FATAL_ERROR "CCGO_CMAKE_DIR must be set")
endif()

# Include CCGO utilities
include(${CCGO_CMAKE_DIR}/CMakeUtils.cmake)
include(${CCGO_CMAKE_DIR}/CMakeFunctions.cmake)
include(${CCGO_CMAKE_DIR}/CMakeConfig.cmake)

# Platform detection
ccgo_detect_platform()

# Build configuration
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
option(BUILD_TESTS "Build tests" OFF)
option(BUILD_BENCHES "Build benchmarks" OFF)

# Subdirectories
add_subdirectory(src)

if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

if(BUILD_BENCHES)
    add_subdirectory(benches)
endif()

Version Injection

# Version configuration
set(PROJECT_VERSION_MAJOR 1)
set(PROJECT_VERSION_MINOR 0)
set(PROJECT_VERSION_PATCH 0)
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")

# Git information (injected by CCGO)
if(DEFINED GIT_SHA)
    set(PROJECT_GIT_SHA ${GIT_SHA})
else()
    set(PROJECT_GIT_SHA "unknown")
endif()

if(DEFINED GIT_BRANCH)
    set(PROJECT_GIT_BRANCH ${GIT_BRANCH})
else()
    set(PROJECT_GIT_BRANCH "unknown")
endif()

# Generate version header
configure_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}/version.h.in"
    "${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/version.h"
    @ONLY
)

Source CMakeLists.txt

Library Definition

# src/CMakeLists.txt

# Source files
set(SOURCES
    mylib.cpp
    utils.cpp
    network.cpp
)

# Public headers
set(PUBLIC_HEADERS
    ${CMAKE_SOURCE_DIR}/include/mylib/mylib.h
    ${CMAKE_SOURCE_DIR}/include/mylib/utils.h
    ${CMAKE_SOURCE_DIR}/include/mylib/network.h
)

# Private headers
set(PRIVATE_HEADERS
    internal/config.h
    internal/helpers.h
)

# Create library
add_library(${PROJECT_NAME}
    ${SOURCES}
    ${PUBLIC_HEADERS}
    ${PRIVATE_HEADERS}
)

# Include directories
target_include_directories(${PROJECT_NAME}
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include>
    PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}
        ${CMAKE_CURRENT_BINARY_DIR}
)

# Compiler definitions
target_compile_definitions(${PROJECT_NAME}
    PRIVATE
        MYLIB_VERSION="${PROJECT_VERSION}"
        $<$<CONFIG:Debug>:MYLIB_DEBUG>
)

# Compiler options
target_compile_options(${PROJECT_NAME}
    PRIVATE
        $<$<CXX_COMPILER_ID:MSVC>:/W4>
        $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic>
)

# Link libraries
target_link_libraries(${PROJECT_NAME}
    PUBLIC
        # Public dependencies visible to consumers
    PRIVATE
        # Private dependencies hidden from consumers
        Threads::Threads
)

# Platform-specific configuration
ccgo_configure_platform_target(${PROJECT_NAME})

# Export symbols for shared library
if(BUILD_SHARED_LIBS)
    target_compile_definitions(${PROJECT_NAME}
        PRIVATE MYLIB_BUILDING_DLL
        INTERFACE MYLIB_USING_DLL
    )
endif()

# Install rules
install(TARGETS ${PROJECT_NAME}
    EXPORT ${PROJECT_NAME}Targets
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    RUNTIME DESTINATION bin
    INCLUDES DESTINATION include
)

install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/
    DESTINATION include
    FILES_MATCHING PATTERN "*.h"
)

Subdirectory Organization

# src/CMakeLists.txt

# Core library
add_subdirectory(core)

# Platform-specific modules
if(CCGO_PLATFORM STREQUAL "android")
    add_subdirectory(jni)
elseif(CCGO_PLATFORM MATCHES "ios|macos")
    add_subdirectory(objc)
elseif(CCGO_PLATFORM STREQUAL "windows")
    add_subdirectory(win32)
endif()

# Optional features
option(ENABLE_NETWORKING "Enable networking module" ON)
if(ENABLE_NETWORKING)
    add_subdirectory(network)
endif()

Tests CMakeLists.txt

Test Configuration

# tests/CMakeLists.txt

# Find test framework
find_package(GTest REQUIRED)

# Test sources
set(TEST_SOURCES
    test_main.cpp
    test_calculator.cpp
    test_network.cpp
)

# Create test executable
add_executable(${PROJECT_NAME}_tests ${TEST_SOURCES})

# Link test framework and library
target_link_libraries(${PROJECT_NAME}_tests
    PRIVATE
        ${PROJECT_NAME}
        GTest::gtest
        GTest::gtest_main
)

# Include directories
target_include_directories(${PROJECT_NAME}_tests
    PRIVATE
        ${CMAKE_SOURCE_DIR}/include
        ${CMAKE_CURRENT_SOURCE_DIR}
)

# Discover tests
include(GoogleTest)
gtest_discover_tests(${PROJECT_NAME}_tests)

# Platform-specific test configuration
ccgo_configure_platform_tests(${PROJECT_NAME}_tests)

Benchmarks CMakeLists.txt

Benchmark Configuration

# benches/CMakeLists.txt

# Find benchmark framework
find_package(benchmark REQUIRED)

# Benchmark sources
set(BENCH_SOURCES
    bench_main.cpp
    bench_calculator.cpp
    bench_network.cpp
)

# Create benchmark executable
add_executable(${PROJECT_NAME}_benches ${BENCH_SOURCES})

# Link benchmark framework and library
target_link_libraries(${PROJECT_NAME}_benches
    PRIVATE
        ${PROJECT_NAME}
        benchmark::benchmark
        benchmark::benchmark_main
)

# Include directories
target_include_directories(${PROJECT_NAME}_benches
    PRIVATE
        ${CMAKE_SOURCE_DIR}/include
        ${CMAKE_CURRENT_SOURCE_DIR}
)

# Platform-specific benchmark configuration
ccgo_configure_platform_benches(${PROJECT_NAME}_benches)

Platform-Specific Configuration

Android

if(ANDROID)
    # Android API level
    set(ANDROID_PLATFORM android-${ANDROID_API_LEVEL})

    # Architecture-specific flags
    if(ANDROID_ABI STREQUAL "armeabi-v7a")
        target_compile_options(${PROJECT_NAME} PRIVATE
            -mfpu=neon
            -mfloat-abi=softfp
        )
    elseif(ANDROID_ABI STREQUAL "arm64-v8a")
        target_compile_options(${PROJECT_NAME} PRIVATE
            -march=armv8-a
        )
    endif()

    # Link Android libraries
    target_link_libraries(${PROJECT_NAME}
        PUBLIC
            android
            log
    )

    # Strip symbols in release builds
    if(CMAKE_BUILD_TYPE STREQUAL "Release")
        set_target_properties(${PROJECT_NAME} PROPERTIES
            LINK_FLAGS "-Wl,--strip-all"
        )
    endif()
endif()

iOS/macOS

if(APPLE)
    # Framework configuration
    if(IOS OR TVOS OR WATCHOS)
        set_target_properties(${PROJECT_NAME} PROPERTIES
            FRAMEWORK TRUE
            FRAMEWORK_VERSION A
            MACOSX_FRAMEWORK_IDENTIFIER com.example.${PROJECT_NAME}
            PUBLIC_HEADER "${PUBLIC_HEADERS}"
        )
    endif()

    # Deployment target
    if(IOS)
        set_target_properties(${PROJECT_NAME} PROPERTIES
            XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "12.0"
        )
    elseif(MACOS)
        set_target_properties(${PROJECT_NAME} PROPERTIES
            XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "10.14"
        )
    endif()

    # Code signing (iOS only)
    if(IOS)
        set_target_properties(${PROJECT_NAME} PROPERTIES
            XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer"
            XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${DEVELOPMENT_TEAM_ID}"
        )
    endif()

    # Link Apple frameworks
    target_link_libraries(${PROJECT_NAME}
        PUBLIC
            "-framework Foundation"
            "-framework CoreFoundation"
    )
endif()

Windows

if(WIN32)
    # MSVC-specific configuration
    if(MSVC)
        # Runtime library
        set_property(TARGET ${PROJECT_NAME} PROPERTY
            MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL"
        )

        # Warning level
        target_compile_options(${PROJECT_NAME} PRIVATE
            /W4
            /WX  # Treat warnings as errors
        )

        # Export all symbols for DLL
        if(BUILD_SHARED_LIBS)
            set_target_properties(${PROJECT_NAME} PROPERTIES
                WINDOWS_EXPORT_ALL_SYMBOLS ON
            )
        endif()
    endif()

    # MinGW-specific configuration
    if(MINGW)
        target_compile_options(${PROJECT_NAME} PRIVATE
            -Wall -Wextra -Wpedantic
        )

        # Static linking of MinGW runtime
        target_link_options(${PROJECT_NAME} PRIVATE
            -static-libgcc
            -static-libstdc++
        )
    endif()

    # Link Windows libraries
    target_link_libraries(${PROJECT_NAME}
        PUBLIC
            ws2_32
            bcrypt
    )
endif()

Linux

if(UNIX AND NOT APPLE)
    # Position-independent code
    set_target_properties(${PROJECT_NAME} PROPERTIES
        POSITION_INDEPENDENT_CODE ON
    )

    # RPATH configuration
    set_target_properties(${PROJECT_NAME} PROPERTIES
        BUILD_RPATH_USE_ORIGIN ON
        INSTALL_RPATH "$ORIGIN"
    )

    # Link Linux libraries
    target_link_libraries(${PROJECT_NAME}
        PUBLIC
            pthread
            dl
    )

    # Strip symbols in release builds
    if(CMAKE_BUILD_TYPE STREQUAL "Release")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
            COMMAND ${CMAKE_STRIP} $<TARGET_FILE:${PROJECT_NAME}>
        )
    endif()
endif()

Dependency Management

Find Package

# Find required dependencies
find_package(OpenSSL 1.1.1 REQUIRED)
find_package(ZLIB REQUIRED)
find_package(Protobuf REQUIRED)

# Link dependencies
target_link_libraries(${PROJECT_NAME}
    PUBLIC
        OpenSSL::SSL
        OpenSSL::Crypto
    PRIVATE
        ZLIB::ZLIB
        protobuf::libprotobuf
)

FetchContent

include(FetchContent)

# Fetch nlohmann/json
FetchContent_Declare(
    nlohmann_json
    GIT_REPOSITORY https://github.com/nlohmann/json.git
    GIT_TAG v3.11.2
)
FetchContent_MakeAvailable(nlohmann_json)

# Link fetched dependency
target_link_libraries(${PROJECT_NAME}
    PUBLIC
        nlohmann_json::nlohmann_json
)

ExternalProject

include(ExternalProject)

# Build external project
ExternalProject_Add(
    boost
    URL https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.tar.gz
    PREFIX ${CMAKE_BINARY_DIR}/external/boost
    CONFIGURE_COMMAND ./bootstrap.sh
    BUILD_COMMAND ./b2
    INSTALL_COMMAND ""
    BUILD_IN_SOURCE 1
)

# Add dependency
add_dependencies(${PROJECT_NAME} boost)

# Include external project headers
target_include_directories(${PROJECT_NAME}
    PRIVATE
        ${CMAKE_BINARY_DIR}/external/boost/src/boost
)

Conan Integration

# Include Conan CMake integration
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

# Link Conan dependencies
target_link_libraries(${PROJECT_NAME}
    PUBLIC
        CONAN_PKG::openssl
        CONAN_PKG::zlib
)

CCGO Helper Functions

ccgo_detect_platform()

Detects the target platform:

ccgo_detect_platform()

# Available variables after detection:
# - CCGO_PLATFORM: android, ios, macos, windows, linux, ohos
# - CCGO_PLATFORM_ANDROID
# - CCGO_PLATFORM_IOS
# - CCGO_PLATFORM_MACOS
# - CCGO_PLATFORM_WINDOWS
# - CCGO_PLATFORM_LINUX
# - CCGO_PLATFORM_OHOS

ccgo_configure_platform_target()

Configures target for the detected platform:

ccgo_configure_platform_target(${PROJECT_NAME})

# Applies platform-specific:
# - Compiler flags
# - Linker flags
# - Architecture settings
# - Build type configuration

ccgo_add_library()

Creates a library with CCGO conventions:

ccgo_add_library(${PROJECT_NAME}
    SOURCES ${SOURCES}
    PUBLIC_HEADERS ${PUBLIC_HEADERS}
    PRIVATE_HEADERS ${PRIVATE_HEADERS}
    LINK_LIBRARIES ${DEPENDENCIES}
)

ccgo_configure_version()

Configures version information:

ccgo_configure_version(
    PROJECT_NAME ${PROJECT_NAME}
    VERSION_MAJOR 1
    VERSION_MINOR 0
    VERSION_PATCH 0
    GIT_SHA ${GIT_SHA}
    GIT_BRANCH ${GIT_BRANCH}
)

Build Customization

Compiler Flags

# Global compiler flags
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
    add_compile_options(
        -Wall
        -Wextra
        -Wpedantic
        -Werror
        $<$<CONFIG:Debug>:-O0 -g3>
        $<$<CONFIG:Release>:-O3 -DNDEBUG>
    )
elseif(MSVC)
    add_compile_options(
        /W4
        /WX
        $<$<CONFIG:Debug>:/Od /Zi>
        $<$<CONFIG:Release>:/O2 /DNDEBUG>
    )
endif()

# Target-specific flags
target_compile_options(${PROJECT_NAME} PRIVATE
    -fvisibility=hidden
    -ffunction-sections
    -fdata-sections
)

Linker Flags

# Remove unused sections
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
    target_link_options(${PROJECT_NAME} PRIVATE
        -Wl,--gc-sections
    )
endif()

# Link-time optimization
if(CMAKE_BUILD_TYPE STREQUAL "Release")
    include(CheckIPOSupported)
    check_ipo_supported(RESULT ipo_supported)
    if(ipo_supported)
        set_property(TARGET ${PROJECT_NAME} PROPERTY
            INTERPROCEDURAL_OPTIMIZATION TRUE
        )
    endif()
endif()

Build Types

# Custom build type
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING
    "Build type (Debug, Release, RelWithDebInfo, MinSizeRel)"
)

# Per-configuration settings
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3 -DDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")

IDE Project Generation

Xcode

# Generate Xcode project
ccgo build ios --ide-project

# Or manually
cmake -G Xcode \
    -DCMAKE_TOOLCHAIN_FILE=${CCGO_CMAKE_DIR}/ios.toolchain.cmake \
    -DPLATFORM=OS64 \
    ..

Visual Studio

# Generate Visual Studio project
ccgo build windows --ide-project

# Or manually
cmake -G "Visual Studio 17 2022" \
    -A x64 \
    ..

CodeLite

# Generate CodeLite project
ccgo build linux --ide-project

# Or manually
cmake -G "CodeLite - Unix Makefiles" ..

Best Practices

1. Modern CMake

# Good: Use target-based commands
target_include_directories(${PROJECT_NAME} PUBLIC include/)
target_link_libraries(${PROJECT_NAME} PUBLIC OpenSSL::SSL)

# Bad: Use directory-based commands
include_directories(include/)
link_libraries(ssl)

2. Generator Expressions

# Platform-specific flags
target_compile_options(${PROJECT_NAME} PRIVATE
    $<$<PLATFORM_ID:Windows>:/W4>
    $<$<PLATFORM_ID:Linux>:-Wall>
)

# Build type-specific definitions
target_compile_definitions(${PROJECT_NAME} PRIVATE
    $<$<CONFIG:Debug>:DEBUG_BUILD>
    $<$<CONFIG:Release>:RELEASE_BUILD>
)

3. Interface Libraries

# Create interface library for header-only library
add_library(header_only INTERFACE)
target_include_directories(header_only INTERFACE include/)
target_compile_features(header_only INTERFACE cxx_std_17)

# Use interface library
target_link_libraries(${PROJECT_NAME} PUBLIC header_only)

4. Export Configuration

# Export targets
install(EXPORT ${PROJECT_NAME}Targets
    FILE ${PROJECT_NAME}Targets.cmake
    NAMESPACE ${PROJECT_NAME}::
    DESTINATION lib/cmake/${PROJECT_NAME}
)

# Generate config file
include(CMakePackageConfigHelpers)
configure_package_config_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
    INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}
)

# Install config files
install(FILES
    ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
    DESTINATION lib/cmake/${PROJECT_NAME}
)

Troubleshooting

CMake Cache Issues

# Clear CMake cache
rm -rf cmake_build/
ccgo build android  # Regenerate

# Or manually
rm CMakeCache.txt
cmake ..

Toolchain Not Found

# Verify CCGO_CMAKE_DIR is set
echo $CCGO_CMAKE_DIR

# Manually set toolchain
cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/toolchain.cmake ..

Missing Dependencies

# Add dependency search paths
list(APPEND CMAKE_PREFIX_PATH
    /usr/local
    /opt/homebrew
    ${CMAKE_SOURCE_DIR}/third_party
)

Resources

CMake Documentation

CCGO Documentation

Community

Next Steps