2009-05-13 25 views
6

私はSymbianプラットフォーム上でC++携帯電話アプリケーションを開発しています。要件の1つは、第2版の電話から第5版の電話に至るまで、すべてのSymbian携帯電話で機能する必要があることです。今やバージョン間で、Symbian SDKには違いがあります。私が開発していたアプリケーションが、それはすぐに数十に成長する些細なことではないので、今プリプロセッサディレクティブの代替手段

#ifdef S60_2nd_ED 
    Code 
#elif S60_3rd_ED 
    Code 
#else 
    Code 

:私は条件付きでアプリケーションが以下のように構築されているSDKに関連するコードをコンパイルするためにプリプロセッサディレクティブを使用する必要があります上記のような数千行のコードとプリプロセッサ指令が全面的に広がっています。私は、これに代わるものがあるかどうか、あるいはこの場合にこれらのプリプロセッサ・ディレクティブを使用するより良い方法かも知りません。

助けてください。

答えて

5

私はあなたがいる場所にいます。

コード内に条件がある場合でも、Symbianバージョンをオンにしないでください。将来、新しいバージョンのサポートを追加することや、何らかの形で珍しいハンドセットをカスタマイズすることが難しくなります。

#if S60_3rd_ED 
    #define CAF_AGENT 1 
    #define HTTP_FILE_UPLOAD 1 
#elif S60_2nd_ED 
    #define CAF_AGENT 0 
    #if S60_2nd_ED_FP2 
     #define HTTP_FILE_UPLOAD 1 
    #else 
     #define HTTP_FILE_UPLOAD 0 
    #endif 
#endif 

など:代わりに、実際のプロパティは、あなたが頼っている、それらの周りのコードを記述することであり、その後、ないヘッダファイルをインクルードするもの識別する。明らかに、バージョンごとに定義するのではなく、設定ごとに完全に異なるヘッダーを持つように、あるいはあなたに合ったスキームで機能を定義することができます。

S60とUIQの間に共通のUIコードがあるように、継承するUIクラスも定義していました。実際、その製品が何であるかに起因して、UI関連のコードがあまりなかったので、まともな割合が一般的でした。

しかし、他の人が言うように、可能な場合はクラスや関数に変数の振る舞いを振り回し、異なるバージョンをリンクする方が良いです。コメントに応答して

は、[編集:

我々は、解像度に依存して何かを行うことを避けるために、非常に懸命に試みた - 幸い、特定のアプリが、これはあまりにも難しいことはありませんでしたので、私たちの限られたUIはかなり一般的なでした。私たちが画面解像度を切り替えた主なものは、スプラッシュ/背景画像などでした。ビルドファイルを前処理するスクリプトが用意されていました。このファイルは、幅と高さをファイル名splash_240x320.bmpなどに置き換えました。私たちは実際に画像を手で生成しました。なぜなら、さまざまなサイズのものがすべてではなく、画像が頻繁に変更されなかったからです。同じスクリプトは、ビルドファイルの生成で使用されたほとんどの値の#defineを含む.hファイルを生成しました。

これはデバイスごとのビルドのためのものです:画像をサイズ変更するだけの一般的なSISファイルもありましたが、基本デバイスイメージ)、およびサイズ変更イメージは、それを少し下に保つための1つの方法でした。私たちはN92、Z8などで画面の回転をサポートするために、アスペクト比を反転すると同じまたは同様の比率にサイズ変更すると良い結果を得られないため、一部の画像のポートレートおよびランドスケープ版が必要でした...]

+0

ねえ、別のモバイル画面の解像度を扱うあなたのアプローチを教えてもらえますか – ardsrk

15

まあ...違いの正確な性質によって異なります。それらを抽象化して特定のクラスに分離することができれば、そのルートに進むことができます。これは、いくつかのクラスのバージョン固有の実装を持つことを意味し、数行だけでなく実装全体を切り替えます。

あなたは

  • MyClass.h
  • MyClass_S60_2nd.cpp
  • MyClass_S60_3rd.cpp

などを持っていると思います。どのCPPファイルをコンパイルするかは、上記の#ifdefsを使用して内部全体をラップするか、さまざまなターゲット用にビルドする際にビルドレベルで(Makefileなどで)どのファイルをインクルードするかによって選択できます。

変更の性質によって、これははるかにクリーンかもしれません。

+1

私のアイデア正確に。行動差をモデル化するための多態性。継承を使用して多態性を実装することができます(この方法はあなたの答えで提案されました)が、集団を使用して、Traitsクラスによって促進されます。 – xtofl

+3

これが最良の方法です。ビルドシステムは、それが意味するものを使用します。 '#ifdef'sは、維持できないコードへのパスです。 –

1

可能であれば、すべてのプラットフォームの共通インターフェイスを定義できます。次に、各プラットフォームのインタフェースを実装します。

プリプロセッサディレクティブを使用して正しい実装を選択してください。

