blob: adbc039c4affe203032f49462868320f9f17c606 [file] [log] [blame]
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Mark Young <marky@lunarg.com>
// Author: Dave Houlton <daveh@lunarg.com>
//
#pragma once
#include <cassert>
#include "xr_dependencies.h"
#if defined(__GNUC__) && __GNUC__ >= 4
#define LOADER_EXPORT __attribute__((visibility("default")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
#define LOADER_EXPORT __attribute__((visibility("default")))
#else
#define LOADER_EXPORT
#endif
// Environment variables
#if defined(XR_OS_LINUX) || defined(XR_OS_APPLE)
#include <sys/types.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
// Dynamic Loading of libraries:
typedef void *LoaderPlatformLibraryHandle;
static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
// When loading the library, we use RTLD_LAZY so that not all symbols have to be
// resolved at this time (which improves performance). Note that if not all symbols
// can be resolved, this could cause crashes later.
// For experimenting/debugging: Define the LD_BIND_NOW environment variable to force all
// symbols to be resolved here.
return dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
}
static inline const char *LoaderPlatformLibraryOpenError(const std::string &path) {
(void)path;
return dlerror();
}
static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { dlclose(library); }
static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
assert(library);
assert(name.size() > 0);
return dlsym(library, name.c_str());
}
static inline const char *LoaderPlatformLibraryGetProcAddrError(const std::string &name) {
(void)name;
return dlerror();
}
#elif defined(XR_OS_WINDOWS)
static inline bool PathFileExists(LPCSTR szPath) {
DWORD dwAttrib = GetFileAttributesA(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
#define PATH_SEPARATOR ';'
#define DIRECTORY_SYMBOL '\\'
// Workaround for MS VS 2010/2013 missing snprintf and vsnprintf
#if defined(_MSC_VER) && _MSC_VER < 1900
#include <stdint.h>
static inline int32_t xr_vsnprintf(char *result_buffer, size_t buffer_size, const char *print_format, va_list varying_list) {
int32_t copy_count = -1;
if (buffer_size != 0) {
copy_count = _vsnprintf_s(result_buffer, buffer_size, _TRUNCATE, print_format, varying_list);
}
if (copy_count == -1) {
copy_count = _vscprintf(print_format, varying_list);
}
return copy_count;
}
static inline int32_t xr_snprintf(char *result_buffer, size_t buffer_size, const char *print_format, ...) {
va_list varying_list;
va_start(varying_list, print_format);
int32_t copy_count = xr_vsnprintf(result_buffer, buffer_size, print_format, varying_list);
va_end(varying_list);
return copy_count;
}
#define snprintf xr_snprintf
#define vsnprintf xr_vsnprintf
#endif
// Dynamic Loading:
typedef HMODULE LoaderPlatformLibraryHandle;
static LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
// Try loading the library the original way first.
LoaderPlatformLibraryHandle handle = LoadLibraryA(path.c_str());
if (handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND && PathFileExists(path.c_str())) {
// If that failed, then try loading it with broader search folders.
handle = LoadLibraryExA(path.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
}
return handle;
}
static char *LoaderPlatformLibraryOpenError(const std::string &path) {
static char errorMsg[164];
(void)snprintf(errorMsg, 163, "Failed to open dynamic library \"%s\" with error %d", path.c_str(), GetLastError());
return errorMsg;
}
static void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { FreeLibrary(library); }
static void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
assert(library);
assert(name.size() > 0);
return GetProcAddress(library, name.c_str());
}
static char *LoaderPlatformLibraryGetProcAddrAddrError(const std::string &name) {
static char errorMsg[120];
(void)snprintf(errorMsg, 119, "Failed to find function \"%s\" in dynamic library", name.c_str());
return errorMsg;
}
#else // Not Linux or Windows
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
// Stub func
#error("Unknown platform, undefined dynamic library routines resulting");
(void)path;
}
static inline const char *LoaderPlatformLibraryOpenError(const std::string &path) {
// Stub func
(void)path;
}
static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) {
// Stub func
(void)library;
}
static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
// Stub func
void(library);
void(name);
}
static inline const char *LoaderPlatformLibraryGetProcAddrError(const std::string &name) {
// Stub func
(void)name;
}
#endif