CMake FindOpenCL CMake module to build OpenCL apps

This is a small CMake module I hacked to build my own OpenCL examples using CMake. I only tested it on Linux (no Windows + NVidia for me currently) and I am pretty new to CMake, so feel free to comment or improve. Use it as you wish, but share alike. I will be happy about any feedback.

Sadly the forum won’t let me upload the file, therefore I put it here as code. Save as FindOpenCL.cmake to use it.

# - Try to find OpenCL

# Once done this will define

#  

#  OPENCL_FOUND		- system has OpenCL

#  OPENCL_INCLUDE_DIR  - the OpenCL include directory

#  OPENCL_LIBRARIES	- link these to use OpenCL

#

# WIN32 should work, but is untested

IF (WIN32)

	FIND_PATH(OPENCL_INCLUDE_DIR CL/cl.h )

	# TODO this is only a hack assuming the 64 bit library will

	# not be found on 32 bit system

	FIND_LIBRARY(OPENCL_LIBRARIES opencl64 )

	IF( OPENCL_LIBRARIES )

		FIND_LIBRARY(OPENCL_LIBRARIES opencl32 )

	ENDIF( OPENCL_LIBRARIES )

ELSE (WIN32)

	# Unix style platforms

	# We also search for OpenCL in the NVIDIA SDK default location

	FIND_PATH(OPENCL_INCLUDE_DIR CL/cl.h ~/NVIDIA_GPU_Computing_SDK/OpenCL/common/inc/ )

	FIND_LIBRARY(OPENCL_LIBRARIES OpenCL 

	  ENV LD_LIBRARY_PATH

	)

ENDIF (WIN32)

SET( OPENCL_FOUND "NO" )

IF(OPENCL_LIBRARIES )

	SET( OPENCL_FOUND "YES" )

ENDIF(OPENCL_LIBRARIES)

MARK_AS_ADVANCED(

  OPENCL_INCLUDE_DIR

)

Usage could look like this:

# This is an example project to show and test the usage of the FindOpenCL

# module.

cmake_minimum_required( VERSION 2.6 )

project( Example )

find_package( OpenCL REQUIRED )

include_directories( ${OPENCL_INCLUDE_DIR} )

add_executable( example example.cpp )

target_link_libraries( example ${OPENCL_LIBRARIES} )

Hi,
Thank you for posting this!

Worked fine for me on fedora core 11 (after having the actual SDK working). everything worked fine , but I had to copy the FindOpenCL.cmake file to /usr/share/cmake/Modules

Regards,
shul

Incidentally, I had to build FindOpenCL.cmake of my own these days, so here is mine:

set(

  OPENCL_INC_SEARCH_PATH

  ${OPENCL_INCLUDE_DIR}

  ${OPENCL_DIR}/include

  ${OPENCL_DIR}/OpenCL/common/inc

  $ENV{OPENCL_INCLUDE_DIR}

  $ENV{OPENCL_DIR}/include

  $ENV{OPENCL_DIR}/OpenCL/common/inc

  /usr/local/include

  /usr/include

  # Append additional search directories for OpenCL include files here.

)

set(

  OPENCL_LIB_SEARCH_PATH

  ${OPENCL_LIBRARY_DIR}

  ${OPENCL_DIR}/lib

  ${OPENCL_DIR}/lib/x86

  $ENV{OPENCL_LIBRARY_DIR}

  $ENV{OPENCL_DIR}/lib

  $ENV{OPENCL_DIR}/lib/x86

  /usr/local/lib64

  /usr/local/lib

  /usr/lib64

  /usr/lib

  # Append additional search directories for OpenCL libraries here.

)

if("${CMAKE_SYSTEM_PROCESSOR}" EQUAL "x86_64")

  set(

	OPENCL_LIB_SEARCH_PATH

	${OPENCL_LIB_SEARCH_PATH}

	${OPENCL_DIR}/OpenCL/common/lib/Linux64

	$ENV{OPENCL_DIR}/OpenCL/common/lib/Linux64

	)

