Technote 1133
Version Territory
|
 
バージョン番号の内容
バージョン・リソースの構造は『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;
|
|
サードパーティのサイトや製品についての記述は情報提供の目的でのみ行っており、支持や推薦を行うものではありません。アップルはここで取り上げたベンダーや製品の選択、性能、用途について一切の責任を負いません。
|
参考文献
ダウンロード
改版履歴
- 1988 年 4 月、初版書き下ろし
- 1990 年 10 月、「Technote OV 12 -- Version
Territory to reflect the changes in MPW C 3.1」として改訂
- 1998 年 6 月、NumVersion 構造体の用途を明確にするため更新
|

更新日: 1998年 6 月 1 日
|