23 #include "casadi_os.hpp"
24 #include "exception.hpp"
25 #include "global_options.hpp"
32 extern char **environ;
48 #define STRING(ITEMS) \
49 ((dynamic_cast<std::ostringstream &>(std::ostringstream() \
50 . seekp(0, std::ios_base::cur) << ITEMS)) . str())
70 std::vector<std::string> search_paths;
74 std::string casadipath;
75 while (std::getline(casadipaths, casadipath,
pathsep())) {
76 search_paths.push_back(casadipath);
81 pLIBDIR = getenv(
"CASADIPATH");
83 if (pLIBDIR!=
nullptr) {
84 std::stringstream casadipaths(pLIBDIR);
85 std::string casadipath;
86 while (std::getline(casadipaths, casadipath,
pathsep())) {
87 search_paths.push_back(casadipath);
92 search_paths.push_back(
"");
95 #ifdef PLUGIN_EXTRA_SEARCH_PATH
96 search_paths.push_back(
97 std::string(
"") + PLUGIN_EXTRA_SEARCH_PATH);
101 search_paths.push_back(
".");
108 handle_t open_shared_library(
const std::string& lib,
const std::vector<std::string> &search_paths,
109 const std::string& caller,
bool global) {
110 std::string resultpath;
111 return open_shared_library(lib, search_paths, resultpath, caller, global);
114 int close_shared_library(handle_t handle) {
116 return !FreeLibrary(handle);
118 return dlclose(handle);
122 handle_t open_shared_library(
const std::string& lib,
const std::vector<std::string> &search_paths,
123 std::string& resultpath,
const std::string& caller,
bool global) {
131 flag = RTLD_NOW | RTLD_GLOBAL;
133 flag = RTLD_LAZY | RTLD_LOCAL;
136 #if !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
137 flag |= RTLD_DEEPBIND;
150 char*** p_environ_rtdl_next =
reinterpret_cast<char ***
>(dlsym(RTLD_NEXT,
"environ"));
151 bool environ_rtdl_next_overridden =
false;
152 char** environ_rtld_next_original_value = NULL;
153 if (p_environ_rtdl_next && p_environ_rtdl_next != &environ) {
154 environ_rtld_next_original_value = *p_environ_rtdl_next;
155 *p_environ_rtdl_next = environ;
156 environ_rtdl_next_overridden =
true;
165 std::stringstream errors;
166 errors << caller <<
": Cannot load shared library '"
167 << lib <<
"': " << std::endl;
169 <<
" Searched directories: 1. casadipath from GlobalOptions\n"
170 <<
" 2. CASADIPATH env var\n"
171 <<
" 3. PATH env var (Windows)\n"
172 <<
" 4. LD_LIBRARY_PATH env var (Linux)\n"
173 <<
" 5. DYLD_LIBRARY_PATH env var (osx)\n"
174 <<
" A library may be 'not found' even if the file exists:\n"
175 <<
" * library is not compatible (different compiler/bitness)\n"
176 <<
" * the dependencies are not found\n"
179 std::string searchpath;
182 for (casadi_int i=0;i<search_paths.size();++i) {
183 searchpath = search_paths[i];
185 SetDllDirectory(TEXT(searchpath.c_str()));
186 handle = LoadLibrary(TEXT(lib.c_str()));
187 SetDllDirectory(NULL);
189 std::string libname = searchpath.empty() ? lib : searchpath +
filesep() + lib;
190 handle = dlopen(libname.c_str(), flag);
193 resultpath = searchpath;
196 errors << std::endl <<
" Tried '" << searchpath <<
"' :";
198 errors << std::endl <<
" Error code (WIN32): " << STRING(GetLastError());
200 errors << std::endl <<
" Error code: " << dlerror();
209 if (environ_rtdl_next_overridden) {
210 *p_environ_rtdl_next = environ_rtld_next_original_value;
211 environ_rtdl_next_overridden =
false;
218 casadi_assert(handle!=
nullptr, errors.str());
228 std::wstring utf8_to_utf16(
const std::string& s) {
229 int wlen = MultiByteToWideChar(CP_UTF8, 0, s.data(),
static_cast<int>(s.size()),
nullptr, 0);
230 if (wlen == 0)
return {};
231 std::wstring ws(wlen, 0);
232 MultiByteToWideChar(CP_UTF8, 0, s.data(),
static_cast<int>(s.size()), &ws[0], wlen);
238 class FdStreamBuf :
public std::streambuf {
240 explicit FdStreamBuf(
int fd,
size_t bufsize = 4096)
241 : fd_(fd), buffer_(bufsize) {
242 setg(buffer_.data(), buffer_.data(), buffer_.data());
245 ~FdStreamBuf()
override {
252 int_type underflow()
override {
253 if (gptr() < egptr()) {
254 return traits_type::to_int_type(*gptr());
257 int n = _read(fd_, buffer_.data(),
static_cast<unsigned int>(buffer_.size()));
259 return traits_type::eof();
262 setg(buffer_.data(), buffer_.data(), buffer_.data() + n);
263 return traits_type::to_int_type(*gptr());
266 std::streampos seekoff(std::streamoff off, std::ios_base::seekdir dir,
267 std::ios_base::openmode which = std::ios_base::in)
override {
268 if (!(which & std::ios_base::in))
return -1;
272 case std::ios_base::beg: whence = SEEK_SET;
break;
273 case std::ios_base::cur:
275 off -= egptr() - gptr();
278 case std::ios_base::end: whence = SEEK_END;
break;
282 __int64 result = _lseeki64(fd_, off,
static_cast<int>(whence));
288 setg(buffer_.data(), buffer_.data(), buffer_.data());
292 std::streampos seekpos(std::streampos pos,
293 std::ios_base::openmode which = std::ios_base::in)
override {
294 return seekoff(
static_cast<std::streamoff
>(pos), std::ios_base::beg, which);
300 std::vector<char> buffer_;
303 class FdOStreamBuf :
public std::streambuf {
305 explicit FdOStreamBuf(
int fd,
size_t bufsize = 4096)
306 : fd_(fd), buffer_(bufsize) {
307 setp(buffer_.data(), buffer_.data() + buffer_.size());
310 ~FdOStreamBuf()
override {
318 int_type overflow(int_type ch)
override {
319 if (flush_buffer() == -1)
return traits_type::eof();
321 if (ch != traits_type::eof()) {
322 *pptr() =
static_cast<char>(ch);
329 int sync()
override {
330 return flush_buffer() == -1 ? -1 : 0;
335 int len =
static_cast<int>(pptr() - pbase());
337 int written = _write(fd_, pbase(), len);
338 if (written != len)
return -1;
345 std::vector<char> buffer_;
348 struct OwnedIStream {
349 std::unique_ptr<FdStreamBuf> buffer;
350 std::unique_ptr<std::istream> stream;
352 explicit OwnedIStream(
int fd)
353 : buffer(
std::make_unique<FdStreamBuf>(fd)),
354 stream(
std::make_unique<
std::istream>(buffer.get())) {}
357 struct StreamWithOwnedBuffer :
public std::istream {
358 std::shared_ptr<OwnedIStream> owned;
359 explicit StreamWithOwnedBuffer(std::shared_ptr<OwnedIStream> o)
360 :
std::istream(o->buffer.get()), owned(
std::move(o)) {}
363 struct OwnedOStream {
364 std::unique_ptr<FdOStreamBuf> buffer;
365 std::unique_ptr<std::ostream> stream;
367 explicit OwnedOStream(
int fd)
368 : buffer(
std::make_unique<FdOStreamBuf>(fd)),
369 stream(
std::make_unique<
std::ostream>(buffer.get())) {}
372 struct StreamWithOwnedOBuffer :
public std::ostream {
373 std::shared_ptr<OwnedOStream> owned;
374 explicit StreamWithOwnedOBuffer(std::shared_ptr<OwnedOStream> o)
375 :
std::ostream(o->buffer.get()), owned(
std::move(o)) {}
381 std::ios::openmode mode) {
383 std::wstring utf16_path = utf8_to_utf16(utf8_path);
385 access |= GENERIC_READ;
386 if (mode & std::ios::out) access |= GENERIC_WRITE;
388 HANDLE h = CreateFileW(utf16_path.c_str(), access,
389 FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
390 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr);
391 if (h == INVALID_HANDLE_VALUE)
return {};
393 int flags = (mode & std::ios::out) ? _O_RDWR : _O_RDONLY;
394 if (mode & std::ios::binary) flags |= _O_BINARY;
396 int fd = _open_osfhandle(
reinterpret_cast<intptr_t
>(h), flags);
401 auto owned = std::make_shared<OwnedIStream>(fd);
402 return std::unique_ptr<StreamWithOwnedBuffer>(
new StreamWithOwnedBuffer(std::move(owned)));
404 auto ifs = std::unique_ptr<std::ifstream>(
new std::ifstream(utf8_path, mode));
405 if (!*ifs)
return {};
406 return std::unique_ptr<std::istream>(std::move(ifs));
411 std::ios::openmode mode) {
413 std::wstring utf16_path = utf8_to_utf16(utf8_path);
416 access |= GENERIC_WRITE;
417 if (mode & std::ios::in) access |= GENERIC_READ;
419 DWORD creation = (mode & std::ios::app) ? OPEN_ALWAYS : CREATE_ALWAYS;
421 HANDLE h = CreateFileW(utf16_path.c_str(), access,
422 FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
423 creation, FILE_ATTRIBUTE_NORMAL,
nullptr);
424 if (h == INVALID_HANDLE_VALUE)
return {};
426 int flags = (mode & std::ios::in) ? _O_RDWR : _O_WRONLY;
427 if (mode & std::ios::app) flags |= _O_APPEND;
428 if (mode & std::ios::binary) flags |= _O_BINARY;
430 int fd = _open_osfhandle(
reinterpret_cast<intptr_t
>(h), flags);
436 auto owned = std::make_shared<OwnedOStream>(fd);
437 return std::unique_ptr<StreamWithOwnedOBuffer>(
new StreamWithOwnedOBuffer(std::move(owned)));
439 auto ofs = std::unique_ptr<std::ofstream>(
new std::ofstream(utf8_path, mode));
440 if (!*ofs)
return {};
441 return std::unique_ptr<std::ostream>(std::move(ofs));
static std::string getCasadiPath()
std::unique_ptr< std::istream > ifstream_compat(const std::string &utf8_path, std::ios::openmode mode)
std::unique_ptr< std::ostream > ofstream_compat(const std::string &utf8_path, std::ios::openmode mode)
std::vector< std::string > get_search_paths()