web-dev-qa-db-fra.com

Écriture de code C ++ multiplateforme (Windows, Linux et Mac OSX)

Ceci est ma première tentative d'écrire quoi que ce soit, même légèrement compliqué en C++, j'essaie de construire une bibliothèque partagée avec laquelle je peux interfacer à partir d'Objective-C et d'applications .NET (ok, cette partie vient plus tard ...)

Le code que j'ai est -

#ifdef TARGET_OS_MAC
  // Mac Includes Here
#endif

#ifdef __linux__
  // Linux Includes Here
  #error Can't be compiled on Linux yet
#endif

#ifdef _WIN32 || _WIN64
  // Windows Includes Here
  #error Can't be compiled on Windows yet
#endif

#include <iostream>

using namespace std;

bool probe(){
  #ifdef TARGET_OS_MAC
    return probe_macosx();
  #endif
  #ifdef __linux__
    return probe_linux();
  #endif
  #ifdef _WIN32 || _WIN64
    return probe_win();
  #endif
}

bool probe_win(){
  // Windows Probe Code Here
  return true;
}

int main(){

  return 1;
}

J'ai un avertissement du compilateur, simplement untitled: In function ‘bool probe()’:untitled:29: warning: control reaches end of non-void function - mais j'apprécierais aussi vraiment toute information ou ressource que les gens pourraient suggérer pour mieux écrire ce type de code ....

35
Lee Hambley

Je vais aborder cette fonction spécifique:

bool probe() {
#ifdef TARGET_OS_MAC
  return probe_macosx();
#Elif defined __linux__
  return probe_linux();
#Elif defined _WIN32 || defined _WIN64
  return probe_win();
#else
#error "unknown platform"
#endif
}

L'écrire de cette façon, en tant que chaîne de if-Elif-else, élimine l'erreur car il est impossible de compiler sans une instruction de retour valide ou sans la #error.

(Je crois que WIN32 est défini pour Windows 32 et 64 bits, mais je ne pourrais pas vous le dire sans le chercher. Cela simplifierait le code.)


Malheureusement, vous ne pouvez pas utiliser #ifdef _WIN32 || _WIN64: voir http://codepad.org/3PArXCxo pour un exemple de message d'erreur. Vous pouvez utiliser l'opérateur spécial de pré-traitement uniquement défini , comme je l'ai fait ci-dessus.


En ce qui concerne la répartition des plates-formes en fonction de fonctions ou de fichiers entiers (comme suggéré ), vous pouvez ou non vouloir le faire. Cela dépendra des détails de votre code, tels que la quantité partagée entre les plates-formes et ce que vous (ou votre équipe) trouvez le mieux pour synchroniser les fonctionnalités, entre autres.

De plus, vous devez gérer la sélection de plate-forme dans votre système de construction, mais cela ne signifie pas que vous ne pouvez pas utiliser le préprocesseur: utilisez des macros définies conditionnellement (par le makefile ou le système de construction) pour chaque plate-forme. En fait, c'est la solution souvent la plus pratique avec des modèles et des fonctions en ligne, ce qui la rend plus flexible que d'essayer d'éliminer le préprocesseur. Il se combine bien avec l'approche du fichier entier, vous pouvez donc toujours l'utiliser lorsque cela est approprié.

Vous voudrez peut-être avoir un seul en-tête de configuration qui traduit toutes les différentes macros spécifiques au compilateur et à la plate-forme en macros bien connues et comprises que vous contrôlez. Ou vous pouvez ajouter -DBEAKS_PLAT_LINUX à votre ligne de commande du compilateur - via votre système de génération - pour définir cette macro (n'oubliez pas d'utiliser un préfixe pour les noms de macro).

32
Roger Pate

au lieu de vous répéter et d'écrire les mêmes lignes #ifdef .... encore et encore, il vaut peut-être mieux déclarer la méthode probe () dans un en-tête et fournir trois fichiers source différents, un pour chaque plate-forme. Cela présente également l'avantage que si vous ajoutez une plate-forme, vous n'avez pas à modifier toutes vos sources existantes, mais simplement à ajouter de nouveaux fichiers. Utilisez votre système de génération pour sélectionner le fichier source approprié.

Exemple de structure:

include/probe.h
src/Arch/win32/probe.cpp
src/Arch/linux/probe.cpp
src/Arch/mac/probe.cpp

L'avertissement est dû au fait que probe () ne renvoie pas de valeur. En d'autres termes, aucune des trois #ifdefs ne correspond.

46
stijn

Il ne semble rien de TARGET_OS_MAC, __linux__, _WIN32 ou _WIN64 est défini au moment où vous compilez votre code.

Donc, comme votre code était:

bool probe(){
}

C'est pourquoi le compilateur se plaint d'atteindre la fin d'une fonction non vide. Il n'y a pas de clause return.


Aussi, pour la question plus générale, voici mes directives lors du développement de logiciels/bibliothèques multi-plateformes/architectures:

Évitez les cas spécifiques. Essayez d'écrire du code indépendant du système d'exploitation.

Lorsque vous traitez avec des choses spécifiques au système, essayez d'enrouler les choses dans des classes "opaques". Par exemple, si vous traitez des fichiers (différentes API sous Linux et Windows), essayez de créer une classe File qui incorporera toute la logique et fournira une interface commune, quel que soit le système d'exploitation. Si une fonctionnalité n'est pas disponible sur l'un des OS, traitez-la: si la fonctionnalité n'a aucun sens pour un OS spécifique, il est souvent correct de ne rien faire du tout.

En bref: moins #ifdef le meilleur. Et peu importe la portabilité de votre code, testez-le sur chaque plate-forme avant de le publier.

Bonne chance ;)

5
ereOn

Pour ajouter quelque chose de plus à cela, à part les options en suspens ci-dessus, les directives __linux__ et _WIN32 sont connus du compilateur, où le TARGET_OS_MAC la directive ne l'était pas, cela peut être résolu en utilisant __Apple__. Source: http://www.winehq.org/pipermail/wine-patches/2003-July/006906.html

1
Lee Hambley

L'avertissement est dû au fait que si aucune des définitions n'est réellement définie, vous n'avez pas de return dans votre fonction de sonde. Le correctif est placé dans un return par défaut.

1
Tristan