IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Systèmes de compilation Discussion :

CMake : générer des sources de noms inconnus et les inclure dans le build de l'exécutable


Sujet :

Systèmes de compilation

  1. #1
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut CMake : générer des sources de noms inconnus et les inclure dans le build de l'exécutable
    Bonjour,

    Je n'ai pas trouvé de section dédiés à CMake sur Developpez, donc je mets ça ici. Si quelqu'un connait une meilleure section, qu'il me le dise et je déplacerai la discussion

    Je découvre CMake depuis quelques jours et je suis arrivé à un blocage pour lequel Google ne m'a pas donné de solution. Je suis donc venu faire appel à votre savoir !

    Pour mon projet, je dois générer des sources à partir de ressources. J'ai des PNG, des TTF, des XLSX et des outils les convertissent en *.cpp / *.hpp. J'ai réussi à faire à ça avec CMake. Le problème vient de la manière dont je pourrai ajouter ces sources à mon exécutable. En effet, je ne connais pas à l'avance le nom de ces fichiers C++ car leurs noms sont dérivés des noms des fichiers ressources. J'ai trouvé sur le net des exemples pour générer des sources et mettre des dépendances entre targets pour regénérer les sources si besoin mais ces exemples connaissent à l'avance les noms des fichiers générés. Moi, non...

    Pour simplifier les choses, j'ai fait un projet minimaliste. J'ai donc le dossier de mon projet avec ce contenu :
    λ ls
    CMakeLists.txt  build/  f.template  main.cpp
    Le dossier build est celui d'où j'exécute cmake.

    Voici mon CMakeLists.txt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    cmake_minimum_required(VERSION 3.7)
     
    project(experiences-project)
     
    file(GLOB cpp_files *.cpp)
    file(GLOB hpp_files *.hpp)
    include_directories(.)
     
    add_executable(experiences ${cpp_files} ${hpp_files} ${CMAKE_SOURCE_DIR}/generated/f.cpp)
     
    add_custom_command(
        OUTPUT ${CMAKE_SOURCE_DIR}/generated/f.cpp
        COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_SOURCE_DIR}/generated
        COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/f.template ${CMAKE_SOURCE_DIR}/generated/f.cpp
        COMMENT "Generating source from template..."
        )
     
    add_custom_target(
        generate_sources
        ALL
        DEPENDS ${CMAKE_SOURCE_DIR}/f.template
        )
     
    add_dependencies(experiences generate_sources)
    Ce code fait ce que je veux conceptuellement, je cherche donc à le généraliser pour ne pas avoir en dur les noms f.cpp et f.template.

    Le problème ici est que les appels file(GLOB ...) ne peuvent pas récupérer les fichiers générés car ils n'existent pas au moment de l'appel à cmake et donc aux appels à file().

    J'ai essayer de faire ceci mais ce n'est pas une syntaxe valide :
    add_executable(experiences ${cpp_files} ${hpp_files} ${CMAKE_SOURCE_DIR}/generated/*.cpp)
    Le seul contournement trouvé est changer la commande add_executable() en :
    add_executable(experiences ${cpp_files} ${hpp_files})
    Gros hic : je me retrouve à devoir appeler cmake (création sans les sources générés), make (génération des sources), cmake (mise à jour en incluant les sources générées), make (génération de l'exécutable) pour obtenir mon exécutable.

    Auriez-vous une solution ?

    Merci d'avance !

  2. #2
    Expert éminent sénior

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 031
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 031
    Points : 11 379
    Points
    11 379
    Billets dans le blog
    10
    Par défaut
    Salut!

    A partir du nom de la ressource, tu n'as vraiment aucun moyen de déduire le nom des fichiers de sortie?
    J'ai dû mettre en place un système de fichiers générés via divers outils (lzz, byacc, basil, ...) dans une solution cmake, mais j'avais toujours la possibilité de déduire le nom des sorties.
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  3. #3
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    A priori, si tu listes toutes les ressources avec glob, tu peux utiliser string() pour générer une liste des fichiers produits.
    Il ne reste alors qu'a ajouter cette liste dans ton build.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  4. #4
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Je rajouterai que add_executable n'a pas besoin des .h, seulement des .cpp
    Et que les trucs générés n'ont rien à faire au milieu des sources -> utilise "${CMAKE_CURRENT_BINARY_DIR}" au lieu de "${CMAKE_SOURCE_DIR}/generated"
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Avoir les headers peut servir pour certaines formes de commandes d'installation (on peut spécifier les "PUBLIC_HEADER", par exemple)
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  6. #6
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Bon, désolé les copains j'ai trouvé une solution avant de revenir ici voir vos conseils

    Je vais commenter vos commentaires (sic) avant de vous exposer ma solution.

    Citation Envoyé par dragonjoker59
    A partir du nom de la ressource, tu n'as vraiment aucun moyen de déduire le nom des fichiers de sortie?
    Si, pour une partie des fichiers (par exemple, je convertis image.png en image.png.cpp) mais pas tous.

    Citation Envoyé par leternel
    A priori, si tu listes toutes les ressources avec glob, tu peux utiliser string() pour générer une liste des fichiers produits.
    Il ne reste alors qu'a ajouter cette liste dans ton build.
    J'ai pas le même problème ? Comment obtenir la liste avant création ?

    Citation Envoyé par Luc Hermitte
    Je rajouterai que add_executable n'a pas besoin des .h, seulement des .cpp
    Et que les trucs générés n'ont rien à faire au milieu des sources -> utilise "${CMAKE_CURRENT_BINARY_DIR}" au lieu de "${CMAKE_SOURCE_DIR}/generated"
    Pour ce qui est des .hpp, j'ai suivi le conseil donné ici : http://florian-goujeon.developpez.co...tion/#LIII-A-2. Il parait que ça permet de les ajouter dans les projets des IDE pour les rendre visibles.
    Pour ce qui est du dossier de génération, c'est pas faux a priori. Mais j'ai des fichiers d'en-tête qui seront générés là-dedans (dans mon vrai projet) donc c'était la simplicité pour les include path.


    Pour ce qui est de ma solution, j'ai décomposé le problème en sous-problèmes.

    Le premier sous-problème est d'appeler un truc pour générer les sources lors du premier appels à cmake. Ce truc pourrait être ensuite rappeler à nouveau par make pour regénérer les sources si besoin. J'ai commencé à regarder du côté des fonctions mais je n'ai pas trouvé comment appeler une fonction là où une COMMAND est appelé (par exemple dans add_custom_target()). Une discussion stackoverflow m'a fait comprendre que je pouvais passer par un script CMake écrit dans un fichier séparé.

    Le deuxième problème était donc de rappeler ce truc, en ajoutant la condition qu'il ne devait être rappelé que si une des ressources étaient modifiées. Cette article m'a montré la lumière : https://samthursfield.wordpress.com/...stom-commands/ L'auteur utilise un fichier bidon comme sorte de marqueur de la génération des ces fichiers.

    J'en suis donc arrivé à la solution suivante :

    CMakeLists.txt
    cmake_minimum_required(VERSION 3.7)
    
    project(experiences-project)
    
    # Generate sources first
    execute_process(
        COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/generate_sources.cmake
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        )
    
    # List sources and headers files
    file(GLOB cpp_files *.cpp)
    file(GLOB hpp_files *.hpp)
    file(GLOB generated_files generated/*)
    include_directories(.)
    
    # Add executable
    add_executable(experiences ${cpp_files} ${hpp_files} ${generated_files})
    
    # Create a target to regenerate sources from templates if needed
    add_custom_command(
        OUTPUT ${CMAKE_SOURCE_DIR}/generated/ressources.stamp
        DEPENDS ${CMAKE_SOURCE_DIR}/*.template
        COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/generate_sources.cmake
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        COMMENT "Command: call cmake script to generate ressources..."
        )
    
    add_custom_target(
        generate_ressources
        ALL
        DEPENDS ${CMAKE_SOURCE_DIR}/generated/ressources.stamp
        COMMENT "Target: generate ressources..."
        )
    
    generate_sources.cmake
    message("***********************")
    message("** Generate sources ***")
    
    message("Delete and re-create 'generated' folder...")
    execute_process(
        COMMAND ${CMAKE_COMMAND} -E remove_directory generated/
        COMMAND ${CMAKE_COMMAND} -E make_directory generated/
        )
    
    message("Generate sources...")
    file(GLOB template_files *.template)
    foreach(template_file ${template_files})
        message("Convert " ${template_file})
        get_filename_component(template_file_name ${template_file} NAME)
        execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${template_file} generated/${template_file_name}.cpp)
    endforeach()
    
    message("Generate stamp file...")
    execute_process(
        COMMAND ${CMAKE_COMMAND} -E touch generated/ressources.stamp
        )
    
    message("***********************")
    Voilà

    Ça semble faire ce que je veux. J'ai actuellement deux fichiers template, qui sont convertis en deux fichiers C++. Le premier contient la fonction f(), le second la fonction g(). La fonction main() contenue dans main.cpp y fait appel.
    - quand je pars du projet à l'état initial, cmake me génère les sources, les trouve avec file(GLOB ...) et les ajouter à l'exécutable. OK.
    - quand je modifie main.cpp, make recompile main.cpp sans regénérer de codes à partir des templates. OK.
    - quand je modifie au moins un des fichiers templates, make regénère les sources et recompiler le tout. OK.

    Des remarques ? Des commentaires ? Des améliorations ?

    Merci encore

  7. #7
    Membre éprouvé
    Avatar de Garvelienn
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2016
    Messages
    244
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Septembre 2016
    Messages : 244
    Points : 993
    Points
    993
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Pour ce qui est des .hpp, j'ai suivi le conseil donné ici : http://florian-goujeon.developpez.co...tion/#LIII-A-2. Il parait que ça permet de les ajouter dans les projets des IDE pour les rendre visibles.
    Je confirme. En tout cas, avec Visual Studio, c'est le seul moyen pour que les headers soient visibles dans le projet.
    «Le management, tel qu’on l’apprend dans les écoles et tel qu’on l’applique ensuite, sous prétexte de «motivation du personnel», organise exactement le contraire, à savoir la démotivation organisée.» - Bernard Stiegler

  8. #8
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Luc Hermitte Voir le message
    Et que les trucs générés n'ont rien à faire au milieu des sources -> utilise "${CMAKE_CURRENT_BINARY_DIR}" au lieu de "${CMAKE_SOURCE_DIR}/generated"
    J'ai potassé cette phrase, j'ai lu cet article http://voices.canonical.com/jussi.pa...d-directories/ et j'ai modifié mes fichiers CMake pour appliquer ce conseil sur mon projet minimaliste. C'était un bon conseil que tu m'as donné !

    Je vais maintenant tenter d'appliquer tout ça à mon vrai projet. Souhaitez-moi bonne chance !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 19/05/2011, 12h48
  2. Réponses: 6
    Dernier message: 24/11/2008, 20h51
  3. Comment générer des sources?
    Par Onarap dans le forum Maven
    Réponses: 2
    Dernier message: 11/01/2007, 10h09
  4. Réponses: 3
    Dernier message: 23/04/2006, 12h14
  5. Des styles pour le texte et les liens dans la meme div?
    Par Donkey' Shot dans le forum Mise en page CSS
    Réponses: 4
    Dernier message: 26/01/2005, 20h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo