Ответы пользователя по тегу CMake
  • Можно ли через CMake собрать проект, собирающийся bash-скриптом?

    @4rtzel
    add_custom_command полезен когда у вас часть исходников генерируются какой-нибудь другой программой (например flex, protobuf). В таком случае OUTPUT будет указывать на сгенерированные файлы с помощью команды COMMAND. Можете посмотреть мой ответ по теме.

    Самый простой способ (но не всегда самый хороший) собрать сторонний не CMake проект -- использовать ExternalProject_Add. Сложности возникают когда надо добавить этот проект как зависимость к своему. Самый очевидный способ -- это использовать find_package с указанием правильных путей. Например для OpenSSL:
    ...
    # Вместо этой строчки также можно указать путь из командой строки:
    # $ cmake -DOPENSSL_ROOT_DIR=/usr/local/ssl -DOPENSSL_LIBRARIES=/usr/local/ssl/lib ..
    set(CMAKE_MODULE_PATH  ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/openssl)
    # Используем FindOpenSSL.cmake для поиска
    find_package(OpenSSL REQUIRED)
    ...

    Проблема этого способа, что ExternalProject_Add выполняется на этапе сборки (вызов make), а не на этапе конфигурации (вызов cmake), find_package не сработает, если уже нет собранной версии openssl где-то в ${CMAKE_CURRENT_SOURCE_DIR}/openssl.

    Другой вариант добавление зависимости -- использовать комбинацию target_link_directories и target_link_libraries. Пример:
    target_link_directories(my_target ${CMAKE_CURRENT_SOURCE_DIR}/openssl/lib)
    target_link_libraries(my_target PRIVATE crypto ssl)

    Проблема этого способа, что мы привязываемся к конкретному пути и названиям библиотек (хотя должны зависеть только от таргетов).

    Во многих проектах такие проблемы решаются, так называемым, SuperBuild'ом. Это когда у вас есть главный CMakeLists.txt файл в которым все остальные проекты (включая ваш) определены как ExternalProject. Тогда можно будет нормально строить зависимости между ними и вызовы типа find_package будут работать, но это уже другая история.
    Ответ написан
  • Как Cmake описать зависимость от не исходника и пост копиляции?

    @4rtzel
    Вам скорее всего поможет add_custom_command с опциями OUTPUT и DEPENDS.
    Пример:
    add_executable(
        my_target
        path/to/generated/file_1
        path/to/generated/file_2
    )
    
    add_custom_command(
        OUTPUT # Файлы, которые генерируем
            path/to/generated/file_1
            path/to/generated/file_2
        COMMAND # Команда генерации
            python generate.py
        DEPENDS # Файл конфига (CMake должен сам отслеживать изменения этого файла и вызывать COMMAND если это необходимо)
            path/to/config.cfg
    )
    Ответ написан
  • Как подключить папку с хедерами?

    @4rtzel
    Первое что бросается в глаза - наличие пробелов в пути к папке. Попробуйте взять его в кавычки:
    include_directories("C:\\Program Files\\...\\include") #в этой папке tlhelp32.h

    По поводу правильности:
    Вообще говоря использование include_directories считается моветоном и структура современного CMake должна строиться на targets и properties. В вашем описании немного недостаёт данных, чтобы понять что вы хотите получить. Было бы неплохо если бы вы привели полный код CMake'а и описали что вы пытаетесь получить.

    Или вы также можете глянуть мой другой ответ по построению приложения с CMake'ом.
    Ответ написан
  • Как правильно организовать модульный проект с использованием CMake?

    @4rtzel
    Поскольку CMake позволяет получить один и тот же результат кучей разный способов, то я постараюсь описать подход, который использовал бы я сам.
    Структура:
    packages_test
    ├── .git
    ├── cmake // Папка с доп. CMake скриптами если в этом есть необходимость
    ├── build // Результат сборки
    │   └─ res.exe // Исполняемый файл
    ├── CMakeLists.txt // Конфигурация сборки проекта
    ├── src
    │   ├─ main.cpp // Точка входа, main()
    │   └─ ...// Прочие файлы проекта
    ├── dependencies // Зависимости (подключаются через механизм submodule)
    │   ├─ vendor_package_0 // У каждой зависимости своя внутренняя организация
    │   └─ vendor_package_1
    └── test // Тесты
        ├── CMakeLists.txt
        └── src
            └── test_main.cpp

    Теперь, как мы будем добавлять зависимости? Это зависит от того где расположены библиотеки и как они собираются. В вашем случае, как я понимаю, все vendor_package_x представляют из себя CMake проекты с использованием add_library и получаемые из git submodule'ей. Это значит, что мы можем использовать add_subdirectory для импорта их target'ов.

    | Note: find_package чаще всего используется для поиска установленных в системе библиотек с помощью FindXXX.cmake скриптов

    Главный CMakeLists.txt:
    cmake_minimum_required(VERSION 3.0)
    project(playrix_project VERSION 1.0 LANGUAGES CXX)
    add_executable(playrix src/main.cpp)
    
    # Импортируем наши зависимости. Это не приводит к сборке, но просто позволяет нам использовать target'ы этих проектов.
    add_subdirectory(dependencies/vendor_package_0)
    add_subdirectory(dependencies/vendor_package_1)
    
    # Забудьте про include_directories и link_directories! В современном CMake следует использовать targets и properties.
    # Опредеяем зависимости нашего проекта
    target_link_libraries(playrix # Имя нашего executable'а
        PRIVATE # Определяет область видимости зависимостей для внешних проектов
            vendor_package_0_target # Настоящее имя target'а надо смотреть в vendor_package_0 CMakeLists.txt (add_library)
            vendor_package_1_target
    )

    target_link_libraries позаботится о том, чтобы собрать все зависимости, слинковать (если надо) их с нашим проектом и инклюднуть необходимые директории. Теперь можно собирать проект!

    Дополнительные ссылки:
    Ответ написан
  • Как включить в статическую библиотеку все зависимости из других стат.библиотек в CMake проекте?

    @4rtzel
    Хотя я бы конечно советовал использовать find_package/add_subdirectory для подключение этой либы к программе, но если всё же стоит задача получить static либу, то можно попробовать что-то вроде этого (на основе этого ответа https://stackoverflow.com/a/37941544/9953527):

    CMakeLists.txt:
    cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
    project(mylib_combined VERSION 0.1 LANGUAGES CXX)
    
    # Нам нужны статические либы
    set(Boost_USE_STATIC_LIBS ON) 
    find_package(Boost COMPONENTS system filesystem REQUIRED) 
    
    # Наша собственная либа.
    # К сожалению мы не может использовать add_library OBJECT либу, т.к.
    # CMake не умеет работать с IMPORTED OBJECT либами, т.е. он не умеет
    # экстрактить (ar -x) существующею static либу, чтобы собрать её потом 
    # в одну большую (ar -qcs).
    add_library(mylib mylib.cpp) 
    add_custom_command(
        TARGET mylib
        POST_BUILD
        # Экстрактим нашу свежесобранную либу. Не самое красивое решение, но
        # что поделать ¯\_(ツ)_/¯
        COMMAND ar -x $<TARGET_FILE:mylib>
        # Теперь наши буст либы
        COMMAND ar -x ${Boost_SYSTEM_LIBRARY}
        COMMAND ar -x ${Boost_FILESYSTEM_LIBRARY}
        # А теперь собираем всё обратно
        COMMAND ar -qcs lib${PROJECT_NAME}.a *.o
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
    )


    Для работы с этой библиотекой с другого CMake проекта понадобиться add_library IMPORTED таргет. Но если вы всё-таки планируете использовать её в других CMake проектов, то лучше сделать что-то вроде этого:

    CMakeLists.txt:
    cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
    project(mylib_combined VERSION 0.1 LANGUAGES CXX)
    
    set(Boost_USE_STATIC_LIBS ON) 
    find_package(Boost COMPONENTS system filesystem REQUIRED) 
    
    add_library(mylib mylib.cpp) 
    
    add_custom_target(mylib_packer
        COMMAND ar -x $<TARGET_FILE:mylib>
        COMMAND ar -x ${Boost_SYSTEM_LIBRARY}
        COMMAND ar -x ${Boost_FILESYSTEM_LIBRARY} 
        COMMAND ar -qcs lib${PROJECT_NAME}.a *.o
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        DEPENDS mylib
    )
    
    add_library(mylib_combined STATIC IMPORTED GLOBAL)
    add_dependencies(mylib_combined mylib_packer)
    set_target_properties(mylib_combined
        PROPERTIES
            IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib${PROJECT_NAME}.a
    )


    И можно использовать mylib_combined таргет.

    Очевидно, код выше будет работать только на unix системах. Для Windows/Mac OS есть свои тулзы, но тут я ничего подсказать не могу. Могу только посоветовать вынести всю работы с ar/libtool/lib в отдельный .cmake файл для дальнейшего переиспользования и подключать его с помщью include.

    Полезные ссылки:
    https://gitlab.kitware.com/cmake/community/wikis/d...
    https://pabloariasal.github.io/2018/02/19/its-time...
    https://cmake.org/pipermail/cmake/2014-August/0582...
    https://cmake.org/gitweb?p=cmake.git;a=blob;f=Test...
    Ответ написан