cmakeopenclnvidia

Cannot detect OpenCL 3.0 for NVIDIA GPU


Faced with strange issue with cmake detection of OpenCL. When I use the following CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)

# Uncomment to make it working
# include(CheckSymbolExists)

# CHECK_SYMBOL_EXISTS(
#     CL_VERSION_3_0
#     "${OPENCL_INCLUDE_DIR}/CL/cl_version.h"
#     OPENCL_VERSION_3_0)

# message(STATUS "OPENCL_VERSION_3_0 = ${OPENCL_VERSION_3_0}")

set(CMAKE_REQUIRED_INCLUDES ${OPENCL_INCLUDE_DIR})
find_package(OpenCL REQUIRED)

message(STATUS "OpenCL_FOUND = ${OpenCL_FOUND}")
message(STATUS "OpenCL_INCLUDE_DIRS = ${OpenCL_INCLUDE_DIRS}")
message(STATUS "OpenCL_LIBRARIES = ${OpenCL_LIBRARIES}")
message(STATUS "OpenCL_VERSION_STRING = ${OpenCL_VERSION_STRING}")
message(STATUS "OpenCL_VERSION_MAJOR = ${OpenCL_VERSION_MAJOR}")
message(STATUS "OpenCL_VERSION_MINOR = ${OpenCL_VERSION_MINOR}")

add_executable(TestOpenCL test_symbol.c)
target_link_libraries(TestOpenCL PUBLIC OpenCL::OpenCL)

It cannot detect OpenCL_VERSION_STRING, this variable is empty. But when I uncomment lines in it, find_package(OpenCL REQUIRED) finally could detect it properly

It is very starange for me, because underhood FindOpenCL.cmake use CHECK_SYMBOL_EXISTS, but it cannot compile simple program, I've debugged it:

Run Build Command(s): /opt/cmake-3.30.2-linux-x86_64/bin/cmake -E env VERBOSE=1 /usr/bin/gmake -f Makefile cmTC_38492/fast
/usr/bin/gmake  -f CMakeFiles/cmTC_38492.dir/build.make CMakeFiles/cmTC_38492.dir/build
gmake[1]: Entering directory '<home_dir>/test_opencl/build/CMakeFiles/CMakeScratch/TryCompile-U9cXep'
Building C object CMakeFiles/cmTC_38492.dir/CheckSymbolExists.c.o
/usr/bin/cc    -o CMakeFiles/cmTC_38492.dir/CheckSymbolExists.c.o -c <home_dir>/test_opencl/build/CMakeFiles/CMakeScratch/TryCompile-U9cXep/CheckSymbolExists.c
In file included from /usr/include/CL/cl.h:20,
                 from <home_dir>/test_opencl/build/CMakeFiles/CMakeScratch/TryCompile-U9cXep/CheckSymbolExists.c:2:
/usr/include/CL/cl_version.h:22:9: note: ‘#pragma message: cl_version.h: CL_TARGET_OPENCL_VERSION is not defined. Defaulting to 300 (OpenCL 3.0)’
   22 | #pragma message("cl_version.h: CL_TARGET_OPENCL_VERSION is not defined. Defaulting to 300 (OpenCL 3.0)")
      |         ^~~~~~~
