Using CMake with C++ Builder
Contents
CMake Command-Line Support
RAD Studio 10.2 Tokyo Release 3 includes support for building CMake projects on the command line using RAD Studio's C++ Compilers. You can compile for Windows or for other platforms from Windows. CMake supports RAD Studio’s Clang-enhanced compilers: BCCAARM for Android, BCCIOSARM64 for 64-bit iOS, BCCIOSARM for 32-bit iOS, BCC64 for 64-bit Windows, and BCC32X for 32-bit Windows. RAD Studio 10.2 Tokyo Release 3 also supports using Ninja with CMake. This allows for fast parallel compilation.
Installing CMake and Ninja
CMake
Download and install CMake 3.10. Use the binary installer, since it can optionally add CMake to the system path. Make sure you select that option during the installation.
CMake files are located in C:\Program Files (x86)\Embarcadero\Studio\19.0\cmake
. However, to prevent errors in the build process, you need to move one file manually. Follow the steps below to do this:
- Locate your CMake installation folder and the Modules\Platform subfolder. E.g.
C:\Program Files\CMake\share\cmake-3.10\Modules\Platform
- Locate the
Windows-Embarcadero.cmake
file and make a backup. - Copy
Windows-Embarcadero.cmake
from theStudio\19.0\cmake
folder and overwrite the version in the CMake folder.
We have greatly extended the inbuilt CMake support for the Windows compilers and you need to use this file to build successfully.
Ninja
Download and install Ninja 1.8.2. You’ll need to add it to the system path manually.
How to use CMake
CMake builds based on a text file called CMakeLists.txt that tells CMake which files to build. You can find more information in their developer documentation. We also recommend Jeff Preshing’s blog series on CMake: How to Build a CMake-based Project and Learn CMake’s Scripting Language in 15 Minutes.
To use CMake, you need the following files:
- C++ source you want to build: A number of C++ files and headers.
- CMakeLists.txt file: Defines the project name, tells it to find all source files, and builds them in one executable, library, package, etc. See below for several sample files. More advanced CMakeLists.txt files specify several projects.
- (Optionally) Batch script to drive CMake: Use the batch script (*.bat) to contain a number of commands. CMake can create a large number of files, and you can use the batch file to create a subfolder where all output including CMake’s files are placed. This blog post on using bcc32c with CMake has more details.
- Run the batch script from the command line to generate the executable file along with many other files in the specified subfolder.
Note: Store the CMakeLists.txt file in the root folder of your project. You can store the source files in a subfolder.
Building using CMake
Start a RAD Studio command prompt from the Start menu, or by opening a command prompt and executing rsvars.bat in the RAD Studio \bin folder.
CMake looks for a CMakeLists.txt file. See below for information on creating one of these for a project.
Targeting Windows
To target Win32:
cmake -DCMAKE_C_COMPILER=bcc32x.exe -DCMAKE_CXX_COMPILER=bcc32x.exe -G Ninja <directory>
[1]
To target Win64:
cmake -DCMAKE_C_COMPILER=bcc64.exe -DCMAKE_CXX_COMPILER=bcc64.exe -G Ninja <directory>
[1]
Then,
ninja
To invoke Ninja to do the actual build.
Targeting iOS and Android
iOS and Android are handled through toolchain files, which are used for cross-compiling. Make sure you can build and deploy from the IDE (including setting up the SDK) before attempting a command-line build.
To target iOS32:
cmake -DCMAKE_TOOLCHAIN_FILE="<BDS>\cmake\bccios32.cmake" -G Ninja <directory>
[1]
To target iOS64:
cmake -DCMAKE_TOOLCHAIN_FILE="<BDS>\cmake\bccios64.cmake" -G Ninja <directory>
[1]
To target Android:
cmake -DCMAKE_TOOLCHAIN_FILE="<BDS>\cmake\bccaarm.cmake" -G Ninja <directory>
[1]
Then,
ninja
To invoke Ninja to do the actual build.
Other command-line flags
- -G”Borland Makefiles” to use old-fashioned make to build.
- -DCMAKE_BUILD_TYPE_INIT=Release to target debug or release builds.
- -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON for easier to debug output.
- --debug-output to put CMake in debug mode.
For example:
cmake -DCMAKE_C_COMPILER=bcc32x.exe -DCMAKE_CXX_COMPILER=bcc32x.exe -DCMAKE_BUILD_TYPE_INIT=Release -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -G "Borland Makefiles" --debug-output -v ..
To use the Win32 compiler, release build, some verbose and debugging flags, and build using make, with CMakeLists.txt located in the parent folder.
C++ Builder-specific support in a CMakeLists.txt
Targets
Using CMake, you can create executables, DLLs, static libraries, and packages.
set_embt_target(FMX) set_embt_target(VCL) set_embt_target(Package) set_embt_target(DynamicRuntime)
Or combinations:
set_embt_target(VCL DynamicRuntime)
Macros and variables
There are a number of macros and variables for Windows, iOS, and Android. This sample CMakeLists.txt shows several of them:
cmake_minimum_required(VERSION 3.9) set(APP "FMXApp") set(CMAKE_BUILD_TYPE "DEBUG") set(EMBT_PROJECT_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/Project_${APP}") project (${APP}) if(EMBT_TARGET STREQUAL iOS64) set(EMBT_IOS_BUNDLE_IDENTIFIER "com.company.adhoc") set(EMBT_IOS_BUNDLE_EXECUTABLE ${APP}) set(EMBT_IOS_BUNDLE_NAME ${APP}) set(EMBT_IOS_BUNDLE_VERSION "1.0") set(EMBT_IOS_BUILD_TYPE "Ad-hoc") add_embt_background_modes(audio) add_embt_background_modes(voip) add_embt_additional_files("${CMAKE_CURRENT_SOURCE_DIR}/cmakelists.txt") add_embt_additional_files("${CMAKE_CURRENT_SOURCE_DIR}/cmakelists.txt" "${EMBT_PROJECT_LOCATION}" "new.txt") set(EMBT_IOS_CAMERA_USAGE_DESCRIPTION "This app needs access to your camera") set_embt_device_family(iphone) set(EMBT_IOS_MINIMUM_OS_VERSION 8.0) set(EMBT_IOS_BUNDLE_ALLOW_MIXED_LOCALIZATIONS YES) set(REMOTE_PROFILE "_mac") set(PROVISIONING_PROFILE "provision.mobileprovision") set(CERTIFICATE "iPhone Distribution:") elseif(EMBT_TARGET STREQUAL iOS32) set(EMBT_IOS_BUNDLE_EXECUTABLE ${APP}) set(EMBT_IOS_BUNDLE_NAME ${APP}) set(EMBT_IOS_BUNDLE_IDENTIFIER "com.company.id") set(EMBT_IOS_BUNDLE_VERSION "1.0") set(EMBT_IOS_MINIMUM_OS_VERSION 8.0) add_embt_background_modes(audio) elseif(EMBT_TARGET STREQUAL Android) set(EMBT_ANDROID_BUILD_TYPE "Development") add_embt_additional_files("${CMAKE_CURRENT_SOURCE_DIR}/cmakelists.txt") add_embt_additional_files("${CMAKE_CURRENT_SOURCE_DIR}/cmakelists.txt" "${EMBT_PROJECT_LOCATION}" "new.txt") #set(EMBT_ANDROID_SPLASH_IMAGE_LARGE "c:/myArtwork/Android/FM_SplashImage_640x480.png") set(EMBT_ANDROID_INCLUDE_SPLASH_IMAGE True) set(EMBT_ANDROID_ALIAS "release-keystore") set(EMBT_ANDROID_KEYSTORE "release.jks") set(EMBT_ANDROID_STOREPASS "cmakeandroid") set(EMBT_ANDROID_KEYPASS "cmakeandroid") endif() # Create a sources variable with a link to all cpp files to compile file(GLOB SOURCES "src/*.h" "src/*.cpp" ) set_embt_target("FMX") if(EMBT_TARGET STREQUAL Windows) add_executable (${APP} WIN32 ${SOURCES}) install(TARGETS ${APP} RUNTIME DESTINATION bin) else() add_fmx_app("${SOURCES}") endif()
Example CMakeLists.txt file
For a project called Example, with source files in the same folder, a very minimal CMakeLists.txt file is:
cmake_minimum_required (VERSION 3.10) project (Example) file(GLOB Example_SRC "*.h" "*.cpp" ) add_executable(Example ${Example_SRC})
This specifies the minimum version (3.10); the project name; that it uses all available .cpp and .h files, and compiles them all into Example.exe.
“Glob”-ing all files together is quick and easy, but is not a recommended best practice; instead, it is better to specify the files you want to use. You can specify .cpp files and headers, but one minimal example specifying .cpp files is:
cmake_minimum_required (VERSION 3.10) project (Example) add_executable(Example main.cpp foo.cpp bar.cpp)
Sample CMakeLists.txt: VCL app
cmake_minimum_required(VERSION 3.9) project (VCLApp) set_embt_target(VCL DynamicRuntime) add_executable (VCLApp WIN32 src/VCLApplication.cpp src/Project1.cpp) install(TARGETS VCLApp RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib/static )
Sample CMakeLists.txt: FMX app
cmake_minimum_required(VERSION 3.9) project (FMXApp) set_embt_target(FMX) add_executable (FMXApp WIN32 src/FMXSample.cpp src/FMXProj.cpp) install(TARGETS FMXApp RUNTIME DESTINATION bin)
project(SharedLibrary) set(SharedLibrary_headers SharedLibrary.h) set(SharedLibrary_sources SharedLibrary.cpp) add_library(SharedLibrary SHARED SharedLibrary.h SharedLibrary.cpp) install(TARGETS SharedLibrary RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib/static )
Sample CMakeLists.txt: Static Library
project(StaticLibrary) set(StaticLibrary_headers StaticLibrary.h) set(StaticLibrary_sources StaticLibrary.cpp) add_library(StaticLibrary STATIC StaticLibrary.h StaticLibrary.cpp) install(TARGETS StaticLibrary RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib/static )
Sample CMakeLists.txt: Package
cmake_minimum_required(VERSION 3.9) project (PackageExample) set_embt_target(Package) add_library(PackageExample SHARED PackageExample.cpp) install(TARGETS PackageExample RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib/static )
Sample CMakeLists.txt: Resources
cmake_minimum_required(VERSION 3.9) project (myapp) set(SYSTEM_SOURCES ${SYSTEM_SOURCES} myapp.rc ) set(StrTableRes_SRCS resource.h myapp.cpp) ADD_EXECUTABLE(myapp WIN32 ${SYSTEM_SOURCES} ${StrTableRes_SRCS} )