blob: 9131bcb80901df25cce1ea29b21ac8265951fadb [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "hal/Extensions.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <cstdio>
8#include <string_view>
Austin Schuh1e69f942020-11-14 15:06:14 -08009#include <vector>
10
Austin Schuh812d0d12021-11-04 20:16:48 -070011#include <fmt/format.h>
12#include <wpi/SmallVector.h>
13#include <wpi/StringExtras.h>
14#include <wpi/fs.h>
Austin Schuh1e69f942020-11-14 15:06:14 -080015#include <wpi/spinlock.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080016
17#if defined(WIN32) || defined(_WIN32)
18#include <windows.h>
19#else
20#include <dlfcn.h>
21#endif
22
23#if defined(WIN32) || defined(_WIN32)
24#define DELIM ';'
25#define HTYPE HMODULE
Austin Schuh1e69f942020-11-14 15:06:14 -080026#define DLOPEN(a) LoadLibraryA(a)
Brian Silverman8fce7482020-01-05 13:18:21 -080027#define DLSYM GetProcAddress
28#define DLCLOSE FreeLibrary
Austin Schuh812d0d12021-11-04 20:16:48 -070029#define DLERROR fmt::format("error #{}", GetLastError())
Brian Silverman8fce7482020-01-05 13:18:21 -080030#else
31#define DELIM ':'
32#define HTYPE void*
33#define PREFIX "lib"
34#define DLOPEN(a) dlopen(a, RTLD_LAZY)
35#define DLSYM dlsym
36#define DLCLOSE dlclose
Austin Schuh1e69f942020-11-14 15:06:14 -080037#define DLERROR dlerror()
Brian Silverman8fce7482020-01-05 13:18:21 -080038#endif
39
Austin Schuh1e69f942020-11-14 15:06:14 -080040static wpi::recursive_spinlock gExtensionRegistryMutex;
41static std::vector<std::pair<const char*, void*>> gExtensionRegistry;
42static std::vector<std::pair<void*, void (*)(void*, const char*, void*)>>
43 gExtensionListeners;
44
Austin Schuh812d0d12021-11-04 20:16:48 -070045namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080046void InitializeExtensions() {}
Austin Schuh812d0d12021-11-04 20:16:48 -070047} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080048
49static bool& GetShowNotFoundMessage() {
50 static bool showMsg = true;
51 return showMsg;
52}
53
54extern "C" {
55
56int HAL_LoadOneExtension(const char* library) {
57 int rc = 1; // It is expected and reasonable not to find an extra simulation
Austin Schuh812d0d12021-11-04 20:16:48 -070058 fmt::print("HAL Extensions: Attempting to load: {}\n",
59 fs::path{library}.stem().string());
60 std::fflush(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -080061 HTYPE handle = DLOPEN(library);
62#if !defined(WIN32) && !defined(_WIN32)
63 if (!handle) {
Brian Silverman8fce7482020-01-05 13:18:21 -080064#if defined(__APPLE__)
Austin Schuh812d0d12021-11-04 20:16:48 -070065 auto libraryName = fmt::format("lib{}.dylib", library);
Brian Silverman8fce7482020-01-05 13:18:21 -080066#else
Austin Schuh812d0d12021-11-04 20:16:48 -070067 auto libraryName = fmt::format("lib{}.so", library);
Brian Silverman8fce7482020-01-05 13:18:21 -080068#endif
Austin Schuh812d0d12021-11-04 20:16:48 -070069 fmt::print("HAL Extensions: Load failed: {}\nTrying modified name: {}\n",
70 DLERROR, fs::path{libraryName}.stem().string());
71 std::fflush(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -080072 handle = DLOPEN(libraryName.c_str());
73 }
74#endif
75 if (!handle) {
Austin Schuh812d0d12021-11-04 20:16:48 -070076 fmt::print("HAL Extensions: Failed to load library: {}\n", DLERROR);
77 std::fflush(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -080078 return rc;
79 }
80
81 auto init = reinterpret_cast<halsim_extension_init_func_t*>(
82 DLSYM(handle, "HALSIM_InitExtension"));
83
Austin Schuh812d0d12021-11-04 20:16:48 -070084 if (init) {
85 rc = (*init)();
86 }
Brian Silverman8fce7482020-01-05 13:18:21 -080087
88 if (rc != 0) {
Austin Schuh812d0d12021-11-04 20:16:48 -070089 std::puts("HAL Extensions: Failed to load extension");
90 std::fflush(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -080091 DLCLOSE(handle);
92 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -070093 std::puts("HAL Extensions: Successfully loaded extension");
94 std::fflush(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -080095 }
96 return rc;
97}
98
99int HAL_LoadExtensions(void) {
100 int rc = 1;
Austin Schuh812d0d12021-11-04 20:16:48 -0700101 wpi::SmallVector<std::string_view, 2> libraries;
Brian Silverman8fce7482020-01-05 13:18:21 -0800102 const char* e = std::getenv("HALSIM_EXTENSIONS");
103 if (!e) {
104 if (GetShowNotFoundMessage()) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700105 std::puts("HAL Extensions: No extensions found");
106 std::fflush(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -0800107 }
108 return rc;
109 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700110 wpi::split(e, libraries, DELIM, -1, false);
111 for (auto& library : libraries) {
112 rc = HAL_LoadOneExtension(std::string(library).c_str());
113 if (rc < 0) {
114 break;
115 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800116 }
117 return rc;
118}
119
Austin Schuh1e69f942020-11-14 15:06:14 -0800120void HAL_RegisterExtension(const char* name, void* data) {
121 std::scoped_lock lock(gExtensionRegistryMutex);
122 gExtensionRegistry.emplace_back(name, data);
Austin Schuh812d0d12021-11-04 20:16:48 -0700123 for (auto&& listener : gExtensionListeners) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800124 listener.second(listener.first, name, data);
Austin Schuh812d0d12021-11-04 20:16:48 -0700125 }
Austin Schuh1e69f942020-11-14 15:06:14 -0800126}
127
128void HAL_RegisterExtensionListener(void* param,
129 void (*func)(void*, const char* name,
130 void* data)) {
131 std::scoped_lock lock(gExtensionRegistryMutex);
132 gExtensionListeners.emplace_back(param, func);
Austin Schuh812d0d12021-11-04 20:16:48 -0700133 for (auto&& extension : gExtensionRegistry) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800134 func(param, extension.first, extension.second);
Austin Schuh812d0d12021-11-04 20:16:48 -0700135 }
Austin Schuh1e69f942020-11-14 15:06:14 -0800136}
137
Brian Silverman8fce7482020-01-05 13:18:21 -0800138void HAL_SetShowExtensionsNotFoundMessages(HAL_Bool showMessage) {
139 GetShowNotFoundMessage() = showMessage;
140}
141
142} // extern "C"