Каталог вывода / сборки CMake

116

Я новичок в CMake, прочитал несколько руководств о том, как его использовать, и написал несколько сложных 50 строк сценария CMake, чтобы создать программу для трех разных компиляторов. На этом, наверное, заканчиваются все мои познания в CMake.

Теперь моя проблема в том, что у меня есть исходный код, папку с которым я не хочу трогать / возиться, когда создаю программу. Я хочу, чтобы все makeфайлы и папки CMake, а также выходные файлы и папки входили в него ../Compile/, поэтому я изменил для этого несколько переменных в моем сценарии CMake, и когда-то это работало, когда я делал что-то подобное на своем ноутбуке:

Compile$ cmake ../src
Compile$ make

Где с этим у меня был чистый вывод в папке, в которой я сейчас нахожусь, и это именно то, что я ищу.

Теперь я перешел на другой компьютер и перекомпилировал CMake 2.8.11.2, и я почти вернулся к исходной точке! Он всегда компилирует вещь в srcпапку, где CMakeLists.txtнаходится my .

Часть, где я выбираю каталог в моем сценарии CMake, такова:

set(dir ${CMAKE_CURRENT_SOURCE_DIR}/../Compile/)
set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dir})
set(CMAKE_BUILD_FILES_DIRECTORY ${dir})
set(CMAKE_BUILD_DIRECTORY ${dir})
set(CMAKE_BINARY_DIR  ${dir})
SET(EXECUTABLE_OUTPUT_PATH ${dir})
SET(LIBRARY_OUTPUT_PATH ${dir}lib)
SET(CMAKE_CACHEFILE_DIR ${dir})

А теперь всегда заканчивается:

-- Build files have been written to: /.../src

Я что-то упускаю?

Квантовый физик
источник
4
Нет необходимости устанавливать все переменные, которые вы устанавливаете. CMake устанавливает для них разумные значения по умолчанию. Вам определенно не следует изменять CMAKE_BINARY_DIRили CMAKE_CACHEFILE_DIR. Что произойдет, если вы удалите все эти set()вызовы и просто сделаете это cd Compile; rm -rf *; cmake ../src?
Энгью больше не гордится SO
5
По сути, пока вы находитесь за пределами исходного каталога при запуске CMake, он не будет изменять исходный каталог, если ваш CMakeList явно не сообщает об этом.
Энгью больше не гордится SO
@Angew Спасибо за подсказку, что удивительно! Я удалил все эти строки и просто использовал cmake ../src, и это сработало отлично! Это так удивительно, потому что я пробовал это раньше, когда впервые изучал CMake, и это не сработало. Пожалуйста, поместите свой ответ в официальный ответ, чтобы поставить вам большую жирную галочку :)
The Quantum Physicist
1
Меня спасло замечание @Adam Bowen о том, что «вы не можете создать сборку вне исходного кода для исходного каталога с помощью сборки из исходного кода»
Аур Сараф

Ответы:

60

Нет необходимости устанавливать все переменные, которые вы устанавливаете. CMake устанавливает для них разумные значения по умолчанию. Вам определенно не следует изменять CMAKE_BINARY_DIRили CMAKE_CACHEFILE_DIR. Считайте их доступными только для чтения.

Сначала удалите существующий проблемный файл кеша из каталога src:

cd src
rm CMakeCache.txt
cd ..

Затем удалите все set()команды и выполните:

cd Compile
rm -rf *
cmake ../src

Пока вы находитесь за пределами исходного каталога при запуске CMake, он не будет изменять исходный каталог, если ваш CMakeList явно не сообщает об этом.

После того, как вы все заработаете, вы можете посмотреть, куда CMake помещает вещи по умолчанию, и только если вас не устраивают местоположения по умолчанию (например, значение по умолчанию EXECUTABLE_OUTPUT_PATH), изменяйте только те, которые вам нужны. И попытаться выразить их относительно CMAKE_BINARY_DIR, CMAKE_CURRENT_BINARY_DIR, и PROJECT_BINARY_DIRт.д.

Если вы посмотрите документацию CMake, вы увидите переменные, разделенные на семантические секции. За исключением очень особых обстоятельств, вы должны относиться ко всем перечисленным в разделе «Переменные , которые предоставляют информацию» только для чтения внутри CMakeLists.

Энгью больше не гордится SO
источник
2
Я начал использовать cmake со сборками в каталоге src ... изначально этот метод не удался. Как только я удалил все файлы / кеши сборки cmake в каталоге src, этот метод сработал. Спасибо!
Ави Тевет
18
Может лучше не советовать пользоваться rm -rf *. Неприятно, если cd Compileне
Роман
2
@Roman Я считаю такие примеры командной строки в значительной степени псевдокодом. Это менее многословно и более точно, чем набирать «войдите в каталог Compile, удалите все там, а затем запустите CMake с путем к исходному каталогу». Я исхожу из здравого смысла и суждения со стороны читателя.
Энгью больше не гордится SO
@AviTevet: Думаю, это правильный ответ. Если внутри исходного каталога есть файлы кеша cmake из предыдущего вызова cmake, вы не получите cmake для выбора другого каталога для сгенерированных файлов, если вы не удалите все старые из исходного каталога. На мой взгляд, довольно некорректное поведение CMake. Почему бы тебе не написать еще один ответ?
Джо Со
113

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

  1. Делай то, что делал, беги

    cd /path/to/my/build/folder
    cmake /path/to/my/source/folder

    что приведет к CMake для создания сборки дерева в /path/to/my/build/folderдля дерева исходных текстов в /path/to/my/source/folder.

    После того, как вы создали его, cmake запоминает, где находится исходная папка, поэтому вы можете повторно запустить cmake в дереве сборки с помощью

    cmake /path/to/my/build/folder

    или даже

    cmake .

    если ваш текущий каталог уже является папкой сборки.

  2. Для CMake 3.13 или более поздней версии используйте эти параметры для установки папок источника и сборки.

    cmake -B/path/to/my/build/folder -S/path/to/my/source/folder
  3. Для более старых версий CMake используйте некоторые недокументированные параметры для установки папок источника и сборки :

    cmake -B/path/to/my/build/folder -H/path/to/my/source/folder

    который будет делать то же самое, что и (1), но без зависимости от текущего рабочего каталога.

