суббота, 21 мая 2011 г.

Организация сборки продуктов с помощью CMake

На работе мы используем CMake для сборки продуктов. При этом собираются различные конфигурации  (Release, Debug), с помощью разных компиляторов (msvc-2008, mingw-gcc-4.4.0, sparc-sunos-gcc-3.4.6, прочие компиляторы для различных устройств: iar, arm-gcc, vrxcc).

Примерная иерархия директорий со сборками выглядит так:

\---buildroot
    \---win32
        +---mingw-gcc-4.4.0
        |   +---Debug
        |   \---Release
        \---msvc-2008
            +---Debug_Dynamic
            +---Debug_Static
            +---Release_Dynamic
            \---Release_Static

Для поддержки такой иерархии написаны скрипты для автоматизации конфигурирования и сборки проекта.



Конфигурирование
При конфигурировании проекта указываем нужный Generator, CMAKE_TOOLCHAIN_FILE (если собирается под другую платформу). Если проект зависит от внешних компонент, то добавляются также параметры для поиска этих компонент: -DCMAKE_FOO_ROOT=/foo -DCMAKE_BAR_LIBRARY_DIR=/bar/lib.

Для того чтобы упростить конфигурирование проектов необходимо придерживаться определенных правил: использовать стандартные механизмы размещения заголовочных файлов, библиотек, исполняемых файлов, либо разработать свои правила.

Компиляция
Для компиляции мы используем опять же CMake, так как он позволяет собрать проект в любой конфигурации одной командой:

cmake --build win32\mingw-gcc-4.4.0\Debug

Единственное небольшое отличие при сборке msvc конфигураций, для сборки Release нужно это явно указать, так как CMake генерирует Solution в котором присутствует две конфигурации: Debug и Release, и по умолчанию всегда собирается  Debug конфигурация. Для явного указания конфигурации используется следующая команда:

cmake --build win32\msvc-2008\Release_Dynamic --config Release

Также, для того чтобы собрать какую-то цель, можно указать параметр --target:

cmake --build win32\msvc-2008\Release_Dynamic --config Release --target install

Естественно, CMake сам следит за зависимостями между целями и сам вызывает нужный native tool для выполнения цели.
Аналогичным образом, если у вас поддержка CTest, можно запускать тесты

cmake --build win32\msvc-2008\Release_Dynamic --config Release --target Experimental

Запустит тест и submit на CDash сервер.

Итого, для компиляции и выполнения различных целей у нас написан простенький скрипт на питоне, который рекурсивно обходит иерархию, находит файл  CMakeCache.txt - это признак того, что в данной директории сконфигурирована сборка - и запускает процесс сборки через CMake. Также, необходимо заметить, что если native tool не поддерживает задание конфигурации (например, MinGW MakeFiles), то этот параметр просто игнорируется.

7 комментариев:

  1. Приветствую, Алексей!
    Вот, решил попробовать CMake под виндой.
    Может, подскажете...
    Файл CMakeLists.txt находится в каталоге buildcat.
    При вызове CMake прямо в этом каталоге все пучком.
    Ежели вызов производится извне командой
    cmake --build buildcat вываливается ошибка
    Error: could not load cache

    Есть идеи?

    ОтветитьУдалить
    Ответы
    1. А где находится директория сборки? Вы натравливаете CMake на директорию с CMakeLists.txt - это неверно. Если у вас сборочная директория находится в той же директории, то так делать не надо. Попробуйте так:

      mkdir build
      cd build
      cmake ../
      cd ..
      cmake --build build


      Таким образом, вы сделаете себе сборочную директорию и в ней будете собирать

      Удалить
  2. Спасибо!
    На самом деле проблема была в том, что я, как нуб, не сделал сперва cmake, а сразу начал cmake --build.
    Тем не менее, идея с разграничением файлов сборки и исходников, конечно же, правильная.

    Вот что еще меня приводит в тупик при использовании компилятора MSVC2010...
    Сборка проходит на ура как Release, так и Debug. Однако, в Release почему-то не прилинковывается ресурс картинки, в то время, как в Debug все отлично.
    Я что-то не нахожу логики в этом. В CMakeLists.txt нигде нет никакого разделения для этих конфигураций...

    Можете что-нибудь посоветовать?

    ОтветитьУдалить
    Ответы
    1. А как вы разделяете Release и Debug? Выбираете в одном solution разные конфигурации?

      Я предпочитаю делать две сборочных директории, одну для релиза, другую для дебага:

      mkdir build_dbg
      cd build_dbg
      cmake ../
      cd ../
      cmake --build build_dbg --config Debug

      mkdir build_rel
      cd build_rel
      cmake ../
      cd ../
      cmake --build build_rel --config Release


      Соответственно, в каждом из сгенерированных solution я выбираю соответствующую конфигурацию. Это конечно, немного неудобно, но у меня возникали некоторые проблемы, когда я собирал Release и Debug из одного solution

      Удалить
  3. Да, это хорошее правило!
    Но тут дело немного в другом, Алексей.
    Проблема в том, что так или иначе - но почему-то в релизе не отображается ресурс-картинка, которая есть в дебаге.
    Именно эту проблему я не могу решить. И она не решается разделением каталогов.
    Тут какая-та тонкость, которая, видимо, очень уж тонкая )))
    Ведь CMake генерит для релиза/дебага общий файл сборки.
    Кроме того, ресурс-локализация (.qm) почему-то прилинковывается, а ресурс-картинка - нет.

    ОтветитьУдалить
  4. Попробуйте создать простой проект, и в нем проверить указанную особенность (и приложить сам проект). У меня под рукой сейчас нет msvc2010, поэтому я проверить не смогу, но могу посмотреть ваш пример

    ОтветитьУдалить
  5. Вот такой простенький проект.
    git clone https://frostyland@code.google.com/p/test-cmake-qt/
    Форма, а на ней картинка с кнопкой.
    Так вот в дебаге картинка присутствует, а в релизе - нет.
    Причем, в ресурсном файле не только картинка, но и языковой файлос.
    Так вот файлос приаттачивается в обоих конфигурациях, что характерно.

    ОтветитьУдалить