This blog post is based on a pre-release version of the RAD Studio software and it has been written with specific permission by Embarcadero. No feature is committed until the product GA release.
RAD Studio 12 is just around the corner, and we have exciting news to share!
In August, we ran an unusual webinar where we shared a behind-the-scenes look at some technology we’ve been working on for C++Builder and the C++ side of RAD Studio. One of the things we previewed was an upgraded Clang-based Win64 compiler – though not just an upgrade but some major technological improvements to core areas, with a new STL, a new linker, and more. It is a thorough rework of the entire toolchain with a strong eye to making the right decisions for quality and longevity.
Table of Contents
New Clang
The C++ compiler is foundational to RAD Studio. Through the Clang & LLVM work, we make LLVM available to Delphi. And, of course, we need a modern, powerful C++ compiler to provide our C++ developers with the best source compatibility, libraries, app performance, and more.
Our goals for the work are:
- Very high quality. A robust STL. A linker that can handle anything and any quantity you give it.
- Excellent quality in all areas, such as exception handling
- Excellent language standards compatibility.
- High performance for the compiled code. Optimised runtimes.
- Match platform standards as much as possible
How are we meeting those? Let’s go in reverse order.
Platform standards
The new toolchain is based on Clang 15*. The previous toolchain used the ELF object file format, a primarily Unix/Linux format, for historical reasons that are actually (long story) related to Kylix. For this toolchain, we are moving to COFF, which is the standard object file format for Windows compilers of any compiled language. Similarly, we are using the PDB debug format, which again is the standard. While we are not officially supporting any third party tools, there are many tools developers use which understand COFF & PDB and we hope that by adhering to the platform norms, we open up the opportunity to use a wide variety of tools with your apps and C++Builder.
[*] Clang 15 was current when this work started, and we are avoiding changing the wheels while the car is in motion. We plan to remain up to date and move forward with Clang itself in future.
High performance for the compiled code.
While we are aiming for correct compiled code behaviour above all else, we are also aiming for high performance. The new toolchain’s technology generates more optimized code, and allows additional optimisations that were not previously possible in future.
Optimised runtimes
A C++ toolchain has multiple layers: a C runtime (providing things like printing to a console or file IO), a C++ runtime (providing things like exception handling), and the STL (providing C++ library functions like standard IO, algorithms, collections, etc.) For our toolchain, we are replacing all three.
![| Embarcadero RAD Studio Delphi C++Builder Blogs Image showing three layers of the C++ runtime standard library C++ RTL and C RTL](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2023/10/DALLE-and-DM-C-Layers-4518001.png?resize=750%2C480&ssl=1)
Image showing three layers of the C++ runtime: standard library, C++ RTL, and C RTL. Image by DALL-E and David Millington
The C level runtime is using the Universal C Runtime (UCRT), a Windows component. It’s highly optimised and, echoing the platform standards, is part of Windows itself. It can also be installed on Windows 8, 7, Vista and even XP (note we do not support XP and Vista.) Of course, we’re adding our own methods that you’re used to from our runtime: if your code uses something of ours without you realising it wasn’t standard, don’t worry, it will be there.
The C++ runtime is new, and is based on a mixture of MinGW and LLVM. MinGW is an open source toolchain, though we are using only select carefully chosen parts. LLVM provides many key runtime areas. By focusing on LLVM we are also again sticking to standard libraries with known, shared behaviour.
Finally, the STL is LLVM’s libc++, an excellent, performant library.
Excellent language standards compatibility.
We run multiple test suites, and we see a much higher number of C++ and STL conformance tests passing with the new runtime trio than we did with the previous toolchain: a mark of the standards compliance, compatibility, and quality. We saw this even in our early internal versions and the passing tests just keep going up.
Excellent quality in all areas, such as exception handling
Our approach has been to do it right. Exception handling, for example, has always been a focus: in 10.4.2 we focused on improving core use cases and significantly improved quality. For the new toolchain, with a new C++ RTL, we are reworking this fully, generating hundreds of new tests for this behaviour alone. There are a wide variety of permutations: throw and catch in the same and different modules, rethrow, exceptions from Delphi, Delphi exceptions from C++, and many more. We also aim to pass this test suite for all except throw/catch in the same frame (something Clang itself does not support.)
A robust STL. A linker that can handle anything
I mentioned the STL above, but along with the change in object file format comes a change in linker.
Say goodbye to ilink.
Say hello to LLVM’s lld.
LLD has a very different architecture to ilink and we believe it will handle the complex, large apps that you build with ease.
Tech details
The toolchain uses:
- Uses Clang 15
- Uses LLVM’s lld as the linker
- Emits COFF64 object files (note this means Delphi can also emit COFF64 object files in 12.0: the compiler option “-jf:coff” is specified by our targets files when the “-JL” or “-JPHN[E]” options are specified)
- Emits PDB format debug info
- Uses the Itanium ABI (not Microsoft ABI)
- Uses LLVM’s libc++ STL
- Uses UCRT for the C runtime
- Uses a mix of LLVM and MinGW for the C++ runtime
- Targets Win64
- Named bcc64x
And of course the C++ extensions (property, closure, and so forth) and Delphi linking for VCL and FMX apps (this is not yet complete, and is coming), plus extensions that you may not even have realised were toolchain-dependent, such as auto-linking. This means you’ll get the same behaviour for your code – what you have already will remain working, of course – on this new, robust, modern, solid, performant, standardised, and exciting foundation.
Status
One key element of our approach to this upgrade has been to ‘do it right’: a solid foundation, thorough work, very high quality, and at every step, making the right decisions. We do not expect the toolchain to be ready in time for the 12.0 release. Doing it right means taking more time.
However, the new toolchain is amazing in many, many ways and we really want you to see the direction we’re going. In version 12.0 we are happy to deliver this new toolchain as a Preview release, in parallel with the older toolchain you can keep using for your projects.
We’d love it if you test it out. Focus on ‘pure C++’; it isn’t ready for testing Delphi VCL/FMX yet. You’ll see a high-quality STL. You’ll see we’re using the COFF object format. You’ll see PDB debug files (and we’re very curious if you try using third party tools here, since it’s a widely supported format.) You’ll see performance. You’ll see standards compatibility. You’ll see a new C RTL. You’ll see a new C++ RTL. You’ll see a new linker (and we expect those of you with large projects that stress our current linker will love this one.) When we release 12.0, we’ll blog with details about using it.
In 12.0, the new toolchain is a Technology Preview. We’re still working on key areas like linking against the Delphi runtime (even though Delphi-compatibility features like properties are working.) But it’s different, and it’s amazing. We believe that the preview is foundational and hope the results of you seeing it will be exciting.
Toolchains in version 12.0
What will the Win64 toolchain in C++Builder / RAD Studio 12.0 look like? Well, as stated above, there will be two.
- We are shipping the existing Clang 5-based toolchain, and this is the one enabled in the IDE
- A Preview version of the new Clang 15-based toolchain, as command-line only (invoke it by calling the compiler, bcc64x.)
Any upgrade is easier if there’s a migration path, and so even when we have the toolchain ready we’re likely to ship the previous and new toolchains in parallel for at least one release to help you migrate and upgrade. (The new toolchain is higher quality in every way, and written for excellent compatibility with existing C++Builder, so we think it will be easy to switch. But once again, we’re trying to do it right, and that means not requiring a sudden switch of toolchains from one release to the next.)
Overall
The new Clang toolchain is exciting, amazing material, with many areas that are far ahead of the existing toolchain, and we want to demonstrate to you, concretely, the direction we’re going with a Preview release in 12.0 – and let you use it, and let you use each new edition. The message: an immense amount of work, solid quality in every area, compatibility, standards, and modernity, built by making the right decisions. C++Builder is on rock-solid ground.
Sign up for the “What’s Coming” event on November 9th to learn more about RAD Studio, Delphi, and C++Builder 12.0.
This blog post is based on a pre-release version of the RAD Studio software and it has been written with specific permission by Embarcadero. No feature is committed until the product GA release.
Design. Code. Compile. Deploy.
Start Free Trial Upgrade Today
Free Delphi Community Edition Free C++Builder Community Edition
Great and relieved to hear about the investments in C++ Builder. I’d be impressed if the new toolchain will compile VidBlaster, definitely looking forward to that. Liking the long-term thinking!
Thanks Mike! We’re looking forward to it too and certainly hope the final version will compile VidBlaster — the goal of course is to compile all existing apps. Yours would be a great complex test case.
> The C++ runtime is new, and is based on a mixture of MinGW and LLVM. MinGW is an open source toolchain, though we are using only select carefully chosen parts. LLVM provides many key runtime areas. By focusing on LLVM we are also again sticking to standard libraries with known, shared behaviour.
Out of curiosity, what drove the decision to do this rather than use either libcxxrt or libc++abi, as most other projects that rely on libc++ do? (At least when they don’t use libsupc++, which I figure you avoided for the obvious GNU reasons.)
We do use libc++ for the STL / standard library. We also use other LLVM things like libunwind. But we need the lower-level C++ runtime that libc++ doesn’t provide, the part that sits below the standard library. MinGW seemed the best existing, clang-compatible, Windows-compatible, open source one that we evaluated. We don’t use all of it, and you’re right that we’ve been careful with licenses, but it was a good known working foundation.
The comprehensive answer is really long 🙂 And I’d need to check with our engineers to ensure I reported it accurately — we had a long process, and actually had a detour for a couple of months hoping to use a different runtime before settling on this one. I think the best short answer is that it is a ‘known good’ foundation in that there’s a shipping Clang+LLVM-based toolchain using the runtime already, so was a good place to start even with extensive modifications. It lets us use the LLVM things we want to, too, such as the linker and libc++ STL.
I think you slightly misunderstood my question; libc++ != libc++abi != libcxxrt. Both libc++abi and libcxxrt are (competing) implementations of exactly that “lower-level C++ runtime”, with libsupc++ being the GNU entrant to the same field.
Basically, I was asking about the details of the conclusion that “MinGW seemed the best existing, clang-compatible, Windows-compatible, open source one that we evaluated” as well was the details of the choice that “We don’t use all of it”.
Have there been improvements to the compilation performance? That has been a major blocker to having my team, as the clang compile time is 4-6 times longer than the classic compiler. That may not be significant for some but for my project it takes the time for a full build from about 20 minutes with the classic compiler to ~1.5 hours for clang (this is with TwineCompile) and would kill developer productivity. As a result my team develops strictly in 32-bit using the classic compiler and produces 64-bit builds only for QA and release, which is far from ideal.
All of these other changes are great to see, but it would be wonderful if there could be some serious attention given to the clang compile performance to make it practical for very large projects.