CMake помещает все свои выходные данные в дерево сборки по умолчанию, поэтому, если вы не используете ${CMAKE_SOURCE_DIR}или ${CMAKE_CURRENT_SOURCE_DIR}в своих файлах cmake, он не должен касаться вашего исходного дерева .

Самое большое, что может пойти не так, - это если вы ранее сгенерировали дерево сборки в своем дереве исходных кодов (т.е. у вас есть сборка в исходном коде ). Как только вы это сделаете, сработает вторая часть (1) выше, и cmake не вносит никаких изменений в исходный код или места сборки. Таким образом, вы не можете создать сборку вне исходного кода для исходного каталога с помощью сборки из исходного кода . Вы можете довольно легко исправить это, удалив (как минимум) CMakeCache.txtиз исходного каталога. CMakeFilesCMake генерирует еще несколько файлов (в основном в каталоге), которые вы также должны удалить, но они не заставят cmake рассматривать исходное дерево как дерево сборки.

Поскольку сборки из исходных кодов часто более желательны, чем сборки из исходных кодов, вы можете изменить свой cmake, чтобы требовать сборки из исходных кодов:

# Ensures that we do an out of source build

MACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD MSG)
     STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
     "${CMAKE_BINARY_DIR}" insource)
     GET_FILENAME_COMPONENT(PARENTDIR ${CMAKE_SOURCE_DIR} PATH)
     STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
     "${PARENTDIR}" insourcesubdir)
    IF(insource OR insourcesubdir)
        MESSAGE(FATAL_ERROR "${MSG}")
    ENDIF(insource OR insourcesubdir)
ENDMACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD)

MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
    "${CMAKE_PROJECT_NAME} requires an out of source build."
)

Вышеупомянутый макрос исходит из часто используемого модуля с именем MacroOutOfSourceBuild. В MacroOutOfSourceBuild.cmakeGoogle есть множество источников, но я не могу найти оригинал, и он достаточно короткий, чтобы включить его здесь полностью.

К сожалению, cmake обычно записывает несколько файлов к моменту вызова макроса, поэтому, хотя это помешает вам выполнить сборку, вам все равно придется удалить CMakeCache.txtи CMakeFiles.

Возможно, вам будет полезно установить пути, по которым записываются двоичные файлы, общие и статические библиотеки - и в этом случае посмотрите, как мне сделать вывод cmake в каталог bin? (отказ от ответственности, у меня есть лучший ответ на этот вопрос ... но вот откуда я об этом знаю).

Адам Боуэн
источник
На самом деле возможности установить исходную папку -Sнет-H
smac89
@ smac89 Спасибо! Похоже, они задокументировали их в версии 3.13 - я обновил ответ, чтобы отразить современный CMake.
Адам Боуэн
8

Превращаю мой комментарий в ответ:

На случай, если кто-то сделал то, что сделал я, для начала поместил все файлы сборки в исходный каталог:

cd src
cmake .

CMake поставит кучу файлов сборки и кэш - файлы ( CMakeCache.txt, CMakeFiles, cmake_install.cmakeи т.д.) в srcреж.

Чтобы перейти на сборку вне исходного кода, мне пришлось удалить все эти файлы. Тогда я мог бы сделать то, что @Angew рекомендовал в своем ответе:

mkdir -p src/build
cd src/build
cmake ..
Ави Тевет
источник
7

По данным CMake Wiki :

CMAKE_BINARY_DIR, если вы строите в исходном коде, это то же самое, что CMAKE_SOURCE_DIR, в противном случае это каталог верхнего уровня вашего дерева сборки

Сравните эти две переменные, чтобы определить, была ли запущена сборка вне исходного кода.

damkrat
источник
6

Вы не должны полагаться на жестко запрограммированное имя каталога сборки в своем скрипте, поэтому ../Compileнеобходимо изменить строку с .

Это потому, что пользователь должен решать, где компилировать.

Вместо этого используйте одну из предопределенных переменных: http://www.cmake.org/Wiki/CMake_Useful_Variables (ищите CMAKE_BINARY_DIRи CMAKE_CURRENT_BINARY_DIR)

Михал Валенчак
источник
2
это как раз то, что я искал - CMAKE_CURRENT_BINARY_DIRобычно рассказывал о текущем пути сборки двоичного файла . Возможно, может использоваться для настройки зависимых сборок libs / bin.
parasrish