137 votes

Organisation de projet C ++ (avec gtest, cmake et doxygen)

Je suis nouveau en programmation en général, donc j'ai décidé de commencer par faire une simple classe vector en C++. Cependant, j'aimerais obtenir de bonnes habitudes dès le début plutôt que d'essayer de modifier mon flux de travail plus tard.

J'ai actuellement seulement deux fichiers vector3.php et vector3.cpp. Ce projet va lentement commencer à se développer (ce qui la rend beaucoup plus générales sur l'algèbre linéaire bibliothèque) que je deviens de plus en plus familiers avec tout, donc je voudrais adopter un "standard" de présentation de projet pour rendre la vie plus facile plus tard. Donc, après avoir regardé autour, j'ai trouvé deux façons d'aller sur l'organisation du php et les fichiers cpp, la première étant:

project
└── src
    ├── vector3.hpp
    └── vector3.cpp

et le second:

project
├── inc
│   └── project
│       └── vector3.hpp
└── src
    └── vector3.cpp

Qui recommanderiez-vous et pourquoi?

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?

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?

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:

├── CMakeLists.txt
├── contrib
│   └── gtest
│       ├── gtest-all.cc
│       └── gtest.h
├── docs
│   └── Doxyfile
├── inc
│   └── project
│       └── vector3.cpp
├── src
│   └── vector3.cpp
└── test
    └── test_vector3.cpp

Comment le CMakeLists.txt ont look de sorte qu'il peut construire la bibliothèque, la bibliothèque et les tests? J'ai aussi 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:

test
├── bin
├── build
└── src
    └── test_vector3.cpp

Je tiens également à utiliser doxygen pour documenter mon code. Est-il possible d'obtenir ce à exécuter automatiquement avec cmake et de faire?

Désolé pour toutes les questions, mais je n'ai pas trouvé un livre sur le C++ qui répond de manière satisfaisante ce type de questions.

91voto

pmr Points 30450

C++ systèmes de construction sont un peu de la magie noire et les plus âgés le projet la plus étrange des choses que vous pouvez trouver de sorte qu'il n'est pas surprenant que beaucoup des questions se posent. Je vais essayer de marcher à travers les questions une par une et de mentionner quelques choses générales concernant la création de bibliothèques C++.

