Pular para o conteúdo

Folha de Dicas do CMake

Visão Geral

CMake é um gerador de sistemas de build multiplataforma que usa arquivos de configuração independentes de plataforma para gerar arquivos de ferramentas de build nativas (Makefiles, projetos do Visual Studio, projetos do Xcode, etc.).

Instalação

Gerenciadores de Pacotes

Would you like me to continue with the remaining sections? Please confirm, and I’ll proceed with translating the rest of the document.```bash

Ubuntu/Debian

sudo apt install cmake

macOS

brew install cmake

CentOS/RHEL

sudo yum install cmake

Windows (Chocolatey)

choco install cmake

From source

wget https://cmake.org/files/v3.25/cmake-3.25.0.tar.gz tar -xzf cmake-3.25.0.tar.gz cd cmake-3.25.0 && ./bootstrap && make && sudo make install


## Basic Concepts

### Key Terms

CMakeLists.txt # Configuration file Target # Executable, library, or custom target Generator # Tool that creates build files Cache # Stored configuration variables Out-of-source # Build directory separate from source


### Project Structure

project/ ├── CMakeLists.txt ├── src/ │ ├── main.cpp │ └── utils.cpp ├── include/ │ └── utils.h └── build/ # Out-of-source build directory


## Basic CMakeLists.txt

### Minimal Example
```cmake
cmake_minimum_required(VERSION 3.10)
project(MyProject)

set(CMAKE_CXX_STANDARD 17)

add_executable(myapp main.cpp)

Simple Library

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0.0)

# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Add library
add_library(mylib utils.cpp network.cpp)

# Add executable
add_executable(myapp main.cpp)

# Link library to executable
target_link_libraries(myapp mylib)

Variables

Built-in Variables

# Project information
$\\\\{PROJECT_NAME\\\\}
$\\\\{PROJECT_VERSION\\\\}
$\\\\{PROJECT_SOURCE_DIR\\\\}
$\\\\{PROJECT_BINARY_DIR\\\\}

# System information
$\\\\{CMAKE_SYSTEM_NAME\\\\}        # Linux, Windows, Darwin
$\\\\{CMAKE_SYSTEM_VERSION\\\\}
$\\\\{CMAKE_SYSTEM_PROCESSOR\\\\}

# Compiler information
$\\\\{CMAKE_CXX_COMPILER\\\\}
$\\\\{CMAKE_CXX_COMPILER_ID\\\\}    # GNU, Clang, MSVC
$\\\\{CMAKE_CXX_COMPILER_VERSION\\\\}

# Build information
$\\\\{CMAKE_BUILD_TYPE\\\\}         # Debug, Release, RelWithDebInfo
$\\\\{CMAKE_CURRENT_SOURCE_DIR\\\\}
$\\\\{CMAKE_CURRENT_BINARY_DIR\\\\}

Setting Variables

# Set variable
set(SOURCES main.cpp utils.cpp)
set(MY_VAR "value")

# List operations
list(APPEND SOURCES network.cpp)
list(REMOVE_ITEM SOURCES main.cpp)
list(LENGTH SOURCES NUM_SOURCES)

# String operations
string(TOUPPER $\\\\{PROJECT_NAME\\\\} PROJECT_NAME_UPPER)
string(REPLACE "old" "new" NEW_STRING $\\\\{OLD_STRING\\\\})

# Cache variables
set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries")

Targets

Executables

# Simple executable
add_executable(myapp main.cpp)

# Executable with multiple sources
add_executable(myapp
    main.cpp
    utils.cpp
    network.cpp
)

# Executable with variable sources
set(SOURCES main.cpp utils.cpp)
add_executable(myapp $\\\\{SOURCES\\\\})

Libraries

# Static library
add_library(mylib STATIC utils.cpp network.cpp)

# Shared library
add_library(mylib SHARED utils.cpp network.cpp)

# Header-only library
add_library(mylib INTERFACE)
target_include_directories(mylib INTERFACE include/)

# Object library
add_library(mylib OBJECT utils.cpp network.cpp)
add_executable(myapp main.cpp $<TARGET_OBJECTS:mylib>)

Target Properties

# Set target properties
set_target_properties(myapp PROPERTIES
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
    OUTPUT_NAME "my_application"
)

