Merge branch 'master' of https://github.com/KhronosGroup/OpenCL-ICD-Loader into KhronosGroup-master
cmake_minimum_required (VERSION 2.8.11)
project (OPENCL_ICD_LOADER)
+include (GNUInstallDirs)
find_package (Threads REQUIRED)
# The option below allows building the ICD Loader library as a shared library
# advance. Use it with discretion.
option (BUILD_SHARED_LIBS "Build shared libs" ON)
+include(CheckFunctionExists)
+check_function_exists(secure_getenv HAVE_SECURE_GETENV)
+check_function_exists(__secure_getenv HAVE___SECURE_GETENV)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/loader/icd_cmake_config.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/icd_cmake_config.h)
+
set (OPENCL_ICD_LOADER_SOURCES
loader/icd.c
- loader/icd_dispatch.c)
+ loader/icd.h
+ loader/icd_dispatch.c
+ loader/icd_dispatch.h
+ loader/icd_envvars.h
+ loader/icd_platform.h)
if (WIN32)
list (APPEND OPENCL_ICD_LOADER_SOURCES
loader/windows/icd_windows.c
- loader/windows/icd_windows_hkr.c
loader/windows/icd_windows_dxgk.c
+ loader/windows/icd_windows_dxgk.h
+ loader/windows/icd_windows_envvars.c
+ loader/windows/icd_windows_hkr.c
+ loader/windows/icd_windows_hkr.h
loader/windows/OpenCL.def
loader/windows/OpenCL.rc)
# Only add the DXSDK include directory if the environment variable is
else ()
list (APPEND OPENCL_ICD_LOADER_SOURCES
loader/linux/icd_linux.c
+ loader/linux/icd_linux_envvars.c
loader/linux/icd_exports.map)
endif ()
include_directories (${OPENCL_ICD_LOADER_HEADERS_DIR})
add_definitions (-DCL_TARGET_OPENCL_VERSION=220)
-target_include_directories (OpenCL PRIVATE loader)
+target_include_directories (OpenCL PRIVATE ${CMAKE_CURRENT_BINARY_DIR} loader)
target_link_libraries (OpenCL ${CMAKE_DL_LIBS})
include (CTest)
endif()
install (TARGETS OpenCL
- RUNTIME DESTINATION bin
- ARCHIVE DESTINATION lib
- LIBRARY DESTINATION lib)
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
Contributions to the OpenCL ICD Loader are welcomed and encouraged.
You will be prompted with a one-time "click-through" CLA dialog as part of submitting your pull request or other contribution to GitHub.
+
+## Table of Debug Environment Variables
+
+The following debug environment variables are available for use with the OpenCL ICD loader:
+
+| Environment Variable | Behavior | Example Format |
+|:---------------------------------:|---------------------|----------------------|
+| OCL_ICD_FILENAMES | Specifies a list of additional ICDs to load. The ICDs will be enumerated first, before any ICDs discovered via default mechanisms. | `export OCL_ICD_FILENAMES=libVendorA.so:libVendorB.so`<br/><br/>`set OCL_ICD_FILENAMES=vendor_a.dll;vendor_b.dll` |
+| OCL_ICD_VENDORS | On Linux and Android, specifies a directory to scan for ICDs to enumerate in place of the default `/etc/OpenCL/vendors'. | `export OCL_ICD_VENDORS=/my/local/icd/search/path` |
#include "icd.h"
#include "icd_dispatch.h"
+#include "icd_envvars.h"
#include <stdlib.h>
#include <string.h>
}
}
+// Get next file or dirname given a string list or registry key path.
+// Note: the input string may be modified!
+static char *loader_get_next_path(char *path) {
+ size_t len;
+ char *next;
+
+ if (path == NULL) return NULL;
+ next = strchr(path, PATH_SEPARATOR);
+ if (next == NULL) {
+ len = strlen(path);
+ next = path + len;
+ } else {
+ *next = '\0';
+ next++;
+ }
+
+ return next;
+}
+
+void khrIcdVendorsEnumerateEnv(void)
+{
+ char* icdFilenames = khrIcd_secure_getenv("OCL_ICD_FILENAMES");
+ char* cur_file = NULL;
+ char* next_file = NULL;
+ if (icdFilenames)
+ {
+ KHR_ICD_TRACE("Found OCL_ICD_FILENAMES environment variable.\n");
+
+ next_file = icdFilenames;
+ while (NULL != next_file && *next_file != '\0') {
+ cur_file = next_file;
+ next_file = loader_get_next_path(cur_file);
+
+ khrIcdVendorAdd(cur_file);
+ }
+
+ khrIcd_free_getenv(icdFilenames);
+ }
+}
+
void khrIcdContextPropertiesGetPlatform(const cl_context_properties *properties, cl_platform_id *outPlatform)
{
if (properties == NULL && khrIcdVendors != NULL)
#ifndef _ICD_H_
#define _ICD_H_
+#include "icd_platform.h"
+
#ifndef CL_USE_DEPRECATED_OPENCL_1_0_APIS
#define CL_USE_DEPRECATED_OPENCL_1_0_APIS
#endif
#include <CL/cl.h>
#include <CL/cl_ext.h>
-#ifdef _WIN32
-#include <tchar.h>
-#endif
-
/*
* type definitions
*/
// n.b, this call is OS-specific
void khrIcdOsVendorsEnumerateOnce(void);
+// read vendors from environment variables
+void khrIcdVendorsEnumerateEnv(void);
+
// add a vendor's implementation to the list of libraries
void khrIcdVendorAdd(const char *libraryName);
--- /dev/null
+#cmakedefine HAVE_SECURE_GETENV
+#cmakedefine HAVE___SECURE_GETENV
--- /dev/null
+/*
+ * Copyright (c) 2016-2019 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * OpenCL is a trademark of Apple Inc. used under license by Khronos.
+ */
+
+#ifndef _ICD_ENVVARS_H_
+#define _ICD_ENVVARS_H_
+
+char *khrIcd_getenv(const char *name);
+char *khrIcd_secure_getenv(const char *name);
+void khrIcd_free_getenv(char *val);
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2016-2019 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * OpenCL is a trademark of Apple Inc. used under license by Khronos.
+ */
+
+#ifndef _ICD_PLATFORM_H_
+#define _ICD_PLATFORM_H_
+
+#if defined(__linux__) || defined(__APPLE__)
+
+#define PATH_SEPARATOR ':'
+#define DIRECTORY_SYMBOL '/'
+#ifdef __ANDROID__
+#define ICD_VENDOR_PATH "/system/vendor/Khronos/OpenCL/vendors/";
+#else
+#define ICD_VENDOR_PATH "/etc/OpenCL/vendors/";
+#endif // ANDROID
+
+#elif defined(_WIN32)
+
+#define PATH_SEPARATOR ';'
+#define DIRECTORY_SYMBOL '\\'
+
+#endif
+
+#endif
*/
#include "icd.h"
+#include "icd_envvars.h"
+
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
{
DIR *dir = NULL;
struct dirent *dirEntry = NULL;
-#ifdef __ANDROID__
- char *vendorPath = "/system/vendor/Khronos/OpenCL/vendors/";
-#else
- char *vendorPath = "/etc/OpenCL/vendors/";
-#endif // ANDROID
+ char* vendorPath = ICD_VENDOR_PATH;
+ char* envPath = NULL;
+
+ khrIcdVendorsEnumerateEnv();
+
+ envPath = khrIcd_secure_getenv("OCL_ICD_VENDORS");
+ if (NULL != envPath)
+ {
+ vendorPath = envPath;
+ }
- // open the directory
dir = opendir(vendorPath);
if (NULL == dir)
{
- KHR_ICD_TRACE("Failed to open path %s\n", vendorPath);
- goto Cleanup;
+ KHR_ICD_TRACE("Failed to open path %s, continuing\n", vendorPath);
}
-
- // attempt to load all files in the directory
- for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir) )
+ else
{
- switch(dirEntry->d_type)
+ // attempt to load all files in the directory
+ for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir) )
{
- case DT_UNKNOWN:
- case DT_REG:
- case DT_LNK:
+ switch(dirEntry->d_type)
{
- const char* extension = ".icd";
- FILE *fin = NULL;
- char* fileName = NULL;
- char* buffer = NULL;
- long bufferSize = 0;
-
- // make sure the file name ends in .icd
- if (strlen(extension) > strlen(dirEntry->d_name) )
- {
- break;
- }
- if (strcmp(dirEntry->d_name + strlen(dirEntry->d_name) - strlen(extension), extension) )
- {
- break;
- }
-
- // allocate space for the full path of the vendor library name
- fileName = malloc(strlen(dirEntry->d_name) + strlen(vendorPath) + 1);
- if (!fileName)
- {
- KHR_ICD_TRACE("Failed allocate space for ICD file path\n");
- break;
- }
- sprintf(fileName, "%s%s", vendorPath, dirEntry->d_name);
-
- // open the file and read its contents
- fin = fopen(fileName, "r");
- if (!fin)
+ case DT_UNKNOWN:
+ case DT_REG:
+ case DT_LNK:
{
- free(fileName);
- break;
- }
- fseek(fin, 0, SEEK_END);
- bufferSize = ftell(fin);
+ const char* extension = ".icd";
+ FILE *fin = NULL;
+ char* fileName = NULL;
+ char* buffer = NULL;
+ long bufferSize = 0;
+
+ // make sure the file name ends in .icd
+ if (strlen(extension) > strlen(dirEntry->d_name) )
+ {
+ break;
+ }
+ if (strcmp(dirEntry->d_name + strlen(dirEntry->d_name) - strlen(extension), extension) )
+ {
+ break;
+ }
+
+ // allocate space for the full path of the vendor library name
+ fileName = malloc(strlen(dirEntry->d_name) + strlen(vendorPath) + 1);
+ if (!fileName)
+ {
+ KHR_ICD_TRACE("Failed allocate space for ICD file path\n");
+ break;
+ }
+ sprintf(fileName, "%s%s", vendorPath, dirEntry->d_name);
+
+ // open the file and read its contents
+ fin = fopen(fileName, "r");
+ if (!fin)
+ {
+ free(fileName);
+ break;
+ }
+ fseek(fin, 0, SEEK_END);
+ bufferSize = ftell(fin);
+
+ buffer = malloc(bufferSize+1);
+ if (!buffer)
+ {
+ free(fileName);
+ fclose(fin);
+ break;
+ }
+ memset(buffer, 0, bufferSize+1);
+ fseek(fin, 0, SEEK_SET);
+ if (bufferSize != (long)fread(buffer, 1, bufferSize, fin) )
+ {
+ free(fileName);
+ free(buffer);
+ fclose(fin);
+ break;
+ }
+ // ignore a newline at the end of the file
+ if (buffer[bufferSize-1] == '\n') buffer[bufferSize-1] = '\0';
+
+ // load the string read from the file
+ khrIcdVendorAdd(buffer);
- buffer = malloc(bufferSize+1);
- if (!buffer)
- {
- free(fileName);
- fclose(fin);
- break;
- }
- memset(buffer, 0, bufferSize+1);
- fseek(fin, 0, SEEK_SET);
- if (bufferSize != (long)fread(buffer, 1, bufferSize, fin) )
- {
free(fileName);
free(buffer);
fclose(fin);
- break;
}
- // ignore a newline at the end of the file
- if (buffer[bufferSize-1] == '\n') buffer[bufferSize-1] = '\0';
-
- // load the string read from the file
- khrIcdVendorAdd(buffer);
-
- free(fileName);
- free(buffer);
- fclose(fin);
+ break;
+ default:
+ break;
}
- break;
- default:
- break;
}
- }
-Cleanup:
+ closedir(dir);
+ }
- // free resources and exit
- if (dir)
+ if (NULL != envPath)
{
- closedir(dir);
+ khrIcd_free_getenv(envPath);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2016-2019 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * OpenCL is a trademark of Apple Inc. used under license by Khronos.
+ */
+
+// for secure_getenv():
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "icd_cmake_config.h"
+
+#include <stdlib.h>
+
+char *khrIcd_getenv(const char *name) {
+ // No allocation of memory necessary for Linux.
+ return getenv(name);
+}
+
+char *khrIcd_secure_getenv(const char *name) {
+#if defined(__APPLE__)
+ // Apple does not appear to have a secure getenv implementation.
+ // The main difference between secure getenv and getenv is that secure getenv
+ // returns NULL if the process is being run with elevated privileges by a normal user.
+ // The idea is to prevent the reading of malicious environment variables by a process
+ // that can do damage.
+ // This algorithm is derived from glibc code that sets an internal
+ // variable (__libc_enable_secure) if the process is running under setuid or setgid.
+ return geteuid() != getuid() || getegid() != getgid() ? NULL : khrIcd_getenv(name);
+#else
+// Linux
+#ifdef HAVE_SECURE_GETENV
+ return secure_getenv(name);
+#elif defined(HAVE___SECURE_GETENV)
+ return __secure_getenv(name);
+#else
+#pragma message( \
+ "Warning: Falling back to non-secure getenv for environmental lookups! Consider" \
+ " updating to a different libc.")
+ return khrIcd_getenv(name);
+#endif
+#endif
+}
+
+void khrIcd_free_getenv(char *val) {
+ // No freeing of memory necessary for Linux, but we should at least touch
+ // val to get rid of compiler warnings.
+ (void)val;
+}
#define OPENCL_ICD_LOADER_VERSION_MAJOR 2
#define OPENCL_ICD_LOADER_VERSION_MINOR 2
-#define OPENCL_ICD_LOADER_VERSION_REV 2
+#define OPENCL_ICD_LOADER_VERSION_REV 3
#ifdef RC_INVOKED
HKEY platformsKey = NULL;
DWORD dwIndex;
+ khrIcdVendorsEnumerateEnv();
+
if (!khrIcdOsVendorsEnumerateDXGK())
{
KHR_ICD_TRACE("Failed to load via DXGK interface on RS4, continuing\n");
{
KHR_ICD_TRACE("Failed to open platforms key %s, continuing\n", platformsName);
}
- else {
+ else
+ {
// for each value
for (dwIndex = 0;; ++dwIndex)
{
- char cszLibraryName[MAX_PATH] = {0};
+ char cszLibraryName[1024] = {0};
DWORD dwLibraryNameSize = sizeof(cszLibraryName);
- DWORD dwLibraryNameType = 0;
+ DWORD dwLibraryNameType = 0;
DWORD dwValue = 0;
DWORD dwValueSize = sizeof(dwValue);
(LPBYTE)&dwValue,
&dwValueSize);
// if RegEnumKeyEx fails, we are done with the enumeration
- if (ERROR_SUCCESS != result)
+ if (ERROR_SUCCESS != result)
{
KHR_ICD_TRACE("Failed to read value %d, done reading key.\n", dwIndex);
break;
KHR_ICD_TRACE("Value %s found...\n", cszLibraryName);
// Require that the value be a DWORD and equal zero
- if (REG_DWORD != dwLibraryNameType)
+ if (REG_DWORD != dwLibraryNameType)
{
KHR_ICD_TRACE("Value not a DWORD, skipping\n");
continue;
--- /dev/null
+/*
+ * Copyright (c) 2016-2019 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * OpenCL is a trademark of Apple Inc. used under license by Khronos.
+ */
+
+#include <windows.h>
+
+char *khrIcd_getenv(const char *name) {
+ char *retVal;
+ DWORD valSize;
+
+ valSize = GetEnvironmentVariableA(name, NULL, 0);
+
+ // valSize DOES include the null terminator, so for any set variable
+ // will always be at least 1. If it's 0, the variable wasn't set.
+ if (valSize == 0) return NULL;
+
+ // Allocate the space necessary for the registry entry
+ retVal = (char *)malloc(valSize);
+
+ if (NULL != retVal) {
+ GetEnvironmentVariableA(name, retVal, valSize);
+ }
+
+ return retVal;
+}
+
+char *khrIcd_secure_getenv(const char *name) {
+ return khrIcd_getenv(name);
+}
+
+void khrIcd_free_getenv(char *val) {
+ free((void *)val);
+}
EXPORTS
clGetExtensionFunctionAddress
-clIcdGetPlatformIDsKHR