Have an amazing solution built in RAD Studio? Let us know. Looking for discounts? Visit our Special Offers page!
C++How-To'sModernizationRAD StudioWindows

How to achieve common tasks with the new Clang toolchain in 12.1

How to achieve common tasks with the new Clang toolchain in 12.1

The new Clang toolchain is here! RAD Studio and C++Builder 12.1 are shipping the entirely revised, wholly updated C++ compiler, linker, STL, runtime, and more – which you can also use in parallel with the old Win64 toolchain to ease upgrading until we remove the previous legacy toolchain in future.

We know this is a ‘version 1’ release and it’s different to our previous toolchains in some ways, and so we’ve put together this post on how to achieve specific things with the new toolchain. This covers both features that are not present yet but are coming in a future release, and things you can achieve now but it’s not necessarily obvious how. We may update this post if we have more info, too.

The release and status!

We’ve been open about the work we’ve been doing and our status, which has been great and I hope we’ll continue doing! Here are the main communications about it, starting with the most recent:

  • Feb 2024: a webinar, Behind the Build for 12.1 – this is the most recently technical overview and is very worth watching
    The 12.1 release webinar skimmed lightly over what is and isn’t present in 12.1 because the Behind the Build went into a lot of detail. This blog post will also clarify.

We strongly recommend watching the Feb 2024 Behind the Build for technical info about what we’ve released in 12.1, and also reading the upgrade documentation. Because the technology is different, and because this is our initial release, there are differences in features.

Common Tasks

Fast Compiling

Bcc64x does not yet have the –jobs parameter, which allows you to saturate multiple CPUs. That will come in future. We recommend using TwineCompile, which is available free with your subscription in GetIt. We worked with the developer during the beta period and it supports the new toolchain.

The new Clang and old Clang are very close in compile performance (the main difference is the linker, which is much faster in the new Clang.) Clang 15 does more than Clang 5, but despite that remains very similar in performance. Here are the results of compiling the Xerces library, in release mode, including link time. This is 300 files on a 4-core VM.

Xerces Release Build (includes link time) – 300 files, 4-core VM. Build time is in minutes:seconds
Old Clang Win64, without TwineCompile 2:13
New Clang 64-bit Modern, without TwineCompile 2:18
Old Clang Win64, with TwineCompile 00:38
New Clang 64-bit Modern, with TwineCompile 00:41

You get a linear decrease in compile time roughly following the number of CPU cores – here, at four cores, it’s about three and a half times faster. This follows to, say, ten to twelve times faster with sixteen cores.

Packages

In 12.1, the new Clang only supports linking packages statically. We know this is important, and dynamic linking is coming!

Most of our Delphi packages are provided (see Behind the Build at 22:16), and they are provided as .libs, and you can link them in to your EXE or DLLs. (That is, just build your projects – they will be linked in automatically because C++Builder’s headers use auto-linking.)

In general, packages are architecturally useful, and also technically useful in that multiple copies of the VCL can cause issues (eg if a DLL uses the VCL.) We know this, and dynamic package consumption is coming. We had a quality focus on what we are shipping this release, ie that what we ship is the best it can be, and so we focused on making sure static packages worked well.

C++-source packages are similarly only buildable as static libs right now, and so building BPL files for C++ packages are also planned.

CMake

CMake support for the new toolchain was not included in 12.1. The main reason was to reduce scope, to let us focus on the toolchain itself, not third party tooling.

Like packages, this is coming.

While we have some hacks we used internally to test building large CMake-only source, they are not suitable for sharing, unfortunately – please wait until we have CMake officially.

Imports

We’ve had a few bug reports around missing imports from import64.lib. We’re looking into this.

Boost

We have released Boost on GetIt for 12.1 for classic, clang Win32, and old Clang Win64; and right now we’re working on Boost for the new toolchain. Please stay tuned.

Preprocessing source and Compiling to Assembly

Currently when you preprocess or compile to assembly within the IDE, it fails. However, the command line shown in the Build Output works. The reason is that the msbuild targets to execute these commands is trying to execute the old toolchain’s DLL compiler. There are two workarounds:

  1. Try to preprocess (for example) in the IDE; copy the command line; change the temporary output filename to your-preferred-name.i, and run in a RAD Studio Command Prompt. The same process works for compiling to assembly.
  2. Edit the Codegear.Cpp.Targets file (note: make a backup first.) This lets the commands run as expected in the IDE.

Creating DLL Import Libraries

To import a random DLL, you need an import library. Any existing COFF one should work with our linker (this includes import libraries made by third parties for their DLLs, intended for use with MSVC.)

