CMAKE: Facilitates joint programming between CUDA and other languages (C, C++, RUST)

In CUDA programming, especially when it involves multi-language mixed programming, such as C/C++ and CUDA or RUST and CUDA, etc., it is still troublesome to use the NVCC compiler to compile some large projects. Using cmake to configure compilation options is relatively simple and powerful.

cmake is a powerful automated configuration tool that is open source and cross-platform. It builds the compilation system by reading the configuration in the script file CMakeLists.txt.

1. How to use

The process of using CMake to build a project under the Linux platform is as follows:

  1. Write C/C++/CUDA C++ source code.
  2. Write the CMake configuration file CMakeLists.txt according to the source code structure.
  3. Execute the command cmake PATH to generate Makefile. Among them, PATH is the directory where CMakeLists.txt is located. A separate folder is generally created here to store the build files, such as creating a build folder in the root directory, and then entering the build directory to execute cmake PATH (if CMakeLists.txt is in the upper directory, execute cmake directly..).
  4. Execute the make command in the build folder to compile.
  5. Use ./project_name to run the code. project_name is generally the compiled project name, and the project name is given in CMakeLists.txt.

2. Writing CMakeLists.txt

Write the CMakeLists.txt file and save it in the same directory as the main function file. The syntax of CMakeLists.txt is relatively simple and consists of commands, comments and spaces. Commands are not case-sensitive. Use ” # ” for comments. A command consists of a command name, parentheses, and parameters. Spaces are used to separate parameters. A simple CMakeLists.txt is as follows:

# Minimum version number requirement
cmake_minimum_required (VERSION 3.27)
# Project name and programming language
project(project LANGUAGES CXX CUDA)

# Set the compilation type to RELEASE or DEBUG (you need to know the difference between the two)

set(CMAKE_BUILD_TYPE RELEASE)

#Specify C++ version

set(CMAKE_CXX_STANDARD 14)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

#Specify the target executable file
add_executable(project main.cpp)

Among them, cmake_minimum_required(); project(); add_executable(); set(); are all commands (can be seen as functions). cmake_minimum_required: Specifies the minimum version of CMake required to run this configuration file, for example, the minimum version is 3.27;
project: The parameter value is project. This command indicates that the name of the project is project, and the programming language is specified after the LANGUAGES keyword.
add_executable: Compile the source file named main.cpp into an executable file named project.

3. Commonly used commands for writing CMakeLists.txt

