高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

Technote 1133

Version Territory

目次

バージョン番号の内容

アップルのバージョン番号の方式

バージョン番号の比較

'vers' リソースの構造体

ダウンロード

Finder 6.1 でバージョン ('vers') リソースが導入され、ファイルの作成者がファイルのバージョンならびにそのファイルを含むファイル群のバージョンを指定することができるようになりました。このリソースの形式は『Inside Macintosh: Macintosh Toolbox Essentials』に説明されています。

この TECHNOTE (オリジナルは「TECHNOTE OV 12 - Version Territory」) では、バージョン・リソース内で使用される NumVersion 構造体のデータ形式について説明し、アップルで採用しているバージョン番号の付け方に基づいてバージョン・リソースを使用するガイドラインを提供します。

どんな種類であれ、プログラム・ファイルを外部に配布する Mac OS プログラマは、必ずファイルにバージョン・リソースを付けてください。

バージョン番号の内容

バージョン・リソースの構造は『Inside Macintosh』に説明されていますが、NumVersion 構造体のフィールドすべてのデータ形式が明確に説明されているわけではありません。NumVersion 構造体はバージョン・リソース内の numericVersion フィールドのデータタイプです。Universal Interfaces 3 の MacTypes.h 内のコメントもあまり役に立ちません。numericVersion 構造体のフィールドの内容について異なる解釈を生じさせる可能性があるからです。

NumVersion 構造体の中には 4 つの UInt8 の値が定義されています。このため、バージョン番号の比較の際、NumVersion の値を構造体として扱い個々のフィールドにアクセスすることも、符号なし整数 (unsigned long) にキャストすることもできます。バージョン番号を unsigned long の値として比較する際には、気をつけなければならない問題があります。

majorRev と minorAndBugRev フィールドの値は各桁が 0〜9 の値を取る 2 進化 10 進数 (binary-coded decimal/BCD) 形式で保存されます (通常の 2 進数の範囲は 0〜15 です)。majorRev フィールドの内容は「メジャーな改訂レベル」を表す 2 桁の BCD です。minorAndBugRev フィールドの内容は、それぞれ 1 桁の BCD として保存された 2 つの値で、それぞれ「マイナーな改訂レベル」と「バグ改訂レベル」を表します。つまり、バージョン番号の取り得る範囲は 0.0.0 から 99.9.9 ということです。

nonRelRev フィールドの値は符号なしの 2 進整数の値として保存されます。つまり nonRelRev フィールドの範囲は 0 から 255 になります。これが、いちばん間違えて解釈されるフィールドです。つまり、2 進数としてではなく、BCD の値と解釈されてしまうのです。

 

nonRelRev を BCD として解釈することで引き起こされる問題について

バージョン・リソースを一貫して同じ方法で作成する限り、BCD 値を使うことで生じる違いは、利用可能な nonRelRev 値が少なくなるということだけです。例えば、BCD の場合は 100 まで、2 進数の場合は 256 までです。ここでは一貫性が重要です。BCD 値と 2 進値は、たとえ表現する値が同じでも、比較すると同じにならないからです。例えば、改訂レベルの 10 は、BCD では 0x10、2 進数では 0x0A になります。

バージョン番号の比較はたいていの場合、numericVersion フィールドをまず unsigned long にキャストしてから行われるため、バージョン・リソースの nonRelRev フィールドが BCD として作成されていても、また 2 進数で表現されていても、同じく一貫した方法で作成されているかぎりは、比較に影響は与えません。

nonRelRev を BCD として解釈するアプリケーションは存在します。有名なものでは ResEdit がそうです。Resorcerer はバージョン 2.0 で nonRelRev フィールドを符号なしの 2 進数として正しく解釈するよう変更されました。


アップルのバージョン番号の方式

アップルは一定の方式でソフトウェア製品にバージョン番号を付けています。皆さんもこれを見習ってみてはいかがでしょう。表 1 はこの方式をまとめたもので、3 つの数字を使い、それぞれをピリオドで区切ります。

改定項目

バージョン

最初のリリース

1.0

マイナーな改訂

1.1

バグフィックス

1.1.1

最初のメジャーな改訂

2.0

Table 1-アップルのバージョン番号の付け方

メジャーな改訂のリリースでは最初の数字を、マイナーな改訂のリリースでは 2 つめの数字を、バグを修正したバージョンのリリースでは 3 つめの数字を増やすことに注目してください。

製品の開発過程では、アップルは開発段階 (stage) を示す英字を最後に付ける方式を採用しています。表 2 はその例を表します。

改定項目

バージョン

段階

最初のバージョン

1.0d1, 1.0d2, ...

development

製品機能を決定 (テスト開始)

1.0a1, 1.0a2, ...

alpha

製品が安定 (最終テスト開始)

1.0b1, 1.0b2, ...

beta

最終候補/FC (出荷開始直前)

1.0fc1, 1.0fc2, ...

final

最初の改訂版を出荷/GM

1.0

final

マイナーな改訂

1.1d1,...,1.1a1,...,1.1b1,...,1.1

バグフィックス

1.1.1d1,...,1.1.1a1,...,1.1.1b1,...,1.1.1

メジャーな改訂

2.0d1,...,2.0a1,...,2.0b1,...,2.0

Table 2-開発過程のバージョン番号

バージョン番号の比較

