2017-01-23 3 views
0

У меня есть проект C++ cmake. В этом проекте я строил (среди прочего) один пример, где мне нужно использовать другой проект, назовите его Foo. Этот проект Foo не предлагает систему сборки cmake. Вместо этого у него есть готовый Makefile.custom.in. Чтобы создать исполняемый файл, который использует функции Foo, нужно скопировать этот make-файл в свой проект и изменить его (как правило, установить переменную SOURCES и несколько флагов компилятора). В основном, этот Makefile заканчивается тем, что есть источники для вашего исполняемого файла, а также все исходные файлы для проекта Foo. Вы не будете использовать Foo в качестве библиотеки.CMake: компиляция скорость при включении внешнего makefile

Теперь это дизайн, который мне не нравится, но, ради вопроса, допустим, мы придерживаемся его.

Чтобы создать свой пример в моей Cmake сборки я добавил пользовательские цели:

CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Makefile.custom.in Makefile.custom) 

ADD_CUSTOM_TARGET(my_target COMMAND $(MAKE) -f Makefile.custom 
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 

Это работает. Я могу указать некоторые переменные cmake, которые будут устранены при вызове CONFIGURE_FILE, и я получаю рабочий файл Makefile.custom. Затем, вызывая make my_target из каталога сборки, я могу создать исполняемый файл. Я даже могу добавить его к all целям (чтобы спасти меня усилие набрав make my_target) с

SET_TARGET_PROPERTIES(my_target PROPERTIES EXCLUDE_FROM_ALL FALSE) 

сладкими. Однако cmake, как представляется, назначает одно задание настраиваемой цели, замедляя мое время компиляции (исходная папка Foo содержит несколько десятков файлов cpp). Кроме того, цель make clean не пересылает пользовательский make-файл. Я в конечном итоге, чтобы добавить другую цель:

ADD_CUSTOM_TARGET(really-clean COMMAND "$(MAKE)" clean 
        COMMAND "$(MAKE)" -f Makefile.custom clean 
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 

, который, в отличие от my_target с all, я не могу включить в clean мишени (можно?).

Теперь я знаю, что более чистое решение будет заключаться в том, чтобы проект Foo был построен как внешний проект, а затем ссылался на него. Тем не менее, мне «рекомендуется» использовать Makefile.custom.in makefile, изменяя несколько строк, которые мне нужны (добавление моих источников, указание флагов компилятора и несколько других незначительных изменений). Таким образом, независимо от того, насколько аккуратно и очистить этот шаблон дизайна есть, мои вопросы:

  • есть способ сказать CMake, что делать следует использовать более 1 задание при создании целевого my_target?
  • есть ли более чистый способ включить ранее существующий makefile в проект cmake? Заметьте, что я не хочу (не могу?) Использовать Foo как библиотеку (и ссылку против нее). Я хочу (нужно?) Скомпилировать его вместе с моим исполняемым файлом, используя make-файл, не сгенерированный cmake (ну, cmake может помочь бит, через CONFIGURE_FILE, путем решения некоторых переменных, но это все).

Примечание: Я знаю ExternalProject (как это было предложено также в this ответ), но я думаю, что это не совсем то, что мне нужно здесь (так как он будет строить Foo, а затем использовать его в качестве библиотеки). Кроме того, оба моих проекта и Foo написаны исключительно на C++ (совсем не уверен в этом).

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

Edit: Я использую CMake версии 3.5.2

+0

Если время сборки имеет значение, подумайте о переключении на ниндзя. Это тоже поможет в вашем случае. – usr1234567

+0

Я думал о ниндзя. Я не использовал его, потому что в какой-то момент я могу или не могу включить какой-либо код fortran, и насколько я понимаю, генератор ниндзя cmake еще не поддерживает fortran (но я признаю, что я не проверял наличие обновлений через некоторое время) , – bartgol

+0

какая версия CMake вы используете? – fedepad

ответ

1

Первый, так как вы определяете свою собственную цель, вы можете назначить больше ядер в процессе сборки для целевого my_target, непосредственно внутри CMakeLists.txt.
Вы можете включить модуль Cmake ProcessCount, чтобы определить количество ядер на вашем компьютере, а затем использовать его для параллельной сборки.

include(ProcessorCount) 
ProcessorCount(N) 
if(NOT N EQUAL 0) 
    # given that cores != 0 you could modify 
    # math(EXPR N "${N}+1") # modify (increment/decrement) N at your will, in this case, just incrementing N by one 
    set(JOBS_IN_PARALLEL -j${N}) 
endif(NOT N EQUAL 0) 

и когда вы определяете собственную цель иметь что-то вроде следующего:

ADD_CUSTOM_TARGET(my_target 
        COMMAND ${CMAKE_MAKE_PROGRAM} ${JOBS_IN_PARALLEL} -f Makefile.custom 
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 

, кстати, я не думаю, что есть необходимость для вас, чтобы включить также CMAKE_BUILD_TOOL среди COMMAND с в вашей цели.
Я считаю, что вместо того, чтобы модифицировать строки, как указано выше, можно было бы назвать

make -j8 my_target 

и он может начать 8 рабочих мест (просто пример), не изменяя CMakeLists.txt, но я не могу гарантировать, что это работает, определив COMMAND в у вас есть, просто попробуйте, если этого достаточно.
Во-вторых, я не могу сейчас думать о «чистом» способе.

+0

Спасибо! Вы имеете в виду, что я должен написать 'make' непосредственно вместо использования '$ {CMAKE_MAKE_PROGRAM}'? Я думал, что использование переменной cmake делает систему сборки немного более портативной, нет? – bartgol

+0

Это две разные вещи. '$ {CMAKE_MAKE_PROGRAM}' используется внутри 'CMakeLists.txt', и вы должны сохранить его таким образом. Команда 'make my_target', которую вы используете в командной строке, запускает сборку настраиваемой цели. – fedepad

Смежные вопросы