diff --git a/source/loader/CMakeLists.txt b/source/loader/CMakeLists.txt index cbebf449..2a013a26 100644 --- a/source/loader/CMakeLists.txt +++ b/source/loader/CMakeLists.txt @@ -1,40 +1,50 @@ -# Copyright (C) 2020-2025 Intel Corporation -# SPDX-License-Identifier: MIT - - -target_sources(${TARGET_LOADER_NAME} - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/ze_object.h - ${CMAKE_CURRENT_SOURCE_DIR}/ze_loader_internal.h - ${CMAKE_CURRENT_SOURCE_DIR}/ze_loader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/ze_loader_api.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/ze_ldrddi.h - ${CMAKE_CURRENT_SOURCE_DIR}/ze_ldrddi_driver_ddi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/ze_ldrddi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/zet_ldrddi.h - ${CMAKE_CURRENT_SOURCE_DIR}/zet_ldrddi_driver_ddi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/zet_ldrddi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/zes_ldrddi.h - ${CMAKE_CURRENT_SOURCE_DIR}/zes_ldrddi_driver_ddi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/zes_ldrddi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/zer_ldrddi.h - ${CMAKE_CURRENT_SOURCE_DIR}/zer_ldrddi_driver_ddi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/zer_ldrddi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/zel_tracing_ldrddi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/driver_discovery.h -) - -if(WIN32) - target_sources(${TARGET_LOADER_NAME} - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/windows/driver_discovery_win.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/windows/loader_init.cpp - ) -else() - target_sources(${TARGET_LOADER_NAME} - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/linux/driver_discovery_lin.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/loader_init.cpp - ) -endif() - +# Copyright (C) 2020-2025 Intel Corporation +# SPDX-License-Identifier: MIT + + +target_sources(${TARGET_LOADER_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/ze_object.h + ${CMAKE_CURRENT_SOURCE_DIR}/ze_loader_internal.h + ${CMAKE_CURRENT_SOURCE_DIR}/ze_loader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ze_loader_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ze_ldrddi.h + ${CMAKE_CURRENT_SOURCE_DIR}/ze_ldrddi_driver_ddi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ze_ldrddi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/zet_ldrddi.h + ${CMAKE_CURRENT_SOURCE_DIR}/zet_ldrddi_driver_ddi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/zet_ldrddi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/zes_ldrddi.h + ${CMAKE_CURRENT_SOURCE_DIR}/zes_ldrddi_driver_ddi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/zes_ldrddi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/zer_ldrddi.h + ${CMAKE_CURRENT_SOURCE_DIR}/zer_ldrddi_driver_ddi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/zer_ldrddi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/zel_tracing_ldrddi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/driver_discovery.h +) + +if(WIN32) + target_sources(${TARGET_LOADER_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/windows/driver_discovery_win.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/windows/loader_init.cpp + ) +else() + target_sources(${TARGET_LOADER_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/linux/driver_discovery_lin.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/loader_init.cpp + ) +endif() + +# An optional build-time configured directory to search for drivers, in +# addition to LD_LIBRARY_PATH and the system locations. Packaging (e.g. +# conda-forge) sets this to the install prefix's lib dir so that a driver +# co-installed in the same prefix is discovered by default. CMake handles the +# string quoting for the compile definition. +if(DEFINED L0_LOADER_EXTRA_DRIVER_DIR AND NOT L0_LOADER_EXTRA_DRIVER_DIR STREQUAL "") + target_compile_definitions(${TARGET_LOADER_NAME} + PRIVATE L0_LOADER_EXTRA_DRIVER_DIR="${L0_LOADER_EXTRA_DRIVER_DIR}") +endif() + diff --git a/source/loader/linux/driver_discovery_lin.cpp b/source/loader/linux/driver_discovery_lin.cpp index f349b7e9..eb1bffdc 100644 --- a/source/loader/linux/driver_discovery_lin.cpp +++ b/source/loader/linux/driver_discovery_lin.cpp @@ -1,183 +1,197 @@ -/* - * - * Copyright (C) 2020 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#include "source/loader/driver_discovery.h" - -#include "source/inc/ze_util.h" -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -// Helper to split a colon-separated path string -static std::vector splitPaths(const std::string& paths) { - std::vector result; - std::stringstream ss(paths); - std::string item; - while (std::getline(ss, item, ':')) { - if (!item.empty()) result.push_back(item); - } - return result; -} - -// Helper to check if a file exists and is readable -static bool fileExistsReadable(const std::string& path) { - struct stat sb; - return (stat(path.c_str(), &sb) == 0) && (access(path.c_str(), R_OK) == 0); -} - -// Helper to get all library search paths from LD_LIBRARY_PATH, standard locations, and /etc/ld.so.conf -static std::vector getLibrarySearchPaths() { - std::vector paths; - // LD_LIBRARY_PATH - const char* ldLibPath = getenv("LD_LIBRARY_PATH"); - if (ldLibPath) { - auto split = splitPaths(ldLibPath); - paths.insert(paths.end(), split.begin(), split.end()); - } -#if defined(ANDROID) - paths.push_back("/vendor/lib64"); -#else - // Standard locations - Common across all Linux distributions - paths.push_back("/lib"); - paths.push_back("/usr/lib"); - paths.push_back("/usr/local/lib"); - - // Multi-arch paths for Ubuntu/Debian - paths.push_back("/lib/x86_64-linux-gnu"); - paths.push_back("/usr/lib/x86_64-linux-gnu"); - paths.push_back("/lib/i386-linux-gnu"); - paths.push_back("/usr/lib/i386-linux-gnu"); - paths.push_back("/lib/aarch64-linux-gnu"); - paths.push_back("/usr/lib/aarch64-linux-gnu"); - - // 64-bit library paths for RHEL/CentOS/Fedora - paths.push_back("/lib64"); - paths.push_back("/usr/lib64"); - paths.push_back("/usr/local/lib64"); - - // Flatpak/Snap paths for containerized applications - paths.push_back("/var/lib/flatpak/runtime"); - paths.push_back("/snap/core/current/lib"); - paths.push_back("/snap/core/current/usr/lib"); -#endif // ANDROID - - // /etc/ld.so.conf and included files - std::ifstream ldSoConf("/etc/ld.so.conf"); - if (ldSoConf) { - std::string line; - while (std::getline(ldSoConf, line)) { - if (line.empty()) continue; - if (line.find("include ") == 0) { - std::string pattern = line.substr(8); - // Simple glob: /etc/ld.so.conf.d/*.conf - std::string dir = pattern.substr(0, pattern.find_last_of('/')); - std::string ext = pattern.substr(pattern.find_last_of('.')); - DIR* d = opendir(dir.c_str()); - if (d) { - struct dirent* ent; - while ((ent = readdir(d)) != nullptr) { - std::string fname = ent->d_name; - if (fname.size() > ext.size() && fname.substr(fname.size()-ext.size()) == ext) { - std::ifstream incFile(dir + "/" + fname); - std::string incLine; - while (std::getline(incFile, incLine)) { - if (!incLine.empty() && incLine[0] != '#') - paths.push_back(incLine); - } - } - } - closedir(d); - } - } else if (line[0] != '#') { - paths.push_back(line); - } - } - } - return paths; -} - -// Main function: search for a library file in all known library paths -static bool libraryExistsInSearchPaths(const std::string& filename) { - auto paths = getLibrarySearchPaths(); - for (const auto& dir : paths) { - std::string fullPath = dir + "/" + filename; - if (fileExistsReadable(fullPath)) { - return true; - } - } - return false; -} - -namespace loader { - -static const char *knownDriverNames[] = { - MAKE_LIBRARY_NAME("ze_intel_gpu", "1"), - MAKE_LIBRARY_NAME("ze_intel_gpu_legacy1", "1"), - MAKE_LIBRARY_NAME("ze_intel_vpu", "1"), - MAKE_LIBRARY_NAME("ze_intel_npu", "1"), -}; - -std::vector discoverEnabledDrivers() { - std::vector enabledDrivers; - const char *altDrivers = nullptr; - - // ZE_ENABLE_ALT_DRIVERS is for development/debug only - altDrivers = getenv("ZE_ENABLE_ALT_DRIVERS"); - if (altDrivers == nullptr) { - // Standard drivers - not custom - for (auto path : knownDriverNames) { - if (libraryExistsInSearchPaths(path)) { - // Extract the base library name for robust driver type detection - // path is like "libze_intel_gpu.so.1" - std::string libName = path; - - // Remove "lib" prefix if present - if (libName.compare(0, 3, "lib") == 0) { - libName = libName.substr(3); - } - - // Remove file extension - size_t dotPos = libName.find('.'); - if (dotPos != std::string::npos) { - libName = libName.substr(0, dotPos); - } - - // Now match against the core driver name (e.g., "ze_intel_gpu", "ze_intel_npu") - // Check for exact matches or word boundaries to avoid substring false positives - zel_driver_type_t driverType = ZEL_DRIVER_TYPE_FORCE_UINT32; - - // Check more specific patterns first to avoid partial matches - if (libName == "ze_intel_gpu" || libName == "ze_intel_gpu_legacy1") { - driverType = ZEL_DRIVER_TYPE_GPU; - } else if (libName == "ze_intel_vpu" || libName == "ze_intel_npu") { - driverType = ZEL_DRIVER_TYPE_NPU; - } - - enabledDrivers.emplace_back(path, false, driverType); - } - } - } else { - // Alternative drivers from environment variable - these are custom - std::stringstream ss(altDrivers); - while (ss.good()) { - std::string substr; - getline(ss, substr, ','); - enabledDrivers.emplace_back(substr, true); - } - } - return enabledDrivers; -} - -} // namespace loader +/* + * + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "source/loader/driver_discovery.h" + +#include "source/inc/ze_util.h" +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +// Helper to split a colon-separated path string +static std::vector splitPaths(const std::string& paths) { + std::vector result; + std::stringstream ss(paths); + std::string item; + while (std::getline(ss, item, ':')) { + if (!item.empty()) result.push_back(item); + } + return result; +} + +// Helper to check if a file exists and is readable +static bool fileExistsReadable(const std::string& path) { + struct stat sb; + return (stat(path.c_str(), &sb) == 0) && (access(path.c_str(), R_OK) == 0); +} + +// Helper to get all library search paths from LD_LIBRARY_PATH, standard locations, and /etc/ld.so.conf +static std::vector getLibrarySearchPaths() { + std::vector paths; + // LD_LIBRARY_PATH + const char* ldLibPath = getenv("LD_LIBRARY_PATH"); + if (ldLibPath) { + auto split = splitPaths(ldLibPath); + paths.insert(paths.end(), split.begin(), split.end()); + } +#ifdef L0_LOADER_EXTRA_DRIVER_DIR + // A driver directory configured at build time (e.g. the install prefix's lib + // dir, baked in at compile time and relocated on install). Searched right + // after LD_LIBRARY_PATH -- so a user's LD_LIBRARY_PATH still takes precedence + // -- but before the system locations. This lets a driver co-installed in the + // same prefix (e.g. a conda environment) be discovered by default, without + // having to set ZE_ENABLE_ALT_DRIVERS. + paths.push_back(L0_LOADER_EXTRA_DRIVER_DIR); +#endif +#if defined(ANDROID) + paths.push_back("/vendor/lib64"); +#else + // Standard locations - Common across all Linux distributions + paths.push_back("/lib"); + paths.push_back("/usr/lib"); + paths.push_back("/usr/local/lib"); + + // Multi-arch paths for Ubuntu/Debian + paths.push_back("/lib/x86_64-linux-gnu"); + paths.push_back("/usr/lib/x86_64-linux-gnu"); + paths.push_back("/lib/i386-linux-gnu"); + paths.push_back("/usr/lib/i386-linux-gnu"); + paths.push_back("/lib/aarch64-linux-gnu"); + paths.push_back("/usr/lib/aarch64-linux-gnu"); + + // 64-bit library paths for RHEL/CentOS/Fedora + paths.push_back("/lib64"); + paths.push_back("/usr/lib64"); + paths.push_back("/usr/local/lib64"); + + // Flatpak/Snap paths for containerized applications + paths.push_back("/var/lib/flatpak/runtime"); + paths.push_back("/snap/core/current/lib"); + paths.push_back("/snap/core/current/usr/lib"); +#endif // ANDROID + + // /etc/ld.so.conf and included files + std::ifstream ldSoConf("/etc/ld.so.conf"); + if (ldSoConf) { + std::string line; + while (std::getline(ldSoConf, line)) { + if (line.empty()) continue; + if (line.find("include ") == 0) { + std::string pattern = line.substr(8); + // Simple glob: /etc/ld.so.conf.d/*.conf + std::string dir = pattern.substr(0, pattern.find_last_of('/')); + std::string ext = pattern.substr(pattern.find_last_of('.')); + DIR* d = opendir(dir.c_str()); + if (d) { + struct dirent* ent; + while ((ent = readdir(d)) != nullptr) { + std::string fname = ent->d_name; + if (fname.size() > ext.size() && fname.substr(fname.size()-ext.size()) == ext) { + std::ifstream incFile(dir + "/" + fname); + std::string incLine; + while (std::getline(incFile, incLine)) { + if (!incLine.empty() && incLine[0] != '#') + paths.push_back(incLine); + } + } + } + closedir(d); + } + } else if (line[0] != '#') { + paths.push_back(line); + } + } + } + return paths; +} + +// Main function: search for a library file in all known library paths. +// Returns the full path of the first match, or an empty string if none. +// The full path is what gets passed to dlopen(), so the file that is loaded +// is the one that was found here, not whatever the dynamic linker resolves +// the bare soname to. +static std::string findLibraryInSearchPaths(const std::string& filename) { + auto paths = getLibrarySearchPaths(); + for (const auto& dir : paths) { + std::string fullPath = dir + "/" + filename; + if (fileExistsReadable(fullPath)) { + return fullPath; + } + } + return std::string(); +} + +namespace loader { + +static const char *knownDriverNames[] = { + MAKE_LIBRARY_NAME("ze_intel_gpu", "1"), + MAKE_LIBRARY_NAME("ze_intel_gpu_legacy1", "1"), + MAKE_LIBRARY_NAME("ze_intel_vpu", "1"), + MAKE_LIBRARY_NAME("ze_intel_npu", "1"), +}; + +std::vector discoverEnabledDrivers() { + std::vector enabledDrivers; + const char *altDrivers = nullptr; + + // ZE_ENABLE_ALT_DRIVERS is for development/debug only + altDrivers = getenv("ZE_ENABLE_ALT_DRIVERS"); + if (altDrivers == nullptr) { + // Standard drivers - not custom + for (auto path : knownDriverNames) { + std::string fullPath = findLibraryInSearchPaths(path); + if (!fullPath.empty()) { + // Extract the base library name for robust driver type detection + // path is like "libze_intel_gpu.so.1" + std::string libName = path; + + // Remove "lib" prefix if present + if (libName.compare(0, 3, "lib") == 0) { + libName = libName.substr(3); + } + + // Remove file extension + size_t dotPos = libName.find('.'); + if (dotPos != std::string::npos) { + libName = libName.substr(0, dotPos); + } + + // Now match against the core driver name (e.g., "ze_intel_gpu", "ze_intel_npu") + // Check for exact matches or word boundaries to avoid substring false positives + zel_driver_type_t driverType = ZEL_DRIVER_TYPE_FORCE_UINT32; + + // Check more specific patterns first to avoid partial matches + if (libName == "ze_intel_gpu" || libName == "ze_intel_gpu_legacy1") { + driverType = ZEL_DRIVER_TYPE_GPU; + } else if (libName == "ze_intel_vpu" || libName == "ze_intel_npu") { + driverType = ZEL_DRIVER_TYPE_NPU; + } + + enabledDrivers.emplace_back(fullPath, false, driverType); + } + } + } else { + // Alternative drivers from environment variable - these are custom + std::stringstream ss(altDrivers); + while (ss.good()) { + std::string substr; + getline(ss, substr, ','); + enabledDrivers.emplace_back(substr, true); + } + } + return enabledDrivers; +} + +} // namespace loader