Ответы пользователя по тегу Кроссплатформенность
  • Как правильно организовать модульный проект с использованием 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 позаботится о том, чтобы собрать все зависимости, слинковать (если надо) их с нашим проектом и инклюднуть необходимые директории. Теперь можно собирать проект!

    Дополнительные ссылки:
    Ответ написан
    2 комментария
  • Как включить в статическую библиотеку все зависимости из других стат.библиотек в 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...
    Ответ написан
    1 комментарий