Comme un démarreur, il y a quelques classiques des noms de répertoires que vous ne pouvez pas ignorer, elles sont basées sur la longue tradition avec le système de fichiers Unix. Ce sont:
trunk
├── bin : for all executables (applications)
├── lib : for all other binaries (static and shared libraries (.so or .dll))
├── include : for all header files
├── src : for source files
└── doc : for documentation
C'est probablement une bonne idée de s'en tenir à cette structure de base, au moins au niveau supérieur.
A propos du fractionnement des fichiers d'en-tête et les fichiers source (rpc), les deux systèmes sont assez communs. Cependant, j'ai tendance à préférer les garder ensemble, il est juste plus pratique au jour le jour les tâches de l'ensemble des fichiers. Aussi, quand tout le code est en vertu d'un dossier de niveau supérieur, c'est à dire, l' trunk/src/
le dossier, vous pouvez remarquer que tous les autres dossiers (bin, lib, include, doc, et peut-être quelques test de dossier) au plus haut niveau, en plus de la "construction" de répertoire pour une source de construire, sont tous les dossiers qui contiennent rien de plus que les fichiers sont générés dans le processus de construction. Et donc, seul le dossier src doit être sauvegardé, ou beaucoup mieux, conservés en vertu d'un système de contrôle de version / serveur (comme Git ou SVN).
Et quand il s'agit de l'installation de votre en-tête des fichiers sur le système de destination (si vous voulez éventuellement distribuer votre bibliothèque), eh bien, CMake a une commande pour l'installation des fichiers (crée implicitement une "installation" de la cible, de faire un "make install") que vous pouvez utiliser pour mettre tous les en-têtes de dans le /usr/include/
répertoire. Je viens d'utiliser la suite de cmake macro à cet effet:
# custom macro to register some headers as target for installation:
# setup_headers("/path/to/header/something.h" "/relative/install/path")
macro(setup_headers HEADER_FILES HEADER_PATH)
foreach(CURRENT_HEADER_FILE ${HEADER_FILES})
install(FILES "${SRCROOT}${CURRENT_HEADER_FILE}" DESTINATION "${INCLUDEROOT}${HEADER_PATH}")
endforeach(CURRENT_HEADER_FILE)
endmacro(setup_headers)
Où SRCROOT
est un cmake variable que j'ai mis à le dossier src, et INCLUDEROOT
est cmake variable que je configurer partout sur les en-têtes doivent aller. Bien sûr, il ya beaucoup d'autres façons de le faire, et je suis sûr que mon chemin n'est pas le meilleur. Le point est, il n'y a aucune raison pour diviser les en-têtes et les sources juste parce que les en-têtes doivent être installés sur le système cible, car il est très facile, surtout avec CMake (ou CPack), de choisir et de configurer les en-têtes pour être installé sans avoir à disposer d'eux dans un répertoire séparé. Et c'est ce que j'ai vu dans la plupart des bibliothèques.
Citation: Deuxièmement, je voudrais utiliser le Google C++ Cadre d'Essais pour les tests unitaires mon code car il semble assez facile à utiliser. Avez-vous suggèrent le groupage avec mon code, par exemple dans un "inc/gtest" ou "contrib/gtest" dossier? Si groupés, ne vous suggérons d'utiliser le fuse_gtest_files.py script pour réduire le nombre de fichiers, ou de les laisser comme c'est? Si pas regroupés de la façon dont est cette dépendance traitées?
Ne pas bundle dépendances avec votre bibliothèque. Ce est généralement une jolie idée horrible, et j'ai toujours déteste quand je suis coincé à essayer de construire une bibliothèque qui l'a fait. Il devrait être votre dernier recours, et méfiez-vous des pièges. Souvent, les gens bundle dépendances avec leur bibliothèque, soit parce qu'ils la cible d'un terrible environnement de développement (par exemple, Windows), ou parce qu'ils prennent uniquement en charge un vieux (obsolète) de la version de la bibliothèque (de la dépendance) en question. Le principal écueil est que votre forfait dépendance qui pourraient entrer en conflit avec déjà les versions installées de la même bibliothèque / application (par exemple, vous avez assemblé gtest, mais la personne qui tente de construire votre bibliothèque a déjà un nouveau (ou plus) de la version de gtest déjà installé, puis les deux peuvent entrer en conflit et de lui donner un très méchant mal de tête). Donc, comme je l'ai dit, le faire à vos propres risques, et je dirais que comme un dernier recours. Demandant aux gens d'installer quelques dépendances avant d'être en mesure de compiler votre bibliothèque est un moindre mal que d'essayer de résoudre les conflits entre dans votre forfait dépendances et installations existantes.
Citation: Quand il s'agit de l'écriture de tests, comment sont-ils généralement organisée? Je pensais l'avoir un fichier cpp pour chaque classe (test_vector3.cpp par exemple), mais le tout compilé dans un binaire pour qu'ils puissent tous être exécutées facilement?
Un fichier cpp par classe (ou un petit groupe homogène de classes et de fonctions) est plus que d'habitude et de pratique à mon avis. Toutefois, sans doute, de ne pas compiler le tout dans un binaire juste pour que "ils peuvent fonctionner ensemble". C'est vraiment une mauvaise idée. Généralement, quand il s'agit de codage, vous voulez diviser les choses autant qu'il est raisonnable de le faire. Dans le cas de l'unité-tests, vous ne voulez pas un binaire à exécuter tous les tests, parce que cela signifie que la moindre petite modification que vous apportez à quelque chose dans votre bibliothèque est susceptible de causer un quasi-totale de la recompilation de l'unité de programme de test, et c'est à seulement quelques minutes / heures perdues en attente pour la recompilation. Il suffit de coller à un schéma simple: 1 unité = 1 unité-programme de test. Ensuite, utiliser un script ou un test unitaire cadre (comme gtest et/ou CTest) pour exécuter tous les programmes de test et le rapport à l'échec/taux de réussite.
Citation: Depuis le gtest bibliothèque est généralement construire en utilisant cmake et de faire, je pensais que ce serait utile pour mon projet aussi être construit comme cela? Si j'ai décidé d'utiliser la suite de présentation de projet:
Je préfère suggérer cette mise en forme:
trunk
├── bin
├── lib
│ └── project
│ └── libvector3.so
│ └── libvector3.a products of installation / building
├── docs
│ └── Doxyfile
├── include
│ └── project
│ └── vector3.hpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── src
│ └── CMakeLists.txt
│ └── Doxyfile.in
│ └── project part of version-control / source-distribution
│ └── CMakeLists.txt
│ └── vector3.hpp
│ └── vector3.cpp
│ └── test
│ └── test_vector3.cpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── build
└── test working directories for building / testing
└── test_vector3
A peu de choses à noter ici. Tout d'abord, les sous-répertoires de votre répertoire src devrait être le reflet de la sous-répertoires de votre répertoire, c'est juste pour garder les choses intuitive (aussi, essayez de garder votre sous-structure de répertoire raisonnablement plat (peu), parce que la profonde imbrication des dossiers est souvent plus une corvée qu'autre chose). Deuxièmement, la "inclure" répertoire est juste un répertoire d'installation, son contenu est juste ce que les en-têtes sont choisi du répertoire src.
Troisièmement, le CMake système est destiné à être distribué sur la source des sous-répertoires, non pas comme un CMakeLists.txt fichier au haut-niveau. Cela permet de maintenir les choses locale, et c'est bon (dans l'esprit de diviser les choses en indépendants des pièces). Si vous ajoutez une nouvelle source, un nouvel en-tête, ou d'un nouveau programme de test, vous avez besoin d'éditer un petit et simple CMakeLists.txt fichier dans le sous-répertoire en question, sans toucher à rien d'autre. Cela vous permet également de restructurer les répertoires avec facilité (CMakeLists sont locales et contenue dans le sous-répertoires être déplacé). Le haut-niveau CMakeLists doit contenir la plupart des configurations de premier niveau, tels que la configuration des répertoires de destination, des commandes personnalisées (ou macros), et de trouver des paquets installés sur le système. Le niveau inférieur CMakeLists ne doit contenir que de simples listes de têtes, des sources et des tests unitaires sources, et le cmake commandes que vous inscrire à la compilation des cibles.
Citation: Quelle serait l'CMakeLists.txt ont look de sorte qu'il peut construire la bibliothèque, la bibliothèque et les tests?
Réponses de base est que CMake permet d'exclure expressément certains objectifs de "tous" (qui est ce qui est construit lorsque vous tapez "make"), et vous pouvez également créer des faisceaux de cibles. Je ne peux pas faire un CMake tutoriel ici, mais il est assez simple de trouver par vous-même. Dans ce cas précis, cependant, la solution recommandée est, bien sûr, à utiliser CTest, qui est juste un jeu supplémentaire de commandes que vous pouvez utiliser dans la CMakeLists fichiers à enregistrer un certain nombre d'objectifs (programmes) qui sont marqués comme unité-tests. Donc, CMake va mettre tous les tests dans une catégorie spéciale de construit, et c'est exactement ce que vous avez demandé, donc, le problème est résolu.
Citation: j'ai Également vu pas mal de projets qui ont un build ad un répertoire bin. Le build se produire dans le répertoire de construction, puis les fichiers binaires déplacé dans le répertoire bin? Serait les binaires pour les tests et la bibliothèque de vivre dans le même endroit? Ou serait-il plus logique de le structurer comme suit:
Avoir un répertoire de construction à l'extérieur de la source ("source") est vraiment la seule sane chose à faire, c'est le standard de facto de ces jours. Donc, certainement, "construire" directory, en dehors du répertoire des sources, tout comme la CMake personnes recommandent, et comme chaque programmeur, je n'ai jamais rencontré. Comme pour le répertoire bin, et bien, c'est une convention, et c'est probablement une bonne idée de s'y tenir, comme je l'ai dit au début de ce post.
Citation: je tiens également à utiliser doxygen pour documenter mon code. Est-il possible d'obtenir ce à exécuter automatiquement avec cmake et de faire?
Oui. Il est plus que possible, il est génial. En fonction de la façon de fantaisie, vous voulez obtenir, il y a plusieurs possibilités. CMake n'ont un module pour Doxygen (c'est à dire, find_package(Doxygen)
), qui vous permet de vous inscrire cibles qui seront exécutés Doxygen sur certains fichiers. Si vous voulez faire plus de choses de fantaisie, comme la mise à jour du numéro de version dans le Doxyfile, ou automatiquement à la saisie d'une date / auteur timbres pour les fichiers source et ainsi de suite, il est possible avec un peu de CMake kung-fu. Généralement, cela impliquera que vous gardez une source Doxyfile (par exemple, le "Doxyfile.dans" que j'ai mis dans le dossier de présentation ci-dessus) qui a des jetons pour être trouvé et remplacé par CMake de l'analyse des commandes. Dans mon top niveau CMakeLists fichier, vous trouverez un de ces morceau de CMake kung-fu qui n'est quelques choses de fantaisie avec cmake-doxygen ensemble.