// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. #include "hal/Extensions.h" #include #include #include #include #include #include #if defined(WIN32) || defined(_WIN32) #include #else #include #endif #if defined(WIN32) || defined(_WIN32) #define DELIM ';' #define HTYPE HMODULE #define DLOPEN(a) LoadLibraryA(a) #define DLSYM GetProcAddress #define DLCLOSE FreeLibrary #define DLERROR "error #" << GetLastError() #else #define DELIM ':' #define HTYPE void* #define PREFIX "lib" #define DLOPEN(a) dlopen(a, RTLD_LAZY) #define DLSYM dlsym #define DLCLOSE dlclose #define DLERROR dlerror() #endif static wpi::recursive_spinlock gExtensionRegistryMutex; static std::vector> gExtensionRegistry; static std::vector> gExtensionListeners; namespace hal::init { void InitializeExtensions() {} } // namespace hal::init static bool& GetShowNotFoundMessage() { static bool showMsg = true; return showMsg; } extern "C" { int HAL_LoadOneExtension(const char* library) { int rc = 1; // It is expected and reasonable not to find an extra simulation wpi::outs() << "HAL Extensions: Attempting to load: " << wpi::sys::path::stem(library) << "\n"; wpi::outs().flush(); HTYPE handle = DLOPEN(library); #if !defined(WIN32) && !defined(_WIN32) if (!handle) { wpi::SmallString<128> libraryName("lib"); libraryName += library; #if defined(__APPLE__) libraryName += ".dylib"; #else libraryName += ".so"; #endif wpi::outs() << "HAL Extensions: Load failed: " << DLERROR << "\nTrying modified name: " << wpi::sys::path::stem(libraryName) << "\n"; wpi::outs().flush(); handle = DLOPEN(libraryName.c_str()); } #endif if (!handle) { wpi::outs() << "HAL Extensions: Failed to load library: " << DLERROR << '\n'; wpi::outs().flush(); return rc; } auto init = reinterpret_cast( DLSYM(handle, "HALSIM_InitExtension")); if (init) { rc = (*init)(); } if (rc != 0) { wpi::outs() << "HAL Extensions: Failed to load extension\n"; wpi::outs().flush(); DLCLOSE(handle); } else { wpi::outs() << "HAL Extensions: Successfully loaded extension\n"; wpi::outs().flush(); } return rc; } int HAL_LoadExtensions(void) { int rc = 1; wpi::SmallVector libraries; const char* e = std::getenv("HALSIM_EXTENSIONS"); if (!e) { if (GetShowNotFoundMessage()) { wpi::outs() << "HAL Extensions: No extensions found\n"; wpi::outs().flush(); } return rc; } wpi::StringRef env{e}; env.split(libraries, DELIM, -1, false); for (auto& libref : libraries) { wpi::SmallString<128> library(libref); rc = HAL_LoadOneExtension(library.c_str()); if (rc < 0) { break; } } return rc; } void HAL_RegisterExtension(const char* name, void* data) { std::scoped_lock lock(gExtensionRegistryMutex); gExtensionRegistry.emplace_back(name, data); for (auto&& listener : gExtensionListeners) { listener.second(listener.first, name, data); } } void HAL_RegisterExtensionListener(void* param, void (*func)(void*, const char* name, void* data)) { std::scoped_lock lock(gExtensionRegistryMutex); gExtensionListeners.emplace_back(param, func); for (auto&& extension : gExtensionRegistry) { func(param, extension.first, extension.second); } } void HAL_SetShowExtensionsNotFoundMessages(HAL_Bool showMessage) { GetShowNotFoundMessage() = showMessage; } } // extern "C"