mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-01-13 11:11:15 +00:00
277 lines
9.3 KiB
Python
Executable File
277 lines
9.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import contextlib
|
|
import json
|
|
from pathlib import Path
|
|
import textwrap
|
|
class Sdl3SymbolIterator:
|
|
def __init__(self, sdl3_json, skip_non_partable_symbols=True):
|
|
self.sdl3_json = sdl3_json
|
|
self.next_index = 0
|
|
self.skip_non_partable_symbols = skip_non_partable_symbols
|
|
|
|
@property
|
|
def symbols_remaining(self):
|
|
return len(self.sdl3_json) - self.next_index
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def __next__(self):
|
|
while True:
|
|
if self.next_index >= len(self.sdl3_json):
|
|
raise StopIteration
|
|
symbol_json = self.sdl3_json[self.next_index]
|
|
self.next_index += 1
|
|
name = symbol_json["name"]
|
|
rettype = symbol_json["retval"]
|
|
parameter_types = symbol_json["parameter"]
|
|
parameter_names = symbol_json["parameter_name"]
|
|
if parameter_types[0] == "void":
|
|
parameter_types = parameter_types[1:]
|
|
parameter_names = parameter_names[1:]
|
|
assert len(parameter_types) == 0
|
|
type_decl = ", ".join(parameter_type.replace("REWRITE_NAME", parameter_name) for parameter_type, parameter_name in zip(parameter_types, parameter_names))
|
|
|
|
if self.skip_non_partable_symbols:
|
|
if name.startswith("Vk") or "vulkan" in name.lower():
|
|
continue
|
|
if "android" in name.lower() or "iOS" in name:
|
|
continue
|
|
if "XTask" in type_decl or "XUser" in type_decl:
|
|
continue
|
|
if "SDL_WindowsMessageHook" in type_decl:
|
|
continue
|
|
|
|
return rettype, name, type_decl
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def iterate_sdl3_symbols(sdl3_json):
|
|
try:
|
|
yield Sdl3SymbolIterator(sdl3_json)
|
|
finally:
|
|
pass
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(allow_abbrev=False)
|
|
parser.add_argument("--api", required=True, type=Path, help="Path of SDL3 json api (generated by SDL/src/dynapi/gendynapi.py --dump)")
|
|
parser.add_argument("--used", required=True, type=Path, help="Path of used SDL3 symbols as a json file")
|
|
args = parser.parse_args()
|
|
|
|
with args.api.open() as f_sdl3:
|
|
sdl3_json = json.load(f_sdl3)
|
|
|
|
with args.used.open() as f_used:
|
|
sdl3_used = set(json.load(f_used))
|
|
|
|
print("#pragma once")
|
|
|
|
print()
|
|
print(f"// This file is auto-generated by {Path(__file__).name}. Do not edit.")
|
|
|
|
print()
|
|
print("#ifdef SDL_h_")
|
|
print("#error This file must be included BEFORE SDL3/SDL.h")
|
|
print("#endif")
|
|
|
|
print()
|
|
print("#include <SDL3/SDL.h>")
|
|
print("#include <SDL3/SDL_revision.h>")
|
|
print("#ifndef MORTAR_IMPLEMENT_SDL_MAIN")
|
|
print("#define SDL_MAIN_HANDLED")
|
|
print("#endif")
|
|
print("#include <SDL3/SDL_main.h>")
|
|
print("#include <cstdio>")
|
|
|
|
print()
|
|
print("#ifdef SDL3_DYNAMIC_LOAD")
|
|
|
|
print()
|
|
print("#define FOREACH_SDL3_SYMBOL(X) \\")
|
|
seen_symbols = set()
|
|
with iterate_sdl3_symbols(sdl3_json) as sdl3_symbol_iterator:
|
|
for rettype, name, type_decl in sdl3_symbol_iterator:
|
|
if name in sdl3_used:
|
|
print(f" X({rettype}, {name}, ({type_decl}))" + ("" if sdl3_symbol_iterator.symbols_remaining == 0 else " \\"))
|
|
seen_symbols.add(name)
|
|
|
|
if seen_symbols != sdl3_used:
|
|
missing = sdl3_used - seen_symbols
|
|
parser.error(f"sdl3 api does not provide all required SDL3 symbols (missing={missing})")
|
|
|
|
print()
|
|
print("#define X_SDL3_SYMBOL_TYPEDEF(RETTYPE, NAME, TYPES) typedef RETTYPE SDLCALL NAME ## _cbfn TYPES;")
|
|
print("#define X_SDL3_STRUCT_MEMBER(RETTYPE, NAME, TYPES) NAME ## _cbfn *NAME##_symbol;")
|
|
|
|
print()
|
|
print("FOREACH_SDL3_SYMBOL(X_SDL3_SYMBOL_TYPEDEF)")
|
|
print("typedef struct SDL3_Symbols {")
|
|
print(" int refcount;")
|
|
print(" void *handle;")
|
|
print(" FOREACH_SDL3_SYMBOL(X_SDL3_STRUCT_MEMBER)")
|
|
print("} SDL3_Symbols;")
|
|
|
|
print()
|
|
print("#undef X_SDL3_SYMBOL_TYPEDEF")
|
|
print("#undef X_SDL3_STRUCT_MEMBER")
|
|
|
|
print()
|
|
print("extern SDL3_Symbols SDL3;")
|
|
|
|
print()
|
|
print("#ifdef IMPLEMENT_DYN_SDL3")
|
|
|
|
print()
|
|
print(textwrap.dedent("""\
|
|
#ifdef _WIN32
|
|
static const char * const sdl3_locations[] = {
|
|
"SDL3.dll",
|
|
};
|
|
#elif defined(__APPLE__)
|
|
#define SDL3_LIBNAME "libSDL3.dylib"
|
|
#define SDL3_FRAMEWORK "SDL3.framework/Versions/A/SDL3"
|
|
static const char * const sdl3_locations[] = {
|
|
"@loader_path/" SDL3_LIBNAME, /* MyApp.app/Contents/MacOS/libSDL3_dylib */
|
|
"@loader_path/../Frameworks/" SDL3_FRAMEWORK, /* MyApp.app/Contents/Frameworks/SDL3_framework */
|
|
"@executable_path/" SDL3_LIBNAME, /* MyApp.app/Contents/MacOS/libSDL3_dylib */
|
|
"@executable_path/../Frameworks/" SDL3_FRAMEWORK, /* MyApp.app/Contents/Frameworks/SDL3_framework */
|
|
NULL, /* /Users/username/Library/Frameworks/SDL3_framework */
|
|
"/Library/Frameworks" SDL3_FRAMEWORK, /* /Library/Frameworks/SDL3_framework */
|
|
SDL3_LIBNAME /* oh well, anywhere the system can see the .dylib (/usr/local/lib or whatever) */
|
|
};
|
|
#undef SDL3_LIBNAME
|
|
#undef SDL3_FRAMEWORK
|
|
#else
|
|
static const char * const sdl3_locations[] = {
|
|
"libSDL3.so.0",
|
|
"libSDL3.so",
|
|
};
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
static void *open_object(const char *name) {
|
|
return (void *)LoadLibraryA(name);
|
|
}
|
|
static void close_object(void *obj) {
|
|
FreeLibrary((HMODULE)obj);
|
|
}
|
|
static void *load_symbol(void *obj, const char *name) {
|
|
return (void *)GetProcAddress((HMODULE)obj, name);
|
|
}
|
|
static const char *load_error(void) {
|
|
static char buffer[512];
|
|
DWORD cchMsg = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
GetLastError(),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
buffer,
|
|
sizeof(buffer)-1,
|
|
NULL);
|
|
if (cchMsg == 0) {
|
|
strncpy(buffer, "GetProcAddress failed", sizeof(buffer));
|
|
buffer[sizeof(buffer)-1] = '\\0';
|
|
}
|
|
return buffer;
|
|
}
|
|
#else
|
|
#include <dlfcn.h>
|
|
static void *open_object(const char *name) {
|
|
return dlopen(name, RTLD_NOW | RTLD_LOCAL);
|
|
}
|
|
static void close_object(void *obj) {
|
|
dlclose(obj);
|
|
}
|
|
static void *load_symbol(void *obj, const char *name) {
|
|
return dlsym(obj, name);
|
|
}
|
|
static const char *load_error(void) {
|
|
return dlerror();
|
|
}
|
|
#endif
|
|
"""))
|
|
|
|
print()
|
|
print(textwrap.dedent("""\
|
|
#define X_SDL3_LOAD_SYMBOL(RETTYPE, NAME, TYPES) \\
|
|
SDL3.NAME##_symbol = (NAME##_cbfn*)load_symbol(SDL3.handle, #NAME); \\
|
|
if (!SDL3.NAME##_symbol) { \\
|
|
missing_symbol = #NAME; \\
|
|
goto error; \\
|
|
}
|
|
static bool load_sdl3_api() {
|
|
if (SDL3.refcount) {
|
|
SDL3.refcount += 1;
|
|
return true;
|
|
}
|
|
SDL_zero(SDL3);
|
|
for (size_t i = 0; i < SDL_arraysize(sdl3_locations); i++) {
|
|
SDL3.handle = open_object(sdl3_locations[i]);
|
|
if (SDL3.handle != NULL) {
|
|
break;
|
|
}
|
|
}
|
|
if (!SDL3.handle) {
|
|
fputs("Could not find SDL3 library\\n", stderr);
|
|
return false;
|
|
}
|
|
const char *missing_symbol = NULL;
|
|
FOREACH_SDL3_SYMBOL(X_SDL3_LOAD_SYMBOL)
|
|
SDL3.refcount = 1;
|
|
return true;
|
|
error:
|
|
fprintf(stderr, "Could not find SDL3 symbol: %s\\n", missing_symbol);
|
|
close_object(SDL3.handle);
|
|
SDL_zero(SDL3);
|
|
return false;
|
|
}"""))
|
|
|
|
|
|
print()
|
|
print(textwrap.dedent("""\
|
|
static void unload_sdl3_api() {
|
|
SDL3.refcount -= 1;
|
|
if (!SDL3.refcount) {
|
|
close_object(SDL3.handle);
|
|
SDL_zero(SDL3.handle);
|
|
}
|
|
}"""))
|
|
|
|
print("#endif // IMPLEMENT_DYN_SDL3")
|
|
print()
|
|
|
|
slow_symbols = ("SDL_memset", "SDL_memmove", "SDL_memcpy")
|
|
print()
|
|
with iterate_sdl3_symbols(sdl3_json) as sdl3_symbol_iterator:
|
|
for rettype, name, type_decl in sdl3_symbol_iterator:
|
|
if name in slow_symbols:
|
|
print(f"#ifndef SDL_SLOW_{name.removeprefix('SDL_').upper()}")
|
|
print(f"#ifdef {name}")
|
|
print(f"#undef {name}")
|
|
print(f"#endif // {name}")
|
|
if name in sdl3_used:
|
|
print(f"#define {name} SDL3.{name}_symbol")
|
|
else:
|
|
print(f"#define {name} SDL3_symbol_{name}_is_marked_unused")
|
|
if name in slow_symbols:
|
|
print(f"#endif // SDL_SLOW_{name.removeprefix('SDL_').upper()}")
|
|
|
|
print()
|
|
print("#else // SDL3_DYNAMIC_LOAD")
|
|
|
|
print()
|
|
print("#define load_sdl3_api() true")
|
|
print("#define unload_sdl3_api() do {} while (0)")
|
|
|
|
print()
|
|
print("#endif // SDL3_DYNAMIC_LOAD")
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|