2020-12-26 14:12:05 -08:00
|
|
|
// 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.
|
2017-10-18 02:27:55 -05:00
|
|
|
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "hal/Extensions.h"
|
2017-10-18 02:27:55 -05:00
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
#include <cstdio>
|
|
|
|
|
#include <string_view>
|
2020-09-03 10:09:01 -07:00
|
|
|
#include <vector>
|
|
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
#include <fmt/format.h>
|
|
|
|
|
#include <wpi/SmallVector.h>
|
|
|
|
|
#include <wpi/StringExtras.h>
|
2021-06-01 21:50:35 -07:00
|
|
|
#include <wpi/fs.h>
|
2020-09-04 08:58:24 -07:00
|
|
|
#include <wpi/spinlock.h>
|
2017-10-18 02:27:55 -05:00
|
|
|
|
|
|
|
|
#if defined(WIN32) || defined(_WIN32)
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(WIN32) || defined(_WIN32)
|
|
|
|
|
#define DELIM ';'
|
|
|
|
|
#define HTYPE HMODULE
|
2020-08-31 00:34:34 -07:00
|
|
|
#define DLOPEN(a) LoadLibraryA(a)
|
2017-10-18 02:27:55 -05:00
|
|
|
#define DLSYM GetProcAddress
|
|
|
|
|
#define DLCLOSE FreeLibrary
|
2021-06-06 16:13:58 -07:00
|
|
|
#define DLERROR fmt::format("error #{}", GetLastError())
|
2017-10-18 02:27:55 -05:00
|
|
|
#else
|
|
|
|
|
#define DELIM ':'
|
|
|
|
|
#define HTYPE void*
|
|
|
|
|
#define PREFIX "lib"
|
|
|
|
|
#define DLOPEN(a) dlopen(a, RTLD_LAZY)
|
|
|
|
|
#define DLSYM dlsym
|
|
|
|
|
#define DLCLOSE dlclose
|
2020-09-02 20:07:03 -07:00
|
|
|
#define DLERROR dlerror()
|
2017-10-18 02:27:55 -05:00
|
|
|
#endif
|
|
|
|
|
|
2020-09-04 08:58:24 -07:00
|
|
|
static wpi::recursive_spinlock gExtensionRegistryMutex;
|
2020-09-03 10:09:01 -07:00
|
|
|
static std::vector<std::pair<const char*, void*>> gExtensionRegistry;
|
|
|
|
|
static std::vector<std::pair<void*, void (*)(void*, const char*, void*)>>
|
|
|
|
|
gExtensionListeners;
|
|
|
|
|
|
2020-12-28 01:19:59 -08:00
|
|
|
namespace hal::init {
|
2017-12-10 19:38:53 -08:00
|
|
|
void InitializeExtensions() {}
|
2020-12-28 01:19:59 -08:00
|
|
|
} // namespace hal::init
|
2017-12-10 19:38:53 -08:00
|
|
|
|
2019-12-06 20:55:36 -08:00
|
|
|
static bool& GetShowNotFoundMessage() {
|
|
|
|
|
static bool showMsg = true;
|
|
|
|
|
return showMsg;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-18 02:27:55 -05:00
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
|
|
int HAL_LoadOneExtension(const char* library) {
|
|
|
|
|
int rc = 1; // It is expected and reasonable not to find an extra simulation
|
2021-06-06 16:13:58 -07:00
|
|
|
fmt::print("HAL Extensions: Attempting to load: {}\n",
|
|
|
|
|
fs::path{library}.stem().string());
|
|
|
|
|
std::fflush(stdout);
|
2017-10-18 02:27:55 -05:00
|
|
|
HTYPE handle = DLOPEN(library);
|
|
|
|
|
#if !defined(WIN32) && !defined(_WIN32)
|
|
|
|
|
if (!handle) {
|
|
|
|
|
#if defined(__APPLE__)
|
2021-06-06 16:13:58 -07:00
|
|
|
auto libraryName = fmt::format("lib{}.dylib", library);
|
2017-10-18 02:27:55 -05:00
|
|
|
#else
|
2021-06-06 16:13:58 -07:00
|
|
|
auto libraryName = fmt::format("lib{}.so", library);
|
2017-10-18 02:27:55 -05:00
|
|
|
#endif
|
2021-06-06 16:13:58 -07:00
|
|
|
fmt::print("HAL Extensions: Load failed: {}\nTrying modified name: {}\n",
|
|
|
|
|
DLERROR, fs::path{libraryName}.stem().string());
|
|
|
|
|
std::fflush(stdout);
|
2017-10-18 02:27:55 -05:00
|
|
|
handle = DLOPEN(libraryName.c_str());
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2019-10-09 22:25:02 -07:00
|
|
|
if (!handle) {
|
2021-06-06 16:13:58 -07:00
|
|
|
fmt::print("HAL Extensions: Failed to load library: {}\n", DLERROR);
|
|
|
|
|
std::fflush(stdout);
|
2019-10-09 22:25:02 -07:00
|
|
|
return rc;
|
|
|
|
|
}
|
2017-10-18 02:27:55 -05:00
|
|
|
|
|
|
|
|
auto init = reinterpret_cast<halsim_extension_init_func_t*>(
|
|
|
|
|
DLSYM(handle, "HALSIM_InitExtension"));
|
|
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (init) {
|
|
|
|
|
rc = (*init)();
|
|
|
|
|
}
|
2017-10-18 02:27:55 -05:00
|
|
|
|
2019-10-09 22:25:02 -07:00
|
|
|
if (rc != 0) {
|
2021-06-06 16:13:58 -07:00
|
|
|
std::puts("HAL Extensions: Failed to load extension");
|
|
|
|
|
std::fflush(stdout);
|
2019-10-09 22:25:02 -07:00
|
|
|
DLCLOSE(handle);
|
|
|
|
|
} else {
|
2021-06-06 16:13:58 -07:00
|
|
|
std::puts("HAL Extensions: Successfully loaded extension");
|
|
|
|
|
std::fflush(stdout);
|
2019-10-09 22:25:02 -07:00
|
|
|
}
|
2017-10-18 02:27:55 -05:00
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int HAL_LoadExtensions(void) {
|
|
|
|
|
int rc = 1;
|
2021-06-06 16:13:58 -07:00
|
|
|
wpi::SmallVector<std::string_view, 2> libraries;
|
2017-10-18 02:27:55 -05:00
|
|
|
const char* e = std::getenv("HALSIM_EXTENSIONS");
|
2019-10-09 22:25:02 -07:00
|
|
|
if (!e) {
|
2019-12-06 20:55:36 -08:00
|
|
|
if (GetShowNotFoundMessage()) {
|
2021-06-06 16:13:58 -07:00
|
|
|
std::puts("HAL Extensions: No extensions found");
|
|
|
|
|
std::fflush(stdout);
|
2019-12-06 20:55:36 -08:00
|
|
|
}
|
2019-10-09 22:25:02 -07:00
|
|
|
return rc;
|
|
|
|
|
}
|
2021-06-06 16:13:58 -07:00
|
|
|
wpi::split(e, libraries, DELIM, -1, false);
|
|
|
|
|
for (auto& library : libraries) {
|
|
|
|
|
rc = HAL_LoadOneExtension(std::string(library).c_str());
|
2020-12-28 12:58:06 -08:00
|
|
|
if (rc < 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-10-18 02:27:55 -05:00
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-03 10:09:01 -07:00
|
|
|
void HAL_RegisterExtension(const char* name, void* data) {
|
2020-09-04 08:58:24 -07:00
|
|
|
std::scoped_lock lock(gExtensionRegistryMutex);
|
2020-09-03 10:09:01 -07:00
|
|
|
gExtensionRegistry.emplace_back(name, data);
|
2020-12-28 12:58:06 -08:00
|
|
|
for (auto&& listener : gExtensionListeners) {
|
2020-09-03 10:09:01 -07:00
|
|
|
listener.second(listener.first, name, data);
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2020-09-03 10:09:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HAL_RegisterExtensionListener(void* param,
|
|
|
|
|
void (*func)(void*, const char* name,
|
|
|
|
|
void* data)) {
|
2020-09-04 08:58:24 -07:00
|
|
|
std::scoped_lock lock(gExtensionRegistryMutex);
|
2020-09-03 10:09:01 -07:00
|
|
|
gExtensionListeners.emplace_back(param, func);
|
2020-12-28 12:58:06 -08:00
|
|
|
for (auto&& extension : gExtensionRegistry) {
|
2020-09-03 10:09:01 -07:00
|
|
|
func(param, extension.first, extension.second);
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2020-09-03 10:09:01 -07:00
|
|
|
}
|
|
|
|
|
|
2019-12-06 20:55:36 -08:00
|
|
|
void HAL_SetShowExtensionsNotFoundMessages(HAL_Bool showMessage) {
|
|
|
|
|
GetShowNotFoundMessage() = showMessage;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-18 02:27:55 -05:00
|
|
|
} // extern "C"
|