In file included from <home_dir>/test_opencl/build/CMakeFiles/CMakeScratch/TryCompile-U9cXep/CheckSymbolExists.c:2:
/usr/include/CL/cl.h:1314:21: error: unknown type name ‘CL_API_PREFIX__VERSION_2_2_DEPRECATED’
 1314 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_2_2_DEPRECATED cl_int CL_API_CALL
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1315:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘clSetProgramReleaseCallback’
 1315 | clSetProgramReleaseCallback(cl_program          program,
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1864:21: error: unknown type name ‘CL_API_PREFIX__VERSION_1_1_DEPRECATED’
 1864 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1865:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘clCreateImage2D’
 1865 | clCreateImage2D(cl_context              context,
      | ^~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1874:21: error: unknown type name ‘CL_API_PREFIX__VERSION_1_1_DEPRECATED’
 1874 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1875:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘clCreateImage3D’
 1875 | clCreateImage3D(cl_context              context,
      | ^~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1886:21: error: unknown type name ‘CL_API_PREFIX__VERSION_1_1_DEPRECATED’
 1886 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1887:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘clEnqueueMarker’
 1887 | clEnqueueMarker(cl_command_queue    command_queue,
      | ^~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1890:21: error: unknown type name ‘CL_API_PREFIX__VERSION_1_1_DEPRECATED’
 1890 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1891:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘clEnqueueWaitForEvents’
 1891 | clEnqueueWaitForEvents(cl_command_queue  command_queue,
      | ^~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1895:21: error: unknown type name ‘CL_API_PREFIX__VERSION_1_1_DEPRECATED’
 1895 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1896:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘clEnqueueBarrier’
 1896 | clEnqueueBarrier(cl_command_queue command_queue) CL_API_SUFFIX__VERSION_1_1_DEPRECATED;
      | ^~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1898:21: error: unknown type name ‘CL_API_PREFIX__VERSION_1_1_DEPRECATED’
 1898 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1899:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘clUnloadCompiler’
 1899 | clUnloadCompiler(void) CL_API_SUFFIX__VERSION_1_1_DEPRECATED;
      | ^~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1901:58: error: expected ‘;’ before ‘void’
 1901 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_1_1_DEPRECATED void * CL_API_CALL
      |                                                          ^~~~~
      |                                                          ;
/usr/include/CL/cl.h: In function ‘clGetExtensionFunctionAddress’:
/usr/include/CL/cl.h:1902:55: error: expected declaration specifiers before ‘CL_API_SUFFIX__VERSION_1_1_DEPRECATED’
 1902 | clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_1_DEPRECATED;
      |                                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1905:21: error: unknown type name ‘CL_API_PREFIX__VERSION_1_2_DEPRECATED’
 1905 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_1_2_DEPRECATED cl_command_queue CL_API_CALL
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1906:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘clCreateCommandQueue’
 1906 | clCreateCommandQueue(cl_context                     context,
      | ^~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1911:21: error: unknown type name ‘CL_API_PREFIX__VERSION_1_2_DEPRECATED’
 1911 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_1_2_DEPRECATED cl_sampler CL_API_CALL
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1912:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘clCreateSampler’
 1912 | clCreateSampler(cl_context          context,
      | ^~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1918:21: error: unknown type name ‘CL_API_PREFIX__VERSION_1_2_DEPRECATED’
 1918 | extern CL_API_ENTRY CL_API_PREFIX__VERSION_1_2_DEPRECATED cl_int CL_API_CALL
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/CL/cl.h:1919:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘clEnqueueTask’
 1919 | clEnqueueTask(cl_command_queue  command_queue,
      | ^~~~~~~~~~~~~
<home_dir>/test_opencl/build/CMakeFiles/CMakeScratch/TryCompile-U9cXep/CheckSymbolExists.c:5:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
    5 | {

It is pretty strange how it works ... Why in CMakeLists.txt it works, but under FindOpenCL.cmake it got the compilation error, even thoguht OPENCL_INCLUDE_DIR was provided as "-DOPENCL_INCLUDE_DIR=/usr/include"

What even more strange, that the if I add the following function, it properly detects version of OpenCL:

function(_FIND_OPENCL_VERSION)
  foreach(VERSION "3_0" "2_2" "2_1" "2_0" "1_2" "1_1" "1_0")
    # Write the test program to check OpenCL
    set(SOURCE_CODE
      "
      #include <CL/cl.h>
      #ifndef CL_VERSION_${VERSION}
      #error \"CL_VERSION_${VERSION} is not defined\"
      #endif

      int main() {
        return 0\;
      }
      ")

    # Create a temporary directory for the test
    set(TEST_DIR "${CMAKE_BINARY_DIR}/CheckOpenCLSymbol")
    file(MAKE_DIRECTORY ${TEST_DIR})

    # Write the test program to a file
    set(TEST_SOURCE "${TEST_DIR}/test_opencl_symbol.c")
    file(WRITE ${TEST_SOURCE} ${SOURCE_CODE})
    file(WRITE "${TEST_DIR}/CMakeLists.txt" 
      "
      cmake_minimum_required(VERSION 3.8)

      project(CheckOpenCLSymbol)

      add_executable(TestOpenCL test_opencl_symbol.c)
      target_include_directories(TestOpenCL PUBLIC ${OpenCL_INCLUDE_DIR})
      target_link_libraries(TestOpenCL PUBLIC ${OpenCL_LIBRARIES})
      ")

    # Use try_compile to check if the symbol exists
    try_compile(
      COMPILE_RESULT
      PROJECT "CheckOpenCLSymbol"
      SOURCE_DIR ${TEST_DIR}
      BINARY_DIR ${TEST_DIR}
      OUTPUT_VARIABLE CONSOLOE_OUTPUT
    )

    # Clean up temporary directory
    file(REMOVE_RECURSE ${TEST_DIR})

    # Output the result
    if(COMPILE_RESULT)
      set(OPENCL_VERSION_${VERSION} ${VERSION})
    else()
      set(OPENCL_VERSION_${VERSION} "")
    endif()
    
    message(STATUS "CONSOLOE_OUTPUT = ${CONSOLOE_OUTPUT}")
    if(OPENCL_VERSION_${VERSION})
    message(STATUS "OPENCL_VERSION_${VERSION} is FOUND !!!!!")
      string(REPLACE "_" "." VERSION "${VERSION}")
      set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE)
      string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}")
      list(GET version_components 0 major_version)
      list(GET version_components 1 minor_version)
      set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE)
      set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE)
      break()
    endif()
  endforeach()
endfunction()

Also one strange this, this works and find properly symbol:

CHECK_SYMBOL_EXISTS(
    CL_VERSION_3_0
    "CL/cl.h"
    OPENCL_VERSION_3_0)

but this one cannot compile:

CHECK_SYMBOL_EXISTS(
    CL_VERSION_3_0
    "/usr/include/CL/cl.h"
    OPENCL_VERSION_3_0)

Have somebody faced with similar issues ??


Solution

  • Finally I've found the root 'cause for this issue

    It happened, because in my system I had multiple versions of OpenCL and find_package(OpenCL) struggles to find proper (@Tsyvarev Thanks for this suggestions in comments)

    After reinstallation there was also an issue with that application that I tried to build requires cl2.hpp headers, but they was available in package opencl-clhpp-headers

    After installation I started to face with the same issue again. It happens again due to system struggle between 2 OpenCL headers: /usr/local/cuda/include/CL (old one without cl2.hpp that is required) and /usr/include/CL (that more new one and has cl2.hpp that is required for building project)

    I have move /usr/local/cuda/include/CL -> /usr/local/cuda/include/CL_backup and issue was finally resolved

    Issue with find_package happened, because underhood it used CHECK_SYMBOL_EXISTS that looks like this:

    CHECK_SYMBOL_EXISTS(
         CL_VERSION_3_0
         "${OPENCL_INCLUDE_DIR}/CL/cl.h"
         OPENCL_VERSION_3_0)
    

    CHECK_SYMBOL_EXISTS try to compile test program with the following include statment: #include <${OPENCL_INCLUDE_DIR}/CL/cl.h>, - where it was in my case: #include </usr/include/CL/cl.h>, after that compiler struggle between 2 type of header files for OpenCL in /usr/include/CL/ and /usr/local/cuda/include/CL/. But if it was used #include <CL/cl.h> and include path to OpenCL was provided as option to compiler, for example using try_compile with include paths -> then detection was working properly

    It was hard to figure out and there are lots of small issue here an there, especially as for me it looks like FindOpenCL.cmake could be modified to check "CL/cl.h" header instead of "${OPENCL_INCLUDE_DIR}/CL/cl.h"

    Thanks everyone who helped me in comments !!