Решение, которое я недавно нашел, состоит в том, чтобы объединить концепцию сборки вне источника с оболочкой Makefile.
В моем файле CMakeLists.txt верхнего уровня я включаю следующее, чтобы предотвратить вход в исходный кодbuilds:
if ( ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR} )
message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt." )
endif()
Затем я создаю Makefile верхнего уровня и включаю следующее:
# -----------------------------------------------------------------------------
# CMake project wrapper Makefile ----------------------------------------------
# -----------------------------------------------------------------------------
SHELL := /bin/bash
RM := rm -rf
MKDIR := mkdir -p
all: ./build/Makefile
@ $(MAKE) -C build
./build/Makefile:
@ ($(MKDIR) build > /dev/null)
@ (cd build > /dev/null 2>&1 && cmake ..)
distclean:
@ ($(MKDIR) build > /dev/null)
@ (cd build > /dev/null 2>&1 && cmake .. > /dev/null 2>&1)
@- $(MAKE) --silent -C build clean || true
@- $(RM) ./build/Makefile
@- $(RM) ./build/src
@- $(RM) ./build/test
@- $(RM) ./build/CMake*
@- $(RM) ./build/cmake.*
@- $(RM) ./build/*.cmake
@- $(RM) ./build/*.txt
ifeq ($(findstring distclean,$(MAKECMDGOALS)),)
$(MAKECMDGOALS): ./build/Makefile
@ $(MAKE) -C build $(MAKECMDGOALS)
endif
Цель по умолчанию all
вызывается путем ввода make
, ивызывает цель ./build/Makefile
.
Первое, что делает цель ./build/Makefile
, это создает каталог build
, используя $(MKDIR)
, который является переменной для mkdir -p
.В каталоге build
мы будем выполнять сборку вне исходного кода.Мы предоставляем аргумент -p
, чтобы гарантировать, что mkdir
не будет кричать на нас за попытку создать каталог, который может уже существовать.
Второе, что делает цель ./build/Makefile
, это изменение каталогов наКаталог build
и вызов cmake
.
Возвращаясь к цели all
, мы вызываем $(MAKE) -C build
, где $(MAKE)
- переменная Makefile, автоматически сгенерированная для make
.make -C
меняет каталог, прежде чем что-либо делать.Следовательно, использование $(MAKE) -C build
эквивалентно cd build; make
.
Подводя итог, вызов этой оболочки Makefile с make all
или make
равносилен выполнению:
mkdir build
cd build
cmake ..
make
target distclean
вызывает cmake ..
, затем make -C build clean
и, наконец, удаляет все содержимое из каталога build
.Я считаю, что это именно то, что вы просили в своем вопросе.
Последний фрагмент Makefile оценивает, является ли предоставленная пользователем цель distclean
или нет.Если нет, он изменит каталоги на build
перед вызовом.Это очень мощно, потому что пользователь может напечатать, например, make clean
, и Makefile преобразует его в эквивалент cd build; make clean
.
В заключение, эта оболочка Makefile в сочетании с обязательным out-of-source build Конфигурация CMake, сделайте так, чтобы пользователю никогда не приходилось взаимодействовать с командой cmake
.Это решение также предоставляет элегантный метод удаления всех выходных файлов CMake из каталога build
.
PS В Makefile мы используем префикс @
для подавления вывода команды оболочки и префикс@-
чтобы игнорировать ошибки команды оболочки.При использовании rm
в качестве части цели distclean
команда вернет ошибку, если файлы не существуют (возможно, они уже были удалены с помощью командной строки с rm -rf build
, или они никогда не создавались в первомместо).Эта ошибка возврата заставит наш Makefile выйти.Мы используем префикс @-
, чтобы предотвратить это.Это приемлемо, если файл уже был удален;мы хотим, чтобы наш Makefile продолжал работать и удалял все остальное.
Еще одна вещь, на которую следует обратить внимание: этот Makefile может не работать, если вы используете переменное число переменных CMake для построения вашего проекта, например, cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"
.Этот Makefile предполагает, что вы вызываете CMake непротиворечивым способом, набирая cmake ..
или предоставляя cmake
постоянное количество аргументов (которые вы можете включить в ваш Makefile).
Наконец, кредит, где кредитв связи.Эта оболочка Makefile была адаптирована из Makefile, предоставленного шаблоном проекта приложения C ++ .