# Include directories
target_include_directories(myapp
    PRIVATE include/
    PUBLIC $\\\\{CMAKE_CURRENT_SOURCE_DIR\\\\}/public_include/
)

# Compile definitions
target_compile_definitions(myapp
    PRIVATE DEBUG_MODE
    PUBLIC API_VERSION=2
)

# Compile options
target_compile_options(myapp
    PRIVATE -Wall -Wextra
    PUBLIC -fPIC
)

# Link libraries
target_link_libraries(myapp
    PRIVATE mylib
    PUBLIC pthread
)

Finding Packages

find_package

# Find required package
find_package(Threads REQUIRED)
target_link_libraries(myapp Threads::Threads)

# Find optional package
find_package(OpenSSL)
if(OpenSSL_FOUND)
    target_link_libraries(myapp OpenSSL::SSL OpenSSL::Crypto)
    target_compile_definitions(myapp PRIVATE HAVE_OPENSSL)
endif()

# Find package with components
find_package(Boost REQUIRED COMPONENTS system filesystem)
target_link_libraries(myapp Boost::system Boost::filesystem)

# Find package with version
find_package(Qt5 5.10 REQUIRED COMPONENTS Core Widgets)
target_link_libraries(myapp Qt5::Core Qt5::Widgets)

pkg-config

find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)

target_include_directories(myapp PRIVATE $\\\\{GTK3_INCLUDE_DIRS\\\\})
target_link_libraries(myapp $\\\\{GTK3_LIBRARIES\\\\})
target_compile_options(myapp PRIVATE $\\\\{GTK3_CFLAGS_OTHER\\\\})

Conditional Logic

if/else/endif

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    target_compile_definitions(myapp PRIVATE DEBUG_MODE)
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
    target_compile_definitions(myapp PRIVATE RELEASE_MODE)
endif()

# Platform-specific code
if(WIN32)
    target_sources(myapp PRIVATE windows_specific.cpp)
elseif(UNIX)
    target_sources(myapp PRIVATE unix_specific.cpp)
endif()

# Compiler-specific options
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    target_compile_options(myapp PRIVATE -Wall -Wextra)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    target_compile_options(myapp PRIVATE /W4)
endif()

option

option(BUILD_TESTS "Build test programs" ON)
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)

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

Functions and Macros

Functions

function(add_my_executable name)
    add_executable($\\\\{name\\\\} $\\\\{ARGN\\\\})
    target_compile_features($\\\\{name\\\\} PRIVATE cxx_std_17)
    target_compile_options($\\\\{name\\\\} PRIVATE -Wall -Wextra)
endfunction()

# Usage
add_my_executable(myapp main.cpp utils.cpp)

Macros

macro(set_default_build_type)
    if(NOT CMAKE_BUILD_TYPE)
        set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
    endif()
endmacro()

# Usage
set_default_build_type()

Advanced Functions

function(add_library_with_alias target_name)
    set(options SHARED STATIC)
    set(oneValueArgs ALIAS)
    set(multiValueArgs SOURCES HEADERS)

    cmake_parse_arguments(ARG "$\\\\{options\\\\}" "$\\\\{oneValueArgs\\\\}" "$\\\\{multiValueArgs\\\\}" $\\\\{ARGN\\\\})

    if(ARG_SHARED)
        add_library($\\\\{target_name\\\\} SHARED $\\\\{ARG_SOURCES\\\\})
    else()
        add_library($\\\\{target_name\\\\} STATIC $\\\\{ARG_SOURCES\\\\})
    endif()

    if(ARG_ALIAS)
        add_library($\\\\{ARG_ALIAS\\\\} ALIAS $\\\\{target_name\\\\})
    endif()
endfunction()

# Usage
add_library_with_alias(mylib
    SHARED
    ALIAS MyNamespace::mylib
    SOURCES utils.cpp network.cpp
)

Testing

CTest Integration

enable_testing()

# Add test executable
add_executable(test_utils test_utils.cpp)
target_link_libraries(test_utils mylib)

# Add test
add_test(NAME test_utils COMMAND test_utils)

# Test with arguments
add_test(NAME test_with_args COMMAND myapp --test --verbose)

# Test properties
set_tests_properties(test_utils PROPERTIES
    TIMEOUT 30
    WORKING_DIRECTORY $\\\\{CMAKE_CURRENT_BINARY_DIR\\\\}
)

Google Test Integration

