こちらのブログの最近のコメントで、C++BuilderのClangプロジェクトがvcle.libをリンクしているケースがあり、Clangのライブラリパス内にvcle.libというファイルが存在しないという質問をお客様からいただきました。
C++Builderの32ビット C++コンパイラには2種類あります。
- Clangコンパイラ(bcc32c)
- ライブラリパス: lib/win32c/release
- クラシックコンパイラ(bcc32)
- ライブラリパス: lib/win32/release
vcle.libは、クラシックコンパイラのライブラリパス(lib/win32/release)にのみ存在します。
このブログでは、この理由やエラーが表示された場合の解決策について解説いたします。
C++Builderを初めて使用する方のために簡単に紹介いたしますと「クラシック」とは、C++Builderの古いバージョンから使用されている従来のBorlandコンパイラのことを指します。
C++Builderでは現在の最新バージョン(11.2)も含めて引き続き、クラシックコンパイラを提供していますが、最近では、Clangベースの多くの拡張機能を備えたモダンなC++コンパイラを使用することを強く推奨しています。
エンバカデロでは、コンパイラを切り替えて微調整するだけでC++プロジェクトを再構築できるように多くの改善が行われてきました。その結果、C++Builderのバージョンアップを重ねるごとにクラシックとClangコンパイラで互換性を保てるようになっていますが、まだ問題が発生することがあります。今回お客様からいただいたコメントがこのブログを作成する良いキッカケとなりました。
C++Builderを使用している場合、RTL を理解するためにこのブログ情報が興味深い内容になるかもしれません。あるいは、もしプロジェクトをクラシックコンパイラから Clang コンパイラへ置き換える際に同様の問題が発生した場合、このブログの情報がおそらく問題を解決する助けになるでしょう。
問題の解決方法を説明する前に、まずはC++Builderがリンクするライブラリについて掘り下げましょう。
Table of Contents
vcleとrtleについて
vcle.libは、古いバージョンから存在するDelphi / C++のブリッジコードを含むライブラリで、この中には、Delphi クラスの C++ 実装も含まれています。
もっとも典型的な例としては、ShortString、AnsiString、WideString、UnicodeString/StringなどDelphiの文字列クラスで、C++Builderから使用するためにC++で実装され、Delphi文字列の動作やバイナリ配置に互換性を持たせるため、内包的にブリッジしています。
これらのヘッダは*string.hファイル(例えば、ustring.h)で確認できます。VCLやFMXのヘッダをインクルードすると、これらのヘッダも自動的に挿入されるので、手動でインクルードする必要はありません。
クラシックコンパイラが利用されている時代では、Win32が唯一のプラットフォームで、UIフレームワークもVCLだけでした。ブリッジライブラリはそれに基づいて「vcle」と名付けられました。しかし、最近のClangコンパイラでは、複数のプラットフォームと複数のUIフレームワークに対応しています。
vcleというブリッジライブラリは、いわば特定のUIフレームワークに依存していた古い時代の名残であり、Clangコンパイラでは、ブリッジライブラリはvcleではなく、低レベルかつ共通ライブラリ(RTL)の役割をもつrtle.lib (Win32) と rtle.a (Win64) という名前に変更されています。
言い換えれば、Clangプロジェクトでは決してvcle.libをリンクしてはいけません。rtle.lib/.a.にのみリンクする必要があります。
なぜClangプロジェクトはクラシックライブラリをリンクするのか?
Clangでコンパイルされたプロジェクトがvcle.libをリンクしようとする最も可能性の高い原因は、プロジェクトが複数のオブジェクトファイル、またはクラシックコンパイラでビルドされたライブラリをリンクしていて、それらのコンパイルされたオブジェクトファイルがvcleを呼び込む原因になっていることです。
同じプロジェクト内で、クラシックコンパイラ/Clangコンパイラで作成されたオブジェクトファイルを混在させないことが非常に重要です。この問題は別として、両者はバイナリとして互換性がありません。すべてClangコンパイラでビルドしてください。
問題を解決するための方法として、例えば、以下のいずれかの手段が考えられます。
- tdumpユーティリティを使用して、リンカがvcle.libのライブラリを探す原因を特定します。プロジェクトにリンクされているオブジェクトとライブラリに対して tdump を実行してください。
- コンパイラにビルトインされているclang/classic 非互換性自動検出の機能を使いましょう! C++Buider 10.3.3以降では、classicビルドとclangビルドのオブジェクトファイルが一緒にリンクされているかどうかを検出するリンカの警告が追加されました。こちらのブログでは、C++BuilderのリンカでClassicオブジェクトとClangオブジェクトを混在してリンクさせたときに、リンカまたはランタイムエラーを回避するために役立つ情報が解説されています。
他の原因として考えられるのは、何らかの歴史的な理由によるもので
- vcle.libをプロジェクトに手動で追加(ブロジェクトビューでライブラリを検索可能)
- リンクするライブラリのプロジェクトの設定
- お客様のコード内に#pragma comment(lib, …)を定義してvcle.libを追加
など
もし上記に該当しているものがあれば、プロジェクトあるいはコードから全て削除してください。
こういった問題が発生した場合は、根本的な原因を調査することが重要です。つまり、プロジェクトが古いライブラリをリンクしようとしている理由を理解し、それを修正するプロセスが非常に大切です。
RTLE.libを正しくリンクする
ここまでの説明で、クラシックコンパイラ向けのvcle.libがClangコンパイラ向けのrtle.libに置き換わっている背景についてご理解いただけたと思います。ということはClangプロジェクトをアップグレードする際、Clangのプロジェクト設定にrtle.libを手動で追加すれば良いと考えるかもしれませんが・・それは間違いです。
まず、このライブラリは自動リンクされます。つまりヘッダーに#pragma commentによって、正しいものがリンクされます。
つまり、vcle/rtle.libの正しいライブラリが自動的にリンクされます。リンカが間違ったファイルを参照している場合、その理由を特定(上記の「なぜClangプロジェクトはクラシックライブラリをリンクするのか?」セクションを参照)し、修正してください。
次に、vcle/rtleはDelphi ランタイムに依存しているため、vcle/rtle 自体のコードをリンクするだけでなく、適切なスタートアップコードをアプリケーションで使用するためにもリンクする必要があります。Delphiランタイムをリンクすることで、Systemユニットが正しく初期化されます。 Delphi ランタイムが C++ アプリケーションにリンクされている場合、TLS 管理などの一部の動作は C++ 実装に委ねられます。
下図は、rtle/vcleのどちらかを明示的にリンクするために有効にすべきオプション設定の画面です。
注意点としては、このオプションはvcle.libをclangベースのプロジェクトに追加しないことです。rtle.libはclangベースのプロジェクトに追加されます。clangベースのプロジェクトがvcle.libを要求する場合、その根本原因を調査する必要があります。解決策は、リンカにライブラリを手動で指定することではありません。
まとめ
Clangプロジェクトをビルドした際、vcle.libが必要になっているケースでの正しい対処方法は、以下の通りです。
- 間違ったライブラリがリンクされる原因が見つかった場合は、それを修正してください。おそらく、異なるコンパイラでビルドされたオブジェクトの混合、プロジェクトの設定、またはプロジェクトのソースでの手動リンクが考えられます。
- プロジェクトオプション > ビルド > C++ リンカ > “Delphi ランタイムライブラリとリンクする “がオンになっていることを確認する
- vcle.lib/rtle.lib どちらのライブラリも手動でリンクしないでください。システムヘッダを使用することで、正しいライブラリが適切にリンクされます。
Design. Code. Compile. Deploy.
Start Free Trial Upgrade Today
Free Delphi Community Edition Free C++Builder Community Edition