1. Specify the minimum version of cmake
cmake_minimum_required(version version number)
For example:
cmake_minimum_required(version 3.27)
2. Define project name
#Define project name
project(project name)
For example:
project(project)
3. Display defined variables
set(var [value])
For example:
# The first usage is to generate a code file list
#First set the value of SRC_LIST directly
set(SRC_LIST XXX.h XXX.cpp)
#Then add main.cpp to SRC_LIST
set(SRC_LIST ${SRC_LIST} main.cpp)
# The second usage is to set the library generation directory or executable file generation directory.
set( LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
set( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
4. Set compilation type
#Compile static library
add_library(library name STATIC code file name)
#Compile dynamic library
add_library(library name SHARED code file name)
# Compile executable program
add_executable(executable program name code file name)
For example:
#Compile static library
add_library(add STATIC add.h add.cpp)
add_library(add STATIC ${ADD_SRC} ${ADD_HDR})
#Compile dynamic library
add_library(add SHARED add.h add.cpp)
add_library(add SHARED ${ADD_SRC} ${ADD_HDR})
# Compile executable program
add_executable(main add.h add.cpp mai.cpp)
add_executable(main ${MAIN_SRC} ${MAIN_HDR})
5. Specify the static library or dynamic library compilation output directory
For example, output the currently compiled static library or dynamic library to the lib subdirectory of the current project folder.
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
6. Specify the executable program compilation output directory
For example, output the current executable program to the bin subdirectory of the current project folder.
#Set the directory for executable binary files
set( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
7. Set the link library search directory
For example, set the link library search directory to the lib/linux folder under the current project folder.
link_directories( ${PROJECT_SOURCE_DIR}/lib/linux)
8. Set include directories
For example, set the include directory to the include folder under the current project folder.
include_directories(${PROJECT_SOURCE_DIR}/include)

Or use target_include_directories(${PROJECT_NAME} PUBLIC “./include”)
9. Set macro definition
#Predefined macros
add_definitions(-D macro name)
For example:
add_definitions(-DWINDOWS)
add_definitions(-DLINUX)
10. Link static libraries
link_libraries(
Static library 1
Static library 2
Static library 3

)
Note that the static libraries in link_libraries are full paths and are often used with link_directories, for example:
lib1.a lib2.a is in the directory ${PROJECT_SOURCE_DIR}/lib/linux, set the link directory first, and then link the corresponding library
#Set link directory
link_directories( ${PROJECT_SOURCE_DIR}/lib/linux)
link_libraries(
lib1.a
lib2.a
)
11. Link dynamic library
target_link_libraries (the name of the file to be generated and the name of the dynamic library to be linked)
For example
target_link_libraries(main dl)
12 The difference between .link_libraries and target_link_libraries
In cmake syntax, link_libraries and target_link_libraries are two very important ways to link libraries. Although they are very similar in writing, they are very different in function:
(1) link_libraries is used before add_executable, target_link_libraries is used after add_executable
(2) link_libraries are used to link static libraries, and target_link_libraries are used to link imported libraries, that is, the .lib library of dynamic libraries is implicitly called according to the header file + .lib + .dll method.
13. file syntax
13.1 Add all types of files in the folder to the file list
For example, add the file names of all .cpp files in the current folder to MAIN_SRC, and add all .h files in the current folder to MAIN_HDR.
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB MAIN_HDR ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
For example, add the file names of all .cpp files in the src folder of the current folder to MAIN_SRC, and add all .h files in the src folder of the current folder to MAIN_HDR.
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_HDR ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h)
13.2 Search the folder recursively and add files of the matching type under the folder (including subdirectories) to the file list
For example, add the file names of all .cpp files in the current folder (including subdirectories) to MAIN_SRC, and add all .h files to MAIN_HDR.
file(GLOB_RECURSE MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE MAIN_HDR ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
14. Add subfolders
For example
add_subdirectory(src)
This statement will execute CMakeLists.txt in the src subdirectory after executing CMakeLists.txt in the current folder.
15. message output message mechanism
The output is normal:
message(STATUS “Enter cmake ${CMAKE_CURRENT_LIST_DIR}”)
Output warning
message(WARNING “Enter cmake ${CMAKE_CURRENT_LIST_DIR}”)
Output error:
message(FATAL_ERROR “Enter cmake ${CMAKE_CURRENT_LIST_DIR}”)
16. Installation
The install command is used to define installation rules. The installed content includes binary executable files, dynamic libraries, static libraries, files, directories, scripts, etc.
16.1 Target file installation
For example:
install(TARGETSutil
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
ARCHIVE refers to the static library, LIBRARY refers to the dynamic library, and RUNTIME refers to the executable target binary. The above example means:
If the target util is an executable binary target, install it to the ${CMAKE_INSTALL_PREFIX}/bin directory. If the target util is a static library, install it to the ${CMAKE_INSTALL_PREFIX}/lib directory. If the target util is a dynamic library, install it to ${CMAKE_INSTALL_PREFIX}/lib directory
16.2 Folder installation
install(DIRECTORY include/ DESTINATION include/util)
This statement means to install the include/ directory to the include/util directory
17. Set compilation options
You can set compilation options through the add_compile_options command, or you can modify CMAKE_CXX_FLAGS or CMAKE_C_FLAGS through the set command.

Way 1
set( CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -std=c + + 11 -march=native -O3 -frtti -fpermissive -fexceptions -pthread”)
Way 2
add_compile_options(-march=native -O3 -fexceptions -pthread -fPIC)
The difference between these two methods is:
The compilation options added by the add_compile_options command are for all compilers (including c and c++ compilers), while the set command to set the CMAKE_C_FLAGS or CMAKE_CXX_FLAGS variables is only for c and c++ compilers respectively.
18. Predefined variables (keywords already available in cmke itself)
18.1 Basic variables
PROJECT_SOURCE_DIR: Generally the root directory of the project;
PROJECT_BINARY_DIR: The directory where the cmake command is executed, usually ${PROJECT_SOURCE_DIR}/build;
CMAKE_INCLUDE_PATH: system environment variable;
CMAKE_LIBRARY_PATH: system environment variable;
CMAKE_CURRENT_SOURCE_DIR: The path where the currently processed CMakeLists.txt is located;
CMAKE_CURRENT_BINARY_DIR: target compilation directory (use ADD_SURDIRECTORY(src bin) to change the value of this variable, SET(EXECUTABLE_OUTPUT_PATH ) will not affect this variable, but only changes the storage path of the final target file);
PROJECT_NAME: The project name defined through the PROJECT directive;
18.2 Operating System Variables
UNIX: TRUE on all UNIX-like platforms, including OS X and cygwin, Linux/Unix operating systems;
WIN32: TRUE on all win32 platforms, including Windows32 and 64-bit operating systems;
APPLE: Apple operating system;
For example, operating system judgment method 1:
if(WIN32)
message(STATUS “This operating system is Windows.”)
elseif(UNIX)
message(STATUS “This operating system is Linux.”)
elseif(APPLE)
message(STATUS “This operating system is APPLE.”)
endif(WIN32)
18.3 Environment variables
Set environment variables:
set(env{name} value)
Call environment variables:
$env{name}
For example
message(STATUS “$env{name}”)
19. Conditional judgment
19.1 Logical judgment and comparison
if (expression): true when expression is not empty, false values include (0,N,NO,OFF,FALSE,NOTFOUND);
if (var1 AND var2): true if both variables are true;
if (var1 OR var2): true if one of the two variables is true;
if (EXISTS dir) if (EXISTS file): true if the directory or file exists;
if (IS_DIRECTORY dir): true when dir is a directory;
19.2 Numerical Comparison
if (variable LESS number): True if variable is less than number;
if (string LESS number): true if string is less than number;
if (variable GREATER number): True if variable is greater than number;
if (string GREATER number): true if string is greater than number;
if (variable EQUAL number): True if variable is equal to number;
if (string EQUAL number): True if string is equal to number.
19.3 Alphabetical Order Comparison
if (variable STRLESS string)
if (string STRLESS string)
if (variable STRGREATER string)
if (string STRGREATER string)
if (variable STREQUAL string)
if (string STREQUAL string)

The following is a CMakeLists.txt example of joint programming in C++ and CUDA:

cmake_minimum_required(VERSION 3.27)
project(project LANGUAGES CXX CUDA)
set(CMAKE_BUILD_TYPE RELEASE)

#Specify C++ version
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)


# Check the CUDA development toolkit and add the development toolkit to the path
include(CheckLanguage)
if(NOT CUDAToolkit_FOUND)
    include(FindCUDAToolkit)
endif()
include_directories(${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
#Specify CUDA C++ version
check_language(CUDA)
set(CMAKE_CUDA_STANDARD 14)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)

ADD_EXECUTABLE(${PROJECT_NAME} kernel.cpp)

#Specify the header file directory included in the target
target_include_directories(${PROJECT_NAME} PUBLIC "./cuda/include")

#Add the library file directory. If you do not add it, the library file will not be found.
target_link_directories(${PROJECT_NAME} PUBLIC "./cuda/build")

#Specify the target library to link to
target_link_libraries(${PROJECT_NAME} PUBLIC cuda_lib)
target_link_libraries(${PROJECT_NAME} PUBLIC CUDA::cudart)

The cuda code has been compiled into a static library “libcuda_lib.a” and stored in the “./cuda/build” file. The file where the main function is located is kernel.cpp. Various header files are placed in the “./cuda/include” folder.

4. Summary

CMAKE is very easy to use when compiling programs written in cuda and other languages under the Linux system. Basically, all the common commands in this article can be used.

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. CUDA entry-level skills treeHomepageOverview 3746 people are learning the system