Как собирать исходные файлы с помощью CMake без сбоев?

В документации CMake прямо говорится, что file(GLOB ...) Не рекомендуется собирать исходные файлы для сборки, но в нем не упоминается, что на самом деле является рекомендуемым методом.

Указание каждого исходного файла вручную звучит слишком вручную для меня. Итак, что является правильным методом для сбора исходных файлов, если нетfile(GLOB ...)?

5 ответов

Решение

Руководство действительно рекомендуемый метод. Рекомендация против использования GLOB, документация просто предупреждает против системы сборки, которая зависит от присутствующих файлов. Например, вы хотите добавить тестовый исполняемый файл, поэтому вы создаете mytest.cpp. К сожалению. Теперь ваша библиотека компилируется. Документация для AUX_SOURCE_DIRECTORY (аналогично назначению для файлов исходного кода) выдает следующее предупреждение:

Соблазнительно использовать эту команду, чтобы избежать записи списка исходных файлов для библиотеки или исполняемой цели. Хотя это, кажется, работает, CMake не может сгенерировать систему сборки, которая знает, когда был добавлен новый исходный файл. Обычно сгенерированная система сборки знает, когда нужно перезапустить CMake, потому что файл CMakeLists.txt изменен для добавления нового источника. Когда источник просто добавляется в каталог без изменения этого файла, необходимо вручную перезапустить CMake, чтобы сгенерировать систему сборки, включающую новый файл.

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

Кроме того, не забывайте, что перечисление файлов вручную не должно включать ввод всех имен файлов. Вы могли бы сделать, например, ls *.cpp >> CMakeLists.txt, затем с помощью редактора переместите список файлов в нужное место в файле.

Я использую GLOB именно для этого, и каждый раз, когда я добавляю файл, я запускаю

touch ../src/CMakeLists.txt

Следующий make Команда повторно проверит каталоги.

"CMake не может сгенерировать систему сборки, которая знает, когда был добавлен новый исходный файл". Ладно, так и скажи!

Это не на 100% автоматически, но чертовски просто, чем добавлять файлы вручную.

Я использую Cog, модуль Python. Вот пример для сбора файла.cpp:

CMakeLists.txt:

set(SRC_FILES "")

# [[[cog
#    import cog, glob
#    for src in glob.glob('*.cpp'):
#       if "skeleton" in src: continue
#       cog.outl("SET(SRC_FILES ${SRC_FILES} %s)" % src)
# ]]]
# [[[end]]]

add_library(mylib STATIC  ${SRC_FILES})

А затем запустите:

python -m cogapp -r CMakeLists.txt

Файл CMakeLists.txt будет обновлен на месте.

Чтобы узнать, как установить Cog и другое использование, пожалуйста, прочитайте статью от автора.

Я использую обычный CMakeLists.txt и скрипт Python для его обновления. Я запускаю скрипт python вручную после добавления файлов.

import os
import re       

def relFiles(base, sub):
    fullSub = os.path.join(base,sub)
    abs = [os.path.join(dp, f) for dp, dn, fn in os.walk(fullSub) for f in fn]
    return [os.path.relpath(f, base) for f in abs]

def updateAddLibrary(cmakelistsDir, subs):
    cmakelists = os.path.join(cmakelistsDir, "CMakeLists.txt")
    listings = [relFiles(cmakelistsDir, sub) for sub in subs]
    files = [f for listing in listings for f in listing] #flatten
    with open(cmakelists, 'r') as file:
        text = file.read()
    sources = "".join(["    %s\n" % f.replace('\\', '/') for f in files])
    text = re.sub(r"add_library\s*\(\s*([^\s\)]+).*?\)",
           r"add_library(\1\n%s)" % sources, 
           text, 1, re.DOTALL)
    with open(cmakelists, "w") as file:
        file.write(text)

dir = os.path.dirname(os.path.abspath(__file__))
updateAddLibrary(dir, ['inc','src'])

Пример перед:

...
add_library(MyLib
    inc/a.h
) 
...

после:

...
add_library(MyLib
    inc/a.h
    inc/sub/b.h
    src/a.cpp
)        
...

После ответа douyw спасибо за ваш ответ.

Не эксперт по Cmake, не хочу им быть, я потратил чертовски 3 часа, пытаясь разобраться с GLOB(отключено) и aux_source_directory (даже близко не к GLOB), и спас свою жизнь.

Я добавляю рекурсивную прогулку по файлу, и она работает в моем проекте:

Во-первых, установите модуль python cogapp (python -m pip install cogapp)

      set(SRC_FILES "")

# [[[cog
#   import cog, os
#   for root, _, files in os.walk(".", topdown=False):
#       for f in files: 
#           if not "_unittest" in f: continue
#           if not f.endswith(".cpp"): continue
#           cog.outl('SET(SRC_FILES ${SRC_FILES} "%s")' % os.path.join(root, f).replace('\\', '/'))
# ]]]
# [[[end]]]

выполнить: python -m cogapp -r CMakeLists.txt

  • Верхние строки добавляют все "*_unittest.cpp" в список
  • Вы можете изменить средние строки, чтобы создать собственное правило, просто питон. Использование регулярных выражений лучше, но простой поиск строки может помочь в описанной выше ситуации.
  • Обратите внимание на последнюю строку, в ней нужно заменить //, чтобы перейти к используемому универсальному разделителю. Вы можете создать свой CMakeList.txt в Windows.
  • Вы можете заменить SRC_FILES на что угодно.
  • Команда python может быть запущена в Jenkins/TeamCity, инициирована коммитом svn/git. Затем мы можем автоматически добавлять новые файлы.
Другие вопросы по тегам