通过cmakelist生成与调用C++动态链接库


前言

此前有写过用编译工具链直接通过命令行的方式生成与调用C++动态链接库的方法,本文记录下通过cmake来实现so的生成。


生成动态链接库

样例项目说明

以下笔者通过具体的开源项目代码进行演示。
在这里插入图片描述

通过以上项目的层级结构,我们可以看到有两个CMakeLists.txt。
其中外层CMakeLists.txt内容为:

# Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
  
# 最低CMake版本
cmake_minimum_required(VERSION 3.5.1)

# 项目名
project(HelmetIdentification)

# 配置环境变量MX_SDK_HOME,如:/home/xxxxxxx/MindX_SDK/mxVision,可在远程环境中用指令env查看
set(MX_SDK_HOME $ENV{MX_SDK_HOME})

if (NOT DEFINED ENV{MX_SDK_HOME})
    set(MX_SDK_HOME "/usr/local/Ascend/mindx_sdk")
    message(STATUS "set default MX_SDK_HOME: ${MX_SDK_HOME}")
else ()
    message(STATUS "env MX_SDK_HOME: ${MX_SDK_HOME}")
endif()

add_subdirectory("./src")

src中的CMakeLists.txt内容为:

# CMake lowest version requirement
cmake_minimum_required(VERSION 3.5.1)
# project information
project(Individual)

# Compile options
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0 -Dgoogle=mindxsdk_private)
add_compile_options(-std=c++11 -fPIC -fstack-protector-all -Wall -D_FORTIFY_SOURCE=2 -O2)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY  "../../")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro,-z,now,-z,noexecstack -s -pie -pthread")
set(CMAKE_SKIP_RPATH TRUE)

SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

# Header path
include_directories(
    ${MX_SDK_HOME}/include/
    ${MX_SDK_HOME}/opensource/include/
    ${MX_SDK_HOME}/opensource/include/opencv4/
    /home/HwHiAiUser/Ascend/ascend-toolkit/latest/include/
    ./
)

# add host lib path
link_directories(
    ${MX_SDK_HOME}/lib/
    ${MX_SDK_HOME}/lib/modelpostprocessors
    ${MX_SDK_HOME}/opensource/lib/
    ${MX_SDK_HOME}/opensource/lib64/
    /usr/lib/aarch64-linux-gnu/
    /home/HwHiAiUser/Ascend/ascend-toolkit/latest/lib64/
    /usr/local/Ascend/driver/lib64/
    ./
)


aux_source_directory(. sourceList)

add_executable(main ${sourceList})

target_link_libraries(main mxbase opencv_world boost_filesystem glog avformat avcodec avutil cpprest yolov3postprocess ascendcl acl_dvpp_mpi)