else("${CMAKE_SYSTEM_PROCESSOR}" EQUAL "x86_64")

  set(

	OPENCL_LIB_SEARCH_PATH

	${OPENCL_LIB_SEARCH_PATH}

	${OPENCL_DIR}/OpenCL/common/lib/Linux32

	$ENV{OPENCL_DIR}/OpenCL/common/lib/Linux32

	)

endif("${CMAKE_SYSTEM_PROCESSOR}" EQUAL "x86_64")

# Do not change anything of below (except if bugs encountered).

find_path(

  OPENCL_INCLUDE_DIR

  NAMES CL/cl.h

  PATHS ${OPENCL_INC_SEARCH_PATH}

  )

find_library(

  OPENCL_LIBRARY

  NAMES OpenCL

  PATHS ${OPENCL_LIB_SEARCH_PATH}

  )

include(FindPackageHandleStandardArgs)

find_package_handle_standard_args(

  OPENCL

  DEFAULT_MSG

  OPENCL_LIBRARY OPENCL_INCLUDE_DIR

  )

if(OPENCL_FOUND)

  set(OPENCL_LIBRARIES ${OPENCL_LIBRARY})

else(OPENCL_FOUND)

  set(OPENCL_LIBRARIES)

endif(OPENCL_FOUND)

mark_as_advanced(

  OPENCL_INCLUDE_DIR

  OPENCL_LIBRARY

  )

This one works on Linux only (sorry - at the moment I don’t care much about other platforms), and makes it possible to switch betwen NVIDIA and AMD SDKs (I export OPENCL_DIR variable, pointing either to NVIDIA or AMD SDK install directory, in my environment before starting work). In order to utilize above module, one should proceed as usual:

find_package(OpenCL REQUIRED)

include_directories(${OPENCL_INCLUDE_DIR})

# ...

target_link_libraries(

  foo

  # ...

  ${OPENCL_LIBRARIES}

  )

@shul: You could save this one, as FindOpenCL.cmake, say in a subdirectory (usually named “config”) of your project, and then add following to your top-level CMakeLists.txt:

set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/config)

This way, you don’t have to copy FindOpenCL.cmake in your system CMake modules directory.

Thanks for sharing this.

If you want to support Apple OSX Snow Leopard, just add those lines to FindOpenCL.cmake

IF (APPLE)

  FIND_LIBRARY(OPENCL_LIBRARY OpenCL DOC "OpenCL lib for OSX")

  FIND_PATH(OPENCL_INCLUDE_DIR OpenCL/cl.h DOC "Include for OpenCL on OSX")

ENDIF (APPLE)

Thanks,

Erwin

Erwin,

Many thanks - incidentally, I’m probably facing blindly adapting the file above for Mac, so your post is of great help.

BTW, as NVIDIA SDK now gets installed headers and libraries into system directories, I came up with somewhat simplified version:

set(ENV_OPENCL_DIR $ENV{OPENCL_DIR})

if(ENV_OPENCL_DIR)

  find_path(

	OPENCL_INCLUDE_DIR

	NAMES CL/cl.h

	PATHS $ENV{OPENCL_DIR}/include

	NO_DEFAULT_PATH

	)

if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")

	if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64")

	  set(

		OPENCL_LIB_SEARCH_PATH

		${OPENCL_LIB_SEARCH_PATH}

		$ENV{OPENCL_DIR}/lib/x86_64

		)

	elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i686")

	  set(

		OPENCL_LIB_SEARCH_PATH

		${OPENCL_LIB_SEARCH_PATH}

		$ENV{OPENCL_DIR}/lib/x86

		)

	endif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64")

  endif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")

  find_library(

	OPENCL_LIBRARY

	NAMES OpenCL

	PATHS ${OPENCL_LIB_SEARCH_PATH}

	NO_DEFAULT_PATH

	)

else(ENV_OPENCL_DIR)

  find_path(

	OPENCL_INCLUDE_DIR

	NAMES CL/cl.h

	)

find_library(

	OPENCL_LIBRARY

	NAMES OpenCL

	)

endif(ENV_OPENCL_DIR)

