C'est peut-être impossible et je lis mal la documentation cmake 3.2 , mais je pensais que la création d'une commande personnalisée créerait une "cible" personnalisée dans le Makefile afin que je puisse construire la cible en invoquant le nom de le fichier de sortie. Les documents CMake disent:
En termes de makefile, cela crée une nouvelle cible sous la forme suivante:
OUTPUT: MAIN_DEPENDENCY DEPENDS COMMAND
donc j'ai pensé que je pourrais alors exécuter make OUTPUT
. Peut-être que la documentation confond les cibles CMake avec les cibles Makefile?
Par exemple,
add_custom_command(OUTPUT foo_out
COMMAND post_process foo_in > foo_out
DEPENDS foo_in
)
Je voudrais faire
make foo_out
et cela fera foo_out
. Cependant, si je fais cela, je reçois
make: **** No rule to make target `foo_out`. Stop.
et bien sûr, le mot "foo_out" n'existe nulle part dans aucun fichier du répertoire de sortie binaire de cmake. Si je le change en ceci
add_custom_target(bar DEPENDS foo_out)
add_custom_command(OUTPUT foo_out COMMAND post_process foo_in > foo_out)
Alors je peux faire
make bar
et je peux faire
make foo_in
mais je ne peux toujours pas faire
make foo_out
Le problème avec make bar
est qu'il n'est pas intuitif, car la sortie réelle du fichier est foo_out
pas bar
.
Comment puis-je faire cela?
Dans mon cas, je dois exécuter une étape de traitement spéciale vers la cible exécutable standard qui insère des ressources facultatives dans le fichier ELF. Je voudrais avoir la possibilité d'avoir les deux exécutables comme cibles Makefile, afin que je puisse construire l'exécutable ELF nu ainsi que l'exécutable ELF injecté de ressources.
Si j'écrivais un Makefile personnalisé, c'est trivial à faire!
foo_in: foo.c
$(CC) $< -o $@
foo_out: foo_in
post_process $< > $@
Et je peux faire make foo_in
et make foo_out
.
add_custom_command
ne pas crée une nouvelle cible. Vous devez définir explicitement les cibles par add_executable
, add_library
ou add_custom_target
afin de les rendre visibles à faire.
Si vous devez arranger les choses pour le déploiement, vous pourriez
1. utilisez la commande install
(quelque part dans votre CMakeLists.txt) comme ceci:
install(SCRIPT <dir>/post_install.cmake)
pour stocker des commandes qui ne sont exécutées que lorsque vous exécutez make install
dans un fichier séparé . cmake . Ou si la cible d'installation est déjà réservée à d'autres choses ou si vous avez des choses plus complexes en cours:
2. définissez manuellement une cible de déploiement . Une fois que vous avez obtenu cela, vous pouvez créer une commande de post-construction personnalisée qui n'est exécutée que lorsque vous exécutez explicitement make sur votre déploiement cible. Cela vous permet d'exécuter des commandes via une cible distincte.
Dans votre CMakeLists.txt, cela pourrait ressembler à:
cmake_minimum_required(VERSION 3.0)
add_executable("App" <sources>)
# option 1: do deployment stuff only when installing
install(SCRIPT <dir>/post_install.cmake)
# option 2: define a deploy target and add post-build commands
add_custom_target("deploy")
add_custom_command(TARGET "deploy" POST_BUILD <some command>)
Les deux approches vous permettent de séparer les versions de développement des versions coûteuses prêtes à déployer (si je comprends bien, c'est le but ici). Je recommanderais l'option 1 car c'est juste plus propre.
J'espère que cela t'aides!
La documentation de CMake n'est pas claire ici. Les générateurs Makefiles de CMake créent les règles de création du fichier source dans des sous Makefiles qui ne sont pas visibles dans le Makefile principal. Dans le Makefile principal, vous ne trouverez que les règles BIDON pour vos cibles CMake. La seule exception que je connaisse est le générateur Ninja
Makefiles qui place toutes les règles de construction dans un seul fichier.
D'après mon expérience - si post_process
Est un script - vous devriez probablement penser à réécrire vos étapes de post-traitement avec/à l'intérieur des scripts CMake, car CMake devrait connaître toutes les dépendances de fichier et les variables utilisées pour le post-traitement ( il se chargera ensuite, par exemple, de toutes les étapes de reconstruction ou de nettoyage nécessaires pour vous).
Voici une version simplifiée/modifiée de ce que je fais:
function(my_add_elf _target)
set(_source_list ${ARGN})
add_executable(${_target}_in ${_source_list})
set_target_properties(
${_target}_in
PROPERTIES
POSITION_INDEPENDENT_CODE 0
SUFFIX .elf
)
add_custom_command(
OUTPUT ${_target}_step1.elf
COMMAND some_conversion_cmd $<TARGET_FILE:${_target}_in> > ${_target}_step1.elf
DEPENDS ${_target}_in
)
add_custom_target(
${_target}_step1
DEPENDS
${_target}_step1.elf
)
add_custom_command(
OUTPUT ${_target}_out.elf
COMMAND final_post_process_cmd ${_target}_step1.elf > ${_target}_out.elf
DEPENDS ${_target}_step1
)
add_custom_target(
${_target}_out
DEPENDS
${_target}_out.elf
)
# alias / PHONY target
add_custom_target(${_target} DEPENDS ${_target}_out)
endfunction(my_add_elf)
puis appeler
my_add_elf(foo foo.c)
Ce n'est qu'un exemple, mais j'espère que cela donne l'idée: vous pourriez appeler make foo
Pour la sortie ELF finale, make foo_in
Ou make foo_step1
Pour l'une des autres étapes. Et je pense que toutes les étapes sont transparentes pour l'utilisateur et CMake.
Lorsque vous essayez de donner à une cible personnalisée le même nom que l'une de ses sorties, par exemple comme ça:
add_executable(foo_in foo.c)
add_custom_command(
OUTPUT foo_out
COMMAND post_process foo_in > foo_out
DEPENDS foo_in
)
add_custom_target(foo_out DEPENDS foo_out)
Vous vous retrouvez avec des fichiers make invalides. J'ai soulevé un problème à ce sujet dans l'espoir qu'il pourrait y avoir une solution possible en étendant CMake lui-même et obtenu la réponse suivante:
CMake n'est pas destiné à produire un contenu spécifique dans un Makefile. Les noms cibles de niveau supérieur créés par add_custom_target sont toujours des noms logiques (c'est-à-dire faux). Il n'est tout simplement pas autorisé d'avoir un fichier du même nom.
Il existe donc des solutions de contournement, mais elles présentent toutes l'un ou l'autre inconvénient.
1. Version la plus courte:
macro(my_add_elf_we _target)
add_executable(${_target}_in ${ARGN})
add_custom_target(
${_target}_out
COMMAND post_process $<TARGET_FILE:${_target}_in> > ${_target}_out
DEPENDS ${_target}_in
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_target}_out)
endmacro(my_add_elf_we)
Vous ne pouvez pas déclarer OUTPUT
s dans la add_custom_target()
elle-même, mais dans ce cas, vous ne voulez pas (parce que vous ne voulez pas avoir de confusion de noms). Mais si vous ne déclarez aucune sortie:
clean
2. Forcer la version du nom de sortie
Voici une version de la macro ci-dessus qui force les noms de cible et de sortie à des valeurs données:
macro(my_add_elf_in_out _target_in _target_out)
add_executable(${_target_in} ${ARGN})
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_custom_target(
${_target_out}
COMMAND post_process ${_target_in} > ${_target_out}
DEPENDS ${_target_in}
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_target_out})
endmacro(my_add_elf_in_out)
Vous l'appelez avec:
my_add_elf_in_out(foo_in.elf foo_out.elf foo.c)
3. Version Libary de l'objet
La version suivante utilise des bibliothèques d'objets, mais le système ne réutilisera pas la liaison cible foo_in
:
macro(my_add_elf_obj_in_out _target_in _target_out)
add_library(${_target_in}_obj OBJECT ${ARGN})
add_executable(${_target_in} $<TARGET_OBJECTS:${_target_in}_obj>)
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_executable(${_target_out} $<TARGET_OBJECTS:${_target_in}_obj>)
set_target_properties(
${_target_out}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_out}"
EXCLUDE_FROM_ALL 1
)
add_custom_command(
TARGET ${_target_out}
POST_BUILD
COMMAND post_process ${_target_in} > ${_target_out}
)
endmacro(my_add_elf_obj_in_out)
4. Dernière et dernière version
Et une version finale qui définitivement ne fonctionne qu'avec les générateurs Makefile et qui m'a fait publier le problème sur le tracker de bogues de CMake:
macro(my_add_elf_ext_in_out _target_in _target_out)
add_executable(${_target_in} ${ARGN})
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_executable(${_target_out} NotExisting.c)
set_source_files_properties(
NotExisting.c
PROPERTIES
GENERATED 1
HEADER_FILE_ONLY 1
)
set_target_properties(
${_target_out}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_out}"
RULE_LAUNCH_LINK "# "
)
add_custom_command(
TARGET ${_target_out}
POST_BUILD
COMMAND post_process ${_target_in} > ${_target_out}
)
add_dependencies(${_target_out} ${_target_in})
endmacro(my_add_elf_ext_in_out)
Contourner les dépendances et utiliser la deuxième signature de add_custom_command
, cela devrait fonctionner:
add_custom_target(foo_out DEPENDS foo_in)
add_custom_command(TARGET foo_out POST_BUILD COMMAND post_process foo_in > foo_out)
Remarque: Ajout de BYPRODUCTS foo_out
fera (par exemple) ninja dire
plusieurs règles génèrent foo_out. les versions impliquant cette cible ne seront pas correctes; continue quand même