CMakeLists.txt写法

本文详细介绍了CMake在OpenCL项目中的配置和管理,包括单文件夹与多文件夹项目的构建、set和OPTION命令的使用,以及OpenCL+CMake的实战案例。涵盖CMakeLists.txt编写、源代码组织和链接OpenCL库等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

在检查 CMakeLists.txt 文件的代码风格时,可以使用一些专门的工具来帮助完成这一任务。这些工具可以帮助开发者发现潜在的错误、不符合最佳实践的写法以及不一致的代码风格问题。以下是一些常用的工具和方法: ### 使用 `cmake-lint` `cmake-lint` 是一个用于检查 CMakeLists.txt 文件风格的工具,它类似于 Python 中的 `pylint`。它能够检测出不符合 CMake 编码规范的地方,并提供相应的建议。 #### 安装 `cmake-lint` 可以通过 Python 的 `pip` 安装 `cmake-lint`: ```bash pip install cmake-lint ``` #### 使用 `cmake-lint` 安装完成后,可以直接在包含 CMakeLists.txt 文件的目录中运行以下命令: ```bash cmake-lint CMakeLists.txt ``` 该命令会输出所有发现的风格问题及其位置,帮助开发者进行修正。 ### 使用 `cmake-format` `cmake-format` 是一个用于格式化 CMakeLists.txt 文件的工具,它可以自动调整代码格式以符合一定的风格指南。这对于统一团队内部的代码风格非常有用。 #### 安装 `cmake-format` 同样,`cmake-format` 也可以通过 `pip` 安装: ```bash pip install cmake-format ``` #### 使用 `cmake-format` 运行以下命令来格式化 CMakeLists.txt 文件: ```bash cmake-format -i CMakeLists.txt ``` 此命令会直接修改原文件,将其格式化为符合默认或自定义配置的风格。 ### 集成到 IDE 或编辑器 许多现代的 IDE 和文本编辑器(如 VSCode、CLion)支持通过插件或扩展集成上述工具。例如,在 VSCode 中,可以通过安装 CMake Tools 插件来获得更好的 CMake 支持,包括代码风格检查和格式化功能。 ### 自定义规则 对于 `cmake-lint` 和 `cmake-format`,用户还可以通过配置文件来自定义规则。这允许团队根据自己的需求定义特定的编码标准,从而确保所有成员遵循一致的代码风格。 ### 持续集成(CI)集成 为了确保每次提交的代码都符合预定的风格指南,可以将这些工具集成到持续集成流程中。例如,在 GitHub Actions 或 GitLab CI 中添加一个步骤来运行 `cmake-lint` 或 `cmake-format`,并在构建失败时通知开发者。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值