BCC64X
Clang 拡張 C++ コンパイラ への移動
BCC64X は、64 ビット Windows 用 RAD Studio C++ コンパイラ(モダン)です。
BCC64X は、Clang をベースとしています。 BCC64X コンパイラと他の Clang 拡張 C++ コンパイラとの共通点に関する詳細については、「Clang 拡張 C++ コンパイラ」を参照してください。
目次
一般情報
| フィールド | 値 |
|---|---|
| Clang バージョン | 20.1 |
| LLVM バージョン | 20.1 |
| 呼び出しの規約 | Microsoft x64 |
| 名前修飾(マングリング) | Itanium |
| 標準ライブラリ | LLVM libc++ |
| C++ ランタイム | MinGW-LLVM ベースのカスタマイズ |
| C ランタイム | UCRT |
出力ファイル
| ファイルの種類 | ファイル拡張子 | ファイルの形式 |
|---|---|---|
| 実行可能ファイル | .exe
|
PE64 (PE32+) |
| 共有ライブラリ | .dll
|
PE64 (PE32+) |
| 静的ライブラリ | .lib および lib[name].a
|
オブジェクト ファイルのライブラリ。拡張子に関する詳細については、「自動リンク」を参照してください。 |
| コンパイル済みオブジェクト | .o
|
COFF64 |
| [デバッグ情報] | .pdb
|
PDB |
EXE や DLLs にリンクすることができます。libc++.dll)に、BDS バージョン番号が接尾辞として付くようになりました(libc++-370.dll)。BCC64X の C++ コードの記述
BCC64X の C++ コードを記述するには、次を使用します。
#if defined(__BORLANDC__) && defined(_WIN64) && defined(__MINGW64__)
特定のリリースに集中するには、次のようにチェックを付けます:
#if __clang_major__ == 20.1
#pragma message("Using version 20.1 of Clang")
#endif
詳細については、「「Clang 拡張 C++ コンパイラ」の「定義済みマクロ」を参照してください。
ツールチェーン
Windows 64 ビット Modern C++ ツールチェーン (bcc64x) は、Clang 拡張および C++Builder 機能の完全に新しい実装で、新しいプラットフォーム標準技術を提供します。 LLD リンカ、新しい RTL、その他を備えた新しい Clang ツールチェーンは、弊社によって推奨される C++ ツールチェーンです。
LLVM libc++ STL、カスタム C++ RTL、C ランタイム用の Windows UCRT を使用し、PDB デバッグ情報を含む COFF64 形式のオブジェクト ファイルを出力します。
このツールチェーンを既存の C++ プロジェクトに追加するには、次の手順を実行します:
- プロジェクト ツリービューでターゲット プラットフォーム ノードを右クリックします。
- [プラットフォームを追加]を選択します。
- [Windows 64 ビット(モダン)]を選択します。
_setmaxstdio および _getstdiomax は、UCRT の Microsoft ランタイム関数です。 これらの関数は、Win64x でのみサポートされています。新しい BCC64X コンパイラのテスト方法
RAD Studio には、開発者が新しいツールチェーンが使用されているかどうかを検知するコードを記述する際に、推奨される方法があります。
- 推奨:
今バージョン以降では、マクロテスト _CODEGEARC_ と _clang_major_ >= 20.1 を使用します。 Clang バージョンは時と共に変更されますが、このツールチェーンの現バージョンおよび将来のバージョンにおいて、このコードは真であるため、RAD Studio はこれを推奨します。 これは、ほぼ間違いなくコードに追加したいチェックです。
- この特定のバージョンでは、マクロテスト
_CODEGEARC_と_clang_major_ == 20.1を使用します。 これは、ツールチェーンの初期バージョンを特にテストするためにのみ使用します。 これは、同じツールチェーンの今後のバージョンの検知には失敗します。これが、前者のテストが推奨される理由です。
- 特定の C++ またはコンパイラ/LLVM 機能や組み込み機能をテストするには、マクロ
_has_featureおよび_has_builtinを使用します。これらは、C++Builder に特化したものではなく、複数の Clang ベースのツールチェーンに適用されます。 機能チェック マクロの詳細については、こちらを参照してください。
以下のコード サンプルでは、新しいツールチェーンに対する推奨されるテストが示されています。 これを使用して、特定のヘッダーのインクルードなど、ツールチェーン固有のコードをラッピングします。
#include <iostream>
#include <tchar.h>
int _tmain(int argc, _TCHAR* argv[])
{
#if defined(__CODEGEARC__) && (__clang_major__ >= 20.1)
std::cout << "C++Builder Modern Compiler, 12.1 or newer";
#else
std::cout << "A different compiler";
#endif
}
既存のコードベースを移行するには、このようなマクロ内に新しいツールチェーンの特定のコードを含めると便利です。
パスの調整
コンパイラが正しいパスを見つけられるよう、ライブラリ パスに $(CC_SUFFIX) 変数を必ず追加します。
例:
$(BDSLIB)\$(PLATFORM)$(CC_SUFFIX)\debug;..\..\..\..\..\Public\Documents\Embarcadero\Studio\15.0\Samples\CPP\Mobile Samples\User Interface\KeyboardToolbar\
$CC_SUFFIX 変数は、2 つの Win64 ツールチェーンでの違いを処理します。 新しい bcc64x の末尾には X が付いています。これは、リンク先のファイルの正しいプラットフォームの場所が 'win64x' であることを意味します。 $CC_SUFFIX は、このプラットフォームを使用する場合に X を評価します。
Windows のテスト vs. 特定のツールチェーンのテスト
サードパーティの C++ ソース コードを使用すると、Windows 固有のヘッダーやメソッド定義などが、ツールチェーン (通常は MSVC) をテストするマクロに誤ってラップされていることがあります。 これを解決するには、これらのマクロをツールチェーン テストではなくプラットフォーム テストに置き換えます。
Windows をテストするには、MSVC、<CBuilder> やその他ツールチェーンにかかわらず、_WIN32 または _WIN64 が定義されているかをテストします。 <CBuilder> および MSVC の両者でこれらのマクロが定義されています。 これは、コードが Windows 固有の場合に推奨されます。
プラットフォーム(Windows)テストとツールチェーン テストが混在したコードは、Windows において減ってきているようです。これは RAD Studio のものや mingw-llvm など、他のツールチェーンの利用が増えてきているためです。 しかしながら、サードパーティの C++ ソース コードやライブラリを統合するときには、依然としてよくある問題です。
ドライバ最適化フラグ
COFF バージョン 20.1 ツールチェーンと ELF バージョン 5 を使用して生成されたバイナリの間で結果を比較する際、バイナリ サイズとパフォーマンスに顕著な違いがみられます。
バイナ リサイズとパフォーマンスを最適化するために、緩和可能な再配置最適化を使用します。以下のいずれかのフラグを使用してください:
| コンパイラ | 設定モード | フラグ | 説明 |
|---|---|---|---|
| LLD | リリース | --strip-all
|
リンカによって生成された COFF シンボル テーブルを削除し、より小さなイメージを生成します。
|
| LLD | --gc-sections
|
未使用の入力セクションのガーベッジ コレクションを有効にします。[1] | |
| Clang/CC1 | -fdata-sections
|
各データを独自のセクションに配置します。[1] | |
| Clang/CC1 | -ffunction-sections
|
各関数を独自のセクションに配置します。 [1] | |
| Clang/CC1 | リリース | -vectorize-loops
|
並列実行のために、ループの自動ベクトル化を有効にします。 |
DLL へのリンク
DLL の構築と .def エクスポート ファイルの生成
RAD Studio には、llvm-dlltool.exe が同梱されていますが、これは、弊社の clang ベース bcc64x.exe コンパイラをビルドしている llvm-project の一部です。 .def ファイルを生成するには、tdump.exe ツールを使用することを推奨します。
DLL へ直接リンクする
新しいツールチェーンは、.dll ファイルに直接リンクできます。
-lmydll 関数を使用するか、.dll ファイルのコピーが LIBRARY パス上にある場合には、ライブラリをインポートする必要もなく、#pragma comment(lib, "mydll") を使用することができます。
詳細については、ドキュメント「自動リンク」を参照してください。
リンカに次のパスを追加することにより、コンパイラを介してリンカを手動で呼び出すことができます:
libclang_rt.builtins-x86_64.a
DLL インポート ライブラリを作成する
RAD Studio では .dll に直接リンクできるようになり、インポート ライブラリが必要なくなりました。 この新しい実装は、Win64x プラットフォームに限定されます。
しかしながら、インポート ライブラリは一般的に .dll ファイルをインポートする際に使用されます。最後に .dll ファイルを検索するのとは逆に、リンカはまず最初にライブラリを検索するからです。
ツールチェーンは既存の COFF ライブラリもサポートしていますが、独自のライブラリも作成することができます。
独自のインポート ライブラリ (.lib) ファイルを作成するには、次の手順に従います:
- DLL の定義ファイル(
.def)を取得します。メモ:tdumpツールを使用して、.dllファイルから.defファイルを生成できます。 - tdump ツールで、次のコマンドを実行して
.defファイルを作成します:tdump -def mydll.dll mydll.def
メモ:.defファイルはプレーン テキストですので、そのファイルを開いて、LIBRARY<dllname>.dllが正しい<dllname>で入っていることを確認してください。 - 新しい LLD リンカを使用して、RAD Studio コマンド プロンプトで次のコマンドを実行して、インポート ライブラリを生成します:
ld.lld.exe -m i386pep --out-implib file.lib file.def
IDE は、ビルド時に自動的に DLL インポート ライブラリを作成しますが、コマンド ラインから次のコードのいずれかを実行することで、手動でこれを行うこともできます:
bcc64x -tD -Xlinker --out-implib=dll.lib dll.cpp
または
bcc64x -tD dll.cpp -Wl,--out-implib,dll.lib
並列コンパイル
新しい Win64 ツールチェーンの C++Builder プロジェクトは、デフォルトで、並列ビルドされます。 これにより、次のビルドに比べて bcc64x でのビルドは高速になります:
- --jobs: 古い bcc64 (古い Win64 ツールチェーン)を使用
- CMake & Ninja: 新旧両方の bcc64/x を使用
- Visual C++: (CMake と Ninja の両方と /MP コマンド ライン スイッチを使用)
これは、このプラットフォームを使用しているプロジェクトに対しては、デフォルトでオンになっています。 設定の調整や、それがどのように動作するかについては、以降のドキュメントを参照してください。
理解する
C++Builder プロジェクトの並列コンパイルには、2 つの機能が組み込まれています: batch compilation では、一回に 1 つのファイルに対してコンパイルを起動するのではなく、複数の C++ ファイルを一度にコンパイラに指定し、--jobs では、指定されたファイル群を並列して処理します。
これらにより、コンパイラには数多くのファイルがコンパイルするよう指定でき(batch compilation)、それらを並列でコンパイルするよう指示されます(--jobs)。
なぜこの 2 つか? バッチ コンパイルだけを行う場合、コンパイラ EXE を 1 回呼び出すだけで多数のファイルをコンパイルしますが、コンパイラはそれらのファイルを 1 つずつシリアルに処理します。 --jobs のみを実行した場合、並列システムを使用してコンパイルされますが、1 つのファイルのみとなり、結果として意味のないファイルが 1 つしかない状態になってしまいます。 このため、両方の設定を有効にする必要があります: (a) 多数ファイルを同時に、そして (b) 並列で。
CPU 使用率と共に並列コンパイルの動作を理解する
次では、--jobs によるバッチ コンパイルがどのように動作するか理解の助けになる情報があります。これにより、より高速で、より効果的にコンパイルを、リソース消費とのバランスを取りつつ実行できるよう、ビルド環境の調整を行ってください。
コンパイラ出力
コンパイラ メッセージはインターリーブされません。 並列で実行されますが、全体のファイルの出力メッセージは、それが完了した後に一度に出力されます。
コンパイル エラーがある場合、すべてのコンパイルが停止します。 そのエラーの後には、正常コンパイルのメッセージが表示されるかもしれませんが、それは、並列コンパイルされている他のファイル群が完了するまで続行されるためです。
ビルド システム
'--jobs' 並列ビルド システムは、IDE およびコマンドライン MSBuild から使用できるほか、コマンドライン ‘bcc64x’ から直接使用することもできます。
コマンドライン MSBuild コマンドでビルドする際に、これを CI、ビルド サーバー、などに完全に使用できる点に注意してください。 コンパイラの直接呼び出しに制限されません。デフォルト ビルド システムでは、コマンド ラインから並列でビルドすることができます。
通常通りビルドまたはコンパイルします。並列ビルドはデフォルトで使用されます。 タスク マネージャを開くと、単一の bcc64x プロセスが複数のスレッドを使用し、100% に近い CPU を使用しているのを確認できるはずです。
プロジェクトが並列ビルドを使用しているか確認するには、プロジェクト オプションを開きます:
- Windows 64 ビット Modern プラットフォームが選択され、プロジェクトでアクティブかどうかを確認します。
- プロジェクト オプションに移動します。 ドロップダウンで[すべての設定]を必ず選択します。
- [ビルド|C++ コンパイラ|バッチ コンパイルの有効化]をオンにします。 他のターゲット設定でこれを上書きするものがないか、今一度チェックしてください。高次の継承レベルで、これはデフォルト設定のはずです。
- [プロジェクトのプロパティ|一般|サブプロセスの数]は
0に設定されているはずです。 これは、すべてのコアを使用します。
プロジェクトで msbuild を呼び出します。 IDE のプロジェクト オプションで上記の設定が設定されていれば、並列コンパイルが行われます。
> msbuild MyProject.cbproj
パラメータの全リストについては、「MSBuild コマンドを使用したプロジェクトのビルド」を参照してください。 思い出してください。並列ビルドは IDE でプロジェクトに対して設定します。これらの設定は、コマンド ラインでその同じプロジェクトに対して msbuild を使用するときにも常に使用されます。
コマンドラインを介して直接実装するには、単純に以下を使用します:
> bcc64x a.cpp b.cpp c.cpp --jobs=0 ...other parameters
これらのバッチは(複数のファイルを一度にコンピュータに送る)、並列でのビルドを指示し(jobs)、使用可能なすべてのコアを使用('0' はすべてのコアを意味します)。
CPU 飽和度
[プロジェクト オプション|プロジェクトのプロパティ|一般]タブで、設定[サブプロセスの数]を検索します。デフォルトは ‘0’ です。 これは、利用可能なすべてのコアを使用することを意味します。 これは、あるコアの2倍の数のスレッドを実行します。
ビルド システムが利用可能なリソースのほぼすべてを使用するようにしたいが、完全には使用しないようにしたい場合には、-1 に設定します。 これは、デフォルト ‘0’ よりも 1 少ないコアが使用されます コンパイル中に何かを行い、他のプロセスの速度が低下する場合にのみ、これを使用してください。
任意の正の整数に設定することもできます。 利用可能なコアの数に応じて、この数までのコアが使用されます。 利用可能なコア数よりも多くのコアを使用するように設定した場合は、可能な限り多くのコアが使用されます。
{{{1}}} コマンドライン パラメータを使用する場合、コンパイラを起動するのと同じ値を設定することができます。command line parameter.
推奨値は 0 です(デフォルト)。 これにより CPU は最大限に使用され、ビルドが可能な限り高速化されます。
C++23 のサポート
RAD Studio Florence 13.0 より、Clang-20 ベースの C++Builder コンパイラで、C++23 サポートが導入されています。
新しい Clang ベースのコンパイラでは、C++23 言語標準を強力にサポートしており、libc++ では、多数の C++23 機能が提供されています。 Win64 Modern プラットフォームを使用する際、新しい C++ プロジェクトでは、デフォルトが C++23 になっています。 C++23 で利用できなくなった特定の機能が必要になった場合には、C++ コンパイラの設定で古いバージョンの切り替えることができます([プロジェクト|オプション...|ビルド|C++ コンパイラ])。
特定の C++23 機能に対する clang および libc++ のサポートの詳細については、次のリンクを参照してください:
コンパイラのバージョン間での違い
RAD Studio 12 Athens 以降、C++ Win64 Modern プラットフォーム ツールチェーンは Clang バージョン 20 を使用しています。
このセクションでは、コンパイラのバージョン 15 と 20 との間の違いを説明します。
Modern BCC64X コンパイラ バージョン 20 は、C のコードをコンパイルする際、C99 ルールを厳守しており、警告の代わりにエラーを発生させます。
暗黙的関数
プロトタイプなしで暗黙的に定義された関するを呼び出すと、エラー メッセージが発生します。
例:
int test2()
{
return implicit_function();
}
上記のサンプル コードでは、2 つの異なる出力が生成されています。
バージョン 15 コンパイラ:
Warning W4856 stricter_c.c 10(10): call to undeclared function 'implicit_function'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
バージョン 20 コンパイラ:
Error E5430 stricter_c.c 10(10): call to undeclared function 'implicit_function'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration].
暗黙の int
暗黙の int の呼び出しは、エラー メッセージを発生させます。
例:
test1()
{
return 42;
}
上記のサンプル コードでは、2 つの異なる出力が生成されています。
バージョン 15 コンパイラ:
Warning W4884 stricter_c.c 1(1): type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int].
バージョン 20 コンパイラ:
Error E5464 stricter_c.c 1(1): type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int].
互換性のない関数ポインタ
次は、互換性のない関数ポインタを混在させたコード例です。
例:
int callback(int a, int b) {
return a+b;
}
int call_callback(int (*callback)(int)) {
return callback(5);
}
int test3() {
return call_callback(callback);
}
上記のサンプル コードは、以前のコンパイラを使用すると警告を発生させましたが、現在のモダン コンパイラの使用では、エラー メッセージが生成されます。
バージョン 15 コンパイラ:
Warning W4971 stricter_c.c 23(24): incompatible function pointer types passing 'int (int, int)' to parameter of type 'int (*)(int)' [-Wincompatible-function-pointer-types]
バージョン 20 コンパイラ:
Error E5558 stricter_c.c 23(24): incompatible function pointer types passing 'int (int, int)' to parameter of type 'int (*)(int)' [-Wincompatible-function-pointer-types]
既知の問題
Delphi プロジェクトを使用して WIN64X に対して作成されたパッケージのコンポーネントは、まずプラットフォームに対して有効化しなければなりません。 Windows 64 ビット(Modern)プラットフォームでコンポーネントを有効化するには、「C++ 用 Delphi パッケージのビルド」の手順を参照してください。
詳細については、ComponentPlatformsAttribute を参照してください。