技术开发 频道

用cmake搭建环境来编译一个CUDA程序

  【IT168 文档一、简介

  在Windows平台下,用cmake来搭建环境环境,在VS2005下运行CUDA程序。其实,在Windows下,在CUDA2.3的SDK里,有一个Cuda.Rules的文件。通过这个文件,在VS2005里可以很方便的设置各个编译参数。不过通过cmake文件可以不用重复设置编译参数。

  二、机子环境

  1 计算机 : ThinkPad R61i

  2 显卡 : NVIDIA Quadro NVS 140M

  3 CUDA版本 : CUDA2.3

  三、所需文件

  1 cmake文件 : CMakeLists.txt - 主要的cmake配置文件 FindCuda.cmake - 设置CUDA编译环境 FindCudaLibrary.cmake - 寻找 CUDA 和 CUDA SDK 库

  2 源代码 : template.cu template_kernel.cu template_gold.cpp -CUDA SDK 里一个很经典的小程序

  注意:各个文件之间的路径

cmake_cuda

    
-bin

    
-cmke

        
- FindCuda.cmake

        
- FindCudaLibrary.cmake

    
-test_cuda

        
- CMakeLists.txt

        
- template.cu

        
- template_kernel.cu

        
- template_gold.cpp

 

  四 步骤

  1 CUDA安装好后,确定一下有没有 CUDA_BIN_PATH 和 NVSDKCUDA_ROOT 这两个环境变量

  2 CMakeList.txt 文件

CMAKE_MINIMUM_REQUIRED( VERSION 2.4 )

PROJECT( test_cuda )

OPTION( BUILD_test

"Build the test of cmake of cuda."

ON )


IF( BUILD_test )

#注意一下FindCuda.cmake所放的路径

  INCLUDE( ..
/cmake/FindCuda.cmake )

  CUDA_ADD_EXECUTABLE( test

   template.cu

   template_gold.cpp template_kernel.cu

   )

ENDIF( BUILD_test )

  3 FindCuda.cmake 文件

# The script creates the following macros:

# CUDA_INCLUDE_DIRECTORIES( path0 path1 ... )

#
-- Sets the directories that should be passed to nvcc

#    (e.g. nvcc
-Ipath0 -Ipath1 ... ). These paths usually contain other .cu

#    files.

#

# CUDA_ADD_LIBRARY( cuda_target file0 file1 ... )

#
-- Creates a shared library "cuda_target" which contains all of the source

#    (
*.c, *.cc, etc.) specified and all of the nvcc'ed .cu files specified.

#    All of the specified source files and generated .c files are compiled

#    using the standard CMake compiler, so the normal INCLUDE_DIRECTORIES,

#    LINK_DIRECTORIES, and TARGET_LINK_LIBRARIES can be used to affect their

#    build and link.

#

# CUDA_ADD_EXECUTABLE( cuda_target file0 file1 ... )

#
-- Same as CUDA_ADD_LIBRARY except that an exectuable is created.

# FindCuda.cmake

# 设置 device 和 emulation 属性

IF( NOT CUDA_BUILD_TYPE )

SET( CUDA_BUILD_TYPE
"Device" CACHE STRING "Cuda build type: Emulation or Device" )

ENDIF( NOT CUDA_BUILD_TYPE )

IF( CUDA_BUILD_TYPE MATCHES
"Device" )

SET( CUDA_NVCC_FLAGS
"")

ELSE( CUDA_BUILD_TYPE MATCHES
"Device" )

SET( CUDA_NVCC_FLAGS
--device-emulation -D_DEVICEEMU -g )

ENDIF( CUDA_BUILD_TYPE MATCHES
"Device")

# 设置DEBUG 和 RELEASE 属性

IF( NOT CUDA_DEBUG_TYPE )

SET( CUDA_DEBUG_TYPE
"Debug" CACHE STRING "Debug or Release" )

ENDIF( NOT CUDA_DEBUG_TYPE )

IF( CUDA_DEBUG_TYPE MATCHES
"Debug" )

SET( CUDA_DEBUG
-D_DEBUG )

SET( CUDA_DEBUG_FLAGS
/0d,/MTd )

ELSE( CUDA_DEBUG_TYPE MATCHES
"Debug" )