このようにして、プラットフォーム選択ディレクティブをコードのより少ない場所(理想的には、インターフェイスを宣言するヘッダーファイル内の明示的に1か所)に配置することができます。

はこのようなものを意味します。私たちの会社で

commoninterface.h /* declaring the common interface API. Platform identification preprocessor directives might be needed for things like common type definitions */ 
platform1.c /*specific implementation*/ 
platform2.c /*specific implementation*/ 
6

を、我々は、クロスプラットフォームのコード(win32の/ PS3/Xbox用gamedevelopment /など)の多くを書きます。異なるプラットフォーム間で同じインタフェースを持って、プラットフォーム抽象化ライブラリへの

  • エキスplatfrom関連のコードではなく、同じ実装:
    は、私たちが一般的に次のいくつかのトリックを使用して、できるだけ多くのプラットフォーム関連macrosesを回避するために、 ;
  • 異なるプラットフォーム(例: "pipe.h"、 "pipe_common.cpp"、 "pipe_linux.cpp"、 "pipe_win32.cpp"、...)の異なる.cppファイルにコードを分割します。
  • プラットフォーム特有の関数呼び出しを統一するマクロとヘルパー関数を使用します(例: "#define usleep(X)Sleep((X)/ 1000u)")。
  • クロスプラットフォームのサードパーティライブラリを使用します。
+1

提案に非常によく似ていますが、各ビルドに固有のインクルード検索ディレクトリを追加することもできます。#include "sound_constants.h"のようなものは、そのファイルのいくつかの順列の1つを見つけるでしょう。 –

+0

ニースのヒント!私は、異なるコンパイル単位での不一致の構造体宣言(#include ""構文は、すべての追加および標準のインクルードディレクトリの中で最も優先度の高い相対インクルードパスを構築できるようにする)のような低レベルのバグを少し恐れています。しかし、このようなガード:http://www.everfall.com/paste/id.php?xxd85sd9c38g - ヘッダーでは、このような問題を解決することができます... – Rageous

0

いいえ代替案については考えていませんが、できることは異なるバージョンのOSに異なるファイルを含めることです。例えば

#ifdef S60_2nd_ED

#include "graphics2"

#elif S60_3rd_ED

#include "graphics3"

#else

#include "graphics"

1

SQLiteをご覧ください。彼らにも同じ問題があります。それらはプラットフォーム依存のものを別々のファイルに移動し、ファイル内容全体を除外するプリプロセッサディレクティブを持つことによって必要なものだけを効果的にコンパイルします。これは広く使われているアプローチです。

0

Linuxカーネルのアセンブリ定義と同じようなことがあります。各アーキテクチャには独自のディレクトリ(asm-x86など)があります。これらのフォルダはすべて、同じインターフェイスを提示する同じ高レベルのヘッダーファイルをクラスタリングします。カーネルが設定されると、適切なasm-archディレクトリをターゲットにしてasmという名前のリンクが作成されます。このように、すべてのCファイルには次のようなファイルが含まれています。

1

コードに限定されないS60 2nd edアプリケーションと3rd edアプリケーションにはいくつかの違いがあります。アプリケーションリソースファイルが異なります。これらをパックするグラフィック形式とツールは異なります。さまざまな点でmmpファイルは異なります。

私の経験に基づいて、それをあまりにも自動化しようとはしませんが、第2版と第3版用に別々のビルドスクリプトを用意してください。コードレベルでは、共通の抽象APIを持つ独自のクラスとの違いを分離するため、まれにしかフラグを使用しません。

+0

+1。我々は、繰り返しのいくつかを避けるためにPythonでビルドスクリプトを自動生成することに使用しました。基本的に置換と条件文がその大部分を占めました。最近では、Djangoテンプレートが試してみる価値があります。もちろん、ビルドチェーンはperlを使ってそれらをmakeファイルに処理します。私は最終的にコンパイラが関わっていると信じるようになった;-) –

0

#ifを拡散させないようにしてください。

むしろ、ヘッダーファイルで#ifを使用して代替マクロを定義し、コード内で単一のマクロを使用します。

この方法では、コードを少しだけ読みやすくすることができます。

例:

Plop.h 
====== 

#if V1 
#define MAKE_CALL(X,Y) makeCallV1(X,Y) 
#elif V2 
#define MAKE_CALL(X,Y) makeCallV2("Plop",X,222,Y) 
.... 
#endif 


Plop.cpp 
======== 

if (pushPlop) 
{ 
    MAKE_CALL(911,"Help"); 
} 

上記のような機能をactiviateするためにマクロを使用し、その後、独自の機能には、この分割されたバージョン固有のコードを容易にするのに役立ちます。また、独自のクラスでSDKの変更部分をラップして一貫したインターフェイスを提供すると、ラッパークラス内ですべての違いが管理され、作業をよりきちんとしたコードにすることができます。