Gamp v0.0.8
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
os_support.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020-2024 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <cstring>
26
27#include <ctime>
28
29#include <jau/cpuid.hpp>
30#include <jau/string_util.hpp>
31
32#include <jau/debug.hpp>
33#include <jau/io/file_util.hpp>
34#include <jau/os/dyn_linker.hpp>
35#include <jau/os/os_support.hpp>
36#include <jau/os/user_info.hpp>
37
38#if !defined(_WIN32)
39 #include <sys/utsname.h>
40#endif
41
42using namespace jau;
43
44#define CASE_TO_STRING(U,V) case U::V: return #V;
45
47 #if !defined(_WIN32)
48 struct utsname uinfo;
49 if( 0 == ::uname(&uinfo) ) {
50 info.sysname = std::string(uinfo.sysname);
51 info.nodename = std::string(uinfo.nodename);
52 info.release = std::string(uinfo.release);
53 info.version = std::string(uinfo.version);
54 info.machine = std::string(uinfo.machine);
55 #if defined(_GNU_SOURCE)
56 info.domainname = std::string(uinfo.domainname);
57 #endif
58 return true;
59 }
60 #endif
61 return false;
62}
63
64std::string jau::os::get_os_and_arch(const os_type_t os, const jau::cpu::cpu_family_t cpu, const abi_type_t abi, const endian_t e) noexcept {
65 std::string os_;
66 std::string _and_arch_tmp, _and_arch_final;
67
68 switch( cpu ) {
70 if( abi_type_t::gnu_armhf == abi ) {
71 _and_arch_tmp = "armv6hf";
72 } else {
73 _and_arch_tmp = "armv6";
74 }
75 break;
77 _and_arch_tmp = "i586";
78 break;
80 _and_arch_tmp = "ppc";
81 break;
83 _and_arch_tmp = jau::is_little_endian(e) ? "mipsel" : "mips";
84 break;
86 _and_arch_tmp = "sparc";
87 break;
89 _and_arch_tmp = "superh";
90 break;
91
93 _and_arch_tmp = "aarch64";
94 break;
96 _and_arch_tmp = "amd64";
97 break;
99 _and_arch_tmp = jau::is_little_endian(e) ? "ppc64le" : "ppc64";
100 break;
102 _and_arch_tmp = "mips64";
103 break;
105 _and_arch_tmp = "ia64";
106 break;
108 _and_arch_tmp = "sparcv9";
109 break;
111 _and_arch_tmp = "superh64";
112 break;
114 _and_arch_tmp = "wasm32";
115 break;
117 _and_arch_tmp = "wasm64";
118 break;
119 default:
120 _and_arch_tmp = "undef_arch";
121 break;
122 }
123
124 switch( os ) {
126 os_ = "android";
127 _and_arch_final = _and_arch_tmp;
128 break;
130 os_ = "darwin";
131 _and_arch_final = "universal";
132 break;
134 os_ = "windows";
135 _and_arch_final = _and_arch_tmp;
136 break;
137 case os_type_t::Linux:
138 os_ = "linux";
139 _and_arch_final = _and_arch_tmp;
140 break;
142 os_ = "freebsd";
143 _and_arch_final = _and_arch_tmp;
144 break;
146 os_ = "qnxnto";
147 _and_arch_final = _and_arch_tmp;
148 break;
150 os_ = "webasm";
151 _and_arch_final = _and_arch_tmp;
152 break;
154 os_ = "emscripten";
155 _and_arch_final = _and_arch_tmp;
156 break;
157 default:
158 os_ = "undef_os";
159 _and_arch_final = _and_arch_tmp;
160 break;
161 }
162 return os_ + "-" + _and_arch_final;
163}
164
165
166std::string jau::os::get_platform_info(std::string& sb) noexcept {
170 bool rti_ok = jau::os::get_rt_os_info(rti);
172
173 sb.append( jau::format_string("Platform: %s %s, %s (",
174 os, ( rti_ok ? rti.release : ""), cpu.family ) );
175 cpu.toString(sb, true);
176 sb.append( jau::format_string("), abi %s, ", abi) );
177 sb.append( jau::os::get_os_and_arch(os, cpu.family, abi, cpu.byte_order) );
178 if( rti_ok ) {
179 sb.append(", runtime: ").append(rti.to_string()).append("\n");
180 }
181 return sb;
182}
183
184static
185std::pair<std::string, bool>
186DynamicLinker_processCanonicalNameImpl(bool strip, const std::string& filename, const bool isBasename,
187 const bool caseInsensitive=jau::os::is_windows()) noexcept
188{
190 const std::string suffix = jau::os::DynamicLinker::getDefaultSuffix();
191 const std::string libBaseName = isBasename ? filename : jau::io::fs::basename(filename);
192 const std::string libBaseNameLC = caseInsensitive ? jau::toLower(libBaseName) : libBaseName;
193 const size_t pre_idx = libBaseNameLC.find(prefix);
194 if( 0 == pre_idx ) { // starts-with
195 const size_t sfx_idx = libBaseNameLC.rfind(suffix);
196 if( std::string::npos != sfx_idx ) {
197 // Check to see if everything after it is a Unix version number
198 bool ok = true;
199 for (size_t i = sfx_idx + suffix.length(); i < libBaseName.size(); i++) {
200 const char c = libBaseName[i];
201 if (!(c == '.' || (c >= '0' && c <= '9'))) {
202 ok = false;
203 break;
204 }
205 }
206 if (ok) {
207 std::string res;
208 if( strip ) {
209 const size_t sfx_len = libBaseName.size() - sfx_idx;
210 res = libBaseName.substr(prefix.size(), libBaseName.size() - prefix.size() - sfx_len);
211 }
212 return std::make_pair(res, true);
213 }
214 }
215 }
216 return std::make_pair(std::string(), false);
217}
218
219std::string jau::os::DynamicLinker::getBaseName(const std::string& filename, const bool isBasename, const bool caseInsensitive) noexcept {
220 return DynamicLinker_processCanonicalNameImpl(true, filename, isBasename, caseInsensitive).first;
221}
222
223bool jau::os::DynamicLinker::isCanonicalName(const std::string& filename, const bool isBasename, const bool caseInsensitive) noexcept {
224 return DynamicLinker_processCanonicalNameImpl(false, filename, isBasename, caseInsensitive).second;
225}
226
227static std::vector<std::string> DynamicLinker_buildNames(const std::string& libName) noexcept {
228 std::vector<std::string> res;
229
230 const std::string libBaseName = jau::io::fs::basename(libName);
231 if( jau::os::DynamicLinker::isCanonicalName(libBaseName, true) ) {
232 // basename is canonical, so use the original with leading path
233 res.push_back(libName);
234 return res;
235 }
236
237 res.push_back( jau::os::DynamicLinker::getCanonicalName(libBaseName, false) );
238 if ( jau::os::is_darwin() ) {
239 // Plain library-base-name in Framework folder
240 res.push_back(libBaseName);
241 }
242 return res;
243}
244
245static void DynamicLinker_addBasenames(const std::string& cause, const std::vector<std::string>& baseNames, std::vector<std::string>& paths) noexcept {
246 for (const std::string& baseName : baseNames) {
247 jau_DBG_PRINT("NativeLibrary.enumerateLibraryPaths: %s: '%s'", cause, baseName);
248 paths.push_back(baseName);
249 }
250}
251static void DynamicLinker_addAbsPaths(const std::string& cause, const std::string& abs_path, const std::vector<std::string>& baseNames, std::vector<std::string>& paths) noexcept {
252 for (const std::string& baseName : baseNames) {
253 std::string p(abs_path); p.append("/").append(baseName);
254 jau_DBG_PRINT("NativeLibrary.enumerateLibraryPaths: %s: '%s', from path '%s'", cause, p, abs_path);
255 paths.push_back(p);
256 }
257}
258static void DynamicLinker_addSysPaths(const std::string& cause, const std::vector<std::string>& baseNames, std::vector<std::string>& paths) noexcept {
259 // First add just the library names to use the OS's search algorithm
260 DynamicLinker_addBasenames(cause, baseNames, paths);
261
262 // Second add full path for each sys-folder to overcome SONAME mismatch (OS's search algorithm)
263 std::vector<std::string> lib_paths = jau::os::DynamicLinker::getSystemEnvLibraryPaths();
264 for(const std::string& p : lib_paths) {
265 DynamicLinker_addAbsPaths(cause, p, baseNames, paths);
266 }
267}
268#if 0
269static void DynamicLinker_addRelPaths(const std::string& cause, const std::string& path, const std::vector<std::string>& baseNames, std::vector<std::string>& paths) noexcept {
270 std::string abs_path;
271 jau::fs::file_stats path_stats(path);
272 if( path_stats.exists() ) {
273 DynamicLinker_addAbsPaths(cause, path_stats.path(), baseNames, paths);
274 }
275}
276#endif
277
278std::vector<std::string> jau::os::DynamicLinker::enumerateLibraryPaths(const std::string& libName,
279 bool searchSystemPath,
280 bool searchSystemPathFirst) noexcept {
281 jau_DBG_PRINT("DynamicLibrary.enumerateLibraryPaths: libName '%s'", libName);
282 std::vector<std::string> paths;
283 if ( 0 == libName.size() ) {
284 return paths;
285 }
286
287 // Allow user's full path specification to override our building of paths
288 if ( jau::io::fs::isAbsolute(libName) ) {
289 paths.push_back(libName);
290 jau_DBG_PRINT("NativeLibrary.enumerateLibraryPaths: done, absolute path found '%s'", libName);
291 return paths;
292 }
293
294 std::vector<std::string> baseNames = DynamicLinker_buildNames(libName);
295 jau_DBG_PRINT("NativeLibrary.enumerateLibraryPaths: baseNames: %s", jau::to_string(baseNames));
296
297 if( searchSystemPath && searchSystemPathFirst ) {
298 DynamicLinker_addSysPaths("add.ssp_1st", baseNames, paths);
299
300 // Add probable Mac OS X-specific paths
301 if ( jau::os::is_darwin() ) {
302 // Add historical location
303 DynamicLinker_addAbsPaths("add.ssp_1st_macos_old", "/Library/Frameworks/" + libName + ".framework", baseNames, paths);
304 // Add current location
305 DynamicLinker_addAbsPaths("add.ssp_1st_macos_cur", "/System/Library/Frameworks/" + libName + ".framework", baseNames, paths);
306 }
307 }
308
309 // Add current working directory
310 {
311 std::string cwd = jau::io::fs::get_cwd();
312 DynamicLinker_addAbsPaths("add.cwd", cwd, baseNames, paths);
313
314 // Add current working directory + natives/os-arch/ + library names (for unpacked archives, if exists)
315 const std::string cwd_bin = cwd+"/natives/"+jau::os::get_os_and_arch();
316 jau::io::fs::file_stats fstats(cwd_bin);
317 if( fstats.exists() ) {
318 DynamicLinker_addAbsPaths("add.cwd.natives.os_arch", cwd_bin, baseNames, paths);
319 }
320 }
321
322 // Add user directory
323 {
325 if( user.isValid() ) {
326 DynamicLinker_addAbsPaths("add.home.std", user.homedir(), baseNames, paths);
327
328 // Add current home + bin/os-arch/ + library names (if exists)
329 const std::string home_bin = user.homedir()+"/bin/"+jau::os::get_os_and_arch();
330 jau::io::fs::file_stats fstats(home_bin);
331 if( fstats.exists() ) {
332 DynamicLinker_addAbsPaths("add.home.bin.os_arch", home_bin, baseNames, paths);
333 }
334 }
335 }
336
337 if( searchSystemPath && !searchSystemPathFirst ) {
338 DynamicLinker_addSysPaths("add.ssp_lst", baseNames, paths);
339
340 // Add probable Mac OS X-specific paths
341 if ( jau::os::is_darwin() ) {
342 // Add historical location
343 DynamicLinker_addAbsPaths("add.ssp_lst_macos_old", "/Library/Frameworks/" + libName + ".framework", baseNames, paths);
344 // Add current location
345 DynamicLinker_addAbsPaths("add.ssp_lst_macos_cur", "/System/Library/Frameworks/" + libName + ".framework", baseNames, paths);
346 }
347 }
348 jau_DBG_PRINT("NativeLibrary.enumerateLibraryPaths: done: %s", jau::to_string(paths));
349 return paths;
350}
351
Singleton CpuInfo caching all jau::cpu information.
Definition cpuid.hpp:179
static const CpuInfo & get() noexcept
Returns reference to const singleton instance.
Definition cpuid.hpp:219
Platform agnostic representation of POSIX ::lstat() and ::stat() for a given pathname.
constexpr bool exists() const noexcept
Returns true if entity does not exist, exclusive bit.
static std::string getBaseName(const std::string &filename, const bool isBasename=false, const bool caseInsensitive=jau::os::is_windows()) noexcept
Returns the library basename, i.e.
static std::vector< std::string > enumerateLibraryPaths(const std::string &libName, bool searchSystemPath=false, bool searchSystemPathFirst=false) noexcept
Returns list of potential absolute library filenames.
static constexpr_cxx20 std::string getDefaultPrefix() noexcept
Returns the native library prefix, e.g.
static constexpr_cxx20 std::string getDefaultSuffix() noexcept
Returns the native library suffix including the dot, e.g.
static constexpr_cxx20 std::string getCanonicalName(const std::string &basename, const bool checkIsCanonical=true) noexcept
Returns canonical library name for this system from given library-basename, e.g.
static bool isCanonicalName(const std::string &filename, const bool isBasename=false, const bool caseInsensitive=jau::os::is_windows()) noexcept
Returns true if the given filename contains the canonical prefix and suffix, otherwise returns false.
static std::vector< std::string > getSystemEnvLibraryPaths()
Returns a list of system paths, from the getSystemEnvLibraryPathVarname() variable.
User account information of the underlying OS.
Definition user_info.hpp:42
const std::string & homedir() const noexcept
Definition user_info.hpp:81
bool isValid() const noexcept
Definition user_info.hpp:77
#define jau_DBG_PRINT(fmt,...)
Use for environment-variable environment::DEBUG conditional debug messages, prefix '[elapsed_time] De...
Definition debug.hpp:102
constexpr bool is_little_endian() noexcept
Evaluates true if platform is running in little endian mode, i.e.
std::string_view to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
endian_t
Endian identifier, indicating endianess of all scalar types.
bool isAbsolute(std::string_view path) noexcept
Returns true if first character is / or - in case of Windows - \\.
std::string get_cwd() noexcept
Return the current working directory or empty on failure.
Definition file_util.cpp:86
std::string basename(std::string_view path) noexcept
Return stripped leading directory components from given path separated by /.
std::string get_os_and_arch() noexcept
Returns this hosts's common name, see get_os_and_arch()
std::string get_platform_info() noexcept
bool get_rt_os_info(RuntimeOSInfo &info) noexcept
constexpr bool is_darwin() noexcept
Evaluates true if platform os_type::native contains os_type::Darwin.
os_type_t
OS type bits and unique IDs.
std::string get_os_and_arch(const os_type_t os, const jau::cpu::cpu_family_t cpu, const abi_type_t abi, const endian_t e) noexcept
Returns the common name for the given os_type, jau::cpu::cpu_family, abi_type and endian.
constexpr bool is_windows() noexcept
Evaluates true if platform os_type::native contains os_type::Windows.
abi_type_t get_abi_type() noexcept
@ Emscripten
WebAssembly with Unix/Posix suport bit (emscripten)
@ native
Identifier for native OS type, one of the above.
@ FreeBSD
FreeBSD bit, includes: unix.
@ Darwin
Darwin (Apple OSX and iOS) bit, includes: unix.
@ GenWasm
Generic WebAssembly bit.
@ Windows
Windows bit.
@ QnxNTO
QNX NTO (>= 6) bit, includes: unix.
@ Android
Android bit, includes: linux and unix.
@ Linux
Linux bit, contained by: android; includes: unix.
@ gnu_armhf
ARM GNU-EABI ARMHF -mfloat-abi=hard.
std::string toLower(const std::string &s)
cpu_family_t
Definition cpuid.hpp:50
@ x86_64
AMD/Intel 64-bit.
Definition cpuid.hpp:62
@ arm64
ARM 64bit.
Definition cpuid.hpp:57
@ x86_32
AMD/Intel 32-bit.
Definition cpuid.hpp:60
@ sparc32
SPARC 32bit.
Definition cpuid.hpp:72
@ wasm64
WebAssembly 64-bit.
Definition cpuid.hpp:89
@ superh32
Hitachi SuperH 32bit.
Definition cpuid.hpp:82
@ superh64
Hitachi SuperH 64bit.
Definition cpuid.hpp:84
@ arm32
ARM 32bit.
Definition cpuid.hpp:55
@ wasm32
WebAssembly 32-bit.
Definition cpuid.hpp:87
@ ppc64
Power PC 32bit.
Definition cpuid.hpp:69
@ mips64
Mips 64bit.
Definition cpuid.hpp:79
@ sparc64
SPARC 32bit.
Definition cpuid.hpp:74
@ mips32
Mips 32bit.
Definition cpuid.hpp:77
@ ppc32
Power PC 32bit.
Definition cpuid.hpp:67
Author: Sven Gothel sgothel@jausoft.com Copyright (c) 2024 Gothel Software e.K.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
std::string format_string(std::string_view fmt, const Args &...args) noexcept
Safely returns a (non-truncated) string according to snprintf() formatting rules using a reserved str...
static std::vector< std::string > DynamicLinker_buildNames(const std::string &libName) noexcept
static void DynamicLinker_addAbsPaths(const std::string &cause, const std::string &abs_path, const std::vector< std::string > &baseNames, std::vector< std::string > &paths) noexcept
static void DynamicLinker_addBasenames(const std::string &cause, const std::vector< std::string > &baseNames, std::vector< std::string > &paths) noexcept
static void DynamicLinker_addSysPaths(const std::string &cause, const std::vector< std::string > &baseNames, std::vector< std::string > &paths) noexcept
static std::pair< std::string, bool > DynamicLinker_processCanonicalNameImpl(bool strip, const std::string &filename, const bool isBasename, const bool caseInsensitive=jau::os::is_windows()) noexcept
std::string to_string() noexcept