С cmake, как бы вы отключили сборку в исходном коде?
Я хочу запретить людям загромождать наше исходное дерево созданными файлами CMake... и, что более важно, запретить им наступать на существующие Makefiles
которые не являются частью того же процесса сборки, для которого мы используем CMake. (лучше не спрашивать)
То, как я придумал, чтобы сделать это, чтобы несколько строк в верхней части моего CMakeLists.txt
, следующее:
if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")
message(SEND_ERROR "In-source builds are not allowed.")
endif("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")
Однако делать это таким образом кажется слишком многословным. Кроме того, если я попробую сборку в исходном коде, она все равно создаст CMakeFiles/
каталог, а CMakeCache.txt
файл в дереве исходных текстов до появления ошибки.
Я пропускаю лучший способ сделать это?
7 ответов
Я думаю, что мне нравится твой путь. Список рассылки cmake отлично справляется с ответами на подобные вопросы.
В качестве примечания: вы можете создать исполняемый файл "cmake" в каталоге, который не работает. В зависимости от того, "или нет". находится на их пути (на Linux). Вы можете даже символическую ссылку /bin/false.
В Windows я не уверен, что файл в вашем текущем каталоге найден первым или нет.
CMake имеет две недокументированные опции:CMAKE_DISABLE_SOURCE_CHANGES
а также CMAKE_DISABLE_IN_SOURCE_BUILD
cmake_minimum_required (VERSION 2.8)
# add this options before PROJECT keyword
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
project (HELLO)
add_executable (hello hello.cxx)
-
andrew@manchester:~/src% cmake .
CMake Error at /usr/local/share/cmake-2.8/Modules/CMakeDetermineSystem.cmake:160 (FILE):
file attempted to write a file: /home/andrew/src/CMakeFiles/CMakeOutput.log
into a source directory.
/home/selivanov/cmake-2.8.8/Source/cmMakefile.cxx
bool cmMakefile::CanIWriteThisFile(const char* fileName)
{
if ( !this->IsOn("CMAKE_DISABLE_SOURCE_CHANGES") )
{
return true;
}
// If we are doing an in-source build, than the test will always fail
if ( cmSystemTools::SameFile(this->GetHomeDirectory(),
this->GetHomeOutputDirectory()) )
{
if ( this->IsOn("CMAKE_DISABLE_IN_SOURCE_BUILD") )
{
return false;
}
return true;
}
// Check if this is subdirectory of the source tree but not a
// subdirectory of a build tree
if ( cmSystemTools::IsSubDirectory(fileName,
this->GetHomeDirectory()) &&
!cmSystemTools::IsSubDirectory(fileName,
this->GetHomeOutputDirectory()) )
{
return false;
}
return true;
}
Включите функцию, подобную этой. Это похоже на то, что вы делаете с этими различиями:
Он инкапсулирован в функцию, которая вызывается при включении
PreventInSourceBuilds.cmake
модуль. Ваш основной CMakeLists.txt должен включать его:set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake) include(PreventInSourceBuilds)
Он использует get_filename_component() с параметром REALPATH, который разрешает символические ссылки перед сравнением путей.
В случае изменения ссылки на GitHub, вот исходный код модуля (который должен быть помещен в PreventInSouceBuilds.cmake
в каталоге под названием CMake
в приведенном выше примере):
#
# This function will prevent in-source builds
function(AssureOutOfSourceBuilds)
# make sure the user doesn't play dirty with symlinks
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
# disallow in-source builds
if("${srcdir}" STREQUAL "${bindir}")
message("######################################################")
message("# ITK should not be configured & built in the ITK source directory")
message("# You must run cmake in a build directory.")
message("# For example:")
message("# mkdir ITK-Sandbox ; cd ITK-sandbox")
message("# git clone http://itk.org/ITK.git # or download & unpack the source tarball")
message("# mkdir ITK-build")
message("# this will create the following directory structure")
message("#")
message("# ITK-Sandbox")
message("# +--ITK")
message("# +--ITK-build")
message("#")
message("# Then you can proceed to configure and build")
message("# by using the following commands")
message("#")
message("# cd ITK-build")
message("# cmake ../ITK # or ccmake, or cmake-gui ")
message("# make")
message("#")
message("# NOTE: Given that you already tried to make an in-source build")
message("# CMake have already created several files & directories")
message("# in your source tree. run 'git status' to find them and")
message("# remove them by doing:")
message("#")
message("# cd ITK-Sandbox/ITK")
message("# git clean -n -d")
message("# git clean -f -d")
message("# git checkout --")
message("#")
message("######################################################")
message(FATAL_ERROR "Quitting configuration")
endif()
endfunction()
AssureOutOfSourceBuilds()
У меня есть cmake()
функция оболочки в моем .bashrc
/.zshrc
похож на этот:
function cmake() {
# Don't invoke cmake from the top-of-tree
if [ -e "CMakeLists.txt" ]
then
echo "CMakeLists.txt file present, cowardly refusing to invoke cmake..."
else
/usr/bin/cmake $*
fi
}
Я предпочитаю это низкое церемониальное решение. Он избавился от самой большой жалобы моих коллег, когда мы перешли на CMake, но это не мешает людям, которые действительно хотят сделать сборку in-source/top-of-tree, - они могут просто вызвать /usr/bin/cmake
напрямую (или вообще не использовать функцию обертки). И это глупо просто.
Вы можете настроить свой файл.bashrc следующим образом
Посмотрите на функции cmakekde и kdebuild. Установите BUILD и SRC env. переменные и редактируйте эти функции в соответствии с вашими потребностями. Это будет построено только в buildDir, а не в srcDir
Для тех, кто в Linux:
добавить к CMakeLists.txt верхнего уровня:
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
создайте файл 'dotme' на вашем верхнем уровне или добавьте в ваш.bashrc (глобально):
#!/bin/bash
cmk() { if [ ! -e $1/CMakeLists.txt ] || ! grep -q "set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)" $1/CMakeLists.txt;then /usr/bin/cmake $*;else echo "CMAKE_DISABLE_IN_SOURCE_BUILD ON";fi }
alias cmake=cmk
Теперь запустите:
. ./dotme
когда вы пытаетесь запустить cmake в дереве исходного кода верхнего уровня:
$ cmake .
CMAKE_DISABLE_IN_SOURCE_BUILD ON
CMakeFiles/ или CMakeCache.txt не генерируется.
Когда вы выполняете сборку вне исходного кода и вам нужно запустить cmake в первый раз, просто вызовите реальный исполняемый файл:
$ cd build
$ /usr/bin/cmake ..
Это по-прежнему лучший ответ для моих целей:
project(myproject)
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
message(FATAL_ERROR "In-source builds are not allowed")
endif()
или разрешите сборку, но покажите предупреждающее сообщение:
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
message(WARNING "In-source builds are not recommended")
endif()
Однако не существует простого способа избежать CMakeFiles/
а также CMakeCache.txt
создается в исходном каталоге.
Просто сделайте каталог доступным только для чтения людьми / процессами, выполняющими сборку. У вас есть отдельный процесс, который проверяет каталог из системы контроля версий (вы используете систему контроля версий, верно?), А затем делает ее доступной только для чтения.