install(TARGETS main DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

项目的主要目的是把src中的main.cpp文件编译成可执行文件输出到指定的地址。我们需要做的是把除main.cpp以外的文件编译成一个so,通过so来编译main.cpp,而不是通过源码的方式。(为了方便,我下面实现的时候把main.cpp也打包进了so)

修改cmakelist

src中的cmakelist,将原来:

aux_source_directory(. sourceList)

add_executable(main ${sourceList})

target_link_libraries(main mxbase opencv_world boost_filesystem glog avformat avcodec avutil cpprest yolov3postprocess ascendcl acl_dvpp_mpi)

install(TARGETS main DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

修改为:

aux_source_directory(. sourceList)

# add_executable(main ${sourceList})

add_library(ai_detection310 SHARED ${sourceList})

target_link_libraries(ai_detection310 mxbase opencv_world boost_filesystem glog avformat avcodec avutil cpprest yolov3postprocess ascendcl acl_dvpp_mpi)

install(TARGETS ai_detection310 DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

在这里插入图片描述

编译运行后将会得到ai_detection310.so

调用动态链接库

修改配置文件

将生成的ai_detection310.so移动台指定的位置,为了方便我在原来的同级目录下,新建了test_so的文件夹,把需要用的文件都复制了过来,结构如下:
在这里插入图片描述
其中test_so中的CMakeLists.txt为src中的文件的拷贝,然后再对test_so中的CMakeLists.txt进行修改:
将CMakeLists.txt中:

aux_source_directory(. sourceList)

# add_executable(main ${sourceList})

add_library(ai_detection310 SHARED ${sourceList})

target_link_libraries(ai_detection310 mxbase opencv_world boost_filesystem glog avformat avcodec avutil cpprest yolov3postprocess ascendcl acl_dvpp_mpi)

install(TARGETS ai_detection310 DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

修改为:

include_directories(${PROJECT_SOURCE_DIR}/include/)

message(STATUS "Include directories: ${PROJECT_SOURCE_DIR}")

add_executable(main ${PROJECT_SOURCE_DIR}/main.cpp)

target_link_libraries(main mxbase opencv_world boost_filesystem glog avformat avcodec avutil cpprest yolov3postprocess ascendcl acl_dvpp_mpi)

target_link_libraries(main ${PROJECT_SOURCE_DIR}/lib/libai_detection310.so)

install(TARGETS main DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

修改原来外层的CMakeLists.txt

将原来外层CMakeLists.txt中:

add_subdirectory("./src")

修改为:

add_subdirectory("./test_so")

编译运行后将会得到main的可执行文件。


总结

通过cmake进行so编译还是比较简单的,主要是用add_library(ai_detection310 SHARED ${sourceList})生成so替换原来add_executable(main ${sourceList})生成的可执行文件,然后对main.cpp进行配置,能够正确调用生成的so。这样我们就实现了通过cmakelist生成与调用C++动态链接库。
如果阅读本文对你有用,欢迎一键三连呀!!!
2024年5月14日16:25:40在这里插入图片描述

<think>我们正在配置Qt5.14CUDA11.6的开发环境,并且用户要求使用CMakeLists.txt进行配置。参考之前的引用,特别是引用[1]和引用[4]中提到的方法,我们可以通过CMake来组织项目,同时编译CPP和CUDA文件。步骤概述:1.确保已安装CUDA Toolkit11.6和Qt5.14,并且CMake版本至少为3.8(推荐3.10以上)。2.在CMakeLists.txt中启用CUDA语言支持,并设置CUDA的路径和编译选项。3.将CUDA源文件(.cu)添加到项目中,并设置它们需要由NVCC编译。4.链接CUDA运行时库(cudart)以及其他可能需要的CUDA库(如cublas、cufft等)。5.配置Qt5.14,确保CMake能够找到Qt的库。详细步骤:1.创建CMakeLists.txt文件,并设置最低CMake版本和项目名称:```cmakecmake_minimum_required(VERSION3.10)project(MyQtCudaProjectLANGUAGES CXX CUDA)#注意这里添加了CUDA语言```2.设置C++标准并查找Qt5组件(例如,如果你的Qt项目需要Core和Widgets):```cmakeset(CMAKE_CXX_STANDARD11)set(CMAKE_CXX_STANDARD_REQUIREDON)#查找Qt5,需要指定你使用的组件find_package(Qt5 COMPONENTSCore Widgets REQUIRED)```3.设置CUDA Toolkit的路径(通常CMake会自动找到,但可以指定):```cmake#可选:如果CMake找不到CUDA,可以手动设置# set(CUDA_TOOLKIT_ROOT_DIR "C:/Program Files/NVIDIAGPU ComputingToolkit/CUDA/v11.6")```4.添加可执行文件,并包含源文件(包括.cpp和.cu文件):```cmake#添加可执行文件add_executable(${PROJECT_NAME}main.cppmainwindow.cpp#...其他cpp文件kernel.cu#CUDA源文件)```5.链接Qt5的库和CUDA的库:```cmake#链接Qt5库target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Widgets)#链接CUDA运行时库target_link_libraries(${PROJECT_NAME} ${CUDA_LIBRARIES})#如果需要其他CUDA库,如cublastarget_link_libraries(${PROJECT_NAME} ${CUDA_cublas_LIBRARY})```6.设置CUDA的编译选项(例如计算能力):```cmake#设置CUDA架构(根据你的GPU调整)set(CUDA_ARCHITECTURES "75")#例如75代表Turing架构(RTX20系列)```7.对于Windows平台,可能需要设置一些额外的链接选项,因为CUDA库通常为动态链接库(.dll),需要将CUDA的bin目录添加到系统路径,或者在CMake中复制dll到输出目录。8.配置Qt的资源文件(.qrc)和元对象编译(moc)等,CMake的Qt5模块会自动处理,但需要确保源文件被正确包含。9.生成项目:在构建目录中运行cmake,指定生成器(如VisualStudio2019或MinGW)和Qt的路径(如果需要)。示例CMakeLists.txt完整内容(简化版):```cmakecmake_minimum_required(VERSION3.10)project(QtCudaDemoLANGUAGES CXX CUDA)set(CMAKE_CXX_STANDARD11)set(CMAKE_CXX_STANDARD_REQUIREDON)#查找Qt5find_package(Qt5COMPONENTS CoreWidgetsREQUIRED)#设置CUDA架构set(CUDA_ARCHITECTURES"75"CACHESTRING"CUDA architectures")#添加可执行文件add_executable(QtCudaDemomain.cppmainwindow.cppmainwindow.hkernel.cu)#自动调用moctarget_link_libraries(QtCudaDemo Qt5::Core Qt5::Widgets)#链接CUDA库target_link_libraries(QtCudaDemo CUDA::cudart)#如果使用其他CUDA库,例如cublas#find_package(CUDAToolkitREQUIRED)# target_link_libraries(QtCudaDemoCUDA::cublas)```注意:CMake3.18之后,对CUDA的支持更好,推荐使用`find_package(CUDAToolkit)`来查找CUDA Toolkit,然后使用`CUDA::`命名空间的目标。对于CUDA源文件,CMake会自动调用NVCC进行编译,并处理C++文件的链接。问题排查: -如果CMake找不到CUDA,可以手动设置`CUDA_TOOLKIT_ROOT_DIR`。-确保Qt的路径被正确设置(例如,通过设置`CMAKE_PREFIX_PATH`指向Qt的安装目录)。 -在Windows上,确保生成Qt的编译器匹配(如使用MSVC编译的Qt,则生成器应为Visual Studio;MinGW编译的Qt则使用MinGW生成器)。这样配置后,就可以在Qt项目中混合使用C++和CUDA代码了。引用说明:参考引用[1]中提到的CMake组织项目,以及引用[4]中关于CMake同时编译cpp和cu文件的方法,我们实现了上述配置。最后,生成相关问题:</think>### 在Qt 5.14中通过CMake配置CUDA 11.6开发环境 以下是完整的配置步骤(基于Windows/Linux通用方案): #### 1. **基础CMakeLists结构** ```cmake cmake_minimum_required(VERSION 3.18) # CUDA 11.6需要CMake≥3.18 project(MyQtCudaProject LANGUAGES CXX CUDA # 关键:启用CUDA语言支持 VERSION 1.0) # 设置C++标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 查找Qt5核心组件 find_package(Qt5 COMPONENTS Core Widgets REQUIRED) # 根据需求添加其他模块 ``` #### 2. **CUDA专用配置** ```cmake # 启用CUDA Toolkit并指定版本 find_package(CUDAToolkit 11.6 REQUIRED) # 设置GPU计算能力(根据实际显卡调整) set(CUDA_ARCHITECTURES "75" CACHE STRING "GPU架构") # RTX 20系列=75, RTX 30系列=86 # 添加CUDA编译选项 target_compile_options(${PROJECT_NAME} PRIVATE $<$<COMPILE_LANGUAGE:CUDA>: --use_fast_math # 启用快速数学运算 -Xcompiler=-Wall # 传递警告选项给主机编译器 > ) ``` #### 3. **项目配置链接** ```cmake # 添加可执行文件(包含CUDA源文件) add_executable(${PROJECT_NAME} main.cpp MainWindow.cpp kernel.cu # CUDA核函数文件 ) # 链接Qt库 target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Widgets ) # 链接CUDA库 target_link_libraries(${PROJECT_NAME} PRIVATE CUDA::cudart # CUDA运行时库 CUDA::cublas # 按需添加其他库 ) ``` #### 4. **目录结构示例 ``` MyProject/ ├── CMakeLists.txt ├── main.cpp ├── MainWindow.{h,cpp} └── cuda/ ├── kernel.cu # CUDA核函数实现 └── cuda_utils.h # CUDA辅助函数 ``` #### 5. **混合代码示例 **kernel.cu** (CUDA核函数): ```cuda #include <cuda_runtime.h> __global__ void vectorAdd(const float* A, const float* B, float* C, int numElements) { int i = blockDim.x * blockIdx.x + threadIdx.x; if (i < numElements) C[i] = A[i] + B[i]; } // 包装函数供C++调用 extern "C" void launchVectorAdd(const float* A, const float* B, float* C, int n) { dim3 blockSize(256); dim3 gridSize((n + blockSize.x - 1) / blockSize.x); vectorAdd<<<gridSize, blockSize>>>(A, B, C, n); } ``` **main.cpp** (Qt调用CUDA): ```cpp #include "MainWindow.h" #include <cuda_runtime.h> extern "C" void launchVectorAdd(const float*, const float*, float*, int); int main(int argc, char *argv[]) { QApplication a(argc, argv); // CUDA内存分配 const int N = 10000; float *d_A, *d_B, *d_C; cudaMalloc(&d_A, N*sizeof(float)); cudaMalloc(&d_B, N*sizeof(float)); cudaMalloc(&d_C, N*sizeof(float)); // 执行CUDA核函数 launchVectorAdd(d_A, d_B, d_C, N); MainWindow w; w.show(); return a.exec(); } ``` #### 6. **构建命令 ```bash # 生成构建系统 mkdir build && cd build cmake .. -DCMAKE_PREFIX_PATH="C:/Qt/5.14.2/msvc2017_64" # Windows指定Qt路径 # 或 Linux: cmake .. -DCMAKE_PREFIX_PATH="/opt/Qt/5.14.2/gcc_64" # 编译项目 cmake --build . --config Release # 或 Debug ``` #### 关键配置说明: 1. **架构兼容性** 在`CUDA_ARCHITECTURES`中指定正确的GPU计算能力: - NVIDIA Tesla V100: `70` - RTX 2080: `75` - RTX 3080: `86` 2. **调试支持** 在CMake中启用调试符号: ```cmake set(CMAKE_CUDA_FLAGS_DEBUG "-G -g") # 生成设备调试信息 ``` 3. **多平台支持** 使用CMake生成器表达式处理平台差异: ```cmake target_link_libraries(${PROJECT_NAME} PRIVATE $<$<PLATFORM_ID:Windows>:CUDA::cudart_static> $<$<PLATFORM_ID:Linux>:CUDA::cudart> ) ``` 4. **Qt Creator集成** 在Qt Creator中: - 打开`CMakeLists.txt`作为项目文件 - 在`项目设置 > CMake`中添加CUDA路径: ``` CUDA_TOOLKIT_ROOT_DIR=C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v11.6 ``` > 验证配置:运行项目后检查`cudaGetLastError()`返回值,0表示成功[^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI小笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值