Как собрать исходные файлы с CMake без globbing?

Документация CMake явно заявляет, что file(GLOB ...) не является рекомендуется собирать исходные файлы для сборки, но это не укажите, какой именно рекомендуемый метод на самом деле.

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

Ответ 1

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

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

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

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

Ответ 2

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

touch ../src/CMakeLists.txt

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

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

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

Ответ 3

Я использую 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 и другое использование, прочитайте статью автора.

Ответ 4

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

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
)        
...