سیستمهای ساخت: CMake و مدیریت بسته
اصول CMake، CMake مدرن مبتنی بر هدف، FetchContent برای وابستگیها، مدیران بسته vcpkg و Conan، و فلگهای کامپایلر برای بیلدهای ایمن و بهینه را فرا بگیرید.
چرا سیستمهای ساخت اهمیت دارند
وقتی پروژههای C++ فراتر از یک فایل واحد رشد میکنند، به یک سیستم ساخت برای مدیریت کامپایل، لینک، وابستگیها و تفاوتهای پلتفرم نیاز دارید. اجرای دستی g++ *.cpp مقیاسپذیر نیست: به بیلدهای افزایشی (فقط فایلهای تغییریافته را بازکامپایل کنید)، تشخیص کتابخانه، پشتیبانی چندسکویی و بیلدهای تکرارپذیر نیاز دارید. CMake به استاندارد واقعی تولیدکننده سیستم ساخت برای C++ تبدیل شده است. خودش کد را کامپایل نمیکند — فایلهای ساخت بومی (Makefiles، فایلهای Ninja، پروژههای Visual Studio) را برای پلتفرم شما تولید میکند.
اصول CMake
یک فایل CMakeLists.txt ساختار پروژه شما را توصیف میکند. CMake مدرن (3.12+) از رویکرد مبتنی بر هدف استفاده میکند که همه چیز به اهداف (فایلهای اجرایی یا کتابخانهها) متصل است:
# CMakeLists.txt — minimum viable project
cmake_minimum_required(VERSION 3.20)
project(MyApp VERSION 1.0.0 LANGUAGES CXX)
# Set C++ standard for the entire project
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # use -std=c++20, not -std=gnu++20
# Create an executable target
add_executable(myapp
src/main.cpp
src/engine.cpp
src/utils.cpp
)
# Add include directories for this target
target_include_directories(myapp PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# Create a library target
add_library(mathlib STATIC
src/math/vector.cpp
src/math/matrix.cpp
)
target_include_directories(mathlib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include/math
)
# Link the library to the executable
target_link_libraries(myapp PRIVATE mathlib)
# Compiler warnings — essential for quality code
target_compile_options(myapp PRIVATE
$<$<CXX_COMPILER_ID:GNU,Clang>:-Wall -Wextra -Wpedantic -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
)ساخت با CMake
CMake از یک فرآیند دومرحلهای استفاده میکند: پیکربندی (تولید فایلهای ساخت) و ساخت (کامپایل). همیشه از بیلدهای خارج از منبع استفاده کنید تا درخت منبع تمیز بماند:
# Configure — generate build files in a 'build' directory
cmake -B build -DCMAKE_BUILD_TYPE=Release
# Build — compile the project
cmake --build build --parallel $(nproc)
# Install (optional)
cmake --install build --prefix /usr/local
# Common build types:
# Debug — -O0 -g (full debug symbols, no optimization)
# Release — -O3 -DNDEBUG (max optimization, no asserts)
# RelWithDebInfo — -O2 -g -DNDEBUG (optimized with debug info)
# MinSizeRel — -Os -DNDEBUG (optimize for size)
# Run with sanitizers (add to CMakeLists.txt or command line)
cmake -B build-asan -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer"FetchContent: مدیریت وابستگی
ماژول FetchContent در CMake وابستگیها را در زمان پیکربندی دانلود و ساخت میکند و افزودن کتابخانهها بدون تنظیم دستی را آسان میسازد:
cmake_minimum_required(VERSION 3.20)
project(MyApp LANGUAGES CXX)
include(FetchContent)
# Fetch GoogleTest
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)
# Fetch fmt (formatting library)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.2.1
)
# Download and make available
FetchContent_MakeAvailable(googletest fmt)
add_executable(myapp src/main.cpp)
target_link_libraries(myapp PRIVATE fmt::fmt)
# Test executable
enable_testing()
add_executable(tests tests/test_main.cpp)
target_link_libraries(tests PRIVATE GTest::gtest_main)
add_test(NAME unit_tests COMMAND tests)vcpkg و Conan
برای پروژههای بزرگتر با وابستگیهای زیاد، مدیران بسته اختصاصی C++ حل وابستگی و کشسازی بهتری فراهم میکنند:
vcpkg (مایکروسافت) — مستقیماً از طریق فایل toolchain با CMake ادغام میشود. بستهها را بهصورت سراسری یا در «حالت مانیفست» با فایل vcpkg.json نصب کنید:
{
"dependencies": ["fmt", "spdlog", "nlohmann-json", "catch2"]
}استفاده با: cmake -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
Conan — از conanfile.txt یا conanfile.py برای اعلان وابستگیها استفاده میکند. از چندین پیکربندی ساخت و کشسازی باینری پشتیبانی میکند:
[requires]
fmt/10.2.1
spdlog/1.13.0
[generators]
CMakeDeps
CMakeToolchainهر دو مدیر بسته مخازنی از هزاران کتابخانه C++ با باینریهای از پیش ساخته و تستشده نگهداری میکنند.
این قوانین را برای CMake قابل نگهداری دنبال کنید:
1. همیشه از دستورات مبتنی بر هدف استفاده کنید: target_include_directories، target_compile_options، target_link_libraries — هرگز include_directories یا add_definitions (که دامنه سراسری را آلوده میکنند).
2. PRIVATE/PUBLIC/INTERFACE را درک کنید: PRIVATE = فقط برای این هدف، PUBLIC = برای این هدف و مصرفکنندگانش، INTERFACE = فقط برای مصرفکنندگان.
3. استاندارد C++ را به ازای هدف یا کل پروژه تنظیم کنید، هرگز با فلگهای خام مانند -std=c++20.
4. حداکثر هشدارها را فعال کنید: -Wall -Wextra -Wpedantic (GCC/Clang) یا /W4 (MSVC). -Werror / /WX را در CI در نظر بگیرید.
5. از cmake --preset برای بیلدهای تکرارپذیر (CMakePresets.json) استفاده کنید.
6. هرگز مسیرها را بهصورت ثابت ننویسید — از find_package، FetchContent یا مدیران بسته استفاده کنید.
استفاده از file(GLOB ...) برای جمعآوری منابع: file(GLOB SOURCES src/*.cpp) وقتی فایلها اضافه یا حذف میشوند دوباره اجرا نمیشود. فایلهای جدید تا زمان پیکربندی مجدد دستی کامپایل نخواهند شد. همیشه فایلهای منبع را بهصورت صریح لیست کنید.
فراموش کردن CMAKE_CXX_EXTENSIONS OFF: بدون این، GCC از -std=gnu++20 بهجای -std=c++20 استفاده میکند و افزونههای غیراستاندارد را فعال میکند که قابلیت حمل را خراب میکنند.
مخلوط کردن add_subdirectory و FetchContent: هر دو پروژههای خارجی را وارد میکنند، اما بهشکل متفاوتی با کش ساخت تعامل دارند. برای هر وابستگی یک رویکرد را انتخاب کنید.
تنظیم نکردن CMAKE_EXPORT_COMPILE_COMMANDS ON: این فایل compile_commands.json را تولید میکند که برای clang-tidy، clangd (LSP) و بسیاری از ادغامهای IDE مورد نیاز است. همیشه آن را فعال کنید.
- CMake تولیدکننده استاندارد سیستم ساخت C++ است — API مبتنی بر هدف آن را بیاموزید
- از دستورات
target_*(نه دامنه سراسری) با قابلیت مشاهده PRIVATE/PUBLIC/INTERFACE استفاده کنید - FetchContent وابستگیها را در زمان پیکربندی دانلود و ساخت میکند — ایدهآل برای مجموعههای کوچک وابستگی
- vcpkg (حالت مانیفست) و Conan گرافهای وابستگی بزرگتر را با کشسازی باینری مدیریت میکنند
- همیشه هشدارها (
-Wall -Wextra -Wpedantic) را فعال کنید و از بیلدهای خارج از منبع استفاده کنید - فایل
compile_commands.jsonرا برای ابزار IDE و تحلیل ایستا تولید کنید
آزمون — دانش خود را بسنجید
(15 امتیاز)1. `target_link_libraries(myapp PRIVATE mathlib)` چه کاری انجام میدهد؟
2. چرا `file(GLOB SOURCES src/*.cpp)` در CMake شیوه بدی محسوب میشود؟
3. هدف `CMAKE_CXX_EXTENSIONS OFF` چیست؟