Solving an interesting issue upgrading a project from Classic to Clang.
A recent blog comment asked for help where a Clang project was linking to vcle.lib, but the library did not exist in the Clang linking path (lib/win32c/release): it’s present only for the classic compiler in lib/win32/release. (Note the C in win32c, meaning Clang.) Why? If you see this error, how do you resolve it and continue?
(For those new to C++Builder, ‘classic’ refers to the original old or legacy C++ compiler C++Builder used to use. We still ship it, but these days we strongly encourage everyone to use our default modern compiler, which is based on Clang but with many enhancements. We have good compatibility, with lots of work to ensure you can simply switch compilers and rebuild with minor tweaks at worst, but sometimes people encounter issues. The blog comment that prompted this post was one of them.)
If you use C++Builder you might find this post interesting for insight into our RTL, or if you encounter this issue when upgrading a project from the classic to Clang compilers, this post should help you resolve that issue.
Let’s dig in to what this library is first, before answering how to solve the issue.
Table of Contents
vcle and rtle
vcle.lib was and still is a library that contains Delphi / C++ bridging code. Some of this also includes C++ implementations of Delphi classes: the typical examples are Delphi strings, where ShortString, AnsiString, WideString and UnicodeString/String are implemented in C++ when you use them from C++Builder, having compatible behaviour and binary layout to a Delphi string, so invisibly bridged. (You can see these in the *string.h files, eg ustring.h. There’s no need to include these headers manually since including VCL or FMX headers brings them in.)
Back in the days of the classic compiler, Win32 was the only platform and VCL was the only UI framework. The compatibility bridge library was named “vcle” based on that. But these days, with the Clang compiler, we have multiple platforms and multiple UI frameworks. The bridging is not really to do with any UI framework: it is low level, basic classes, and so is a RTL issue. Thus, for Clang, the same library has the name rtle.lib (Win32) and rtle.a (Win64.)
In other words, a Clang project should never link to vcle.lib. It should only ever link to rtle.lib/.a.
Why would a Clang project link to the Classic library?
The most likely cause for a Clang-compiled project to try to link to vcle.lib is that the project is linking in some object files or a library built with the classic compiler, and those classic-compiled object files are causing vcle to be brought in. It is very important that you don’t mix object files created with both compilers together in the same app. Entirely aside from this issue, they are not binary compatible. Build everything with Clang.
To resolve this:
- Use tdump to identify what’s causing the linker to look for that library. Run tdump on the objects and libraries being linked into your project. Or…
- Use our inbuilt clang/classic incompatibility autodetection! A couple of years ago in version 10.3.3 we added a linker warning that detects if classic-built and clang-built object files are being linked together. That post has full information on why it’s a bad idea (possibly link-time errors, but the bad scenario is apparently random runtime instability in your app) and the information the linker provides to let you resolve this. It provides full diagnostic info.
Another possible cause is that, for some historical reason, vcle.lib was manually added to the project (look for a library in the Projects view), the project settings for libraries to link in, or added to your code (via a #pragma comment(lib, …) or similar: find this by searching your code for “vcle”.). If so, just delete it.
If you see this issue, it’s important you investigate the root cause. Resolve that – that is, understand and fix why the project is trying to link the old library – before continuing.
Linking RTLE.lib correctly
Understanding that what was vcle.lib for classic is now rtle.lib for Clang, it might be natural to add rtle.lib to your Clang C++ project settings when you upgrade a project to Clang. This would be a mistake.
First, this glue library is auto-linked: that is, our headers emit a pragma causing the right one to be linked in:
That is, the right one of vcle/rtle.lib will be linked in automatically. If you see the wrong one being looked for by the linker, you must identify why (see the ‘Why would…’ section above) and fix it before going further.
Second, vcle/rtle depend on the Delphi runtime, and that needs to be linked in not only for the code in vcle/rtle itself to link, but also for the right startup code to be used in your application. Linking the Delphi runtime initialises the System unit correctly. When the Delphi runtime is linked into a C++ application, some behaviour, like TLS management, is deferred to the C++ implementation.
It’s important to note that this option will not add vcle.lib to a clang-based project. It will add rtle.lib to a clang-based project. This returns to the point made above: if a clang-based project asks for vcle.lib, the root cause must be investigated. The solution is not to give the linker the library manually.
If your Clang project is trying to link to vcle.lib, the right thing to do is:
- Find and fix whatever is causing the wrong library to be linked: most likely mixing objects built with different compilers, a project setting, or manually linking in the project source.
- Ensure Project Options > Building > C++ Linker > “Link with the Delphi Runtime Library” is turned on
- Do not manually link either library. Using the system headers will ensure one of them is linked.
Many thanks to our engineers Lee and Bruneau for their input on this post.