Android update and small improvements
-fixed code do cross compiling to android -fixed build with GCC (workaround) -added little benchmark -several small fixes -updated meson build (demos building, working with GCC, LDC and DMD) -added some meson options -added ImGUI bind for OpenGL3
This commit is contained in:
parent
86edfa4a57
commit
66860b9042
30 changed files with 1358 additions and 173 deletions
335
demos/external/android/bindbc/loader/sharedlib.d
vendored
Normal file
335
demos/external/android/bindbc/loader/sharedlib.d
vendored
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
|
||||
// Copyright Michael D. Parker 2018.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
module bindbc.loader.sharedlib;
|
||||
|
||||
import core.stdc.stdlib;
|
||||
import core.stdc.string;
|
||||
|
||||
/// Handle to a shared library
|
||||
struct SharedLib {
|
||||
private void* _handle;
|
||||
}
|
||||
|
||||
/// Indicates an uninitialized or unassigned handle.
|
||||
enum invalidHandle = SharedLib.init;
|
||||
|
||||
// Contains information about shared library and symbol load failures.
|
||||
struct ErrorInfo {
|
||||
private:
|
||||
char[32] _error;
|
||||
char[96] _message;
|
||||
|
||||
public @nogc nothrow @property:
|
||||
/**
|
||||
Returns the string "Missing Symbol" to indicate a symbol load failure, and
|
||||
the name of a library to indicate a library load failure.
|
||||
*/
|
||||
const(char)* error() const { return _error.ptr; }
|
||||
|
||||
/**
|
||||
Returns a symbol name for symbol load failures, and a system-specific error
|
||||
message for library load failures.
|
||||
*/
|
||||
const(char)* message() const { return _message.ptr; }
|
||||
}
|
||||
|
||||
private {
|
||||
__gshared ErrorInfo[] _errors;
|
||||
__gshared size_t _errorCount;
|
||||
}
|
||||
|
||||
@nogc nothrow:
|
||||
|
||||
/**
|
||||
Returns an slice containing all errors that have been accumulated by the
|
||||
`load` and `bindSymbol` functions since the last call to `resetErrors`.
|
||||
*/
|
||||
const(ErrorInfo)[] errors()
|
||||
{
|
||||
return _errors[0 .. _errorCount];
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the total number of errors that have been accumulated by the
|
||||
`load` and `bindSymbol` functions since the last call to `resetErrors`.
|
||||
*/
|
||||
size_t errorCount()
|
||||
{
|
||||
return _errorCount;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the error count to 0 and erases all accumulated errors. This function
|
||||
does not release any memory allocated for the error list.
|
||||
*/
|
||||
void resetErrors()
|
||||
{
|
||||
_errorCount = 0;
|
||||
memset(_errors.ptr, 0, _errors.length * ErrorInfo.sizeof);
|
||||
}
|
||||
|
||||
/*
|
||||
void freeErrors()
|
||||
{
|
||||
free(_errors.ptr);
|
||||
_errors.length = _errorCount = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
Loads a symbol from a shared library and assigns it to a caller-supplied pointer.
|
||||
|
||||
Params:
|
||||
lib = a valid handle to a shared library loaded via the `load` function.
|
||||
ptr = a pointer to a function or variable pointer whose declaration is
|
||||
appropriate for the symbol being bound (it is up to the caller to
|
||||
verify the types match).
|
||||
symbolName = the name of the symbol to bind.
|
||||
*/
|
||||
void bindSymbol(SharedLib lib, void** ptr, const(char)* symbolName)
|
||||
{
|
||||
// Without this, DMD can hang in release builds
|
||||
pragma(inline, false);
|
||||
|
||||
assert(lib._handle);
|
||||
auto sym = loadSymbol(lib._handle, symbolName);
|
||||
if(sym) {
|
||||
*ptr = sym;
|
||||
}
|
||||
else {
|
||||
addErr("Missing Symbol", symbolName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Formats a symbol using the Windows stdcall mangling if necessary before passing it on to
|
||||
bindSymbol.
|
||||
|
||||
Params:
|
||||
lib = a valid handle to a shared library loaded via the `load` function.
|
||||
ptr = a pointer to a function or variable pointer whose declaration is
|
||||
appropriate for the symbol being bound (it is up to the caller to
|
||||
verify the types match).
|
||||
symbolName = the name of the symbol to bind.
|
||||
*/
|
||||
void bindSymbol_stdcall(Func)(SharedLib lib, ref Func f, const(char)* symbolName)
|
||||
{
|
||||
import bindbc.loader.system : bindWindows, bind32;
|
||||
|
||||
static if(bindWindows && bind32) {
|
||||
import core.stdc.stdio : snprintf;
|
||||
import std.traits : ParameterTypeTuple;
|
||||
|
||||
uint paramSize(A...)(A args)
|
||||
{
|
||||
size_t sum = 0;
|
||||
foreach(arg; args) {
|
||||
sum += arg.sizeof;
|
||||
|
||||
// Align on 32-bit stack
|
||||
if((sum & 3) != 0) {
|
||||
sum += 4 - (sum & 3);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
ParameterTypeTuple!f params;
|
||||
char[128] mangled;
|
||||
snprintf(mangled.ptr, mangled.length, "_%s@%d", symbolName, paramSize(params));
|
||||
symbolName = mangled.ptr;
|
||||
}
|
||||
bindSymbol(lib, cast(void**)&f, symbolName);
|
||||
}
|
||||
|
||||
/**
|
||||
Loads a shared library from disk, using the system-specific API and search rules.
|
||||
|
||||
libName = the name of the library to load. May include the full or relative
|
||||
path for the file.
|
||||
*/
|
||||
SharedLib load(const(char)* libName)
|
||||
{
|
||||
auto handle = loadLib(libName);
|
||||
if(handle) return SharedLib(handle);
|
||||
else {
|
||||
addErr(libName, null);
|
||||
return invalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Unloads a shared library from process memory.
|
||||
|
||||
Generally, it is not necessary to call this function at program exit, as the system will ensure
|
||||
any shared libraries loaded by the process will be unloaded then. However, any loaded shared
|
||||
libraries that are no longer needed by the program during runtime, such as those that are part
|
||||
of a "hot swap" mechanism, should be unloaded to free up resources.
|
||||
*/
|
||||
void unload(ref SharedLib lib) {
|
||||
if(lib._handle) {
|
||||
unloadLib(lib._handle);
|
||||
lib = invalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void allocErrs() {
|
||||
size_t newSize = _errorCount == 0 ? 16 : _errors.length * 2;
|
||||
auto errs = cast(ErrorInfo*)malloc(ErrorInfo.sizeof * newSize);
|
||||
if(!errs) exit(EXIT_FAILURE);
|
||||
|
||||
if(_errorCount > 0) {
|
||||
memcpy(errs, _errors.ptr, ErrorInfo.sizeof * _errors.length);
|
||||
free(_errors.ptr);
|
||||
}
|
||||
|
||||
_errors = errs[0 .. newSize];
|
||||
}
|
||||
|
||||
void addErr(const(char)* errstr, const(char)* message)
|
||||
{
|
||||
if(_errors.length == 0 || _errorCount >= _errors.length) {
|
||||
allocErrs();
|
||||
}
|
||||
|
||||
auto pinfo = &_errors[_errorCount];
|
||||
strcpy(pinfo._error.ptr, errstr);
|
||||
|
||||
if(message) {
|
||||
strncpy(pinfo._message.ptr, message, pinfo._message.length);
|
||||
pinfo._message[pinfo._message.length - 1] = 0;
|
||||
}
|
||||
else {
|
||||
sysError(pinfo._message.ptr, pinfo._message.length);
|
||||
}
|
||||
++_errorCount;
|
||||
}
|
||||
|
||||
version(Windows)
|
||||
{
|
||||
import core.sys.windows.windows;
|
||||
extern(Windows) @nogc nothrow alias pSetDLLDirectory = BOOL function(const(char)*);
|
||||
pSetDLLDirectory setDLLDirectory;
|
||||
|
||||
void* loadLib(const(char)* name)
|
||||
{
|
||||
return LoadLibraryA(name);
|
||||
}
|
||||
|
||||
void unloadLib(void* lib)
|
||||
{
|
||||
FreeLibrary(lib);
|
||||
}
|
||||
|
||||
void* loadSymbol(void* lib, const(char)* symbolName)
|
||||
{
|
||||
return GetProcAddress(lib, symbolName);
|
||||
}
|
||||
|
||||
void sysError(char* buf, size_t len)
|
||||
{
|
||||
char* msgBuf;
|
||||
enum uint langID = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
|
||||
|
||||
FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
null,
|
||||
GetLastError(),
|
||||
langID,
|
||||
cast(char*)&msgBuf,
|
||||
0,
|
||||
null
|
||||
);
|
||||
|
||||
if(msgBuf) {
|
||||
strncpy(buf, msgBuf, len);
|
||||
buf[len - 1] = 0;
|
||||
LocalFree(msgBuf);
|
||||
}
|
||||
else strncpy(buf, "Unknown Error\0", len);
|
||||
}
|
||||
|
||||
/**
|
||||
Adds a path to the default search path on Windows, replacing the path set in a previous
|
||||
call to the same function.
|
||||
|
||||
Any path added to this function will be added to the default DLL search path as documented at
|
||||
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setdlldirectoryw.
|
||||
|
||||
Generally, when loading DLLs on a path that is not on the search path, e.g., from a subdirectory
|
||||
of the application, the path should be prepended to the DLL name passed to the load function,
|
||||
e.g., "dlls\\SDL2.dll". If `setCustomLoaderSearchPath(".\\dlls")` is called first, then the subdirectory
|
||||
will become part of the DLL search path and the path may be omitted from the load function. (Be
|
||||
aware that ".\\dlls" is relative to the current working directory, which may not be the application
|
||||
directory, so the path should be built appropriately.)
|
||||
|
||||
Some DLLs may depend on other DLLs, perhaps even attempting to load them dynamically at run time
|
||||
(e.g., SDL2_image only loads dependencies such as libpng if it is initialized at run time with
|
||||
PNG support). In this case, if the DLL and its dependencies are placed in a subdirectory and
|
||||
loaded as e.g., "dlls\\SDL2_image.dll", then it will not be able to find its dependencies; the
|
||||
system loader will look for them on the regular DLL search path. When that happens, the solution
|
||||
is to call `setCustomLoaderSearchPath` with the subdirectory before initializing the library.
|
||||
|
||||
Calling this function with `null` as the argument will reset the default search path.
|
||||
|
||||
When the function returns `false`, the relevant `ErrorInfo` is added to the global error list and can
|
||||
be retrieved by looping through the array returned by the `errors` function.
|
||||
|
||||
When placing DLLs in a subdirectory of the application, it should be considered good practice to
|
||||
call `setCustomLoaderSearchPath` to ensure all DLLs load properly. It should also be considered good
|
||||
practice to reset the default search path once all DLLs are loaded.
|
||||
|
||||
This function is only available on Windows, so any usage of it should be preceded with
|
||||
`version(Windows)`.
|
||||
|
||||
Params:
|
||||
path = the path to add to the DLL search path, or `null` to reset the default.
|
||||
|
||||
Returns:
|
||||
`true` if the path was successfully added to the DLL search path, otherwise `false`.
|
||||
*/
|
||||
public
|
||||
bool setCustomLoaderSearchPath(const(char)* path)
|
||||
{
|
||||
if(!setDLLDirectory) {
|
||||
auto lib = load("Kernel32.dll");
|
||||
if(lib == invalidHandle) return false;
|
||||
lib.bindSymbol(cast(void**)&setDLLDirectory, "SetDllDirectoryA");
|
||||
if(!setDLLDirectory) return false;
|
||||
}
|
||||
return setDLLDirectory(path) != 0;
|
||||
}
|
||||
}
|
||||
else version(Posix) {
|
||||
import core.sys.posix.dlfcn;
|
||||
|
||||
void* loadLib(const(char)* name)
|
||||
{
|
||||
return dlopen(name, RTLD_NOW);
|
||||
}
|
||||
|
||||
void unloadLib(void* lib)
|
||||
{
|
||||
dlclose(lib);
|
||||
}
|
||||
|
||||
void* loadSymbol(void* lib, const(char)* symbolName)
|
||||
{
|
||||
return dlsym(lib, symbolName);
|
||||
}
|
||||
|
||||
void sysError(char* buf, size_t len)
|
||||
{
|
||||
const (char)* msg = dlerror();
|
||||
strncpy(buf, msg != null ? msg : "Unknown Error", len);
|
||||
buf[len - 1] = 0;
|
||||
}
|
||||
}
|
||||
else static assert(0, "bindbc-loader is not implemented on this platform.");
|
||||
Loading…
Add table
Add a link
Reference in a new issue