Techniken zur Sicherstellung der plattformübergreifenden Kompatibilität (C ++)?

13

Ich beendete eines meiner frühesten C ++ - Projekte, das (laut Framework) plattformübergreifend sein soll. Ich habe das Projekt vollständig in Windows und Visual Studio entwickelt und dachte, da die Bibliotheken alle plattformübergreifend sind, wäre es trivial, den OSX-Build "später" durchzuführen. Dies stellte sich als nicht der Fall heraus, sondern der "Windows-Code" lief nicht richtig und einige Kompilierungsfehler mussten behoben werden.

Welche Techniken sind vorhanden, um vorher sicherzustellen, dass der Code mit allen Plattformen kompatibel ist? Entwickeln Sie alle Plattformen gleichzeitig und testen Sie so den Code gleichzeitig auf allen Plattformen, wenn neue Funktionen hinzugefügt werden, anstatt die verschiedenen Plattformversionen nacheinander zu entwickeln? (*)

Suchen Sie gezielt nach Empfehlungen, die nicht von den Tools abhängen, sondern eher von "Entwicklungsprozessen", die zur plattformübergreifenden Kompatibilität beitragen, unabhängig davon, welche Tools verwendet werden. Wie der (*) oben.


Insbesondere entwickle ich ein VST-Plug-In mit WDL-OL ( https://github.com/olilarkin/wdl-ol ) und einigen plattformübergreifenden DSP-Bibliotheken. WDL-OL-Projekte haben sowohl VS- als auch Xcode-Projekte eingerichtet, aber ich denke, die Probleme kommen von den Bibliotheken und dann von den Unterschieden bei den Compilern.

mavavilj
quelle
1
es gibt keinen Weg , um sicherzustellen , nur Möglichkeiten Tragbarkeit zu verbessern / maximize Portabilität
phuclv
und warum ist das nicht ein Duplikat? Ich glaube, es gab viele ähnliche Fragen
phuclv
Was macht Ihre Bewerbung? Wie würden Sie es benutzen? Auf der Kommandozeile oder über eine grafische Oberfläche? Bitte bearbeiten Sie Ihre Frage , um sie zu verbessern.
Basile Starynkevitch
Und welches Framework benutzt du?
Basile Starynkevitch

Antworten:

15

Das Erstellen von portablem Code kann sehr schwierig sein.

Zuerst einige offensichtliche sprachbezogene Ratschläge:

  • Verwenden Sie Standard-C ++ und vermeiden Sie sorgfältig undefiniertes Verhalten
  • in erster Linie auf Standardbibliothek (und portable Bibliotheken wie Boost ) verlassen
  • Schließen Sie immer alle erwarteten Überschriften ein. Gehen Sie nicht davon aus, dass Sie keinen Header benötigen, da dieser in einem anderen enthalten ist (dh in einer bestimmten Implementierung !): Dies kann zu Kompilierungsfehlern führen
  • Vermeiden Sie Konstrukte, die vom Compiler unterstützt, aber vom C ++ - Standard nicht garantiert werden (z. B. anonyme Strukturen oder Arrays mit variabler Länge ). Dies kann zu Kompilierungsfehlern führen.
  • Verwenden Sie Compiler-Optionen, um die Kompatibilität durchzusetzen (Deaktivieren compilerspezifischer Erweiterungen, Maximieren der Anzahl der zurückgegebenen Warnmeldungen).
  • Denken Sie daran, dass es nicht ausreicht, dass der Code funktioniert: Es gibt viele implementierungsabhängige Portabilitätsprobleme: Größe der (auch elementaren) Datentypen, Zeichen, die standardmäßig signiert oder unsigniert sein können , Annahmen über Endianness , Reihenfolge der Auswertung in Ausdrücken, wenn diese Verwenden Sie Nebenwirkungen usw.

Dann ein paar Designempfehlungen:

  • Bevorzugen Sie eine Standardbibliotheksalternative gegenüber einer entsprechenden Betriebssystemfunktionalität
  • Isolieren Sie die Verwendung von Betriebssystemabhängigkeiten so weit wie möglich (z. B. in einer mit bedingter Kompilierung gesteuerten Wrapper-Funktion).

Zum Schluss die heiklen Punkte:

  • Zeichenkodierung: Auf vielen Systemen können Sie sich auf utf8 verlassen . Aber für Windows ist es heikler, da das System entweder ansi oder utf-16 erwartet. Sie können sich natürlich auf ein typedef (wie TCHAR) verlassen, aber dies kann in Kombination mit der Standardbibliothek eine Herausforderung sein (z. B. coutvs wcout, je nachdem, ob charoder verwendet wird wchar_t).
  • Wenn Sie für GUI / Graphics / Advanced I / O keine tragbare Bibliothek finden können, die Ihren Erwartungen / Anforderungen entspricht, entwerfen Sie die Gesamtarchitektur, um betriebssystemspezifische Komponenten zu isolieren. Wrapper könnten hier aufgrund der vielen unterschiedlichen Interaktionen und Konzepte nicht ausreichen.
  • Profitieren Sie von einigen interessanten Entwurfsmustern, wie zum Beispiel der abstrakten Factory (ideal zum Entwerfen von Familien verwandter Objekte wie in der betriebssystemspezifischen Benutzeroberfläche) oder dem Mediator (ideal zum Implementieren der Zusammenarbeit zwischen Familien verwandter Objekte), und verwenden Sie sie zusammen mit der bedingten Kompilierung .

Dies sind aber nur Ratschläge. In diesem Bereich kann man keine Gewissheit gewinnen.

Christophe
quelle
-Wall -Wextra -Werror
Pipe
1
@pipe solltest du auch sein -pedantic.
5gon12eder
@ 5gon12eder Ein sehr guter Punkt im Kontext dieser Antwort.
Pipe
11

Es gibt keine Garantie dafür, dass der Code mit einer anderen Plattform kompatibel ist, als ihn zu erstellen, auszuführen und dort zu testen. Daher besteht der Ansatz aller vernünftigen Menschen darin, ihre Anwendung auf jeder Plattform zu erstellen, auszuführen und zu testen, auf der sie voraussichtlich erstellt, ausgeführt und getestet werden muss.

Continuous Integration (CI) kann diese Belastung für kleinere Projekte ein wenig verringern, da Sie günstige oder kostenlose Build-Agenten für einige Plattformen (hauptsächlich Linux) erhalten, Ihre Entwicklung unter Windows durchführen und bei Problemen einfach zu Linux zurückkehren können.

OSX CI ist allerdings ziemlich knifflig.

DeadMG
quelle
Es gibt keine Erwähnung, was ist CI?
Mavavilj
5
Continuous Integration - im Grunde genommen eine Reihe von Servern, die Builds und Tests für Sie ausführen.
DeadMG
@DeadMG Du meinst wie Mozilla Tinderbox?
Damian Yerrick
1
Travis CI bietet kostenlose OSX-Build-Hosts
Daenyth
Verwenden Sie einfach Cmake.
Raaj
9

Wenn Sie nach "Entwicklungsprozessen" fragen und Ihre primäre Entwicklungsplattform Windows mit Visual Studio ist, würde ich vorschlagen, Ihr Projekt ohne "windows.h" zu erstellen. Sie erhalten viele Kompilierungsfehler, die Sie auf viele Stellen verweisen, an denen Sie Ihren Code überarbeiten müssen. Zum Beispiel wird 'DWORD' nicht als # definiert und muss durch " uint32_tüberall" ersetzt werden (google for stdint.hund Sie finden nützliche Informationen zu Ganzzahltypen und deren plattformübergreifenden Definitionen). Als Nächstes müssen Sie alle Aufrufe der Win32-API ersetzen, z.Sleep()mit ihrer plattformübergreifenden Entsprechung (auch hier ist Google Ihr bester Freund, der relevante Fragen und Antworten auf Stack * .com-Websites anzeigt). Es wird Ihnen wahrscheinlich nicht gelingen, alle relevanten plattformübergreifenden Ersetzungen für Ihren Code zu finden, und Sie müssen Ihre include "windows."Direktive zurücksenden, aber unterstellen #ifdef _WIN32- weitere Details finden Sie hier

Immer konkretere Fragen stellen und Antworten bekommen - dies ist ein allgemeiner Vorschlag für "Was sollte Entwicklungsprozess sein?"

BEARBEITEN 1 Ein weiterer Vorschlag von mir ist die Verwendung von gcc und / oder clang auf Ihrem Windows-Entwicklungscomputer (zusammen mit Visual Studio).

mvidelgauz
quelle
3

Es hängt von den "einigen Kompilierungsfehlern" ab, die Sie erwähnen. Ohne zu wissen, was sie waren, ist es unmöglich, spezifisch zu sein.

Ich habe plattformübergreifenden Code für Windows / Linux / iOS / Android / Mac. Jede neue Plattform brachte einige zusätzliche Fehler und Warnungen mit sich, als sie zum ersten Mal hinzugefügt wurde. Sie werden schnell lernen, welche Konstrukte Probleme bringen. Vermeiden Sie sie oder abstrahieren Sie die Unterschiede in einen Header mit #ifdefs. Versuchen Sie niemals, #ifdefzwischen Plattformen in Ihrem Code selbst zu wechseln.

Ein Beispiel:

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

Erstellt eine temporäre Instanz, MyClassdie nach myfunctionder Rückkehr gelöscht wird. Bei einigen meiner C ++ - Compiler ist diese Instanz schreibgeschützt (und die Tatsache, dass sie temporär ist und bald zerstört wird, macht dem Compiler keine Sorgen). Bei anderen myfunctionmuss neu definiert werden, um ein zu nehmen const MyClass &, oder der Compiler beschwert sich. Es spielt keine Rolle, was der C ++ - Standard sagt oder welcher Compiler richtig und welcher falsch ist. Nachdem die Begegnung mit dem Fehler ein paar Male , die ich (a) weiß entweder eine temporäre Variable vom Typ deklarieren MyClassund begeben myfunctionoder (b) erklären die Referenz constin myfunctionund verwendet mutablehier und dort deconstify.

Fazit: Sammeln Sie Erfahrung und entwickeln Sie Ihre eigenen Codierungsstandards.

Martin Kochanski
quelle
2
Das ist eine Fehlfunktion von MSVC. Wenn Sie der Meinung sind, dass die Entwicklung auf einem System es ermöglicht, dass sich diese einschleichen, wird der Punkt genommen. Aber genau das sollten Sie nicht tun.
JDługosz
1
Eine gute Sache bei der Verwendung mehrerer Toolketten ist, dass die gemeinsame Teilmenge, die sie akzeptieren, mit größerer Wahrscheinlichkeit korrekt und standardkonform zu C ++ ist, als das, was jeder von ihnen einzeln akzeptiert. In Ihrem Fall ist der angezeigte Code vom Standard her eindeutig falsch, und beide von Ihnen genannten Fixes sind gültige Alternativen. Ich würde sagen, es ist wichtig, was der Standard sagt.
5gon12eder
1
Oder ich würde sagen, plattformübergreifendes C ++ ist restriktiver als der Standard sagt. Mit anderen Worten, auch wenn der Standard dies vorgibt, unterliegen Sie immer noch den niedrigsten gemeinsamen Nennern (oder der geringsten Anbieterfähigkeit) für die Plattformen, die Sie unterstützen müssen. Es gibt viele Open-Source-Bibliotheken, die beispielsweise C ++ 11 ausschließen mussten, weil ein Teil ihrer Bestandteile (wie bei Bürgern) nicht C ++ 11-fähig sind.
Rwong
3

Eine mögliche Möglichkeit, die Portabilität zu verbessern, besteht darin, sich nur auf die vom C ++ 11- Standard bereitgestellten Deklarationen und Funktionen zu verlassen und plattformübergreifende Bibliotheken und Frameworks wie POCO & Qt zu verwenden .

Aber auch das ist nicht ausfallsicher. Erinnere dich an den Aphorismus

Es gibt kein portierbares Programm, sondern nur Programme, die erfolgreich (auf eine bestimmte Plattform) portiert wurden.

Mit Übung, Disziplin und viel Erfahrung kann ein Programm normalerweise schnell auf eine andere Plattform portiert werden. Aber Erfahrung und Know-how sind sehr wichtig.

Basile Starynkevitch
quelle
1
Ein weiterer Rat ist, dass, wenn die Portierung von verschiedenen Personen und Teams vorgenommen wird, die Codeänderungen erneut in die Hauptzeile integriert werden müssen. Andernfalls werden die Plattformunterschiede zu einem Wissen, das von dem Team gehortet wird, das es getan hat.
Rwong