cmake 检测 OpenCL 时遇到奇怪的问题。 当我使用以下
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)
无法检测到OpenCL_VERSION_STRING,该变量为空。 但是当我取消其中的注释行时,
find_package(OpenCL REQUIRED)
终于可以正确检测到它了
这对我来说很奇怪,因为FindOpenCL.cmake底层使用CHECK_SYMBOL_EXISTS,但它无法编译简单的程序,我已经调试了它:
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 | {
它的工作原理非常奇怪......为什么在
CMakeLists.txt
中它可以工作,但在FindOpenCL.cmake下却出现编译错误,
即使 OPENCL_INCLUDE_DIR 被提供为“-DOPENCL_INCLUDE_DIR=/usr/include”
更奇怪的是,如果我添加以下函数,它可以正确检测 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()
这也是一个奇怪的现象,它可以正常工作并找到正确的符号:
CHECK_SYMBOL_EXISTS(
CL_VERSION_3_0
"CL/cl.h"
OPENCL_VERSION_3_0)
但是这个无法编译:
CHECK_SYMBOL_EXISTS(
CL_VERSION_3_0
"/usr/include/CL/cl.h"
OPENCL_VERSION_3_0)
有人遇到类似问题吗?
尝试以下操作。我在原始 CMakeLists.txt 中没有看到启用编程语言所需的
project
调用。默认情况下使用 C 和 C++,但我会在示例中明确说明。
cmake_minimum_required(VERSION 3.16)
project(FOOBAR LANGUAGES C)
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)