Using CMake with C++ Builder

From RAD Studio
Jump to: navigation, search

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:

  1. Locate your CMake installation folder and the Modules\Platform subfolder. E.g. C:\Program Files\CMake\share\cmake-3.10\Modules\Platform
  2. Locate the Windows-Embarcadero.cmake file and make a backup.
  3. Copy Windows-Embarcadero.cmake from the Studio\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.

  1. 1.0 1.1 1.2 1.3 1.4 Directory where cmakelists.txt file is located

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)

Sample CMakeLists.txt: shared library

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} )

See Also