Techniques pour assurer la compatibilité multiplateforme (C ++)?

13

Je terminais l'un de mes premiers projets C ++ qui est (selon le cadre) censé être multiplateforme. J'ai développé le projet entièrement dans Windows et Visual Studio, pensant que puisque les bibliothèques sont toutes multiplates-formes, faire la construction OSX "plus tard" serait trivial. Cela ne s'est pas avéré être le cas, mais le "code Windows" ne fonctionne pas correctement et a dû corriger quelques erreurs de compilation.

Quelles techniques existent pour s'assurer au préalable que le code est compatible avec toutes les plateformes? Développer toutes les plates-formes simultanément, testant ainsi le code contre chaque plate-forme en même temps, lorsque de nouvelles fonctionnalités sont ajoutées, plutôt que de développer les différentes versions de plate-forme les unes après les autres? (*)

En regardant spécifiquement, cela ne dépend pas des outils, mais plutôt des «processus de développement» qui aident à la compatibilité entre plates-formes, quels que soient les outils utilisés. Comme celui (*) ci-dessus.


Plus précisément, je développe un plug-in VST avec WDL-OL ( https://github.com/olilarkin/wdl-ol ) et quelques bibliothèques DSP multiplateformes. Les projets WDL-OL ont des projets VS et Xcode mis en place, mais je suppose que les problèmes viennent des bibliothèques, puis des différences dans les compilateurs.

mavavilj
la source
1
il n'y a aucun moyen d' assurer la portabilité, seulement des moyens d'améliorer / maximiser la portabilité
phuclv
et pourquoi n'est-ce pas un doublon? Je crois qu'il y avait beaucoup de questions similaires
phuclv
Que fait votre application? Comment l'utiliseriez-vous? Sur la ligne de commande, ou via une interface graphique? Veuillez modifier votre question pour l'améliorer.
Basile Starynkevitch
Et quel cadre utilisez-vous?
Basile Starynkevitch
Duplication possible de Qu'est
gbjbaanb

Réponses:

15

La création de code portable peut être très difficile.

D'abord quelques conseils liés au langage:

  • utiliser le C ++ standard et éviter soigneusement tout comportement indéfini
  • s'appuyer principalement sur une bibliothèque standard (et des bibliothèques portables telles que boost )
  • incluez toujours tous les en-têtes attendus. Ne supposez pas que vous n'avez pas besoin d'un en-tête car il est inclus dans un autre (c'est- à- dire sur une implémentation spécifique !): Cela peut provoquer des erreurs de compilation
  • éviter les constructions prises en charge par le compilateur mais non garanties par la norme C ++ (par exemple, structure anonyme ou tableau de longueur variable ): peut provoquer des erreurs de compilation.
  • utiliser les options du compilateur pour vous aider à appliquer la conformité (désactivation des extensions spécifiques au compilateur, maximisation du niveau des messages d'avertissement renvoyés)
  • gardez à l'esprit qu'il ne suffit pas que le code fonctionne: il existe de nombreux pièges de portabilité dépendants de l'implémentation: taille des types de données (même élémentaires), caractères qui peuvent être signés ou non signés par défaut , hypothèses sur l' endianité , ordre d'évaluation dans les expressions lorsque ceux-ci utiliser des effets secondaires , etc.

Ensuite, quelques recommandations de conception:

  • Préfère une alternative de bibliothèque standard aux fonctionnalités équivalentes du système d'exploitation
  • Isoler autant que possible l'utilisation des dépendances du système d'exploitation (par exemple, dans une fonction wrapper contrôlée avec une compilation conditionnelle)

Enfin les points délicats:

  • encodage de caractères: sur de nombreux systèmes, vous pouvez compter sur utf8 . Mais pour Windows, c'est plus délicat car le système attend ansi ou utf-16. Vous pouvez bien sûr compter sur un typedef (comme TCHAR), mais cela peut alors être difficile en combinaison avec la bibliothèque standard (par exemple coutvs wcoutà utiliser selon l'utilisation de charou wchar_t)
  • Si pour l'interface graphique / les graphiques / les E / S avancées, vous ne trouvez pas de bibliothèque portable qui correspond à vos attentes / exigences, concevez l'architecture globale pour isoler les composants spécifiques au système d'exploitation. Les emballages peuvent ne pas être suffisants ici, en raison des nombreuses interactions et concepts différents impliqués.
  • Profitez de certains modèles de conception intéressants tels que, par exemple, l' usine abstraite (idéale pour concevoir des familles d'objets liés comme dans l'interface utilisateur spécifique au système d'exploitation) ou le médiateur (idéal pour implémenter la collaboration entre les familles d'objets liés) et les utiliser avec la compilation conditionnelle .

Mais ce ne sont que des conseils. Dans ce domaine, vous ne pouvez pas gagner en certitude.

Christophe
la source
-Wall -Wextra -Werror
pipe
1
@pipe Vous devriez également l'être -pedantic.
5gon12eder
@ 5gon12eder Un très bon point dans le contexte de cette réponse.
pipe
11

Il n'y a rien qui puisse garantir que le code est compatible avec une plate-forme autre que le construire, l'exécuter et le tester là-bas. Par conséquent, l'approche de toutes les personnes sensées consiste à créer, exécuter et tester leur application sur chaque plate-forme sur laquelle ils projettent qu'elle devra être construite, exécutée et testée.

L'intégration continue (CI) peut alléger un peu ce fardeau pour les petits projets, car vous pouvez obtenir des agents de construction bon marché ou gratuits pour certaines plates-formes (principalement Linux), faire votre développement sur Windows et simplement retourner à Linux en cas de problème.

OSX CI est cependant assez délicat.

DeadMG
la source
Il n'y a aucune mention, qu'est-ce que CI?
mavavilj
5
Intégration continue - essentiellement un groupe de serveurs qui exécutent des builds et des tests pour vous.
DeadMG
@DeadMG Vous voulez dire comme Mozilla Tinderbox?
Damian Yerrick
1
Travis CI fournit des hôtes de build OSX gratuits
Daenyth
Utilisez simplement Cmake.
raaj
9

Si vous demandez des "processus de développement" et que votre plate-forme de développement principale est Windows avec Visual Studio, je vous suggère d'essayer de créer votre projet sans "windows.h" inclus. Vous obtiendrez beaucoup d'erreurs de compilation qui vous dirigeront vers de nombreux endroits où vous devrez refactoriser votre code. Par exemple, 'DWORD' ne sera pas # défini et vous devrez le remplacer par uint32_tpartout (google for stdint.het vous trouverez des informations utiles sur les types entiers et leurs définitions multiplateformes). Ensuite, vous devrez remplacer tous les appels à l'API Win32, tels que,Sleep()avec leur équivalent multiplateforme (encore une fois, Google est votre meilleur ami, qui affichera les questions et réponses pertinentes dans les sites stack * .com). Vous ne réussirez probablement pas à trouver tous les remplacements multiplateformes pertinents pour votre code et vous devrez renvoyer votre include "windows."directive mais la mettre sous #ifdef _WIN32- plus de détails ici

Continuez à poser des questions plus concrètes et à obtenir des réponses - c'est une suggestion générale pour «ce qui devrait être le processus de développement»

EDIT 1 Une autre de mes suggestions est d'utiliser gcc et / ou clang sur votre machine de développement Windows (avec Visual Studio)

mvidelgauz
la source
3

Cela dépend des "quelques erreurs de compilation" que vous mentionnez. Sans savoir ce qu'ils étaient, il est impossible d'être précis.

J'ai du code multiplateforme pour Windows / Linux / iOS / Android / Mac. Chaque nouvelle plate-forme a généré des erreurs et des avertissements supplémentaires lors de son ajout. Vous apprendrez rapidement quelles constructions posent des problèmes. Soit les éviter, soit résumer les différences dans un en-tête avec #ifdefs. N'essayez jamais de #ifdefpasser d'une plate-forme à l'autre dans votre code.

Un exemple:

void myfunction(MyClass &);
myfunction(MyClass());

crée une instance temporaire MyClassqui est supprimée après myfunctionson retour. Avec certains de mes compilateurs C ++, cette instance est en lecture / écriture (et le fait qu'elle soit temporaire et sera bientôt détruite n'inquiète pas le compilateur). Avec d'autres, myfunctiondoit être redéfini pour prendre un const MyClass &, ou le compilateur se plaint. Peu importe ce que dit la norme C ++, ou quel compilateur a raison et lequel est faux. Après avoir rencontré l'erreur deux ou trois fois je sais que (a) soit déclarer une variable temporaire de type MyClasset que passer à myfunctionou (b) déclarer la référence constdans myfunctionet d' utiliser mutableici et là pour deconstify.

Conclusion: accumulez de l'expérience et développez vos propres normes de codage.

Martin Kochanski
la source
2
C'est une mauvaise fonctionnalité de MSVC. Si votre point est que le développement sur 1 système permet à ceux-ci de s'infiltrer, point pris. Mais cette chose spécifique n'est pas quelque chose que vous devriez faire.
JDługosz
1
Une bonne chose d'utiliser plusieurs chaînes d'outils est que le sous-ensemble commun qu'ils acceptent est plus susceptible d'être un C ++ correct et conforme aux normes que ce que chacun accepte individuellement. Dans votre cas, le code affiché est clairement erroné par la norme et les deux correctifs mentionnés sont des alternatives valides. Je dirais que ce que dit la norme importe .
5gon12eder
1
Ou je dirais que le C ++ multiplateforme est plus restrictif que ce que dit la norme. En d'autres termes, même si la norme le dit, vous êtes toujours soumis aux dénominateurs communs les plus bas (ou, au moins, la capacité du fournisseur) pour les plates-formes que vous devez prendre en charge. Il existe de nombreuses bibliothèques open source qui ont dû exclure, disons C ++ 11, car une fraction de leurs composants (comme chez les citoyens) ne sont pas capables de C ++ 11.
rwong
3

Un moyen possible d'aider la portabilité pourrait être de s'appuyer uniquement sur les déclarations et les fonctionnalités fournies par la norme C ++ 11 , et en utilisant des bibliothèques et des cadres multiplateformes comme POCO & Qt .

Mais même cela n'est pas infaillible. Rappelez-vous l'aphorisme

il n'y a pas de programme portable, il n'y a que des programmes qui ont été portés avec succès (vers une plate-forme particulière)

Avec de la pratique, de la discipline et beaucoup d'expérience, le portage d'un programme vers une autre plateforme peut généralement se faire rapidement. Mais l'expérience et le savoir-faire comptent beaucoup.

Basile Starynkevitch
la source
1
Un autre conseil est que, lorsque le portage est effectué par différentes personnes et équipes, les modifications de code doivent être réintégrées dans la ligne principale. Sinon, les différences de plate-forme deviennent une connaissance accumulée par l'équipe qui l'a fait.
rwong