Cmake: борется с зависимостями add_custom_command
Я пытаюсь получить файл, созданный командой add_custom_command в одном каталоге, в зависимости от add_custom_command в другом каталоге.
В первом каталоге (lib/core) у меня есть команда сборки, которая выглядит так:
add_custom_command(
OUTPUT libcore.bc
COMMAND tartln -filetype=bc -link-as-library -o libcore.bc ${STDLIB_BC_FILES}
DEPENDS ${STDLIB_BC_FILES} tartln
COMMENT "Linking libcore.bc")
Во втором каталоге у меня есть команда, которая использует вывод этой команды:
add_custom_command(OUTPUT ${OBJ_FILE}
COMMAND tartln -disable-fp-elim -filetype=obj -o ${OBJ_FILE} ${BC_FILE}
"${PROJECT_BINARY_DIR}/lib/core/libcore.bc"
MAIN_DEPENDENCY "${BC_FILE}"
DEPENDS "${PROJECT_BINARY_DIR}/lib/core/libcore.bc"
COMMENT "Linking Tart bitcode file ${BC_FILE}")
Однако, когда я пытаюсь построить, я получаю следующую ошибку:
make[3]: *** No rule to make target `lib/core/libcore.bc', needed by `test/stdlib/ReflectionTest.o'. Stop.
Одна странная вещь, которую я вижу, заключается в том, что путь в сообщении об ошибке является относительным, а не абсолютным путем, несмотря на то, что я знаю, что ${PROJECT_BINARY_DIR} - полный, правильный путь. Я не знаю, является ли это проблемой или просто странностью make.
Я также попытался создать целевой уровень верхнего уровня для библиотеки libcore в каталоге lib/core:
add_custom_target(libcore DEPENDS libcore.bc libcore.deps)
И затем используя это в предложении DEPENDS. Странная вещь в том, что это работает в первый раз, когда вы делаете чистую сборку, но выдает ошибку при любой последующей сборке. В любом случае, я понимаю, что DEPENDS должен работать только для зависимостей файлов, поэтому это не похоже на правильное решение. (Как у вас есть пользовательская команда, которая зависит от целевого уровня верхнего уровня?)
Я также старался помещать абсолютные пути везде, без эффекта.
Ответы
Ответ 1
Документация cmake говорит о параметре DEPENDS:
Параметр DEPENDS указывает файлы, от которых зависит команда. Если любая зависимость - это OUTPUT другой пользовательской команды в том же каталог (файл CMakeLists.txt). CMake автоматически передает другой пользовательская команда в цель, в которой эта команда построена. Если DEPENDS указывает любую цель (созданную командой ADD_ *) a зависимость уровня цели создана, чтобы убедиться, что цель построена перед любой целью, используя эту пользовательскую команду.
Поэтому я думаю, что вам нужно будет определить цель с помощью add_custom_target и зависеть от этого.
В документации для add_custom_target говорится:
Зависимости, перечисленные с аргументом DEPENDS может ссылаться на файлы и выходы пользовательских команд, созданных с помощью add_custom_command() в том же каталоге (файл CMakeLists.txt).
Итак, вам нужно будет использовать add_custom_command и add_custom_target следующим образом:
-
В первом каталоге, создающем файл bc, вы делаете
add_custom_command(OUTPUT libcore.bc ... ) # just as in your question
add_custom_target (LibCoreBC DEPENDS libcore.bc)
-
Во втором каталоге вы
add_custom_command (OUT ${OBJ_FILE} DEPENDS LibCoreBC ....)
Ответ 2
Это не ответ, но пояснение к одному из ваших ответов выше.
В соответствии с документами cmake пользовательская цель, созданная add_custom_target
, всегда считается устаревшей и всегда построена.
IMO, документы cmake должны сказать вместо этого:
Пользовательская цель, созданная add_custom_target, всегда считается устаревшей и всегда построена, , но только при запросе.
Это означает, что если все ваши цели отмечены как EXCLUDE_FROM_ALL
, и у вас есть команды add_custom_target
, которые создают новые цели, и вы вводите make
из командной строки без заданных целей, цели, добавленные с помощью add_custom_target
не. Но если вы явно укажете их в командной строке make
, то они будут построены. Кроме того, существует ключевое слово ALL
, которое вы можете указать add_custom_target
, чтобы заставить их быть встроенными как часть всего правила, которое, как я считаю, означает, когда make
выполняется без аргументов.
Ответ 3
Я не думаю, что add_custom_target
будет работать для того, чего я хочу. Согласно документам cmake, пользовательская цель, созданная add_custom_target, всегда считается устаревшей и всегда строится.
Проблема в том, что я пытаюсь вывести результат из одного add_custom_command
и подавать его на вход другого add_custom_command
в другой каталог. Я хочу, чтобы это произошло только в том случае, если исходный исходный файл устарел - если я использовал add_custom_target
, то вывод всегда будет перестроен, даже если исходный файл не изменился. Учитывая, что есть сотни этих исходных файлов, это сделает сборку очень медленной.
Вот то, что я пытаюсь сделать: у меня есть программа, которая генерирует .bc файл (бит-код LLVM) с заданным исходным файлом. Есть много этих исходных файлов, которые создают много .bc файлов.
Вторая программа преобразует все файлы .bc в один файл .obj(объект ELF). Таким образом, шаги преобразования выглядят следующим образом:
source file -> .bc (via add_custom_command)
.bc -> .obj (via add_custom_command)
.obj -> .exe (via add_executable)
Исходные файлы исходного кода находятся в разных каталогах, потому что они являются библиотеками классов - я не хочу, чтобы каждый код для каждого класса был помещен в тот же каталог.