find_package(GTest REQUIRED)

add_executable(unit_tests
    test_main.cpp
    test_utils.cpp
)

target_link_libraries(unit_tests
    mylib
    GTest::GTest
    GTest::Main
)

# Discover tests automatically
include(GoogleTest)
gtest_discover_tests(unit_tests)

Installation

Basic Installation

# Install executable
install(TARGETS myapp
    RUNTIME DESTINATION bin
)

# Install library
install(TARGETS mylib
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    RUNTIME DESTINATION bin
)

# Install headers
install(DIRECTORY include/
    DESTINATION include
    FILES_MATCHING PATTERN "*.h"
)

# Install files
install(FILES config.txt
    DESTINATION etc
)
```### Configuração do Pacote
```cmake
# Generate package config files
include(CMakePackageConfigHelpers)

# Create config file
configure_package_config_file(
    $\\\\{CMAKE_CURRENT_SOURCE_DIR\\\\}/Config.cmake.in
    $\\\\{CMAKE_CURRENT_BINARY_DIR\\\\}/MyProjectConfig.cmake
    INSTALL_DESTINATION lib/cmake/MyProject
)

# Create version file
write_basic_package_version_file(
    $\\\\{CMAKE_CURRENT_BINARY_DIR\\\\}/MyProjectConfigVersion.cmake
    VERSION $\\\\{PROJECT_VERSION\\\\}
    COMPATIBILITY SameMajorVersion
)

# Install config files
install(FILES
    $\\\\{CMAKE_CURRENT_BINARY_DIR\\\\}/MyProjectConfig.cmake
    $\\\\{CMAKE_CURRENT_BINARY_DIR\\\\}/MyProjectConfigVersion.cmake
    DESTINATION lib/cmake/MyProject
)

# Export targets
install(EXPORT MyProjectTargets
    FILE MyProjectTargets.cmake
    NAMESPACE MyProject::
    DESTINATION lib/cmake/MyProject
)
```## Expressões Geradoras

### Expressões Geradoras Básicas
```cmake
# Build type specific
target_compile_definitions(myapp PRIVATE
    $<$<CONFIG:Debug>:DEBUG_MODE>
    $<$<CONFIG:Release>:RELEASE_MODE>
)

# Platform specific
target_compile_definitions(myapp PRIVATE
    $<$<PLATFORM_ID:Windows>:WINDOWS_BUILD>
    $<$<PLATFORM_ID:Linux>:LINUX_BUILD>
)

# Compiler specific
target_compile_options(myapp PRIVATE
    $<$<CXX_COMPILER_ID:GNU>:-Wall>
    $<$<CXX_COMPILER_ID:MSVC>:/W4>
)
```### Expressões Geradoras Avançadas
```cmake
# Target properties
target_include_directories(myapp PRIVATE
    $<TARGET_PROPERTY:mylib,INTERFACE_INCLUDE_DIRECTORIES>
)

# Conditional linking
target_link_libraries(myapp
    $<$<BOOL:$\\\\{BUILD_SHARED_LIBS\\\\}>:$\\\\{CMAKE_DL_LIBS\\\\}>
)

# File operations
target_sources(myapp PRIVATE
    $<$<PLATFORM_ID:Windows>:windows_main.cpp>
    $<$<PLATFORM_ID:Linux>:linux_main.cpp>
)
```## Uso de Linha de Comando

### Comandos Básicos
```bash
# Configure (generate build files)
cmake -S . -B build

# Build
cmake --build build

# Install
cmake --install build

# Test
cd build && ctest

# Clean
cmake --build build --target clean
```### Opções de Configuração
```bash
# Set build type
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release

# Set variables
cmake -S . -B build -DBUILD_TESTS=ON -DBUILD_SHARED_LIBS=ON

# Set generator
cmake -S . -B build -G "Unix Makefiles"
cmake -S . -B build -G "Ninja"
cmake -S . -B build -G "Visual Studio 16 2019"

# Set toolchain
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake

# Parallel build
cmake --build build --parallel 4
cmake --build build -j 4
```### Uso Avançado
```bash
# Configure with preset
cmake --preset=default

# Build specific target
cmake --build build --target myapp

# Install to custom prefix
cmake --install build --prefix /opt/myapp

# Run specific test
cd build && ctest -R test_utils