Séparer les têtes et les fichiers cpp dans les annuaires. Ce n'est qu' indispensable si vous créez un composant qui est censé être utilisé comme une bibliothèque, par opposition à une application réelle. Vos en-têtes sont les base pour les utilisateurs d'interagir avec ce que vous offrez et doit être installé. Cela signifie qu'ils doivent être dans un sous-répertoire (personne ne veut beaucoup d'en-têtes de finir dans le top-niveau /usr/include/) et de votre les en-têtes doivent être en mesure d'inclure eux-mêmes avec une telle configuration.

└── prj
 ├── include
 │   └── prj
 │       ├── header2.h
 │       └── header.h
 └── src
     └── x.cpp

fonctionne bien, parce que comprennent les chemins de travailler et vous pouvez utiliser facile d'expansion pour installer des cibles.

Le regroupement des dépendances: je pense que cela dépend en grande partie sur la capacité de le système de construction pour localiser et configurer les dépendances et comment dépendant de votre code sur une seule version. Elle dépend aussi de la façon dont mesure de vos utilisateurs et comment facile est la dépendance à installer sur leur la plate-forme. CMake est livré avec un find_package script pour Google Test. Cela rend les choses beaucoup plus facile. Je voudrais aller avec le regroupement seulement en cas de besoin et d'éviter autrement.

Comment construire: Éviter à la source s'appuie. CMake fait de la source s'appuie facile et ça rend la vie beaucoup plus facile.

Je suppose que vous aussi, vous souhaitez utiliser CTest pour exécuter des tests pour votre système (c' est également livré avec construire-dans le soutien à GTest). Une décision importante pour annuaire de mise en page et de l'organisation de tests seront: - vous jusqu'à la fin avec sous-projets? Si oui, vous avez besoin d'un peu plus de travail lors de la configuration de CMakeLists et devrait diviser votre sous-projets dans les sous-répertoires, chacun avec ses propre include et src fichiers. Peut-être même leur propre doxygen s'exécute et sorties (combinaison de plusieurs doxygen projets est possible, mais pas facile ou assez).

Vous allez vous retrouver avec quelque chose comme ceci:

└── prj
    ├── CMakeLists.txt <-- (1)
    ├── include
    │   └── prj
    │       ├── header2.hpp
    │       └── header.hpp
    ├── src
    │   ├── CMakeLists.txt <-- (2)
    │   └── x.cpp
    └── test
        ├── CMakeLists.txt <-- (3)
        ├── data
        │   └── testdata.yyy
        └── testcase.cpp

  • (1) configure les dépendances, la plate-forme les spécificités et les chemins de sortie
  • (2) configure la bibliothèque, vous allez construire
  • (3) configure le test exécutables et des cas de test

Dans le cas où vous avez des sous-composants, je voudrais suggérer l'ajout d'une autre hiérarchie et de l'utilisation de l'arbre ci-dessus pour chaque sous-projet. Puis les choses se complique, parce que vous devez décider si les sous-composantes de la recherche et de configurer leurs dépendances ou si vous le faites dans le top-niveau. Cela doit être décidé au cas par cas.

Doxygen: Après avoir réussi à passer à travers la configuration de la danse de doxygen, c'est facile à utiliser CMake add_custom_command ajouter un doc cible.

C'est de cette façon mes projets de fin et j'ai vu de très des projets similaires, mais bien sûr ce n'est pas la panacée à tous.

Addendum À un certain point, vous aurez envie de générer un config.hpp fichier qui contient une version de définir et peut-être de définir à une certaine version contrôle de l'identificateur (un Git de hachage ou de numéro de révision SVN). CMake a modules pour automatiser la recherche que de l'information et de générer des les fichiers. Vous pouvez utiliser CMake l' configure_file de remplacer les variables dans un fichier de modèle avec les variables définies à l'intérieur de l' CMakeLists.txt.

Si vous êtes à la construction des bibliothèques, vous aurez également besoin d'une exportation à définir obtenez la différence entre les compilateurs droit, par exemple, __declspec sur MSVC et visibility attributs sur GCC/clang.

41voto

Mikael Persson Points 7174

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)

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.

18voto

Fraser Points 20579

Structurer le projet

Je voudrais favorisent généralement les suivantes:

├── CMakeLists.txt
|
├── docs/
│   └── Doxyfile
|
├── include/
│   └── project/
│       └── vector3.hpp
|
├── src/
    └── project/
        └── vector3.cpp
        └── test/
            └── test_vector3.cpp

Cela signifie que vous avez une très ensemble clairement défini de l'API de fichiers de votre bibliothèque, et la structure signifie que les clients de votre bibliothèque devrait le faire

#include "project/vector3.hpp"

plutôt que le moins explicite

#include "vector3.hpp"


J'aime la structure de l' /src arbre correspondre à celui de la /des arbres, mais c'est une préférence personnelle pour vraiment. Toutefois, si votre projet se développe à contenir des sous-répertoires dans /include/projet, il serait généralement aider à correspondre à ceux de l'intérieur, de l' /src arbre.

Pour les tests, je suis en faveur de leur maintien sur "fermer" pour les fichiers de test, et si vous vous retrouvez avec des sous-répertoires dans /src, il est assez facile de paradigme pour les autres à suivre s'ils veulent trouver un fichier de code de test.


Les tests

Deuxièmement, je voudrais utiliser le Google C++ Cadre d'Essais pour les tests unitaires mon code car il semble assez facile à utiliser.

Gtest est en effet simple d'utilisation et assez complet en fonction de ses capacités. Il peut être utilisé avec la gmock très facilement d'étendre ses capacités, mais de mes propres expériences avec gmock ont été moins favorables. Je suis tout à fait prêt à accepter qu'il peut être par mes propres défauts, mais gmock tests tendance à être plus difficile à créer, et beaucoup plus fragiles et difficiles à maintenir. Un gros clou dans le gmock cercueil, c'est qu'il n'a vraiment pas jouer gentil avec les pointeurs intelligents.

C'est un très trivial et subjective de la réponse à une question énorme (ce qui, probablement, n'appartient pas vraiment sur S. O.)

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?

