Несколько дней новогоднего волшебства:
Успейте начать обучение в 2018-ом году со скидкой до 30%!
Выбрать курс

Какие есть проблемы у систем сборки языка C++?

С___Deep_23-5020-25b88f.08_Site.png

Проблема только одна – отсутствие каких бы то ни было стандартных систем сборки. Но нас спасут нестандартные! В данном случае великий и ужасный CMake, в котором есть две переменные с не совсем очевидными отличиями.

– CMAKE_SOURCE_DIR – путь к директории исходников (директория, в которой расположен корневой файл CMakeLists.txt, с которого началась обработка);

– CMAKE_CURRENT_SOURCE_DIR – путь к текущей директории исходников (директория, в которой расположен CMakeLists.txt, который обрабатывается в данный момент).

Какую переменную лучше использовать для относительных путей в иерархии проекта?

Предположим, мы написали ещё один велосипед (но на этот раз превзошли всех предшественников в «велосипедостроении») и реализовали свой модуль суммирования переменных типа int. Структура проекта примерно такая:

|   CMakeLists.txt
|
+---SuperProject
|       CMakeLists.txt
|       Summator.cpp
|       Summator.h
|
\---Tests
        CMakeLists.txt
        Summator_test.cpp

Если вы, как и подобает нормальному человеку, не сразу воспринимаете вывод команды tree. Поясню: в корне проекта находится файл CMakeLists.txt и две директории – SuperProject (реализация нашего велосипеда) и Tests (так сказать, юнит-тесты). Думаю, теперь стало понятно, что где лежит.

С корневым CMakeLists.txt всё очевидно: в нём только добавляем две поддиректории (если уж совсем занудствовать, то было бы неплохо добавить минимальную требуемую версию CMake в начало файла, но опустим это во имя простоты восприятия):

add_subdirectory(SuperProject)
add_subdirectory(Tests)

С файлом CMakeLists.txt из директории SuperProject тоже всё просто:

project(SuperProject)
add_library(SuperProjectLib SHARED Summator.cpp)

И, наконец, самый смак: директория Tests и её файл CMakeLists.txt:

set(SOURCES
    ${CMAKE_SOURCE_DIR}/SuperProject/Summator.cpp
    Summator_test.cpp)
include_directories(${CMAKE_SOURCE_DIR})
add_executable(Summator_test ${SOURCES} ${HEADERS})

Заметили?

Мы используем CMAKE_SOURCE_DIR, чтобы собирать исходники проекта вместе с тестами. Обычно так делается для тестирования внутренних модулей продукта (иначе можно было бы просто прилинковать уже собранную библиотеку SuperProject.so(dll)).

Вроде, всё работает, проект собирается, тесты собираются (проходят или нет в данном случае неважно), можно на этом и остановиться. Но лучше подумать её разок. А в идеале попробовать использовать наш проект так, как могли бы его использовать другие члены сообщества.

Один из возможных вариантов использования – добавить наш репозиторий в свой в качестве git submodule и где-то в своём корневом CMakeLists.txt добавить команду:

add_subdirectory(SuperProjectPackage)

Иерархия проекта нашего благодарного пользователя будет выглядеть примерно так:

\---OtherProject
    |   CMakeLists.txt
    |
    +---sources
    \---SuperProjectPackage
        |   CMakeLists.txt
        |
        +---SuperProject
        |       CMakeLists.txt
        |       Summator.cpp
        |       Summator.h
        |
        \---Tests
                CMakeLists.txt
                Summator_test.cpp

Когда дело дойдёт до сборки проекта SuperProjectPackage, а если конкретнее, то до сборки тестов в директории Tests, куда будет указывать переменная CMAKE_SOURCE_DIR ?

Правильно, указывать она будет на директорию OtherProject, потому что именно она теперь и является хранилищем корневого файла CMakeLists.txt. А наш файл CMakeLists.txt корневым быть перестал.

В итоге на этапе CMake возникнет ошибка при выполнении вот этой строчки:

${CMAKE_SOURCE_DIR}/SuperProject/Summator.cpp

Что вполне законно, ибо корневая директория проекта теперь не содержит директорию SuperProject.

Что же делать?

Если вы читали эту заметку с начала, вероятно, вы можете заподозрить, что помочь нам призвана переменная CMAKE_CURRENT_SOURCE_DIR. И данный вывод совершенно верен!

Переменная CMAKE_CURRENT_SOURCE_DIR всегда указывает на директорию с текущим файлом CMakeFiles.txt, который в настоящий момент подвергается обработке. Использование этой переменной вместо CMAKE_SOURCE_DIR убережёт пользователей ваших супер-модулей от нервных расстройств, а вам даст дополнительный повод для гордости.

Ведь что может сравниться с ощущением того, что результаты твоей работы не пылятся на жёстком диске, а приносят пользу человечеству?

Было бы неплохо привести в конце статьи правильное решение. Можно было бы, конечно, оставить его в качестве домашнего задания. Но жестокость я оставлю для учебных занятий, а правильное решение выглядит следующим образом.

Правильное решение

В файле Tests/CMakeLists.txt следовало написать:

project(Tests)

set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/../SuperProject/Summator.cpp
    Summator_test.cpp)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../.)

add_executable(Summator_test ${SOURCES} ${HEADERS})

Есть вопрос? Напишите в комментариях!

Автор
0 комментариев
Для комментирования необходимо авторизоваться