バージョン番号を unsigned long にキャストして比較すると、問題が起こる場合があります。この方法で比較を行うと、最初の出荷バージョン (Golden Master/GM) が最終候補 (Final Candidate/FC) の番号よりも古いという結果になってしまうのです。

GM リリースのバージョンリソースは、開発段階 (stage) フィールドが「ファイナル」を表すコードに設定され、nonRelRev フィールドはゼロに設定されます。FC リリースのバージョン・リソースはたいてい、開発段階フィールドは「ファイナル」に設定され、nonRelRev フィールドはゼロよりも大きい値になっています。ここでの問題はバージョン番号を unsigned long にキャストすると、FC バージョンのバージョン・リソースの nonRelRev フィールドがゼロでないため、実際には一番新しいバージョンであるはずの GM バージョンよりも大きくなってしまう、すなわち新しいという比較結果になってしまうことです。

これまでよく起こった問題は、同じ製品の最終候補バージョンがすでにインストールされているところに出荷バージョンのパッケージを上書きインストールできないというものでした。インストーラが、新しいバージョンのファイルを置き換えようとしている、という警告を出すのです。もちろんそうではありません。アップルのインストーラ (および他の大半のインストーラ) は、バージョン・リソースの個々のフィールドを比較することでこの問題を回避しています。

次の関数は 2 つの NumVersion の値を正しく比較しています。

pascal SInt16 CompareVersions( NumVersion *vers1, NumVersion *vers2 )
{
    UInt16 nonRelRev1, nonRelRev2;
         
    if (vers1->majorRev        > vers2->majorRev)        return  1;
    if (vers1->majorRev        < vers2->majorRev)        return -1;
    if (vers1->minorAndBugRev  > vers2->minorAndBugRev)  return  1;
    if (vers1->minorAndBugRev  < vers2->minorAndBugRev)  return -1;
    if (vers1->stage           > vers2->stage)           return  1;
    if (vers1->stage           < vers2->stage)           return -1;
         
    nonRelRev1 = vers1->nonRelRev;
    nonRelRev2 = vers2->nonRelRev;
         
    if (vers1->stage == finalStage) {
        if (vers1->nonRelRev == 0)             nonRelRev1 = 0xFFFF;
        if (vers2->nonRelRev == 0)             nonRelRev2 = 0xFFFF;
    }
         
    if (nonRelRev1 > nonRelRev2)                         return  1;
    if (nonRelRev1 < nonRelRev2)                         return -1;
         
    return 0;
}
         

'vers' リソースの構造体

'vers' リソースの構造体は、MacTypes.h (Universal Interfaces 3.1 に入っています) に次のように定義されています。

type 'vers' {
    hex byte;                       /* メジャーな改訂 - BCD */
    hex byte;                       /* マイナーな改訂 - BCD */
    hex byte    development = 0x20, /* リリース段階         */
                alpha = 0x40,
                beta = 0x60,
                final = 0x80, /* または */ release = 0x80;
    hex byte;                       /* 出荷前のリリース番号  */
    integer;                        /* リージョンコード      */
    pstring;                        /* 短いバージョン番号    */
    pstring;                        /* 長いバージョン番号    */
};

これに対応する VersRec 構造体は、MacTypes.h (Universal Interfaces 3.1 に入っています) に次のように定義されています。

struct VersRec {
                                 /* 'vers' リソース形式 */
    NumVersion  numericVersion;  /* エンコードされたバージョン番号 */
    short       countryCode;     /* Int'l ユーティリティの国コード */
    Str255      shortVersion;    /* バージョン番号文字列 - 最悪の場合 */
    Str255      reserved;        /* パックされた longMessage 文字列
                                    shortVersion に続く */
};
typedef struct VersRec           VersRec;
typedef VersRec *                VersRecPtr;
typedef VersRecPtr *             VersRecHndl;

NumVersion 構造体は、MacTypes.h (Universal Interfaces 3.1 に入っています) に次のように定義されています。

struct NumVersion {
               /* 'vers' リソースの数値部分 */
    UInt8      majorRev;       /* バージョン番号の最初の部分 - BCD */
    UInt8      minorAndBugRev; /* バージョン番号の第 2、第 3 の部分 - BCD
                                  バイトを共有 */
    UInt8      stage;          /* 段階コード:
                                  dev, alpha, beta, final */
    UInt8      nonRelRev;      /* 出荷前のリリースレベル */
};
typedef struct NumVersion      NumVersion;
         

NumVersionVariant タイプの構造体は、MacTypes.h (Universal Interfaces 3.1 に入っています) に次のように定義されています。

union NumVersionVariant {
                 /* NumVersionVariant は NumVersion を 32 ビット値としてアクセス
                    できるようにするラッパー */
    NumVersion       parts;
    unsigned long    whole;
};
typedef union NumVersionVariant NumVersionVariant;
         

サードパーティのサイトや製品についての記述は情報提供の目的でのみ行っており、支持や推薦を行うものではありません。アップルはここで取り上げたベンダーや製品の選択、性能、用途について一切の責任を負いません。

参考文献


ダウンロード

Acrobat version of Inside Macintosh: Macintosh Toolbox Essentials

Universal Interfaces 3.1


改版履歴

  • 1988 年 4 月、初版書き下ろし
  • 1990 年 10 月、「Technote OV 12 -- Version Territory to reflect the changes in MPW C 3.1」として改訂
  • 1998 年 6 月、NumVersion 構造体の用途を明確にするため更新

更新日: 1998年 6 月 1 日