Je préfère utiliser CMake l' ExternalProject_Add module. Ceci vous évite d'avoir à garder gtest code source dans votre référentiel, ou de l'installer n'importe où. Il est téléchargé et construit dans votre arbre de construction automatiquement.

Voir ma réponse de traiter avec les détails ici.

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?

Bon plan.


Bâtiment

Je suis un fan de CMake, mais comme avec votre test-questions connexes, S. O. est probablement pas le meilleur endroit pour demander des avis sur une question subjective.

Comment le CMakeLists.txt ont look de sorte qu'il peut construire la bibliothèque, la bibliothèque et les tests?

add_library(ProjectLibrary <All library sources and headers>)
add_executable(ProjectTest <All test files>)
target_link_libraries(ProjectTest ProjectLibrary)

La bibliothèque apparaît comme une cible "ProjectLibrary", et la suite de test comme une cible "ProjectTest". En spécifiant la bibliothèque comme une dépendance de l'essai exe, la construction du test exe automatiquement entraîner la bibliothèque pour être reconstruit si il est à jour.

J'ai aussi 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?

CMake recommande "out-of-source" s'appuie, soit vous créez votre propre répertoire de construction à l'extérieur du projet et de lancer CMake à partir de là. Cela évite de "polluer" votre arborescence des sources avec les fichiers de compilation, et il est très souhaitable si vous utilisez un vcs.

Vous pouvez spécifier que les binaires sont déplacés ou copiés dans un répertoire différent, une fois construit, ou qu'ils sont créés par défaut dans un autre répertoire, mais il n'y a généralement pas besoin. CMake propose des façons d'installer votre projet si vous le souhaitez, ou de le rendre facile pour d'autres CMake projets de "trouver" les fichiers de votre projet.

En ce qui concerne CMake propre soutien pour la recherche et l'exécution de gtest tests, cette mesure serait très approprié si vous construisez gtest dans le cadre de votre projet. L' FindGtest module est vraiment conçu pour être utilisé dans le cas où gtest a été construit séparément en dehors de votre projet.

CMake dispose de son propre framework de test (CTest), et, idéalement, tous les gtest cas serait ajouté en tant que CTest cas.

Cependant, l' GTEST_ADD_TESTS macro fournie par FindGtest afin de faciliter l'ajout de gtest cas individuels, ctest cas est un peu en manque en ce qu'il ne fonctionne pas pour gtest macros autre que TEST et TEST_F. La valeur ou le Type paramétré tests à l'aide d' TEST_P, TYPED_TEST_P, etc. ne sont pas traitées du tout.

Le problème n'a pas de solution facile à ce que je sache. Le plus robuste de manière à obtenir une liste de gtest cas, c'est pour exécuter le test exe avec le drapeau de l' --gtest_list_tests. Cependant, ceci ne peut être fait qu'une fois le fichier exe est construit, donc CMake ne pouvez pas faire usage de cette. Qui vous laisse avec deux choix; CMake doit essayer d'analyser le code C++ pour en déduire le nom des tests (non trivial à l'extrême si vous voulez prendre en compte tous les gtest macros, commenté de tests, les handicapés tests), ou de cas de test sont ajoutées à la main à l'CMakeLists.txt fichier.

Je tiens également à utiliser doxygen pour documenter mon code. Est-il possible d'obtenir ce à exécuter automatiquement avec cmake et de faire?

Oui - bien que je n'ai aucune expérience sur ce front. CMake fournit FindDoxygen pour ce but.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X