2009-07-09 11 views
1

J'ai pour certaines de mes classes différentes implémentations par OS.
Ma structure est source comme ceci:Multiplatform C++ Project: Inclusion de sources spécifiques à la plate-forme

  • comprennent/AExample.h
  • include/windows/WindowsExample.h
  • include/linux/LinuxExample.h
  • src/AExample.cpp
  • src/windows/WindowsExample.cpp
  • src/linux/LinuxExample.cpp

les classes A * sont les interfaces pour les implémentations spécifiques

Mon système de construction actuel est cmake - mais pour le moment il est seulement capable de construire la version linux.

Dans versions Windows j'ai seulement besoin d'inclure les fenêtres/fichier * et sur les fichiers linux seulement linux/*

Je dois

  • comprennent uniquement les fichiers qui sont pertinents pour mon courant construire
  • choisir la bonne mise en œuvre quand je besoin d'une instance de AExample

Quelles techniques pouvez-vous recommander de réaliser cela de manière professionnelle?

Répondre

7

C'est assez facile dans CMake.

Ayez juste votre fichier CMakeLists.txt vérifier la plate-forme, et ajouter dans les fichiers appropriés ou inclure le sous-répertoire approprié au besoin.

La syntaxe de base est:

IF(WIN32) 
    # Do windows specific includes 
ELSEIF(UNIX) 
    # Do linux specific includes 
ENDIF(WIN32) 
2

Si les en-têtes ont les mêmes noms, mais ils résident dans différentes hiérarchies, vous pouvez simplement définir le -I (include_path) drapeau correctement pour votre compilateur. C'est beaucoup plus facile que de gérer tous les inclusions dépendantes de la plateforme séparément.

Si les en-têtes résident dans le même répertoire et/ou si vous voulez personnaliser des choses, vous généralement faire dans votre C/C++ Code:

#ifdef _WIN32 
    .. include Win headers .. 
#endif 

#ifdef LINUX 
    .. include Linux headers ... 
#endif 

Je ne recommanderais pas la solution spécifique CMake à moins vous êtes sûr de ne pas devoir changer de système de construction plus tard.

+1

Cela ne gère pas, y compris les différents fichiers source dans la construction, cependant. L'utilisation de CMake entraîne généralement le paramétrage approprié, mais vous pouvez également inclure des fichiers source spécifiques à la plate-forme. C'est l'une des (bonnes) raisons d'utiliser cmake en premier lieu. –

+0

C'est une de ces techniques qui est facile et qui fonctionne bien pour les petits projets, mais qui devient problématique lorsque les projets prennent de l'ampleur. _Large Scale C++ Software Design_ recommande de ne pas arroser la totalité de votre source. Je pense que l'utilisation du système de build pour gérer le code spécifique à la plate-forme est la meilleure, mais si vous voulez le faire dans la source elle-même, il est conseillé d'utiliser un [organisation hautement structurée] (http://stackoverflow.com/a/31304341/365496). – bames53

0

Bien que je pense que l'utilisation du système de construction pour gérer les fichiers multiplateformes soit la meilleure, il est possible d'écrire simplement votre source pour la gérer via le préprocesseur. Cependant, la méthode très courante, rapide et sale de faire cela, où vous saupoudrez les contrôles de la plate-forme partout dans le code est problématique et devrait être évitée. A la place, vous devriez utiliser une méthode plus structurée pour organiser le code spécifique à la plate-forme afin d'éviter les problèmes au fur et à mesure que le projet prend de l'ampleur.

Le code spécifique à la plateforme doit être clairement identifié au niveau du fichier: Par exemple, utilisez une structure de répertoires avec des répertoires pour chaque plate-forme et placez tous les fichiers source spécifiques à la plate-forme dans le répertoire approprié. Les fichiers source ne doivent pas contenir de code pour plusieurs plates-formes ou pour toute vérification de plate-forme de préprocesseur (sauf pour une exception). En outre, la source spécifique à la plate-forme ne doit généralement pas être directement construite ou #include d. Au lieu de cela, le code spécifique à la plate-forme ne doit être utilisé que de manière indirecte, via des fichiers source non spécifiques à la plate-forme qui ne contiennent rien d'autre que les vérifications de plate-forme et les fichiers spécifiques à la plate-forme.

Exemple organisation source:

src/ 
    main.cpp 
    foo.h 
    foo.cpp 
    windows/ 
    foo.cpp.inc 
    posix/ 
    foo.cpp.inc 

Exemple contenu de la source:

// main.cpp 
#include "foo.h" 

int main() { 
    foo(); 
} 

// foo.h 
void foo(); 

// foo.cpp 
#if defined(_WIN32) 
# include "windows/foo.cpp.inc" 
#elif __has_include(<unistd.h>) 
# include<unistd.h> 
# if defined(_POSIX_VERSION) 
# include "posix/foo.cpp.inc" 
# endif 
#else 
# error Unknown platform 
#endif 

// windows/foo.cpp.inc 
#include "foo.h" 

#include <iostream> 
#include <Windows.h> 

void foo() { 
    std::cout << "Windows\n"; 
} 

// posix/foo.cpp.inc 
#include "foo.h" 

#include <iostream> 
#include <unistd.h> 

void foo() { 
    std::cout << "POSIX\n"; 
} 

versions Windows et la sortie:

cl.exe /EHsc /W4 /WX src\main.cpp src\foo.cpp
main

de Windows

Linux build et sortie:

g++ -Wall -Wextra -Werror -Isrc src/main.cpp src/foo.cpp
./a.out

Posix

La méthode illustrée dans l'exemple ci-dessus fonctionne plutôt bien lorsque le code de différentes plates-formes peut raisonnablement partager la même organisation de fichier. Si le code pour différentes plates-formes est suffisamment différent pour que vous souhaitiez différentes structures de fichiers pour chaque plate-forme, il est plus difficile d'utiliser cette technique, et passer à l'utilisation du système de build pour gérer le code pour différentes plates-formes devient nettement supérieur.

Il est également possible de mélanger cette technique avec le système de construction; Le code qui partage la structure de fichiers entre les plates-formes peut l'utiliser, tandis que les modules uniques à différentes plates-formes peuvent être gérés par le système de construction.