目录
1 常用命令
1.1 单文件夹项目
CMAKE_MINIMUM_REQUIRED(VERSION 3.10) #规定cmake最低版本号,其中“3.10”可变
PROJECT(demo) #项目名称,基本没影响
ADD_EXECUTABLE(hello hello.c)
#hello为可执行文件的名字,hello.c为源文件,可以有多个源文件,源文件之间以空格隔开,并且只需写.c或者.cpp文件
AUX_SOURCE_DIRECTORY(./ DIR_SRC)
#意思是将当前目录下的所有源文件指代为名为“DIR_SRC"的变量
#可以配合ADD_EXECUTABLE(hello ${DIR_SRC})使用,减少输入量
1.2 多文件夹项目
ADD_LIBRARY(TEST SHARED ${DIR_LIB})
#将DIR_LIB所指代的源代码,生成libMYLIB.so动态运行库文件
#第二个参数为指代生成动态运行库,静态库参数为STATIC
ADD_SUBDIRECTORY(./sublib) #添加项目子目录,并执行子目录下的cmake文件
#一般写在父目录的cmake文件内
TARGET_LINK_LIBRARIES(hello TEST)
#将hello可执行程序连接名为TEST的动态或静态库文件
#第一个参数为ADD_EXECUTABLE生成的可执行文件名 第二个参数为动态库或静态库名
INCLUDE_DIRECTORIES(./demo/include)
#include的.h文件搜索路径使得.c文件引用可以省略前面的路径
#参数可以有多个,每个参数之间以空格隔开
LINK_DIRECTORIES(./lib)
#指明要引用的.so或.a路径,与TARGET_LINK_LIBRARIES配合使用
#参数可以有多个,每个参数之间以空格隔开
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so")
#要引用的.so或.a文件的所在位置,每个参数都要表明全路径
#这一条命令的效果与LINK_DIRECTORIES和TARGET_LINK_LIBRARIES合体等同
ADD_DEFINITIONS(-DGPU)
#向c语言文件添加预定义宏,相当于在c文件中使用#define GPU
例子1
INCLUDE_DIRECTORIES("/opt/MATLAB/R2012a/extern/include")
LINK_DIRECTORIES("/opt/MATLAB/R2012a/bin/glnxa64")
ADD_EXECUTABLE(myProject main.cpp)
target_link_libraries(myProject eng mx)
#equals to below
#target_link_libraries(myProject -leng -lmx)
#target_link_libraries(myProject libeng.so libmx.so)
例子2
INCLUDE_DIRECTORIES("/opt/MATLAB/R2012a/extern/include")
#directly link to the libraries.
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so")
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")
#equals to below
#LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so" "/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")
ADD_EXECUTABLE(myProject main.cpp
1.3 set 命令常用用法
(1)用法1设置普通变量
SET(OPENCL_PATH /usr/local/OpenCL) #设置OpenCL_PATH为/usr.....
#此种用法也可以为变量设置多个值,每个值以空格隔开
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}\build)
#可执行文件放在源代码目录的build文件夹下
#EXECUTABLE_OUTPUT_PATH为CMake预定义宏,指代可执行文件路径
#PROJECT_SOURCE_DIR为CMake预定义宏,指代拥有project命令的cmakelists文件位置
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}\lib)
#设置library文件输出位置为build\lib目录下,与ADD_LIBRARY一起使用
#LIBRARY_OUTPUT_PATH为CMake预定义宏,指代lib文件输出文职
#PROJECT_BINARY_DIR指代build文件位置
(2)设置缓存条目
缓存条目可以通过CMAKE的GUI界面的add entry按钮来增加。缓存条目的实质为可以跨层级进行传递的变量,类似于全局变量
SET(cache_entry_val2 ON CACHE BOOL "choose ON to enable" FORCE)
#第一个参数为变量名;第二个参数为变量值;第三个参数指明为缓存条目;
#第四个参数为变量的类型,除BOOL外还有FILEPATH、PATH、STRING / STRINGS、INTERNAL;
#第五个参数是变量的解释,供阅读者理解
#第五个参数FORCE用于是否强制更新缓存里面的值,配置后,每次都会强制更新
1.4 OPTION命令
option(TEST_DEBUG "option for debug" OFF)
#设置cmake选项,可与if endif结合是使用
2 实战例子(OpenCL+CMAKE)
2.1 文件树
2.2 CMakeLists.txt内容
CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
PROJECT(DEMO4-15-1)
INCLUDE_DIRECTORIES(/usr/include/)
LINK_DIRECTORIES(/usr/local/lib /usr/lib/aarch64-linux-gnu/)
ADD_EXECUTABLE(demo4-15-1 src/main.c)
TARGET_LINK_LIBRARIES(demo4-15-1 -lOpenCL)
2.3 main.c文件内容
#include <stdio.h>
#include <CL/cl.h>
#include <iostream>
#include "ocl_macros.h"
#define NUM_OF_ELEMENTS 32
int main(int argc, char *argv[])
{
cl_int status = 0;
cl_device_type dType = CL_DEVICE_TYPE_GPU;
cl_platform_id platform = NULL;
cl_device_id device;
cl_context context;
cl_command_queue commandQueue;
cl_mem clBuffer;
cl_int hostBuffer[NUM_OF_ELEMENTS] =
{
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
16, 17, 18, 19,
20, 21, 22, 23,
24, 25, 26, 27,
28, 29, 30, 31,
};
//Setup the OpenCL Platform,
//Get the first available platform. Use it as the default platform
status = clGetPlatformIDs(1, &platform, NULL);
LOG_OCL_ERROR(status, "clGetPlatformIDs Failed..." );
//Get the first available device
status = clGetDeviceIDs (platform, dType, 1, &device, NULL);
LOG_OCL_ERROR(status, "clGetDeviceIDs Failed..." );
//Create an execution context for the selected platform and device.
cl_context_properties cps[3] =
{
CL_CONTEXT_PLATFORM,
(cl_context_properties)platform,
0
};
context = clCreateContextFromType(
cps,
dType,
NULL,
NULL,
&status);
LOG_OCL_ERROR(status, "clCreateContextFromType Failed..." );
// Create command queue
commandQueue = clCreateCommandQueue(context,
device,
0,
&status);
LOG_OCL_ERROR(status, "clCreateCommandQueue Failed..." );
//Create OpenCL device input buffer
clBuffer = clCreateBuffer(
context,
CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
sizeof(cl_uint) * NUM_OF_ELEMENTS,
hostBuffer,
&status);
LOG_OCL_ERROR(status, "clCreateBuffer Failed..." );
//Read a 2D rectangular object from the clBuffer of 32 elements
int hostPtr2D[6] = {0, 0, 0, 0, 0, 0};
size_t bufferOrigin2D[3] = {1*sizeof(int), 6, 0};
size_t hostOrigin2D[3] = {0 ,0, 0};
size_t region2D[3] = {3* sizeof(int), 2,1};
status = clEnqueueReadBufferRect(
commandQueue,
clBuffer,
CL_TRUE,
bufferOrigin2D, /*Start of a 2D buffer to read from*/
hostOrigin2D,
region2D,
(NUM_OF_ELEMENTS / 8) * sizeof(int), /*buffer_row_pitch */
0, /*buffer_slice_pitch*/
0, /*host_row_pitch */
0, /*host_slice_pitch */
static_cast<void*>(hostPtr2D),
0,
NULL,
NULL);
LOG_OCL_ERROR(status, "clEnqueueReadBufferRect Failed..." );
std::cout << "2D rectangle selected is as follows" << std::endl;
std::cout << " " << hostPtr2D[0];
std::cout << " " << hostPtr2D[1];
std::cout << " " << hostPtr2D[2] << std::endl;
std::cout << " " << hostPtr2D[3];
std::cout << " " << hostPtr2D[4];
std::cout << " " << hostPtr2D[5] << std::endl;
//Read a 3D rectangular object from the clBuffer of 32 elements
int hostPtr3D[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
size_t bufferOrigin3D[3] = {1*sizeof(int), 1, 0};
size_t hostOrigin3D[3] = {0 ,0, 0};
size_t region3D[3] = {3* sizeof(int), 1,3};
status = clEnqueueReadBufferRect(
commandQueue,
clBuffer,
CL_TRUE,
bufferOrigin3D, /*Start of a 2D buffer to read from*/
hostOrigin3D,
region3D,
(NUM_OF_ELEMENTS / 8) * sizeof(int), /*buffer_row_pitch */
(NUM_OF_ELEMENTS / 4) * sizeof(int), /*buffer_slice_pitch*/
0, /*host_row_pitch */
0, /*host_slice_pitch */
static_cast<void*>(hostPtr3D),
0,
NULL,
NULL);
LOG_OCL_ERROR(status, "clEnqueueReadBufferRect Failed..." );
std::cout << "3D rectangle selected is as follows" << std::endl;
std::cout << " " << hostPtr3D[0];
std::cout << " " << hostPtr3D[1];
std::cout << " " << hostPtr3D[2] << std::endl;
std::cout << " " << hostPtr3D[3];
std::cout << " " << hostPtr3D[4];
std::cout << " " << hostPtr3D[5] << std::endl;
std::cout << " " << hostPtr3D[6];
std::cout << " " << hostPtr3D[7];
std::cout << " " << hostPtr3D[8] << std::endl;
return 0;
}
ocl_macros.h内容
#if !defined OCL_MACROS_H
#define OCL_MACROS_H
#define LOG_OCL_ERROR(x, STRING ) if(x!=CL_SUCCESS) {printf( "\nLine No: %d ", __LINE__ ); printf(STRING); printf("\n Error= %d\n",x); exit(-1); }
#define LOG_OCL_COMPILER_ERROR(PROGRAM, DEVICE) \
{ \
cl_int logStatus; \
char * buildLog = NULL; \
size_t buildLogSize = 0; \
logStatus = clGetProgramBuildInfo(PROGRAM, \
DEVICE, \
CL_PROGRAM_BUILD_LOG, \
buildLogSize, \
buildLog, \
&buildLogSize); \
if(logStatus != CL_SUCCESS) \
{ \
printf( "Error # %d logStatus", logStatus ); \
printf( ":: clGetProgramBuildInfo<CL_PROGRAM_BUILD_LOG> failed."); \
exit(1); \
} \
\
buildLog = (char*)malloc(buildLogSize); \
if(buildLog == NULL) \
{ \
printf("Failed to allocate host memory. (buildLog)\n"); \
exit(1); \
} \
memset(buildLog, 0, buildLogSize); \
\
logStatus = clGetProgramBuildInfo(PROGRAM, \
DEVICE, \
CL_PROGRAM_BUILD_LOG, \
buildLogSize, \
buildLog, \
NULL); \
if(logStatus != CL_SUCCESS) \
{ \
printf( "Error # %d logStatus ", logStatus); \
printf( ":: clGetProgramBuildInfo<CL_PROGRAM_BUILD_LOG> failed."); \
exit(1); \
} \
\
printf(" \n\t\t\tBUILD LOG\n"); \
printf(" ************************************************\n"); \
printf("%s",buildLog); \
printf(" ************************************************\n"); \
free(buildLog); \
exit(1); \
}
/* Get platform information and set up the Platform for the defined vendor*/
#define OCL_CREATE_PLATFORMS( PLATFORM ) \
cl_uint num_platforms; \
if ((clGetPlatformIDs(0, NULL, &num_platforms)) == CL_SUCCESS) \
{ \
PLATFORM = (cl_platform_id *)malloc(sizeof(cl_platform_id)*num_platforms); \
if(clGetPlatformIDs(num_platforms, PLATFORM, NULL) != CL_SUCCESS) \
{ \
free(PLATFORM); \
exit(-1); \
} \
}
/*Release the Allocated Platforms*/
#define OCL_RELEASE_PLATFORMS( PLATFORM ) \
free(PLATFORM);
#define OCL_CREATE_DEVICE( PLATFORM, DEVICE_TYPE, DEVICES ) \
cl_uint num_devices; \
if (clGetDeviceIDs( PLATFORM, DEVICE_TYPE, 0, \
NULL, &num_devices) == CL_SUCCESS) \
{ \
DEVICES = (cl_device_id *)malloc(sizeof(cl_device_id)*num_devices); \
if (clGetDeviceIDs( PLATFORM, DEVICE_TYPE, num_devices, \
DEVICES, NULL) != CL_SUCCESS) \
{ \
free(DEVICES); \
exit(-1); \
} \
}
/*Release the Allocated Device*/
#define OCL_RELEASE_DEVICES( DEVICES ) \
free(DEVICES);
#endif
3 参考链接
(1)demo代码下载
https://github.com/AdamWSL/CMake_Tutorial.git
(2)cmake下载地址
https://cmake.org/download/
(3)CMake官方教程— CMake 3.17.0-rc1文档
https://cmake.org/cmake/help/latest/guide/tutorial/index.html
(4)CMake入门实战
https://www.hahack.com/codes/cmake/
(5)cmake使用示例与整理总结
https://blog.csdn.net/QTVLC/article/details/82380413
(6)CMake命令/函数汇总(翻译自官方手册)
https://www.cnblogs.com/52php/p/5684588.html
(7)CMake视频教程
https://www.bilibili.com/video/BV16V411k7eF?p=2