Creating ComputeCpp™ (SYCL™) Projects with CMake

05 October 2021

Introduction

While interning at Codeplay®, I was tasked with writing two programs that demonstrated using SYCL in practical projects. At that point, I had not been exposed to build automation tools such as CMake and struggled to create my own SYCL projects without it. CMake is a powerful tool for developers to generate build files for their projects quickly and across multiple platforms. This blog aims to provide a beginner’s step-by-step guide on setting up a basic SYCL project using CMake. I will be using Windows 10 for this blog, however CMake should work on the most common operating systems and generate project files for whichever IDE the user chooses to use. At the end of this blog, the reader should be able to use CMake to automate the building of basic SYCL applications. SYCL knowledge is only required in order to test the build system (resources to help you write a simple SYCL program are included at the bottom of this blog).

Step 1. Setting up

In order to follow along with this blog, the reader must download the following prerequisites:

  • A C++ compiler such as GCC, Microsoft® Visual C++®, or Clang.
  • CMake (3.4.3 or newer) (Make sure to add it to PATH when installing for easy use in the terminal).
  • ComputeCpp (any version) is a SYCL implementation which will be used to compile SYCL source files. (A simple registration is required to download the latest Community Edition installer for free. On Windows, extract and run the installer which will install ComputeCpp).
  • OpenCL (latest version) (Get Intel® SDK for OpenCL™ Applications for the desired operating system. This will also require quickly creating an account to access the download link. Once the installer has finished, a computer restart may be required for OpenCL to be detected properly. This step may be skipped by users with CUDA installed as it includes OpenCL).

Step 2. Creating a basic CMake project

Navigate into the root directory containing the C++ project and create a file called CMakeLists.txt. This file will be recognized by CMake as the entry point to the CMake project and will contain important information about how the project needs to be linked. Once this file is created, open it in a text editor and we will begin writing some CMake code.

First the user must declare the minimum version of CMake required for the project, in this particular case we will use 3.4.3 which is the minimum version that ComputeCpp supports.

cmake_minimum_required(VERSION 3.4.3)

Next the user must give the CMake project a name, such as

project(test_application)

Every C++ project consists of source (.cpp) files used for generating object files that allow the compiler to create the executable / library file for an application. These source files need to be linked to the executable which is often done by creating a CMake variable which contains a list of paths to all the source files in the project relative to the CMakeLists.txt file's root directory. For example:

set(SRC_FILES
    "src/main.cpp"
    "src/program.cpp")

Where SRC_FILES will be the name of a variable which will encompass the main.cpp and program.cpp source files.

The same can be done for SYCL source files (.cpp files containing SYCL code) and regular C++ header files.

set(SYCL_FILES
    "src/main.cpp")

set(HEADER_FILES
    "src/program.h")

While not required, creating variables to represent groups of files makes the CMake file easier to read and may avoid repetition in the future.

After this, we must inform CMake where it can find what is called a Find-module package file for ComputeCpp. In essence, this is a CMake file which handles configuring variables and creating functions to simplify interaction with an external library. Usually, these files are placed in a folder called cmake in the root of the project (where the CMakeLists.txt is located). ComputeCpp provides such a file here to simplify the build process (right click anywhere on the page and save the file as a .cmake file into a known directory). The following line will let CMake know the directory of this file:

list(APPEND CMAKE_MODULE_PATH
    "${CMAKE_SOURCE_DIR}/cmake/")

Where CMAKE_SOURCE_DIR is an intrinsic variable which points to the root directory of the CMake project (the location of the CMakeLists.txt file). CMAKE_MODULE_PATH is a variable which contains a list of paths that CMake will check for FindNameOfPackage.cmake files.

In order to use ComputeCpp, the user must provide CMake with a variable called ComputeCpp_DIR corresponding to the location of the ComputeCpp installation (usually something like C:/Program Files/Codeplay/ComputeCpp on Windows). This variable is often provided to CMake as an argument in the terminal with the -D flag

cmake .. -DComputeCpp_DIR="C:/Program Files/Codeplay/ComputeCpp"

However, this can get tedious to write out each time. In order to avoid having to retype this, the user can specify

set(ComputeCpp_DIR CACHESTRING"NOT-FOUND")

Within their CMake project to cache the variable between running CMake. If the path changes simply set the -DComputeCpp_DIR flag again.

Optionally, it is useful to add a warning for the user if the variable is not defined, something such as

if (NOT ComputeCpp_DIR)
    message(FATAL_ERROR"SYCL implementation root not provided, please specify "
    "the path to the root of the chosen SYCL implementation using "
    "ComputeCpp_DIR=<path/to/install/root>.")
endif()

Now the user will be able to add

find_package(ComputeCpp REQUIRED)

And CMake will automatically run the FindComputeCpp.cmake file to create some functions and variables for easily linking ComputeCpp to the project.

The user can generate a C++ executable for their source files using

add_executable(${PROJECT_NAME}${SRC_FILES} ${HEADER_FILES})

where PROJECT_NAME is simply a CMake intrinsic variable containing the project name defined at the very beginning.

Now that the executable (also known as a target in CMake) has been created, the user must specify the include directories for the target with

target_include_directories(${PROJECT_NAME} PRIVATE 
                          "${ComputeCpp_INCLUDE_DIRS}"
                          "${CMAKE_SOURCE_DIR}/src")

This informs CMake that the directories defined in the ComputeCpp_INCLUDE_DIRS variable, which was generated by FindComputeCpp.cmake, should be included in the project, alongside any files in the source directory.

Lastly, we must inform the executable which of the source files will contain SYCL code as the SYCL implementation will generate .sycl files for each of them. This can be done using the add_sycl_to_target function which was defined by the FindComputeCpp.cmake file. If, for example, main.cpp is the only file with SYCL code in it, the following CMake code can be added after creating the executable

add_sycl_to_target(TARGET ${PROJECT_NAME}
                   SOURCES "src/main.cpp")

Which will link SYCL to the desired target with the desired source files.

Once complete, the CMakeLists.txt file should look something like this.

Step 3. Generating project files

It is highly advisable that before attempting to generate build files for their C++ compiler, the user first creates a build directory in the root of their project. This makes it easier to clean the project and keep the built binaries separate. First open the terminal in (or navigate into) the project’s root directory and call

mkdir build

which will create a directory called build. Afterward, the user should navigate into this directory using

cd build

and finally call CMake to generate the build files in the build directory using (replacing the path with the location of their ComputeCpp installation)

cmake .. -DComputeCpp_DIR="C:/Program Files/Codeplay/ComputeCpp"

The two dots simply tell CMake that the location of the CMakeLists.txt file is in the outer directory and -D is a CMake flag for defining variables in the terminal. This should produce some terminal messages and generate build / project files for the appropriate user installed compiler automatically in the build directory. Note that if using an NVIDIA GPU, PTX instructions are required, and the user should add -DCOMPUTECPP_BITCODE=ptx64 to the end of the above CMake command.

Here is a link to a repository containing a basic SYCL project template following along this blog.

Please see resources such as

for guides on how to write basic SYCL code or applications.

Martin Starkov's Avatar

Martin Starkov

Intern Software Engineer