chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
54 / 57
94.7%
Branches:
52 / 55
94.5%
Functions:
8 / 8
100.0%

util/library.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/util/library.h"
3
4 #include <algorithm>
5 #include <string_view>
6
7 #ifdef _WIN32
8 #include <windows.h>
9 #else
10 #include <dlfcn.h>
11 #endif
12 #ifdef __linux__
13 #include <link.h>
14 #endif
15
16 #include <fmt/format.h>
17
18 namespace chrono::batch_render {
19 namespace {
20
21 208 void* OpenHandle(const char* name, bool loadedOnly) {
22 #ifdef _WIN32
23 return loadedOnly ? GetModuleHandleA(name) : LoadLibraryA(name);
24 #else
25
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 132 times.
284 return dlopen(name, RTLD_NOW | RTLD_LOCAL | (loadedOnly ? RTLD_NOLOAD : 0));
26 #endif
27 }
28
29 50 std::vector<std::string> WithUnversioned(std::initializer_list<const char*> names) {
30 50 std::vector<std::string> all(names.begin(), names.end());
31
2/2
✓ Branch 1 taken 103 times.
✓ Branch 2 taken 50 times.
153 for (const std::string_view name : names) {
32 103 const size_t suffix = name.find(".so.");
33
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 33 times.
103 if (suffix != std::string_view::npos) {
34
2/2
✓ Branch 1 taken 70 times.
✓ Branch 4 taken 70 times.
70 const std::string unversioned(name.substr(0, suffix + 3));
35
2/2
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 36 times.
70 if (std::ranges::find(all, unversioned) == all.end()) {
36
1/1
✓ Branch 1 taken 34 times.
34 all.push_back(unversioned);
37 }
38 70 }
39 }
40 50 return all;
41 ✗ }
42
43 }
44
45 102 Library Library::First(const std::vector<std::string>& names, bool loadedOnly) {
46 102 Library library;
47
2/2
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 93 times.
301 for (const std::string& name : names) {
48
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 199 times.
208 if (void* handle = OpenHandle(name.c_str(), loadedOnly)) {
49 9 library.m_handle = handle;
50
1/1
✓ Branch 1 taken 9 times.
9 library.m_name = name;
51 break;
52 }
53 }
54 102 return library;
55 ✗ }
56
57 18 Library Library::Find(std::initializer_list<const char*> names) {
58
1/1
✓ Branch 2 taken 18 times.
18 return First(WithUnversioned(names), true);
59 }
60
61 32 Library Library::Load(std::initializer_list<const char*> names,
62 std::initializer_list<const char*> paths,
63 const std::filesystem::path& beside) {
64 32 const std::vector<std::string> candidates = WithUnversioned(names);
65
3/3
✓ Branch 1 taken 32 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 27 times.
32 if (Library loaded = First(candidates, true)) {
66
1/1
✓ Branch 1 taken 5 times.
5 Log(LogLevel::Debug, "using the {} already in the process", loaded.Name());
67 5 return loaded;
68 5 }
69
70
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 26 times.
27 Library library;
71
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 26 times.
27 if (!beside.empty()) {
72 1 std::vector<std::string> besidePaths;
73
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 for (const std::string& name : candidates) {
74
3/3
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
8 besidePaths.push_back((beside / name).string());
75 }
76
1/1
✓ Branch 1 taken 1 time.
2 library = First(besidePaths, false);
77 1 }
78
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1 time.
27 if (!library) {
79
2/2
✓ Branch 1 taken 26 times.
✓ Branch 4 taken 26 times.
52 library = First({names.begin(), names.end()}, false);
80 }
81
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 2 times.
27 if (!library) {
82
2/2
✓ Branch 1 taken 25 times.
✓ Branch 4 taken 25 times.
50 library = First({paths.begin(), paths.end()}, false);
83 }
84
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24 times.
27 if (library) {
85
1/1
✓ Branch 1 taken 3 times.
3 Log(LogLevel::Debug, "loaded {}", library.Name());
86 }
87 27 return library;
88 32 }
89
90 3 std::filesystem::path Library::Directory() const {
91
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 if (m_handle == nullptr) {
92 1 return {};
93 }
94 #if defined(_WIN32)
95 wchar_t path[MAX_PATH] = {};
96 const DWORD length = GetModuleFileNameW(static_cast<HMODULE>(m_handle), path, MAX_PATH);
97 return length == 0 || length == MAX_PATH ? std::filesystem::path{}
98 : std::filesystem::path(path).parent_path();
99 #elif defined(__linux__)
100 2 link_map* map = nullptr;
101
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 if (dlinfo(m_handle, RTLD_DI_LINKMAP, &map) != 0 || map == nullptr || map->l_name == nullptr) {
102 ✗ return {};
103 }
104
1/1
✓ Branch 2 taken 2 times.
4 return std::filesystem::path(map->l_name).parent_path();
105 #else
106 return {};
107 #endif
108 }
109
110 9 void* Library::Symbol(const char* symbol) const {
111
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 time.
9 if (m_handle == nullptr) {
112 return nullptr;
113 }
114 #ifdef _WIN32
115 return reinterpret_cast<void*>(GetProcAddress(static_cast<HMODULE>(m_handle), symbol));
116 #else
117 8 return dlsym(m_handle, symbol);
118 #endif
119 }
120
121 1 std::string TooOld(std::string_view what, Version found, Version needed) {
122 1 return fmt::format("{} is version {}; Chrono Batch Render needs {} or later", what,
123
2/2
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
2 found.ToString(), needed.ToString());
124 }
125
126 }
127