SET( CUDA_DEBUG
"" )

SET( CUDA_DEBUG_FLAGS
/2d,/MT )

ENDIF( CUDA_DEBUG_TYPE MATCHES
"Debug" )

# 寻找CUDA安装路径

IF( NOT CUDA_INSTALL_PREFIX )

# 寻找 nvcc.exe

FIND_PROGRAM( CUDA_NVCC

nvcc

PATHS $ENV{CUDA_BIN_PATH}

)

IF( NOT CUDA_NVCC )

MESSAGE( STATUS
"Could not find nvcc" )

ENDIF( NOT CUDA_NVCC )


# 找 CUDA 库所在的路径

FIND_PATH( CUDA_INSTALL_PREFIX

bin
/nvcc.exe

PATHS $ENV{CUDA_BIN_PATH}
/../

)

IF( NOT EXISTS ${CUDA_INSTALL_PREFIX} )

MESSAGE( STATUS
"Specify CUDA_INSTALL_PREFIX" )

ENDIF( NOT EXISTS ${CUDA_INSTALL_PREFIX} )

ENDIF( NOT CUDA_INSTALL_PREFIX )

#  寻找 cuda 和 cutil 库的头文件和库文件

INCLUDE( ..
/cmake/FindCudaLibrary.cmake )

##################################################

# 自定义规则命令

##################################################

MACRO( CUDA_ADD_CUSTOM_COMMANDS )

  # 非
*.cu 文件

  SET( target_srcs
"" )

  #
*.cu 文件

  SET( cuda_cu_sources
"" )

  FOREACH( file ${ARGN} )

IF( ${file} MATCHES
".*\\.cu$" )

GET_FILENAME_COMPONENT( file_we ${file} NAME_WE )

# 设置输出文件

SET( generated_object
"${file_we}.obj" )

# 设置文件

SET( source_file ${file} )


# 设置文件属性

SET_SOURCE_FILES_PROPERTIES( ${source_file} PROPERTIES CPLUSPLUS ON )


# 自定义命令 - CUDA编译命令

ADD_CUSTOM_COMMAND(

OUTPUT ..
/bin/$(ConfigurationName)/${generated_object}

MAIN_DEPENDENCY ${source_file}

COMMAND ${CUDA_NVCC}

ARGS
-c

${CUDA_DEBUG}

${CUDA_NVCC_FLAGS}

-Xcompiler

/EHsc,/W3,/nologo,/Wp64,/Zi,/RTC1,${CUDA_DEBUG_FLAGS}

${CUDA_NVCC_INCLUDE_ARGS}

${CUDA_INCLUDE_COMMAND_DIR}

-o ../bin/$(ConfigurationName)/${generated_object}

#${source_file}

$(InputPath)    # 注意:这些变量是针对于 VS2005的

COMMENT
"Building NVCC ${file}: ${generated_object}\n"

)


SET( cuda_cu_sources ${cuda_cu_sources} ${source_file} )

ELSE( ${file} MATCHES
".*\\.cu$" )

SET( target_srcs ${target_srcs} ${file} )

ENDIF( ${file} MATCHES
".*\\.cu$" )

  ENDFOREACH( file ${ARGN} )

ENDMACRO( CUDA_ADD_CUSTOM_COMMANDS )

##################################################

# 加头文件路径宏

##################################################

MACRO( CUDA_INCLUDE_DIRECTORIES )

  FOREACH( dir ${ARGN} )

SET( CUDA_NVCC_INCLUDE_ARGS ${CUDA_NVCC_INCLUDE_ARGS}
-I${dir} )  

  ENDFOREACH( dir ${ARGN} )

ENDMACRO( CUDA_INCLUDE_DIRECTORIES )

##################################################

# 建立生成静态库工程

##################################################

MACRO( CUDA_ADD_LIBRARY cuda_target )

  # 生成命令规则

  CUDA_ADD_CUSTOM_COMMANDS( ${ARGN} )

  # 加入头文件路径

  INCLUDE_DIRECTORIES( ${CUDA_INCLUDE_DIR} )

  # 库工程

  ADD_LIBRARY( ${cuda_target}

${target_srcs}

${cuda_cu_sources}

)

  # 加入工程所需的库名

  TARGET_LINK_LIBRARIES( ${cuda_target}

${CUDA_LIBRARIES}

)