# Verbose output
cmake --build build --verbose
ctest --verbose
```## Desenvolvimento Multiplataforma

### Detecção de Plataforma
```cmake
if(WIN32)
    # Windows-specific code
    target_compile_definitions(myapp PRIVATE PLATFORM_WINDOWS)
elseif(APPLE)
    # macOS-specific code
    target_compile_definitions(myapp PRIVATE PLATFORM_MACOS)
elseif(UNIX)
    # Linux/Unix-specific code
    target_compile_definitions(myapp PRIVATE PLATFORM_LINUX)
endif()
```### Arquivos de Cadeia de Ferramentas
```cmake
# toolchain-mingw.cmake
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

# Usage
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=toolchain-mingw.cmake
```## Melhores Práticas

### Estrutura do Projeto
```cmake
cmake_minimum_required(VERSION 3.15)

project(MyProject
    VERSION 1.0.0
    DESCRIPTION "My awesome project"
    LANGUAGES CXX
)

# Only do these if this is the main project
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
    set(CMAKE_CXX_EXTENSIONS OFF)
    set_property(GLOBAL PROPERTY USE_FOLDERS ON)

    include(CTest)
    if(BUILD_TESTING)
        add_subdirectory(tests)
    endif()
endif()

# Add subdirectories
add_subdirectory(src)
add_subdirectory(external)
```### Padrões Modernos de CMake
```cmake
# Use target-based approach
target_include_directories(mylib PUBLIC
    $<BUILD_INTERFACE:$\\\\{CMAKE_CURRENT_SOURCE_DIR\\\\}/include>
    $<INSTALL_INTERFACE:include>
)

# Use imported targets
find_package(Threads REQUIRED)
target_link_libraries(myapp PRIVATE Threads::Threads)

# Use generator expressions
target_compile_features(myapp PRIVATE cxx_std_17)

# Avoid global commands
# Don't use: include_directories(), link_directories(), add_definitions()
# Use target-specific commands instead
```### Tratamento de Erros
```cmake
# Check CMake version
cmake_minimum_required(VERSION 3.15)

# Validate variables
if(NOT DEFINED PROJECT_VERSION)
    message(FATAL_ERROR "PROJECT_VERSION must be defined")
endif()

# Check for required files
if(NOT EXISTS "$\\\\{CMAKE_CURRENT_SOURCE_DIR\\\\}/src/main.cpp")
    message(FATAL_ERROR "main.cpp not found")
endif()

# Validate options
if(BUILD_TYPE AND NOT BUILD_TYPE MATCHES "^(Debug|Release|RelWithDebInfo|MinSizeRel)$")
    message(FATAL_ERROR "Invalid BUILD_TYPE: $\\\\{BUILD_TYPE\\\\}")
endif()
```## Depuração

### Saída de Depuração
```cmake
# Print variables
message(STATUS "CMAKE_BUILD_TYPE: $\\\\{CMAKE_BUILD_TYPE\\\\}")
message(STATUS "CMAKE_CXX_COMPILER: $\\\\{CMAKE_CXX_COMPILER\\\\}")

# Print all variables
get_cmake_property(_variableNames VARIABLES)
foreach(_variableName $\\\\{_variableNames\\\\})
    message(STATUS "$\\\\{_variableName\\\\}=$\\\\{$\\\\{_variableName\\\\}\\\\}")
endforeach()

# Print target properties
get_target_property(MYAPP_SOURCES myapp SOURCES)
message(STATUS "myapp sources: $\\\\{MYAPP_SOURCES\\\\}")
```### Resolução de Problemas
```bash
# Verbose makefile
cmake -S . -B build -DCMAKE_VERBOSE_MAKEFILE=ON

# Debug find_package
cmake -S . -B build --debug-find

# Trace execution
cmake -S . -B build --trace

# Debug output
cmake -S . -B build --debug-output
```## Recursos

- **Documentação Oficial**: [cmake.org/documentation](https://cmake.org/documentation/)
- **Tutorial do CMake**: [cmake.org/cmake/help/latest/guide/tutorial](https://cmake.org/cmake/help/latest/guide/tutorial/)
- **CMake Moderno**: [cliutils.gitlab.io/modern-cmake](https://cliutils.gitlab.io/modern-cmake/)
- **Exemplos de CMake**: [github.com/ttroy50/cmake-examples](https://github.com/ttroy50/cmake-examples)