include(FindPackageHandleStandardArgs)

find_package_handle_standard_args(

  OPENCL

  DEFAULT_MSG

  OPENCL_LIBRARY OPENCL_INCLUDE_DIR

  )

if(OPENCL_FOUND)

  set(OPENCL_LIBRARIES ${OPENCL_LIBRARY})

else(OPENCL_FOUND)

  set(OPENCL_LIBRARIES)

endif(OPENCL_FOUND)

mark_as_advanced(

  OPENCL_INCLUDE_DIR

  OPENCL_LIBRARY

  )

It’s still Linux only, but it should be able to find NVIDIA SDK directly, and only for AMD SDK one would have to define, prior to running CMake, OPENCL_DIR environment variable to point to SDK installation directory (both SDK could be installed on the same machine).

Anyway - I’d appreciate further feedback, and if I really have to adapt it for Mac (or Windows), I’ll post updates here.

Hi sagrailo,

thanks alot for providing your FindOpenCL.cmake script as a starting point for developing OpenCL apps based upon CMake. I have to admit I’m a total beginner when it comes to OpenCL or GPU computing in general.

So far I have been able to base a little sample application upon the template project provided by the NVIDIA GPU Computing SDK and also were able to find my OpenCL installation with your FindOpenCL script. I also came across FindCUDA.cmake and were fascinated by the complexity of the build system it incorporates. Now - how to do something usefull with all this?

Could you provide (for me and all the other curious out there) a little CMake based OpenCL sample application that shows how to build a OpenCL app via CMake?

Sure. Please create a directory, and copy attached files there:

    [*]foo.cpp - this is functionally the same thing as oclVectorAdd example from SDK (thus: creating some vectors in main memory, doing all OpenCL initialization work, then copying input vectors over to GPU memory, launching the OpenCL kernel to add vectors, copying resulting vector back to main memory, checking that elements of this vector are as expected, and finally doing OpenCL cleanup), but streamlined so that liboclUtil stuff is not used (I hate thin wrappers like this one), but vanilla OpenCL calls are employed instead

    [*]FindOpenCL.cmake.txt - please rename this one to FindOpenCL.cmake (this forum seems to not allowing attaching files with .cmake extension), this is the version I use at the moment - still Linux only, and further simplified considerably from versions from my previous posts (which should be good, as I think anyone with even basic knowledge of CMake should be able to understand it now)

    [*]CMakeLists.txt - this is CMake script for this small project (again - minimalistic, so it should be simple to understand)

Now, create a build directory somewhere (as you know, with CMake out-of-tree builds are preferred), and then build the project:

cmake <path-to-source-directory>

make

If you would like to work with AMD SDK, then the first command above should read:

ATISTREAMSDKROOT=<path-to-your-AMD-SDK-installation> cmake <path-to-source-directory>

In that case, you should also change “CL_DEVICE_TYPE_GPU” in line 39 of foo.cpp to “CL_DEVICE_TYPE_CPU” (of course, there are many ways to avoid re-compiling to support running either on GPU or CPU, but I’m trying to keep everything as simple as possible here). Once you run cmake command in the former or later version, you could keep changing the code and re-running make - it will always build with NVIDIA and AMD SDK respectively; to switch to using other SDK, just clean your build directory, and re-run corresponding cmake command.

That’s it, please let me know does it work for you (note that at the moment I’m using GPU Computing SDK 2.3a from NVIDIA, as well as Stream SDK 2.0-beta3 from AMD). The CMake scripts for CUDA are much more complicated, mainly for following three reasons:

    [*]CUDA infrastructure is more complicated (for example: kernel compiler has to be run from your build system, while with OpenCL it is run programmatically)

    [*]FindCUDA.cmake is fully multi-platform

    [*]FindCUDA.cmake is much more feature rich

But - you don’t need if for your OpenCL work, and for this work even the simple FindOpenCL.cmake I’m attaching could do (at least under Linux). On the other side, if you are going to work with CUDA, please note that release candidate for upcoming CMake 2.8.0 (available from here) has FindCUDA.cmake included - so at least you don’t have to include all of related files to your project.
foo.cpp (4.28 KB)
CMakeLists.txt (276 Bytes)
FindOpenCL.cmake.txt (1.26 KB)

