既存の C++ プロジェクトを 64 ビット Windows にアップグレードする
C++Builder 64 ビット Windows アプリケーションの開発 への移動
BCC32 ベースの既存プロジェクトは、BCC64 で正常にコンパイルできるように、あるいは両方のプラットフォームで同時に同じコードベースを使用できるように、更新する必要があります。 これらのプロジェクト関連およびツール関連の相違点に加えて、BCC64 はより厳密なコンパイラでもあることに注意してください。
目次
オブジェクト ファイルとライブラリ ファイルの形式
- BCC32 とその関連ツールでは、
.obj
ファイルと.lib
ファイルで OMF を使用します。 - BCC64 では、
.o
ファイルと.a
ファイルで ELF を使用します。 - BCC64X は、COFF をファイル
.o
および.lib
に対して使用します。 - BCC64X は、PDB をデバッグ情報に対して使用します。
可能な限り、オブジェクト ファイルやライブラリ ファイルの拡張子は削除し、各ツールが適切な拡張子を使用できるようにします。必要な場合には、バージョン検知による条件分けを行い、拡張子を変更します(カスタム スクリプトと同様に)。
新しい Win64 Modern ツールチェーンにおける自動リンクに関する推奨方式については、ドキュメントを参照してください。
#pragma link
#pragma link
文で指定されたファイルに拡張子が付いている場合は、それらの拡張子を取り除く必要があります。 各コンパイラにより、適切な拡張子が付加されます。
たとえば、次のような文を使用しているコントロール パネル アプリケーションは、
#pragma link "Ctlpanel.obj"
以下のように更新する必要があります。
#pragma link "Ctlpanel"
詳細については、#pragma リンク を参照してください。
#pragma comment
ライブラリの場合、#pragma comment(lib ..)
を使うと最も良く、次のようになります:
#pragma comment(lib, "library-name") // Looks for library-name.lib in WIN32 and library-name.a in WIN64
#include <windows.h>
Windows API を使用するアプリケーションでは、以下の文を明示的に含める必要があります。
#include <windows.h>
BCC32 では windows.h のインクルードは必須ではありませんが、BCC64 では windows.h が必須で、#include についてより厳密な扱いがなされます。
さらなる情報については、「#include」を参照してください。
NO_STRICT マクロ
NO_STRICT の型チェック方式は BCC64 ではサポートされていません。 使用している既存のプロジェクトがある場合には、それを削除しなければなりません。
詳細については、「C++ アプリケーションでの厳密な型チェックの使用」を参照してください。
WebBroker プロジェクトの更新
#pragma link
を上記のように変更します。
bcc64x(Windows 64 ビット(Modern))へのアップグレード
従来の以前の Clang コンパイラと新しいコンパイラ間には、主な違いがあります。
Windows 64 ビット(Modern)ツールチェーンは、以前の Clang ベースのツールチェーンとはいくつか顕著な違いがあります。
従来の RTL メソッド
C RTL
新しいツールチェーンでは、組み込み Windows システム コンポーネントである Universal C ランタイムを使用することで、C ランタイム ライブラリを提供しています。つまり、すべての C RTL メソッドおよびオプションの Microsoft スタイルの拡張機能が標準装備されています。
POSIX スタイル関数(例:itoa vs _itoa)
以前の Windows ツールチェーンは POSIX スタイル メソッド(itoa など)を含んでいました。これらのメソッドとネーミングは非標準であり(itoa は標準の一部ではありません)、非標準メソッドを追加する正しい方法は、それらの接頭辞にアンダースコアを付けます。このプラットフォームでは、変換関数(itoa など)は、`_`
付きの名前(`_itoa`
)で提供されています。これが、`stdlib.h`
など、RTL/標準のヘッダーにある関数に対する正しい規則です。
Turbo C
以前の Windows ツールチェーンには、Turbo C または Turbo C++ のランタイム ライブラリに由来し、C++ が標準化される前、あるいはC99より前の時代に遡る、非標準の RTL メソッドが含まれていました。これらは現在含まれていません。
C および C++ 標準では、同等の機能を直接提供する、または提供するために使用できるメソッドが追加されているため、それぞれのメソッドは簡単に置き換えることができます。たとえば、Trubo C に由来する古い random()
メソッドは、次のコードを使用して置き換えることができます:
rand()
(C の場合)std::rand()
(C++ の場合)
場合によりますが、範囲内に収めるためにモジュロ演算子 %
を使用する場合もあります。
_import および _export キーワード
_import
および _export
キーワードは存在しません。
代わりに __declspec(dllimport)
および __declspec(dllexport)
を使用するか、古いキーワードをこれらの declspecs にマッピングするマクロを定義してください。
ユニットの初期化
ユニットの初期化とは、アプリケーションの起動時に異なるトランスレーション ユニットでグローバルが作成/初期化される順序(およびプログラムの終了時に破棄される順序)、または、このトランスレーション ユニットでの起動/シャットダウン時に実行される前に他のユニットで行われるグローバルまたはその他の初期化に依存するコードです。
以前の C++ ツールチェーンでは、特に Delphi 由来のユニットにリンクする場合に、正しいユニット初期化順序を取得するために依存関係を計算する際に微妙な問題がありました。
Windows 64 ビット(Modern)プラットフォームの新しいリンカと RTL は、かつてモバイルで使用されていたアプローチを反映して、Windows 上のユニットを初期化するために init レコードを使用します。
サードパーティ コンポーネントの開発者の場合: 一部のユニットは {$HPPEMIT LINKUNIT}
で参照されており、Vcl.Styles で見られるような 自動リンク pragma を生成します。このメソッドがなければ、初期化は失敗し、VCL *.vsf
スタイルの動的読み込みが、動作しなくなります。
BCC64X については、ドキュメント ページ「C++ の新しいツールチェーンのユニットの初期化と終了処理」を参照してください。
クラッシュを回避するための警告の修正
Clang と LLVM の新しいバージョンでは、より多くのコンパイラ最適化を適用しようとしており、多くの場合、未定義の動作に対してより厳格になります。
よくある未定義の動作の一つに、初期化されていない変数が残ってしまうというものがあります。過去のリリースでは、たとえ偶然であっても、多くの場合「正常に動作」していました。リリース モードでは、Clang はトラップ命令を残し、初期化されていない変数が存在する場合、ランタイム エラーを発生させるようになりました。詳しくはトラブルシューティングのページをご覧ください。
アップグレードするときは、-Wall(すべての有用な警告をオンにする)を使用してビルドし、それらを解決することをお勧めします。
異なるメモリマネージャ
過去のツールチェーンでは、C++Builder はメモリ マネージャとして FastMM のバージョンを提供していました。
新しいツールチェーンでは、C++Builder は Windows システム コンポーネントである Universal C Runtime(UCRT)を使用します。これはメモリマネージャを提供しますが、これをフックして別のメモリマネージャに置き換えることはできません。つまり、新しいツールチェーンでビルドされたすべての C++ アプリケーションは、VCL や FMX アプリケーションと同様、Delphi ランタイムにリンクする場合も含め、このメモリマネージャを使用します。
FastMM とは異なり、解放されたメモリも 0x80 バイトで埋められます。これにより、解放後使用の問題がより顕著になる場合があります。詳細については、「トラブルシューティング」のページを参照してください。
std::make_shared<>()
メソッドは、Delphi スタイル クラスでは使用できません(Delphi で定義されているもの、または、C++ で定義されているが Delphi クラスを継承しているもの)。これは、Delphi スタイルのクラスが新しい配置をサポートしていないためです。
これらの型では、new() で作成して shared_ptr を使用できます。
std::make_unique<>
は、すべての想定される型で利用可能です。
バイナリから出力されるシンボル
EXE または DLL をビルドすると、バイナリは Package 属性でマークされた RTTI データまたはグローバル変数をエクスポートします。
DLL からのシンボルのエクスポート
DLL をビルドする際、__declspec(export) でマークされたシンボルがない場合、すべてのシンボルがエクスポートされます。これは期待してない動作の場合もあるでしょう。
これを解決するには、少なくとも 1 つのシンボル(ダミー メソッドを作っても構いません)に __declspec(export) がマークされているようにします。1 つ以上のシンボルに declspec がマークされている場合、その declspec のついたシンボルのみがエクスポートされます(上記の通り、RTTI とグローバルには注意してください)。
リンカ フラグ、-Xlinker -exclude-all-symbols
を使用することもできます。
関連項目
- C++ の新しいツールチェーンのパッケージ
- C++ の新しいツールチェーンのパッケージのインポートとエクスポート
- C++ の新しいツールチェーンのユニット初期化と終了処理
- C++Builder 64 ビット Windows 版の相違点
- より厳密な C++ コンパイラ(Clang 拡張 C++ コンパイラ)
- C++Builder 64 ビット Windows アプリケーションのデバッグ
- BCC64.EXE - C++ 64 ビット Windows コンパイラ
- 64 ビット Windows クロスプラットフォーム アプリケーション(Delphi および C++)
- #if、#elif、#else、#endif