BCC64X
Go Up to Clang-enhanced C++ Compilers
BCC64X is a RAD Studio C++ compiler for 64-bit Windows (Modern).
BCC64X is based on Clang. For more information about what the BCC64X compiler has in common with other Clang-enhanced C++ compilers, see Clang-enhanced C++ Compilers.
- The BCC64X C++ compiler based on Clang 20.1 now defaults to C++23. It is possible to choose to target C++20 or C++17 if needed.
- For 32-bit Windows, use BCC32C (Clang-enhanced compiler) or BCC32 (previous-generation compiler).
- BCC64X is the Modern Win64 compiler/toolchain and is recommended for all applications. However, the legacy BCC64 still exists.
Contents
General Information
| Field | Value |
|---|---|
| Clang Version | 20.1 |
| LLVM Version | 20.1 |
| Calling Conventions | Microsoft x64 |
| Name Mangling | Itanium |
| Standard Library | LLVM libc++ |
| C++ Runtime | Custom based on MinGW-LLVM |
| C Runtime | UCRT |
Output Files
| File Type | File Extension | File Format |
|---|---|---|
| Executable | .exe
|
PE64 (PE32+) |
| Shared Library | .dll
|
PE64 (PE32+) |
| Static Library | .liband lib[name].a
|
Library of object files; see Auto Linking for more info on extensions. |
| Compiled Object | .o
|
COFF64 |
| Debug Information | .pdb
|
PDB |
The new Clang supports linking packages statically and dynamically. You can link these files to your
EXE or DLLs.To prevent runtime conflicts when multiple versions of RAD Studio are installed, shared runtime libraries (
libc++.dll) are now suffixed with the BDS version number (libc++-370.dll).Writing C++ Code for BCC64X
To write C++ code specifically for BCC64X, use:
#if defined(__BORLANDC__) && defined(_WIN64) && defined(__MINGW64__)
To focus on a specific release, add a check as follows:
#if __clang_major__ == 20.1
#pragma message("Using version 20.1 of Clang")
#endif
For more information, see Clang-enhanced C++ Compilers, Predefined Macros.
Toolchain
The Windows 64-bit Modern C++ toolchain (bcc64x) is an entirely new implementation of the Clang extensions and C++Builder features with new platform-standard technology. With the LLD linker, new RTL, and more, the new Clang toolchain is our recommended C++ toolchain.
It uses the LLVM libc++ STL, a custom C++ RTL, the Windows UCRT for the C runtime, and emits object files in COFF64 format with PDB debug info.
To add this toolchain to your existing C++ project, perform the following steps:
- Right-click the Target Platforms node in the Projects treeview.
- Select Add Platform.
- Choose Windows 64-bit (Modern).
You can toggle between the old and new Win64 platforms easily because both are installed and can be added to a project side by side, allowing easy upgrading.
Legacy toolchains provided multiple versions of the runtime to handle single-threaded-only and multithreaded applications. The Modern toolchain has a single multithreaded runtime. Therefore, a multithreaded runtime is the only available option. If your app uses only a single thread, this is still fine to use.
_setmaxstdio and _getstdiomax are Microsoft runtime functions part of UCRT. These functions are only supported on Win64x.How to test for the new BCC64X compiler
RAD Studio has a recommended way for developers to write code that detects if the new toolchain is being used:
- Recommended: Use a macro test for
_CODEGEARC_and_clang_major_ >= 20.1for this and newer versions. RAD Studio recommends this because the Clang version will change over time, and this code will be true for this toolchain's current and future versions. This is almost certainly the check you want to add to your code. - Use a macro test
_CODEGEARC_and_clang_major_ == 20.1for this specific version. Only use this to test the initial version of the toolchain specifically. This test will fail to detect future versions of the same toolchain, which is why the previous test is recommended.
Learn more on how to detect LLVM and its version here.
- Use the
_has_featureand_has_builtinmacros to test for specific C++ or compiler/LLVM features and builtins, which are not C++Builder specific but apply to multiple Clang-based toolchains. Learn more about feature-checking macros here.
The code sample below demonstrates our recommended test for the new toolchain. Use this to wrap toolchain-specific code, such as including specific headers.
#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
}
To migrate your existing codebase forward, including specific code for the new toolchain inside such a macro is useful.
See a complete list of macros in our Predefined Macros page.
Adjusting Paths
To ensure the compiler finds the correct paths, make sure to add the $(CC_SUFFIX) variable to the library path.
For example:
$(BDSLIB)\$(PLATFORM)$(CC_SUFFIX)\debug;..\..\..\..\..\Public\Documents\Embarcadero\Studio\15.0\Samples\CPP\Mobile Samples\User Interface\KeyboardToolbar\
The $CC_SUFFIX variable handles the difference in the two Win64 toolchains. The new one, bcc64x, has an X on the end, meaning the correct platform location for files it links to is ‘win64x’. The $CC_SUFFIX evaluates to X when using this platform.
Testing for Windows vs. Testing for a Specific Toolchain
When using third-party C++ source code, you may see headers, method definitions, etc., that are Windows-specific and incorrectly wrapped in a macro testing the toolchain (usually MSVC). To solve this, replace those macros with a platform test, not a toolchain test.
To test for Windows, whether MSVC, C++Builder, or another toolchain, test for _WIN32 or _WIN64 being defined. Both C++Builder and MSVC define these macros. This is recommended when your code is specific to Windows.
Code mixing platform (Windows) tests with toolchain tests seem to be decreasing on Windows due to the growing use of other toolchains such as RAD Studio's and mingw-llvm. However, it remains a common issue when integrating third-party C++ source code or libraries.
Driver Optimization Flags
When comparing the results between binaries generated using the COFF version 20.1 toolchain and the ELF version 5, significant differences are observed in binary size and performance.
Use relaxable relocation optimization to optimize binary size and performance. Use any of the following flags:
| Compiler | Configuration mode | Flag | Description |
|---|---|---|---|
| LLD | Release | --strip-all
|
Eliminates the COFF symbol table generated by the linker, producing smaller images.
|
| LLD | --gc-sections
|
Enables garbage collection of unused input sections. [1] | |
| Clang/CC1 | -fdata-sections
|
Places each data in its own section. [1] | |
| Clang/CC1 | -ffunction-sections
|
Places each function in its own section. [1] | |
| Clang/CC1 | Release | -vectorize-loops
|
Enables automatic vectorization of loops for parallel execution. |
Linking to DLLs
Building a DLL and generating the export .def file
RAD Studio ships with llvm-dlltool.exe as it’s part of the llvm-project from which our clang-based bcc64x.exe compiler is build. To generate a .def file, it is recommended using the tdump.exe tool.
Link directly to a DLL
The new toolchain can link directly to a .dll file.
You can either use the -lmydll function or, if you have a copy of the .dll file on the LIBRARY path, use the #pragma comment(lib, "mydll") without the need of an import library.
See our Auto Linking documentation for more information.
The linker can be invoked manually through the compiler by adding the following path to the linker:
libclang_rt.builtins-x86_64.a
Creating DLL Import Libraries
RAD Studio now allows you to link a .dll directly, eliminating the need for an import library. This new implementation is only for Win64x platforms.
However, the import library is commonly used to import a .dll file because the linker will look for libraries first, in opposition to .dll files that are searched last.
The toolchain supports any existing COFF library; however, you can create your own.
To create your own import library (.lib) file, follow the steps below:
- Get the definition (
.def) file for the DLL.Note:
You can generate the.deffile from a.dllfile by using ourtdumptool. - With the tdump tool, run the following command to create the
.deffile:tdump -def mydll.dll mydll.def
Note:
A.deffile is plain text, open the file and ensure it contains LIBRARY<dllname>.dllwith the correct<dllname>. - Use the new LLD linker to generate the import library by running the following command in the RAD Studio Command Prompt:
ld.lld.exe -m i386pep --out-implib file.lib file.def
The IDE automatically creates your DLL import library when building, but you can also do this manually by running any of the following codes in the command line:
bcc64x -tD -Xlinker --out-implib=dll.lib dll.cpp
or
bcc64x -tD dll.cpp -Wl,--out-implib,dll.lib
Parallel Compilation
C++Builder projects for the new Win64 toolchain build in parallel by default. This leads to a faster building with bcc64x compared to building with:
- --jobs using the old bcc64 (old Win64 toolchain).
- CMake & Ninja, using both the old and new bcc64/x.
- Visual C++, both with CMake and Ninja, and the /MP command line switch.
This is on by default for projects using this platform. Read the following documentation to configure settings or understand how it works.
Understanding
Parallel compilation of C++Builder projects combines two features: batch compilation, where the compiler is given multiple C++ files at once instead of invoking compilation for one file at a time, and --jobs, where it processes the files it has in parallel.
Thus, the compiler is given lots of files to compile (batch compilation) and told to compile them in parallel (--jobs.)
Why both? If you do just batch compilation, it will compile many files with a single invocation of the compiler EXE, but the compiler will process them one by one after the other in serial; if you do just --jobs, it will compile using the parallel system, but only with a single file, and since there's only one meaningless file. You must enable both settings: (a) lots of files simultaneously and (b) in parallel.
Understanding parallel compilation behavior, including CPU utilization
Below, you can find some information that will help you understand how batch compilation with --jobs works so you can fine-tune your build environments to achieve faster, more efficient compilation while balancing resource utilization.
Compiler output
Compiler messages are not interleaved. Although they run in parallel, an entire file’s output messages will be printed at once after it is complete.
If there is a compile error, all compilation will be terminated. After the error, you might get successful compile messages because the other files being compiled in parallel will continue until completion.
Build systems
The '--jobs' parallel building system can be used from the IDE and command line MSBuild and also directly via the command line ‘bcc64x’.
Note that you absolutely can use this for CI, builds servers, and more when you build via a command-line MSBuild command. You are not restricted to invoking the compiler directly; the default build system can build in parallel from the command line.
In-IDE building
Build or compile as normal; parallel building is used by default. If you open Task Manager, you should see a single bcc64x process using multiple threads, taking close to 100% CPU.
To verify your project is using parallel builds, open the Project Options:
- Make sure the Windows 64-bit Modern platform is selected and active in your project.
- Go to Project Options. Make sure you select ‘All Configurations’ in the dropdown.
- Building > C++ Compiler > Enable Batch Compilation should be set to true. Double-check that none of the other target configurations override it; this should be the default set at a high inherited level.
- Project Properties > General > Number of subprocesses should be set to
0. This uses every core you have.
Command line building, using msbuild
Invoke msbuild with your project. So long as the above settings are set in-IDE in the project options, you will compile in parallel.
> msbuild MyProject.cbproj
See Building a Project Using an MSBuild Command for a full list of parameters. Remember, ensure the parallel building is configured for the project in the IDE; those settings will always be used when using msbuild on the command line with the same project.
Command line building, using the compiler driver
To implement directly via the command line, simply use the following:
> bcc64x a.cpp b.cpp c.cpp --jobs=0 ...other parameters
These batches (send multiple files to the compiler at once), telling it to build in parallel (jobs), using as many cores as are available ('0' means all cores.)
CPU Saturation
In the Project Options > Project Properties > General tab, look for the Number of subprocesses setting; the default is ‘0’. This means using all cores available. It runs twice as many threads as there are cores.
If you want the build system to take almost but not quite all resources available, set it to -1. This uses one core less than the default, ‘0’. Only use this if you want to do something while compiling and find that other processes slow down.
You can also set it to any positive integer. Depending on how many are available, it will use up to this number of cores. If you set it to use more cores than you have, it will simply use as many cores as it can.
You can set the same value by invoking the compiler directly when using the {{{1}}} command line parameter.
Our recommended value is 0 (the default). This saturates the CPU and builds as fast as possible.
C++23 Support
Starting with RAD Studio Florence 13.0, the Clang-20-based C++Builder Compiler introduces C++23 support.
The new Clang-based compiler offers robust support for the C++23 language standard, while libc++ provides a large number of C++23 features. When using the Win64 Modern platform, new C++ projects now default to C++23. If you are looking for specific features no longer available in C++23, it is possible to switch to an older version in the C++ compiler settings located in Project > Options > Building > C++ Compiler
Read more about the current clang and libc++ support for specific C++23 features in the links below:
Differences between Compiler Versions
Starting with RAD Studio 13 Florence, the C++ Win64 Modern platform toolchain now uses Clang version 20.
This section describes the differences between compiler versions 15 and 20.
RAD Studio Athens 12 shipped with clang version 15.
The Modern BCC64X compiler version 20 strictly enforces the C99 rules when compiling C code, which results in errors instead of warnings.
Implicit Functions
Calling an implicitly defined function without a prototype results in an error message.
Example:
int test2()
{
return implicit_function();
}
The sample code above yields two distinct outcomes.
Version 15 compiler:
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]
Version 20 compiler:
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].
Implicit int
Calling an implicit int results in an error message.
Example:
test1()
{
return 42;
}
The sample code above results in two different outcomes.
Version 15 compiler:
Warning W4884 stricter_c.c 1(1): type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int].
Version 20 compiler:
Error E5464 stricter_c.c 1(1): type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int].
Incompatible Function Pointers
The following is an example of code that mixes incompatible function pointers.
Example:
int callback(int a, int b) {
return a+b;
}
int call_callback(int (*callback)(int)) {
return callback(5);
}
int test3() {
return call_callback(callback);
}
The sample code above generated a warning using the previous compiler, but now, using the modern compiler, an error message is generated.
Version 15 compiler:
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]
Version 20 compiler:
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]
Known Issues
Components from packages
Components from packages created for WIN64X using Delphi projects must be enabled for the platform first. To enable components for the Windows 64-bit (Modern) platform, see the instructions on Build Delphi Packages for C++.
The issue only happens for existing projects. Newly created projects are not affected.
For more information, see ComponentPlatformsAttribute.
UTF8 Limitation
When building C++ apps using the bcc64x compiler, there is a limitation when building using the UTF8 locale.
The runtime that ships with the bcc64x compiler relies on the operating system to provide native UTF-8 support. UTF-8 locale support on Windows began with Windows 10 1803 (Apr 2018 update), which is why C++ apps requesting the UTF-8 locale do not run on the following Operating Systems:
- Windows 10 (before Version 1903, May 2019)
- Windows Server 2016
- Windows 8
- Windows 7
- Windows Vista
Running on a Windows version that does not provide the native UTF8 support raises a std::runtime_error exception with the following message:
collate_byname<char>::collate_byname failed to construct for .UTF8
The issue only occurs when one explicitly requests the UTF-8 locale.
See Also
- C++Builder 64-bit Windows (Modern) Application Development
- Build Delphi Packages for C++
- C++Builder 64-bit Windows Application Development
- Unit Initialization and Finalization for C++ New Toolchain
- Packages for C++ New Toolchain
- Package Import and Export for C++ New Toolchain
- BCC64-specific Differences
- Modern C++ Features
- Legacy 64-bit Windows Compiler