web-dev-qa-db-ja.com

クロスプラットフォーム互換性を確保するための手法(C ++)?

私は、(フレームワークによると)クロスプラットフォームであることが想定されている、最も初期のC++プロジェクトの1つを仕上げていました。ライブラリはすべてクロスプラットフォームなので、OSXビルドを「後で」行うのは簡単だと思い、WindowsとVisual Studioでプロジェクトを完全に開発しました。これは事実ではなく、「Windowsコード」が適切に実行されず、いくつかのコンパイルエラーが修正されました。

コードがすべてのプラットフォームと互換性があることを事前に確認するためにどのようなテクニックが存在しますか?すべてのプラットフォームを同時に開発し、新しい機能を追加するときに、異なるプラットフォームのバージョンを次々に開発するのではなく、すべてのプラットフォームに対して同時にコードをテストしますか?(*)

具体的には、ツールに依存するのではなく、使用するツールに関係なく、クロスプラットフォームの互換性を支援する「開発プロセス」をアドバイスします。上記の(*)のように。


具体的には、WDL-OL( https://github.com/olilarkin/wdl-ol )といくつかのクロスプラットフォームDSPライブラリを備えたVSTプラグインを開発しています。 WDL-OLプロジェクトにはVSプロジェクトとXcodeプロジェクトの両方がセットアップされていますが、問題はライブラリに起因し、コンパイラの違いに起因すると思います。

13
mavavilj

移植可能なコードを作成することは非常に困難です。

最初にいくつかの明らかな言語関連のアドバイス:

  • 標準C++を使用し、慎重に避けてください 未定義の動作
  • 主に標準ライブラリ(および boost などのポータブルライブラリ)に依存
  • 常に予想されるすべてのヘッダーを含めます。ヘッダーは別のヘッダーに含まれているため(つまり、 1つの特定の実装!)であるため、ヘッダーが不要であると想定しないでください。これにより、コンパイルエラーが発生する可能性があります。
  • コンパイラではサポートされているがC++標準では保証されていない構造体(例 anonymous struct または 可変長配列)は避けてください ):コンパイルエラーが発生する可能性があります。
  • コンパイラー・オプションを使用して、コンプライアンスの実施を支援します(コンパイラー固有の拡張を無効にし、返される警告メッセージのレベルを最大化します)
  • コードが機能するだけでは不十分であることを覚えておいてください。多くの実装依存の移植性の落とし穴があります:(基本的な)データ型のサイズ、 デフォルトで符号付きまたは符号なし 、約についての仮定- エンディアンネス 、これらが使用される場合の式の評価順序 副作用 など.

次に、いくつかの設計上の推奨事項:

  • 同等のオペレーティングシステム機能に代わる標準ライブラリを優先する
  • オペレーティングシステムの依存関係の使用を可能な限り分離する(たとえば、条件付きコンパイルで制御されるラッパー関数で)

最後に、デリケートなポイント:

  • 文字エンコーディング:多くのシステムでは tf8 を信頼できます。しかし、Windowsの場合、システムはansiまたはutf-16を想定しているため、よりデリケートです。もちろんtypedef( TCHAR など)に依存することもできますが、これは標準ライブラリ(例:cout vs wcoutcharまたはwchar_tを使用するかどうかに応じて使用されます)
  • GUI /グラフィックス/高度なI/Oで、期待/要件に合うポータブルライブラリが見つからない場合は、OS固有のコンポーネントを分離するために全体的なアーキテクチャを設計してください。関係する多くの異なる相互作用と概念のために、ラッパーはここでは十分でないかもしれません。
  • abstract factory (OS固有のUIなどの関連オブジェクトのファミリーを設計するのに理想的)または mediator (実装するのに理想的)など、いくつかの興味深い設計パターンを利用します。関連オブジェクトのファミリー間のコラボレーション)、条件付きコンパイルと一緒に使用します。

しかし、これらはアドバイスにすぎません。この領域では確実性を得ることができません。

15
Christophe

コードをビルドして実行し、そこでテストする以外に、コードがプラットフォームと互換性があることを保証できるものはありません。したがって、すべての正気の人々のアプローチは、構築、実行、テストが必要になると予測するすべてのプラットフォームでアプリケーションを構築、実行、テストすることです。

継続的インテグレーション(CI)は、一部のプラットフォーム(主にLinux)の安価なまたは無料のビルドエージェントを入手し、Windowsで開発を行い、問題が発生したときにLinuxに戻るだけなので、小規模プロジェクトの負担をかなり軽減できます。

OSX CIはかなりトリッキーです。

11
DeadMG

「開発プロセス」を要求していて、主な開発プラットフォームがWindowsとVisual Studioの場合、「windows.h」を含めずにプロジェクトをビルドしてみることをお勧めします。コードをリファクタリングする必要のある多くの場所を示す多くのコンパイルエラーが発生します。たとえば、「DWORD」は#definedにはならず、どこでも_uint32_t_に置き換える必要があります(google for _stdint.h_)。整数型とそのクロスプラットフォーム定義に関する有用な情報が見つかります。 )。次に、Sleep()などのWin32 APIへのすべての呼び出しを、クロスプラットフォームの同等のもので置き換える必要があります(ここでも、googleがあなたの親友であり、関連する質問と回答をスタックに表示します* .comサイト)。おそらく、コードに関連するすべてのクロスプラットフォーム置換を見つけることができず、_include "windows."_ディレクティブを返す必要がありますが、_#ifdef _WIN32_の下に配置する必要があります-詳細 ここ

より具体的な質問を繰り返し、回答を得る-これは、「開発プロセスとは何か」に対する一般的な提案です

EDIT 1もう1つの私の提案は、Windows開発マシンで(Visual Studioとともに)gccやclangを使用することです。

9
mvidelgauz

それはあなたが言及する「いくつかのコンパイルエラー」に依存します。それらが何であるかを知らずに、特定することは不可能です。

Windows/Linux/iOS/Android/Mac用のクロスプラットフォームコードを持っています。新しいプラットフォームでは、最初に追加されたときにいくつかの追加のエラーと警告が表示されました。どのコンストラクトがもたらすかがすぐにわかります。問題を回避するか、#ifdefsを使用してヘッダーに違いを抽象化します。コード自体の中でプラットフォーム間で#ifdefを実行しないでください。

一例:

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

MyClassが返された後に削除されるmyfunctionの一時インスタンスを作成します。一部のC++コンパイラーでは、そのインスタンスは読み取り/書き込み可能です(それが一時的ですぐに破棄されるという事実は、コンパイラーを気にする必要はありません)。その他の場合、const MyClass &を取得するためにmyfunctionを再定義する必要があります。そうしないと、コンパイラからエラーが発生します。 C++標準の内容、または正しいコンパイラと間違っているコンパイラは関係ありません。エラーが数回発生した後、(a)MyClass型の一時変数を宣言します。そして、それをmyfunctionに渡すか、(b)constmyfunctionの参照を宣言し、mutableをあちこちで使用して非圧縮化します。

結論:経験を蓄積し、独自のコーディング標準を開発します。

3

C++ 11 標準によって提供される宣言と機能にonlyを使用することで、移植性を向上させることができます。 [〜#〜] poco [〜#〜]Qt のようなクロスプラットフォームライブラリとフレームワークを使用する。

しかし、これでも確実なものではありません。格言を覚えて

移植可能なプログラムなどはなく、(特定のプラットフォームに)正常に移植されたプログラムのみがあります。

実践、規律、そして多くの経験があれば、プログラムを別のプラットフォームに移植することは通常迅速に行うことができます。しかし、経験とノウハウは非常に重要です。