ENDMACRO( CUDA_ADD_LIBRARY cuda_target )

##################################################

# 建立生成可执行文件的工程

##################################################

MACRO( CUDA_ADD_EXECUTABLE cuda_target )

  #  生成命令规则

  CUDA_ADD_CUSTOM_COMMANDS( ${ARGN} )

  # 加入头文件路径

  INCLUDE_DIRECTORIES( ${CUDA_INCLUDE_DIR} )

  # 加入库路径

  LINK_DIRECTORIES( ${CUDA_LIBRARY_DIR} )

  #可执行工程

  ADD_EXECUTABLE( ${cuda_target}

${target_srcs}

${cuda_cu_sources}

)


  # 加入的库名

  TARGET_LINK_LIBRARIES( ${cuda_target}

${CUDA_LIBRARIES}

)

ENDMACRO( CUDA_ADD_EXECUTABLE cuda_target )

  4 FindCudaLibrary.cmake

# - Try to find CUDA

# Once done
this will define

# neek known the var ENV CUDA_BIN_PATH and ENV NVSDKCUDA_ROOT

#  

#  CUDA_FOUND        
- system has CUDA

#  CUDA_INCLUDE_DIR  
- the include directory

#  CUDA_LIBRARY_DIR  
- the directory containing the libraries

#  CUDA_LIBRARIES    
- Link these to use CUDA

#  

IF( WIN32 )

  # 寻找CUDA库路径

  FIND_PATH( CUDA_LIBRARY_DIR

NAMES cublas.lib cudart.lib cufft.lib

PATHS $ENV{CUDA_BIN_PATH}
/../lib

  )

  # 寻找CUDA头文件路径

  FIND_PATH( CUDA_INCLUDE_DIR

NAMES cuda.h cublas.h cufft.h

PATHS $ENV{CUDA_BIN_PATH}
/../include

  )

  # 寻找CUDA SDK库路径

  FIND_PATH( CUDA_SDK_LIBRARY_DIR

NAMES cutil.lib glut32.lib

PATHS $ENV{NVSDKCUDA_ROOT}
/common/lib

  )

  # 寻找CUDA SDK头文件路径

  FIND_PATH( CUDA_SDK_INCLUDE_DIR

NAMES cutil.h cutil_gl_error.h

PATHS $ENV{NVSDKCUDA_ROOT}
/common/inc

  )

ELSE( WIN32 )

ENDIF( WIN32 )

SET( CUDA_FOUND FALSE )

IF ( CUDA_INCLUDE_DIR AND CUDA_LIBRARY_DIR )

  SET ( CUDA_FOUND TRUE )

  SET ( CUDA_INCLUDE_COMMAND_DIR

    
-I${CUDA_INCLUDE_DIR}

    
-I${CUDA_SDK_INCLUDE_DIR}

    )

  SET ( CUDA_INCLUDE_DIR

    ${CUDA_INCLUDE_DIR}

    ${CUDA_SDK_INCLUDE_DIR}

    )

  SET( CUDA_LIBRARY_DIR

${CUDA_LIBRARY_DIR}

${CUDA_SDK_LIBRARY_DIR}

)

  SET ( CUDA_LIBRARIES cutil32D.lib cudart.lib cufft.lib cublas.lib cuda.lib )

ENDIF ( CUDA_INCLUDE_DIR AND CUDA_LIBRARY_DIR )

   5 把所需要的dll文件放在生成exe文件的目录下。

  6 由于编译cpp文件时,用到的是 /MDd 选项,而cu文件用到的是 /MTd 选项。这两个选项不统一会出现链接错误。改掉一个设置,统一起来就行了。

  7 template_kernel.cu 文件不用编译,所以要改一个这文件的编译选项。让这个文件变成 “从生成中排掉”

  五 总结

  虽然用写cmake很复杂,但对以后就比较简单了。不过如果只在windows底下写程序的话,还是用别人的工具比较好用。如果跨平台的话,还是写个cmake文件吧。这次写的cmake文件还是有很多限制的。在好多规定的条件下才能执行成功。而且也没有在linux底下的代码。如果下次有机会的话,会补上的。

0
相关文章