BCC64X

From RAD Studio
Jump to: navigation, search

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.

Note: For 32-bit Windows, use BCC32C (Clang-enhanced compiler) or BCC32 (previous-generation compiler).
Note: BCC64X is the Modern Win64 compiler/toolchain and is recommended for all applications. However, the legacy BCC64 still exists.

General Information

Field Value
Clang Version 15.0
LLVM Version 15.0
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
Note: The new clang supports linking packages statically and dynamically. You can link these files to your EXE or DLLs.

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__ == 15
  #pragma message("Using version 15 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:

  1. Right-click the Target Platforms node in the Projects treeview.
  2. Select Add Platform.
  3. Choose Windows 64-bit (Modern).
Note: 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.
Attention: 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, multithreaded runtime is the only available option. If your app uses only a single thread, this is still fine to use.

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_ >= 15 for 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_ == 15 for 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.
Note: Learn more on how to detect LLVM and its version here.
  • Use the _has_feature and _has_builtin macros 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__ >= 15)
           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.

Note: 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 Windows-specific.

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's still a common issue when pulling in third-party C++ source code or libraries.

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:

  1. Get the definition (.def) file for the DLL.
    Note: You can generate the .def file from a .dll file by using our tdump tool.
  2. With the tdump tool, run the following command to create the .def file:
    tdump -def mydll.dll mydll.def
    
    Note: A .def file is plain text, open the file and ensure it contains LIBRARY <dllname>.dll with the correct <dllname>.
  3. 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 compiling 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.

C++ parallel building (batch and jobs) options.png

To verify your project is using parallel builds, open the Project Options:

  1. Make sure the Windows 64-bit Modern platform is selected and active in your project.
  2. Go to Project Options. Make sure you select ‘All Configurations’ in the dropdown.
  3. 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.
  4. 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 invoking the compiler directly when using the '--jobs=n' command line parameter.

Our recommended value is 0 (the default.) This saturates the CPU and builds as fast as possible.

Known Issues

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++.

Note: The issue only happens for existing projects. Newly created projects are not affected.

For more information, see ComponentPlatformsAttribute.

See Also