Thanks alot sagrailo,

with your help I were finally able to get things going. I’ll report back if I encounter any issues - or if I happen to find the time to give your script a chance on windows. (I’m well aware this might require some additional tweaking - but I think it’ll be worth it.)

Update:

Hi sagrailo, I have yet another question that comes to my mind. I don’t really like having my kernel as a #define in my source code - not knowing if it is valid until I run my code. Is there any way to precompile the kernel and link that precompiled kernel into my program? I prefer compile time errors over runtime errors…

sagrailo,

Thanks very much for sharing this with us - I am able to get this working under Ubuntu 8.10, a GeForce 9600 card OpenCL supported Nvidia driver 190.29.

Its really cool, as I don’t have to use a make file (CMake is much easier). I appreciate your comments about (thin wrapper) and should be vanilla OpenCL, however I am a newbee to this OpenCL (even GPU programming world) and would find it useful to compile and play with NVIDA examples under OpenCL within a CMake environment.

Can you tell me, how I can modify the CMakeLists.txt file to include all the relevant include and lib stuff?

Cheers,
sv650

@pandaemonium: Sorry that I haven’t noticed your edit previously. All of my OpenCL work so far was with kernels in plain text, so I really don’t know much about how to pre-compile kernels (in order to employ clCreateProgramWithBinary()). I know that there is kind of compiler in AMD SDK - the binary is called “clc”, and I’m using it occasionally to check for syntax errors in my kernels (as you said, it’s easier to work when these errors spotted in build time, than in run time), but I’m not aware of corresponding tool in NVIDIA SDK. So, it would be indeed very helpful if someone with more knowledge could shed some light on all of this (and it would be even better if an example of this put in SDK). Once steps to pre-compile an OpenCL kernel known, supporting this in CMake files should not be hard. However, this is all probably of limited usage, as kernels would get compiled to the code very specific to given CPU/GPU architecture (albeit: as far as I was able to understand, both AMD and NVIDIA are using LLVM during the compilation, so maybe some kind of LLVM virtual machine bytecode is actually expected by clCreateProgramWithBinary() in both implementations - actually, the files generated by “clc” compiler mentioned above looks exactly like LLVM bytecodes to me), so the approach with keeping kernel sources in plain text, and doing clCreateProgramWithSource(), is probably better anyway.

@sv650: Basically, the only issue with SDK samples is that these have to link with two auxiliary libraries: “shrutil” (that is I think used by CUDA SDK samples too), and “oclUtil”. If you built SDK samples, then you have built these libraries too, so an ugly but simplest way to use them would be just to refer them directly. So, for example, you could put following CMakeLists.txt file (together with FindOpenCL.cmake attached to my previous message) into oclDeviceQuery sample source directory (this is “OpenCL/src/oclDeviceQuery” subdirectory of your GPU SDK installation directory):

cmake_minimum_required(VERSION 2.6 FATAL_ERROR)

project(oclDeviceQuery)

set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})

find_package(OpenCL REQUIRED)

include_directories(${OPENCL_INCLUDE_DIR})

include_directories(${PROJECT_SOURCE_DIR}/../../../shared/inc)

include_directories(${PROJECT_SOURCE_DIR}/../../common/inc)

add_executable(

  oclDeviceQuery

  oclDeviceQuery.cpp

  )

target_link_libraries(

  oclDeviceQuery

  ${OPENCL_LIBRARIES}

  ${PROJECT_SOURCE_DIR}/../../../shared/lib/libshrutil.a

  ${PROJECT_SOURCE_DIR}/../../common/lib/liboclUtil.a

  )

and then you should be able to build oclDeviceQuery example using CMake. For other SDK samples, you could follow the same procedure, changing only project and executable name, and list of source files, in above CMakeLists.txt.

Hi! Thanks for posting it. External Image it is working good…like it very much…