However, if you need to generate your own, you first need the definition (.def) file for the DLL. To do this, you can use the gendef.exe file from LLVM-MinGW. We aren’t shipping this yet, so you need to download it. Note that the following is third party and not verified or virus-checked by us, but the official llvm-mingw site recommends Martin Storsjö’s github for release. One release is: https://github.com/mstorsjo/llvm-mingw/releases/tag/20220906

Once you’ve found a copy of gendef.exe, run:

This will create file.def.

Note: some people have found that the filename in the .def file is incorrect. A .def file is plain text: you can open it and ensure it contains LIBRARY <dllname>.dll where <dllname> might be wrong: we’ve seen just “a” instead of the actual DLL name.

You can then use our new linker to generate the import library (run this at a RAD Studio Command Prompt, or run rsvars.bat in a normal command prompt):

(Or, using the LLVM tools, use llvm-dlltool.exe.)

And you now have an import library for your DLL: for file.dll, you have a file.lib import library.

Creating a DLL import library when building a DLL

Do you want to do the same thing, but not for a third-party DLL but for your own DLL? The IDE does this automatically when building, but you can do this on the command line:

Or

Both variations create the import library at the same time as the DLL.

Building a Delphi component / package for C++ Win64 Modern

When you build a package, you need it to be able to be used by the new Win64 target platform, not just the old one. If you don’t do this, then C++ Win64 Modern customers will see your component greyed out in the Palette when they have their project using the Win64 Modern target platform. (There’s also the technical building side: for Delphi, there is only one Win64, but for C++ there are two: ELF and COFF, and you need to provide the COFF static library files for your package.) So, how do you update your components?

In your package, right-click Target Platforms and add both Windows 64-bit and Windows 64-bit (Modern). If you rebuild each platform now, you will get the output files that are required – that is, bcc64x can link against the (static) package built for the Windows 64-bit Modern platform.Screenshot of the Palette showing a component enabled for Win32 Win64 and Win64 Modern

However, the package also needs to be installed in the IDE, and the IDE tracks which platforms a component can be used in (this is used so that a Windows-only component can’t be used in a macOS app, for example.) Now that you’ve added both Win64 platforms, rebuild the Win32 designtime package. This is the package that is installed in the IDE and contains the info about which platforms are ok for the components it contains. Now, when you install the component, and hover your mouse over it in the Palette, you will see Windows 64-bit Modern listed as a platform.

The files you’re generating are:

  1. Win32: <package>.lib (package as a static library) and  <package>.bpi (dynamic package import library)
    1. For Win32, a component package should be split into two packages, designtime (for the IDE, Win32 only) and runtime (for the app, every platform, ie Win32, Win64, and Win64 Modern.)
  2. Win64: <package>.a (package as a static library) and <package>.bpi (dynamic package import library)
  3. Win64X* / Windows 64-bit Modern: <package>.lib (package as a static library — see note above re dynamic packages coming in future)

* We use the “x” naming quite often because the compiler is named bcc64x.

You’ve achieved two things:

  1. Provided the binary files required to link in the package when an app is built by adding the Windows 64-bit Modern platform to your runtime package
  2. Told the IDE that the components are usable for Windows 64-bit modern: after adding the platform to the project, by rebuilding the designtime Win32 package and reinstalling it in the IDE

Productive happy programmer outdoorsLet us know how you like it!

The new toolchain is a foundational release, and means many good things for the future and what we’ll be able to do in the future. We’ve aimed to make the right decisions when building it: you can see evidence of that everywhere, from the platform conventions to choice of C runtime to 64-bit binaries to the focus on quality vs feature breadth. We’ve also worked very hard to minimise differences and ensure compatibility with your existing code. Check out our documentation for more info.

We’re looking forward to what we release using this toolchain in future, and are keen to see how well it works for you now!

 


Safe Harbour Statement

Any plans discussed represent our intentions as of this date, and our development plans and priorities are subject to change, due to competitive factors, availability of resources and other matters common to all independent software vendors.  

Accordingly, we can’t offer any commitments or other forms of assurance that we will ultimately release any or all of the described products on the schedule or in the order described, or at all.  

These general indications of development schedules or “product roadmaps” should not be interpreted or construed as any form of a commitment, and our customers’ rights to upgrades, updates, enhancements and other maintenance releases will be set forth only in the applicable software license agreement.

IMPORTANT: Features are not committed until completed and Generally Available (GA) released

 

See What's New in 12.2 Athens See What's New in 12.2 Athens Dev Days of Summer 2-24

Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder.
Design. Code. Compile. Deploy.
Start Free Trial   Upgrade Today

   Free Delphi Community Edition   Free C++Builder Community Edition

About author

David is an Australian developer, currently living in far-north Europe. He is the senior product manager for C++ at Idera, looking after C++Builder and Visual Assist.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

IN THE ARTICLES