From b7e8753f7790489609c6fd60870831c723ca47d9 Mon Sep 17 00:00:00 2001 From: yanovskyy Date: Sun, 16 Jun 2024 11:08:17 +0200 Subject: [PATCH 01/10] added cross emcripten config Signed-off-by: yanovskyy --- machines/cross-emscripten.ini | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 machines/cross-emscripten.ini diff --git a/machines/cross-emscripten.ini b/machines/cross-emscripten.ini new file mode 100644 index 0000000..1d7477c --- /dev/null +++ b/machines/cross-emscripten.ini @@ -0,0 +1,27 @@ +[binaries] +c = 'emcc' +cpp = 'em++' +ld = 'wasm-ld' +ar = 'emar' +ranlib = 'emranlib' +#pkgconfig = 'pkg-config' + +# https://docs.gtk.org/glib/cross-compiling.html#cross-properties +[properties] +growing_stack = true +have_c99_vsnprintf = true +have_c99_snprintf = true +have_unix98_printf = true +openslide_bin_platform = 'wasm32' +python_platform_tag = 'wasm32' + +[built-in options] +# Ensure that '-s PTHREAD_POOL_SIZE=*' is not injected into .pc files +c_thread_count = 0 +cpp_thread_count = 0 + +[host_machine] +system = 'emscripten' +cpu_family = 'wasm32' +cpu = 'wasm32' +endian = 'little' \ No newline at end of file From 82e29cbd940b6412d25bafc92b7c8f921b328845 Mon Sep 17 00:00:00 2001 From: yanovskyy Date: Sun, 16 Jun 2024 11:29:42 +0200 Subject: [PATCH 02/10] added libffi patch to support wasm architecture Signed-off-by: yanovskyy --- .../packagefiles/libffi-wasm-3.4.4.patch | 1061 +++++++++++++++++ 1 file changed, 1061 insertions(+) create mode 100644 subprojects/packagefiles/libffi-wasm-3.4.4.patch diff --git a/subprojects/packagefiles/libffi-wasm-3.4.4.patch b/subprojects/packagefiles/libffi-wasm-3.4.4.patch new file mode 100644 index 0000000..ef74fa7 --- /dev/null +++ b/subprojects/packagefiles/libffi-wasm-3.4.4.patch @@ -0,0 +1,1061 @@ +diff --git a/meson.build b/meson.build +index 9fecce3..dcb6add 100644 +--- a/meson.build ++++ b/meson.build +@@ -211,6 +211,11 @@ elif host_cpu_family == 'm88k' + asm_sources = ['obsd.S'] + elif host_cpu_family == 'microblaze' + target = 'MICROBLAZE' ++elif host_cpu_family == 'wasm32' ++ target = 'wasm32' ++ arch_subdir = 'wasm32' ++ c_sources = ['ffi.c'] ++ asm_sources = [] + elif host_cpu_family == 'moxie' + # This CPU family is used in CI cross compilation + target = 'MOXIE' +diff --git a/src/wasm32/ffi.c b/src/wasm32/ffi.c +new file mode 100644 +index 0000000..91d1b5e +--- /dev/null ++++ b/src/wasm32/ffi.c +@@ -0,0 +1,970 @@ ++/* ----------------------------------------------------------------------- ++ ffi.c - Copyright (c) 2018-2023 Hood Chatham, Brion Vibber, Kleis Auke Wolthuizen, and others. ++ ++ wasm32/emscripten Foreign Function Interface ++ ++ Permission is hereby granted, free of charge, to any person obtaining ++ a copy of this software and associated documentation files (the ++ ``Software''), to deal in the Software without restriction, including ++ without limitation the rights to use, copy, modify, merge, publish, ++ distribute, sublicense, and/or sell copies of the Software, and to ++ permit persons to whom the Software is furnished to do so, subject to ++ the following conditions: ++ ++ The above copyright notice and this permission notice shall be included ++ in all copies or substantial portions of the Software. ++ ++ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, ++ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ++ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ DEALINGS IN THE SOFTWARE. ++ ----------------------------------------------------------------------- */ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#ifdef DEBUG_F ++#define LOG_DEBUG(args...) console.warn(`== == LIBFFI(line __LINE__)`, args) ++#else ++#define LOG_DEBUG(args...) 0 ++#endif ++ ++#define EM_JS_MACROS(ret, name, args, body...) EM_JS(ret, name, args, body) ++ ++#if WASM_BIGINT ++EM_JS_DEPS(libffi, "$getWasmTableEntry,$setWasmTableEntry,$getEmptyTableSlot,$convertJsFunctionToWasm"); ++#define CALL_FUNCTION_POINTER(ptr, args...) \ ++ (LOG_DEBUG("CALL_FUNC_PTR", ptr, args), getWasmTableEntry(ptr).apply(null, args)) ++ ++#define JS_FUNCTION_TO_WASM convertJsFunctionToWasm ++#else ++EM_JS_DEPS(libffi, "$getWasmTableEntry,$setWasmTableEntry,$getEmptyTableSlot,$convertJsFunctionToWasm,$dynCall,$" ++ "generateFuncType,$uleb128Encode"); ++#define CALL_FUNCTION_POINTER(ptr, args...) (LOG_DEBUG("CALL_FUNC_PTR", sig, ptr, args), dynCall(sig, ptr, args)) ++ ++#define JS_FUNCTION_TO_WASM createLegalizerWrapper ++#endif ++ ++// Signature calculations are not needed if WASM_BIGINT is present. ++#if WASM_BIGINT ++#define SIG(sig) ++#else ++#define SIG(sig) sig ++#endif ++ ++#define DEREF_U8(addr, offset) HEAPU8[addr + offset] ++#define DEREF_S8(addr, offset) HEAP8[addr + offset] ++#define DEREF_U16(addr, offset) HEAPU16[(addr >> 1) + offset] ++#define DEREF_S16(addr, offset) HEAP16[(addr >> 1) + offset] ++#define DEREF_U32(addr, offset) HEAPU32[(addr >> 2) + offset] ++#define DEREF_S32(addr, offset) HEAP32[(addr >> 2) + offset] ++ ++#define DEREF_F32(addr, offset) HEAPF32[(addr >> 2) + offset] ++#define DEREF_F64(addr, offset) HEAPF64[(addr >> 3) + offset] ++ ++#if WASM_BIGINT ++// We have HEAPU64 in this case. ++#define DEREF_U64(addr, offset) HEAPU64[(addr >> 3) + offset] ++#endif ++ ++#define CHECK_FIELD_OFFSET(struct, field, offset) \ ++ _Static_assert(offsetof(struct, field) == offset, \ ++ "Memory layout of '" #struct "' has changed: '" #field "' is in an unexpected location"); ++ ++CHECK_FIELD_OFFSET(ffi_cif, abi, 4 * 0); ++CHECK_FIELD_OFFSET(ffi_cif, nargs, 4 * 1); ++CHECK_FIELD_OFFSET(ffi_cif, arg_types, 4 * 2); ++CHECK_FIELD_OFFSET(ffi_cif, rtype, 4 * 3); ++CHECK_FIELD_OFFSET(ffi_cif, nfixedargs, 4 * 6); ++ ++#define CIF__ABI(addr) DEREF_U32(addr, 0) ++#define CIF__NARGS(addr) DEREF_U32(addr, 1) ++#define CIF__ARGTYPES(addr) DEREF_U32(addr, 2) ++#define CIF__RTYPE(addr) DEREF_U32(addr, 3) ++#define CIF__NFIXEDARGS(addr) DEREF_U32(addr, 6) ++ ++CHECK_FIELD_OFFSET(ffi_type, size, 0); ++CHECK_FIELD_OFFSET(ffi_type, alignment, 4); ++CHECK_FIELD_OFFSET(ffi_type, type, 6); ++CHECK_FIELD_OFFSET(ffi_type, elements, 8); ++ ++#define FFI_TYPE__SIZE(addr) DEREF_U32(addr, 0) ++#define FFI_TYPE__ALIGN(addr) DEREF_U16(addr + 4, 0) ++#define FFI_TYPE__TYPEID(addr) DEREF_U16(addr + 6, 0) ++#define FFI_TYPE__ELEMENTS(addr) DEREF_U32(addr + 8, 0) ++ ++#define ALIGN_ADDRESS(addr, align) (addr &= (~((align) - 1))) ++#define STACK_ALLOC(stack, size, align) ((stack -= (size)), ALIGN_ADDRESS(stack, align)) ++ ++// Most wasm runtimes support at most 1000 Js trampoline args. ++#define MAX_ARGS 1000 ++ ++#include ++ ++#define VARARGS_FLAG 1 ++ ++#define FFI_OK_MACRO 0 ++_Static_assert(FFI_OK_MACRO == FFI_OK, "FFI_OK must be 0"); ++ ++#define FFI_BAD_TYPEDEF_MACRO 1 ++_Static_assert(FFI_BAD_TYPEDEF_MACRO == FFI_BAD_TYPEDEF, "FFI_BAD_TYPEDEF must be 1"); ++ ++ffi_status FFI_HIDDEN ffi_prep_cif_machdep(ffi_cif *cif) ++{ ++ if (cif->abi != FFI_WASM32_EMSCRIPTEN) ++ return FFI_BAD_ABI; ++ // This is called after ffi_prep_cif_machdep_var so we need to avoid ++ // overwriting cif->nfixedargs. ++ if (!(cif->flags & VARARGS_FLAG)) ++ cif->nfixedargs = cif->nargs; ++ if (cif->nargs > MAX_ARGS) ++ return FFI_BAD_TYPEDEF; ++ if (cif->rtype->type == FFI_TYPE_COMPLEX) ++ return FFI_BAD_TYPEDEF; ++ // If they put the COMPLEX type into a struct we won't notice, but whatever. ++ for (int i = 0; i < cif->nargs; i++) ++ if (cif->arg_types[i]->type == FFI_TYPE_COMPLEX) ++ return FFI_BAD_TYPEDEF; ++ return FFI_OK; ++} ++ ++ffi_status FFI_HIDDEN ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned nfixedargs, unsigned ntotalargs) ++{ ++ cif->flags |= VARARGS_FLAG; ++ cif->nfixedargs = nfixedargs; ++ // The varargs takes up one extra argument ++ if (cif->nfixedargs + 1 > MAX_ARGS) ++ return FFI_BAD_TYPEDEF; ++ return FFI_OK; ++} ++ ++/** ++ * A Javascript helper function. This takes an argument typ which is a wasm ++ * pointer to an ffi_type object. It returns a pair a type and a type id. ++ * ++ * - If it is not a struct, return its type and its typeid field. ++ * - If it is a struct of size >= 2, return the type and its typeid (which ++ * will be FFI_TYPE_STRUCT) ++ * - If it is a struct of size 0, return FFI_TYPE_VOID (????? this is broken) ++ * - If it is a struct of size 1, replace it with the single field and apply ++ * the same logic again to that. ++ * ++ * By always unboxing structs up front, we can avoid messy casework later. ++ */ ++EM_JS_MACROS(void, unbox_small_structs, (ffi_type type_ptr), { ++ var type_id = FFI_TYPE__TYPEID(type_ptr); ++ while (type_id == = FFI_TYPE_STRUCT) ++ { ++ // Don't unbox single element structs if they are bigger than 16 bytes. This ++ // is a work around for the fact that Python will give incorrect values for ++ // the size of the field in these cases: it says that the struct has pointer ++ // size and alignment and are of type pointer, even though it is more ++ // accurately a struct and has a larger size. Keeping it as a struct here ++ // will let us get the ABI right (which is in fact that the true argument is ++ // a pointer to the stack... so maybe Python issn't so wrong??) ++ // ++ // See the Python comment here: ++ // https://github.com/python/cpython/blob/a16a9f978f42b8a09297c1efbf33877f6388c403/Modules/_ctypes/stgdict.c#L718-L779 ++ if (FFI_TYPE__SIZE(type_ptr) > 16) ++ { ++ break; ++ } ++ var elements = FFI_TYPE__ELEMENTS(type_ptr); ++ var first_element = DEREF_U32(elements, 0); ++ if (first_element == = 0) ++ { ++ type_id = FFI_TYPE_VOID; ++ break; ++ } ++ else if (DEREF_U32(elements, 1) == = 0) ++ { ++ type_ptr = first_element; ++ type_id = FFI_TYPE__TYPEID(first_element); ++ } ++ else ++ { ++ break; ++ } ++ } ++ return [ type_ptr, type_id ]; ++}) ++ ++EM_JS_MACROS(void, ffi_call_js, (ffi_cif * cif, ffi_fp fn, void *rvalue, void **avalue), { ++ var abi = CIF__ABI(cif); ++ var nargs = CIF__NARGS(cif); ++ var nfixedargs = CIF__NFIXEDARGS(cif); ++ var arg_types_ptr = CIF__ARGTYPES(cif); ++ var rtype_unboxed = unbox_small_structs(CIF__RTYPE(cif)); ++ var rtype_ptr = rtype_unboxed[0]; ++ var rtype_id = rtype_unboxed[1]; ++ var orig_stack_ptr = stackSave(); ++ var cur_stack_ptr = orig_stack_ptr; ++ ++ var args = []; ++ // Does our onwards call return by argument or normally? We return by argument ++ // no matter what. ++ var ret_by_arg = false; ++ ++ if (rtype_id == = FFI_TYPE_COMPLEX) ++ { ++ throw new Error('complex ret marshalling nyi'); ++ } ++ if (rtype_id < 0 || rtype_id > FFI_TYPE_LAST) ++ { ++ throw new Error('Unexpected rtype ' + rtype_id); ++ } ++ // If the return type is a struct with multiple entries or a long double, the ++ // function takes an extra first argument which is a pointer to return value. ++ // Conveniently, we've already received a pointer to return value, so we can ++ // just use this. We also mark a flag that we don't need to convert the return ++ // value of the dynamic call back to C. ++ if (rtype_id == = FFI_TYPE_LONGDOUBLE || rtype_id == = FFI_TYPE_STRUCT) ++ { ++ args.push(rvalue); ++ ret_by_arg = true; ++ } ++ ++ SIG(var sig = ""); ++ ++#if !WASM_BIGINT ++ switch (rtype_id) ++ { ++ case FFI_TYPE_VOID: ++ SIG(sig = 'v'); ++ break; ++ case FFI_TYPE_STRUCT: ++ case FFI_TYPE_LONGDOUBLE: ++ SIG(sig = 'vi'); ++ break; ++ case FFI_TYPE_INT: ++ case FFI_TYPE_UINT8: ++ case FFI_TYPE_SINT8: ++ case FFI_TYPE_UINT16: ++ case FFI_TYPE_SINT16: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_POINTER: ++ SIG(sig = 'i'); ++ break; ++ case FFI_TYPE_FLOAT: ++ SIG(sig = 'f'); ++ break; ++ case FFI_TYPE_DOUBLE: ++ SIG(sig = 'd'); ++ break; ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ SIG(sig = 'j'); ++ break; ++ } ++#endif ++ ++ // Accumulate a Javascript list of arguments for the Javascript wrapper for ++ // the wasm function. The Javascript wrapper does a type conversion from ++ // Javascript to C automatically, here we manually do the inverse conversion ++ // from C to Javascript. ++ for (var i = 0; i < nfixedargs; i++) ++ { ++ var arg_ptr = DEREF_U32(avalue, i); ++ var arg_unboxed = unbox_small_structs(DEREF_U32(arg_types_ptr, i)); ++ var arg_type_ptr = arg_unboxed[0]; ++ var arg_type_id = arg_unboxed[1]; ++ ++ // It's okay here to always use unsigned integers as long as the size is 32 ++ // or 64 bits. Smaller sizes get extended to 32 bits differently according ++ // to whether they are signed or unsigned. ++ switch (arg_type_id) ++ { ++ case FFI_TYPE_INT: ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_POINTER: ++ args.push(DEREF_U32(arg_ptr, 0)); ++ SIG(sig += 'i'); ++ break; ++ case FFI_TYPE_FLOAT: ++ args.push(DEREF_F32(arg_ptr, 0)); ++ SIG(sig += 'f'); ++ break; ++ case FFI_TYPE_DOUBLE: ++ args.push(DEREF_F64(arg_ptr, 0)); ++ SIG(sig += 'd'); ++ break; ++ case FFI_TYPE_UINT8: ++ args.push(DEREF_U8(arg_ptr, 0)); ++ SIG(sig += 'i'); ++ break; ++ case FFI_TYPE_SINT8: ++ args.push(DEREF_S8(arg_ptr, 0)); ++ SIG(sig += 'i'); ++ break; ++ case FFI_TYPE_UINT16: ++ args.push(DEREF_U16(arg_ptr, 0)); ++ SIG(sig += 'i'); ++ break; ++ case FFI_TYPE_SINT16: ++ args.push(DEREF_S16(arg_ptr, 0)); ++ SIG(sig += 'i'); ++ break; ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++#if WASM_BIGINT ++ args.push(DEREF_U64(arg_ptr, 0)); ++#else ++ args.push(DEREF_U32(arg_ptr, 0)); ++ args.push(DEREF_U32(arg_ptr, 1)); ++#endif ++ SIG(sig += 'j'); ++ break; ++ case FFI_TYPE_LONGDOUBLE: ++// long double is passed as a pair of BigInts. ++#if WASM_BIGINT ++ args.push(DEREF_U64(arg_ptr, 0)); ++ args.push(DEREF_U64(arg_ptr, 1)); ++#else ++ args.push(DEREF_U32(arg_ptr, 0)); ++ args.push(DEREF_U32(arg_ptr, 1)); ++ args.push(DEREF_U32(arg_ptr, 2)); ++ args.push(DEREF_U32(arg_ptr, 3)); ++#endif ++ SIG(sig += "jj"); ++ break; ++ case FFI_TYPE_STRUCT: ++ // Nontrivial structs are passed by pointer. ++ // Have to copy the struct onto the stack though because C ABI says it's ++ // call by value. ++ var size = FFI_TYPE__SIZE(arg_type_ptr); ++ var align = FFI_TYPE__ALIGN(arg_type_ptr); ++ STACK_ALLOC(cur_stack_ptr, size, align); ++ HEAP8.subarray(cur_stack_ptr, cur_stack_ptr + size).set(HEAP8.subarray(arg_ptr, arg_ptr + size)); ++ args.push(cur_stack_ptr); ++ SIG(sig += 'i'); ++ break; ++ case FFI_TYPE_COMPLEX: ++ throw new Error('complex marshalling nyi'); ++ default: ++ throw new Error('Unexpected type ' + arg_type_id); ++ } ++ } ++ ++ // Wasm functions can't directly manipulate the callstack, so varargs ++ // arguments have to go on a separate stack. A varags function takes one extra ++ // argument which is a pointer to where on the separate stack the args are ++ // located. Because stacks are allocated backwards, we have to loop over the ++ // varargs backwards. ++ // ++ // We don't have any way of knowing how many args were actually passed, so we ++ // just always copy extra nonsense past the end. The ownwards call will know ++ // not to look at it. ++ if (nfixedargs != nargs) ++ { ++ SIG(sig += 'i'); ++ var struct_arg_info = []; ++ for (var i = nargs - 1; i >= nfixedargs; i--) ++ { ++ var arg_ptr = DEREF_U32(avalue, i); ++ var arg_unboxed = unbox_small_structs(DEREF_U32(arg_types_ptr, i)); ++ var arg_type_ptr = arg_unboxed[0]; ++ var arg_type_id = arg_unboxed[1]; ++ switch (arg_type_id) ++ { ++ case FFI_TYPE_UINT8: ++ case FFI_TYPE_SINT8: ++ STACK_ALLOC(cur_stack_ptr, 1, 1); ++ DEREF_U8(cur_stack_ptr, 0) = DEREF_U8(arg_ptr, 0); ++ break; ++ case FFI_TYPE_UINT16: ++ case FFI_TYPE_SINT16: ++ STACK_ALLOC(cur_stack_ptr, 2, 2); ++ DEREF_U16(cur_stack_ptr, 0) = DEREF_U16(arg_ptr, 0); ++ break; ++ case FFI_TYPE_INT: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_POINTER: ++ case FFI_TYPE_FLOAT: ++ STACK_ALLOC(cur_stack_ptr, 4, 4); ++ DEREF_U32(cur_stack_ptr, 0) = DEREF_U32(arg_ptr, 0); ++ break; ++ case FFI_TYPE_DOUBLE: ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ STACK_ALLOC(cur_stack_ptr, 8, 8); ++ DEREF_U32(cur_stack_ptr, 0) = DEREF_U32(arg_ptr, 0); ++ DEREF_U32(cur_stack_ptr, 1) = DEREF_U32(arg_ptr, 1); ++ break; ++ case FFI_TYPE_LONGDOUBLE: ++ STACK_ALLOC(cur_stack_ptr, 16, 8); ++ DEREF_U32(cur_stack_ptr, 0) = DEREF_U32(arg_ptr, 0); ++ DEREF_U32(cur_stack_ptr, 1) = DEREF_U32(arg_ptr, 1); ++ DEREF_U32(cur_stack_ptr, 2) = DEREF_U32(arg_ptr, 2); ++ DEREF_U32(cur_stack_ptr, 3) = DEREF_U32(arg_ptr, 3); ++ break; ++ case FFI_TYPE_STRUCT: ++ // Again, struct must be passed by pointer. ++ // But ABI is by value, so have to copy struct onto stack. ++ // Currently arguments are going onto stack so we can't put it there now. Come back for this. ++ STACK_ALLOC(cur_stack_ptr, 4, 4); ++ struct_arg_info.push( ++ [ cur_stack_ptr, arg_ptr, FFI_TYPE__SIZE(arg_type_ptr), FFI_TYPE__ALIGN(arg_type_ptr) ]); ++ break; ++ case FFI_TYPE_COMPLEX: ++ throw new Error('complex arg marshalling nyi'); ++ default: ++ throw new Error('Unexpected argtype ' + arg_type_id); ++ } ++ } ++ // extra normal argument which is the pointer to the varargs. ++ args.push(cur_stack_ptr); ++ // Now allocate variable struct args on stack too. ++ for (var i = 0; i < struct_arg_info.length; i++) ++ { ++ var struct_info = struct_arg_info[i]; ++ var arg_target = struct_info[0]; ++ var arg_ptr = struct_info[1]; ++ var size = struct_info[2]; ++ var align = struct_info[3]; ++ STACK_ALLOC(cur_stack_ptr, size, align); ++ HEAP8.subarray(cur_stack_ptr, cur_stack_ptr + size).set(HEAP8.subarray(arg_ptr, arg_ptr + size)); ++ DEREF_U32(arg_target, 0) = cur_stack_ptr; ++ } ++ } ++ stackRestore(cur_stack_ptr); ++ stackAlloc(0); // stackAlloc enforces alignment invariants on the stack pointer ++ var result = CALL_FUNCTION_POINTER(fn, args); ++ // Put the stack pointer back (we moved it if there were any struct args or we ++ // made a varargs call) ++ stackRestore(orig_stack_ptr); ++ ++ // We need to return by argument. If return value was a nontrivial struct or ++ // long double, the onwards call already put the return value in rvalue ++ if (ret_by_arg) ++ { ++ return; ++ } ++ ++ // Otherwise the result was automatically converted from C into Javascript and ++ // we need to manually convert it back to C. ++ switch (rtype_id) ++ { ++ case FFI_TYPE_VOID: ++ break; ++ case FFI_TYPE_INT: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_POINTER: ++ DEREF_U32(rvalue, 0) = result; ++ break; ++ case FFI_TYPE_FLOAT: ++ DEREF_F32(rvalue, 0) = result; ++ break; ++ case FFI_TYPE_DOUBLE: ++ DEREF_F64(rvalue, 0) = result; ++ break; ++ case FFI_TYPE_UINT8: ++ case FFI_TYPE_SINT8: ++ DEREF_U8(rvalue, 0) = result; ++ break; ++ case FFI_TYPE_UINT16: ++ case FFI_TYPE_SINT16: ++ DEREF_U16(rvalue, 0) = result; ++ break; ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++#if WASM_BIGINT ++ DEREF_U64(rvalue, 0) = result; ++#else ++ DEREF_U32(rvalue, 0) = result; ++ DEREF_U32(rvalue, 1) = getTempRet0(); ++#endif ++ break; ++ case FFI_TYPE_COMPLEX: ++ throw new Error('complex ret marshalling nyi'); ++ default: ++ throw new Error('Unexpected rtype ' + rtype_id); ++ } ++}); ++ ++void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { ffi_call_js(cif, fn, rvalue, avalue); } ++ ++CHECK_FIELD_OFFSET(ffi_closure, ftramp, 4 * 0); ++CHECK_FIELD_OFFSET(ffi_closure, cif, 4 * 1); ++CHECK_FIELD_OFFSET(ffi_closure, fun, 4 * 2); ++CHECK_FIELD_OFFSET(ffi_closure, user_data, 4 * 3); ++ ++#define CLOSURE__wrapper(addr) DEREF_U32(addr, 0) ++#define CLOSURE__cif(addr) DEREF_U32(addr, 1) ++#define CLOSURE__fun(addr) DEREF_U32(addr, 2) ++#define CLOSURE__user_data(addr) DEREF_U32(addr, 3) ++ ++EM_JS_MACROS(void *, ffi_closure_alloc_js, (size_t size, void **code), { ++ var closure = _malloc(size); ++ var index = getEmptyTableSlot(); ++ DEREF_U32(code, 0) = index; ++ CLOSURE__wrapper(closure) = index; ++ return closure; ++}) ++ ++void *__attribute__((visibility("default"))) ffi_closure_alloc(size_t size, void **code) ++{ ++ return ffi_closure_alloc_js(size, code); ++} ++ ++EM_JS_MACROS(void, ffi_closure_free_js, (void *closure), { ++ var index = CLOSURE__wrapper(closure); ++ freeTableIndexes.push(index); ++ _free(closure); ++}) ++ ++void __attribute__((visibility("default"))) ffi_closure_free(void *closure) { return ffi_closure_free_js(closure); } ++ ++#if !WASM_BIGINT ++ ++// When !WASM_BIGINT, we assume there is no JS bigint integration, so JavaScript ++// functions cannot take 64 bit integer arguments. ++// ++// We need to make our own wasm legalizer adaptor that splits 64 bit integer ++// arguments and then calls the JavaScript trampoline, then the JavaScript ++// trampoline reassembles them, calls the closure, then splits the result (if ++// it's a 64 bit integer) and the adaptor puts it back together. ++// ++// This is basically the reverse of the Emscripten function ++// createDyncallWrapper. ++EM_JS(void, createLegalizerWrapper, (int trampoline, int sig), { ++ if (!sig.includes("j")) ++ { ++ return convertJsFunctionToWasm(trampoline, sig); ++ } ++ var sections = []; ++ var prelude = [ ++ 0x00, 0x61, 0x73, 0x6d, // magic ("\0asm") ++ 0x01, 0x00, 0x00, 0x00, // version: 1 ++ ]; ++ sections.push(prelude); ++ var wrappersig = ++ [ ++ // if return type is j, we will put the upper 32 bits into tempRet0. ++ sig[0].replace("j", "i"), ++ // in the rest of the argument list, one 64 bit integer is legalized into ++ // two 32 bit integers. ++ sig.slice(1).replace(/ j / g, "ii"), ++ ] ++ .join(""); ++ ++ var typeSectionBody = [ ++ 0x03, // number of types = 3 ++ ]; ++ generateFuncType(wrappersig, typeSectionBody); // The signature of the wrapper we are generating ++ generateFuncType(sig, typeSectionBody); // the signature of the function pointer we will call ++ generateFuncType("i", typeSectionBody); // the signature of getTempRet0 ++ ++ var typeSection = [0x01 /* Type section code */]; ++ uleb128Encode(typeSectionBody.length, typeSection); // length of section in bytes ++ typeSection.push.apply(typeSection, typeSectionBody); ++ sections.push(typeSection); ++ ++ var importSection = [ ++ 0x02, // import section code ++ 0x0d, // length of section in bytes ++ 0x02, // number of imports = 2 ++ // Import the getTempRet0 function, which we will call "r" ++ 0x01, 0x65, // name "e" ++ 0x01, 0x72, // name "r" ++ 0x00, // importing a function ++ 0x02, // type 2 = () -> i32 ++ // Import the wrapped function, which we will call "f" ++ 0x01, 0x65, // name "e" ++ 0x01, 0x66, // name "f" ++ 0x00, // importing a function ++ 0x00, // type 0 = wrappersig ++ ]; ++ sections.push(importSection); ++ ++ var functionSection = [ ++ 0x03, // function section code ++ 0x02, // length of section in bytes ++ 0x01, // number of functions = 1 ++ 0x01, // type 1 = sig ++ ]; ++ sections.push(functionSection); ++ ++ var exportSection = [ ++ 0x07, // export section code ++ 0x05, // length of section in bytes ++ 0x01, // One export ++ 0x01, 0x66, // name "f" ++ 0x00, // type: function ++ 0x02, // function index 2 = the wrapper function ++ ]; ++ sections.push(exportSection); ++ ++ var convert_code = []; ++ convert_code.push(0x00); // no local variables (except the arguments) ++ ++ function localGet(j) ++ { ++ convert_code.push(0x20); // local.get ++ uleb128Encode(j, convert_code); ++ } ++ ++ for (var i = 1; i < sig.length; i++) ++ { ++ if (sig[i] == "j") ++ { ++ localGet(i - 1); ++ convert_code.push(0xa7 // i32.wrap_i64 ++ ); ++ localGet(i - 1); ++ convert_code.push(0x42, 0x20, // i64.const 32 ++ 0x88, // i64.shr_u ++ 0xa7 // i32.wrap_i64 ++ ); ++ } ++ else ++ { ++ localGet(i - 1); ++ } ++ } ++ convert_code.push(0x10, 0x01 // call f ++ ); ++ if (sig[0] == = "j") ++ { ++ // Need to reassemble a 64 bit integer. Lower 32 bits is on stack. Upper 32 ++ // bits we get from getTempRet0 ++ convert_code.push(0xad, // i64.extend_i32_unsigned ++ 0x10, 0x00, // Call function 0 (r = getTempRet0) ++ // join lower 32 bits and upper 32 bits ++ 0xac, // i64.extend_i32_signed ++ 0x42, 0x20, // i64.const 32 ++ 0x86, // i64.shl, ++ 0x84 // i64.or ++ ); ++ } ++ convert_code.push(0x0b); // end ++ ++ var codeBody = [0x01]; // one code ++ uleb128Encode(convert_code.length, codeBody); ++ codeBody.push.apply(codeBody, convert_code); ++ var codeSection = [0x0a /* Code section code */]; ++ uleb128Encode(codeBody.length, codeSection); ++ codeSection.push.apply(codeSection, codeBody); ++ sections.push(codeSection); ++ ++ var bytes = new Uint8Array([].concat.apply([], sections)); ++ // We can compile this wasm module synchronously because it is small. ++ var module = new WebAssembly.Module(bytes); ++ var instance = new WebAssembly.Instance(module, { ++ e : { ++ r : getTempRet0, ++ f : trampoline, ++ }, ++ }); ++ return instance.exports.f; ++}); ++#endif ++ ++EM_JS_MACROS( ++ ffi_status, ffi_prep_closure_loc_js, ++ (ffi_closure * closure, ffi_cif *cif, void *fun, void *user_data, void *codeloc), { ++ var abi = CIF__ABI(cif); ++ var nargs = CIF__NARGS(cif); ++ var nfixedargs = CIF__NFIXEDARGS(cif); ++ var arg_types_ptr = CIF__ARGTYPES(cif); ++ var rtype_unboxed = unbox_small_structs(CIF__RTYPE(cif)); ++ var rtype_ptr = rtype_unboxed[0]; ++ var rtype_id = rtype_unboxed[1]; ++ ++ // First construct the signature of the javascript trampoline we are going to create. ++ // Important: this is the signature for calling us, the onward call always has sig viiii. ++ var sig; ++ var ret_by_arg = false; ++ switch (rtype_id) ++ { ++ case FFI_TYPE_VOID: ++ sig = 'v'; ++ break; ++ case FFI_TYPE_STRUCT: ++ case FFI_TYPE_LONGDOUBLE: ++ // Return via a first pointer argument. ++ sig = 'vi'; ++ ret_by_arg = true; ++ break; ++ case FFI_TYPE_INT: ++ case FFI_TYPE_UINT8: ++ case FFI_TYPE_SINT8: ++ case FFI_TYPE_UINT16: ++ case FFI_TYPE_SINT16: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_POINTER: ++ sig = 'i'; ++ break; ++ case FFI_TYPE_FLOAT: ++ sig = 'f'; ++ break; ++ case FFI_TYPE_DOUBLE: ++ sig = 'd'; ++ break; ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ sig = 'j'; ++ break; ++ case FFI_TYPE_COMPLEX: ++ throw new Error('complex ret marshalling nyi'); ++ default: ++ throw new Error('Unexpected rtype ' + rtype_id); ++ } ++ var unboxed_arg_type_id_list = []; ++ var unboxed_arg_type_info_list = []; ++ for (var i = 0; i < nargs; i++) ++ { ++ var arg_unboxed = unbox_small_structs(DEREF_U32(arg_types_ptr, i)); ++ var arg_type_ptr = arg_unboxed[0]; ++ var arg_type_id = arg_unboxed[1]; ++ unboxed_arg_type_id_list.push(arg_type_id); ++ unboxed_arg_type_info_list.push([ FFI_TYPE__SIZE(arg_type_ptr), FFI_TYPE__ALIGN(arg_type_ptr) ]); ++ } ++ for (var i = 0; i < nfixedargs; i++) ++ { ++ switch (unboxed_arg_type_id_list[i]) ++ { ++ case FFI_TYPE_INT: ++ case FFI_TYPE_UINT8: ++ case FFI_TYPE_SINT8: ++ case FFI_TYPE_UINT16: ++ case FFI_TYPE_SINT16: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_POINTER: ++ case FFI_TYPE_STRUCT: ++ sig += 'i'; ++ break; ++ case FFI_TYPE_FLOAT: ++ sig += 'f'; ++ break; ++ case FFI_TYPE_DOUBLE: ++ sig += 'd'; ++ break; ++ case FFI_TYPE_LONGDOUBLE: ++ sig += 'jj'; ++ break; ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ sig += 'j'; ++ break; ++ case FFI_TYPE_COMPLEX: ++ throw new Error('complex marshalling nyi'); ++ default: ++ throw new Error('Unexpected argtype ' + arg_type_id); ++ } ++ } ++ if (nfixedargs < nargs) ++ { ++ // extra pointer to varargs stack ++ sig += "i"; ++ } ++ LOG_DEBUG("CREATE_CLOSURE", "sig:", sig); ++ function trampoline() ++ { ++ var args = Array.prototype.slice.call(arguments); ++ var size = 0; ++ var orig_stack_ptr = stackSave(); ++ var cur_ptr = orig_stack_ptr; ++ var ret_ptr; ++ var jsarg_idx = 0; ++ // Should we return by argument or not? The onwards call returns by argument ++ // no matter what. (Warning: ret_by_arg means the opposite in ffi_call) ++ if (ret_by_arg) ++ { ++ ret_ptr = args[jsarg_idx++]; ++ } ++ else ++ { ++ // We might return 4 bytes or 8 bytes, allocate 8 just in case. ++ STACK_ALLOC(cur_ptr, 8, 8); ++ ret_ptr = cur_ptr; ++ } ++ cur_ptr -= 4 * nargs; ++ var args_ptr = cur_ptr; ++ var carg_idx = 0; ++ // Here we either have the actual argument, or a pair of BigInts for long ++ // double, or a pointer to struct. We have to store into args_ptr[i] a ++ // pointer to the ith argument. If the argument is a struct, just store the ++ // pointer. Otherwise allocate stack space and copy the js argument onto the ++ // stack. ++ for (; carg_idx < nfixedargs; carg_idx++) ++ { ++ // jsarg_idx might start out as 0 or 1 depending on ret_by_arg ++ // it advances an extra time for long double ++ var cur_arg = args[jsarg_idx++]; ++ var arg_type_info = unboxed_arg_type_info_list[carg_idx]; ++ var arg_size = arg_type_info[0]; ++ var arg_align = arg_type_info[1]; ++ var arg_type_id = unboxed_arg_type_id_list[carg_idx]; ++ switch (arg_type_id) ++ { ++ case FFI_TYPE_UINT8: ++ case FFI_TYPE_SINT8: ++ // Bad things happen if we don't align to 4 here ++ STACK_ALLOC(cur_ptr, 1, 4); ++ DEREF_U32(args_ptr, carg_idx) = cur_ptr; ++ DEREF_U8(cur_ptr, 0) = cur_arg; ++ break; ++ case FFI_TYPE_UINT16: ++ case FFI_TYPE_SINT16: ++ // Bad things happen if we don't align to 4 here ++ STACK_ALLOC(cur_ptr, 2, 4); ++ DEREF_U32(args_ptr, carg_idx) = cur_ptr; ++ DEREF_U16(cur_ptr, 0) = cur_arg; ++ break; ++ case FFI_TYPE_INT: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_POINTER: ++ STACK_ALLOC(cur_ptr, 4, 4); ++ DEREF_U32(args_ptr, carg_idx) = cur_ptr; ++ DEREF_U32(cur_ptr, 0) = cur_arg; ++ break; ++ case FFI_TYPE_STRUCT: ++ // cur_arg is already a pointer to struct ++ // copy it onto stack to pass by value ++ STACK_ALLOC(cur_ptr, arg_size, arg_align); ++ HEAP8.subarray(cur_ptr, cur_ptr + arg_size).set(HEAP8.subarray(cur_arg, cur_arg + arg_size)); ++ DEREF_U32(args_ptr, carg_idx) = cur_ptr; ++ break; ++ case FFI_TYPE_FLOAT: ++ STACK_ALLOC(cur_ptr, 4, 4); ++ DEREF_U32(args_ptr, carg_idx) = cur_ptr; ++ DEREF_F32(cur_ptr, 0) = cur_arg; ++ break; ++ case FFI_TYPE_DOUBLE: ++ STACK_ALLOC(cur_ptr, 8, 8); ++ DEREF_U32(args_ptr, carg_idx) = cur_ptr; ++ DEREF_F64(cur_ptr, 0) = cur_arg; ++ break; ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ STACK_ALLOC(cur_ptr, 8, 8); ++ DEREF_U32(args_ptr, carg_idx) = cur_ptr; ++#if WASM_BIGINT ++ DEREF_U64(cur_ptr, 0) = cur_arg; ++#else ++ // Bigint arg was split by legalizer adaptor ++ DEREF_U32(cur_ptr, 0) = cur_arg; ++ cur_arg = args[jsarg_idx++]; ++ DEREF_U32(cur_ptr, 1) = cur_arg; ++#endif ++ break; ++ case FFI_TYPE_LONGDOUBLE: ++ STACK_ALLOC(cur_ptr, 16, 8); ++ DEREF_U32(args_ptr, carg_idx) = cur_ptr; ++#if WASM_BIGINT ++ DEREF_U64(cur_ptr, 0) = cur_arg; ++ cur_arg = args[jsarg_idx++]; ++ DEREF_U64(cur_ptr, 1) = cur_arg; ++#else ++ // Was split by legalizer adaptor ++ DEREF_U32(cur_ptr, 0) = cur_arg; ++ cur_arg = args[jsarg_idx++]; ++ DEREF_U32(cur_ptr, 1) = cur_arg; ++ cur_arg = args[jsarg_idx++]; ++ DEREF_U32(cur_ptr, 2) = cur_arg; ++ cur_arg = args[jsarg_idx++]; ++ DEREF_U32(cur_ptr, 3) = cur_arg; ++#endif ++ break; ++ } ++ } ++ // If its a varargs call, last js argument is a pointer to the varargs. ++ var varargs = args[args.length - 1]; ++ // We have no way of knowing how many varargs were actually provided, this ++ // fills the rest of the stack space allocated with nonsense. The onward ++ // call will know to ignore the nonsense. ++ ++ // We either have a pointer to the argument if the argument is not a struct ++ // or a pointer to pointer to struct. We need to store a pointer to the ++ // argument into args_ptr[i] ++ for (; carg_idx < nargs; carg_idx++) ++ { ++ var arg_type_id = unboxed_arg_type_id_list[carg_idx]; ++ var arg_type_info = unboxed_arg_type_info_list[carg_idx]; ++ var arg_size = arg_type_info[0]; ++ var arg_align = arg_type_info[1]; ++ if (arg_type_id == = FFI_TYPE_STRUCT) ++ { ++ // In this case varargs is a pointer to pointer to struct so we need to ++ // deref once ++ var struct_ptr = DEREF_U32(varargs, 0); ++ STACK_ALLOC(cur_ptr, arg_size, arg_align); ++ HEAP8.subarray(cur_ptr, cur_ptr + arg_size).set(HEAP8.subarray(struct_ptr, struct_ptr + arg_size)); ++ DEREF_U32(args_ptr, carg_idx) = cur_ptr; ++ } ++ else ++ { ++ DEREF_U32(args_ptr, carg_idx) = varargs; ++ } ++ varargs += 4; ++ } ++ stackRestore(cur_ptr); ++ stackAlloc(0); // stackAlloc enforces alignment invariants on the stack pointer ++ LOG_DEBUG("CALL_CLOSURE", "closure:", closure, "fptr", CLOSURE__fun(closure), "cif", CLOSURE__cif(closure)); ++ getWasmTableEntry(CLOSURE__fun(closure))(CLOSURE__cif(closure), ret_ptr, args_ptr, ++ CLOSURE__user_data(closure)); ++ stackRestore(orig_stack_ptr); ++ ++ // If we aren't supposed to return by argument, figure out what to return. ++ if (!ret_by_arg) ++ { ++ switch (sig[0]) ++ { ++ case "i": ++ return DEREF_U32(ret_ptr, 0); ++ case "j": ++#if WASM_BIGINT ++ return DEREF_U64(ret_ptr, 0); ++#else ++ // Split the return i64, set the upper 32 bits into tempRet0 and return ++ // the lower 32 bits. ++ setTempRet0(DEREF_U32(ret_ptr, 1)); ++ return DEREF_U32(ret_ptr, 0); ++#endif ++ case "d": ++ return DEREF_F64(ret_ptr, 0); ++ case "f": ++ return DEREF_F32(ret_ptr, 0); ++ } ++ } ++ } ++ try ++ { ++ var wasm_trampoline = JS_FUNCTION_TO_WASM(trampoline, sig); ++ } ++ catch (e) ++ { ++ return FFI_BAD_TYPEDEF_MACRO; ++ } ++ setWasmTableEntry(codeloc, wasm_trampoline); ++ CLOSURE__cif(closure) = cif; ++ CLOSURE__fun(closure) = fun; ++ CLOSURE__user_data(closure) = user_data; ++ return FFI_OK_MACRO; ++ }) ++ ++// EM_JS does not correctly handle function pointer arguments, so we need a ++// helper ++ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void (*fun)(ffi_cif *, void *, void **, void *), ++ void *user_data, void *codeloc) ++{ ++ if (cif->abi != FFI_WASM32_EMSCRIPTEN) ++ return FFI_BAD_ABI; ++ return ffi_prep_closure_loc_js(closure, cif, (void *)fun, user_data, codeloc); ++} +diff --git a/src/wasm32/ffitarget.h b/src/wasm32/ffitarget.h +new file mode 100644 +index 0000000..ad9e25b +--- /dev/null ++++ b/src/wasm32/ffitarget.h +@@ -0,0 +1,63 @@ ++/* -----------------------------------------------------------------*-C-*- ++ ffitarget.h - Copyright (c) 2018-2023 Hood Chatham, Brion Vibber, Kleis Auke Wolthuizen, and others. ++ ++ Target configuration macros for wasm32. ++ ++ Permission is hereby granted, free of charge, to any person obtaining ++ a copy of this software and associated documentation files (the ++ ``Software''), to deal in the Software without restriction, including ++ without limitation the rights to use, copy, modify, merge, publish, ++ distribute, sublicense, and/or sell copies of the Software, and to ++ permit persons to whom the Software is furnished to do so, subject to ++ the following conditions: ++ ++ The above copyright notice and this permission notice shall be included ++ in all copies or substantial portions of the Software. ++ ++ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, ++ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ++ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ DEALINGS IN THE SOFTWARE. ++ ++ ----------------------------------------------------------------------- */ ++ ++#ifndef LIBFFI_TARGET_H ++#define LIBFFI_TARGET_H ++ ++#ifndef LIBFFI_H ++#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." ++#endif ++ ++/* ---- Generic type definitions ----------------------------------------- */ ++ ++typedef unsigned long ffi_arg; ++typedef signed long ffi_sarg; ++ ++// TODO: https://github.com/emscripten-core/emscripten/issues/9868 ++typedef void (*ffi_fp)(void); ++ ++typedef enum ffi_abi ++{ ++ FFI_FIRST_ABI = 0, ++ FFI_WASM32, // "raw", no structures, varargs, or closures (not implemented!) ++ FFI_WASM32_EMSCRIPTEN, // structures, varargs, and split 64-bit params ++ FFI_LAST_ABI, ++#ifdef __EMSCRIPTEN__ ++ FFI_DEFAULT_ABI = FFI_WASM32_EMSCRIPTEN ++#else ++ FFI_DEFAULT_ABI = FFI_WASM32 ++#endif ++} ffi_abi; ++ ++#define FFI_CLOSURES 1 ++// #define FFI_GO_CLOSURES 0 ++#define FFI_TRAMPOLINE_SIZE 4 ++// #define FFI_NATIVE_RAW_API 0 ++#define FFI_TARGET_SPECIFIC_VARIADIC 1 ++#define FFI_EXTRA_CIF_FIELDS unsigned int nfixedargs ++ ++#endif From 99db8058be8bdd7e36812ec0fc86863c11387961 Mon Sep 17 00:00:00 2001 From: yanovskyy Date: Sun, 16 Jun 2024 11:33:53 +0200 Subject: [PATCH 03/10] changed glib.wrap for wasm support Signed-off-by: yanovskyy --- subprojects/glib.wrap | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/subprojects/glib.wrap b/subprojects/glib.wrap index 8fdcb41..e115792 100644 --- a/subprojects/glib.wrap +++ b/subprojects/glib.wrap @@ -1,10 +1,8 @@ -[wrap-file] -directory = glib-2.80.3 -source_url = https://download.gnome.org/sources/glib/2.80/glib-2.80.3.tar.xz -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/glib_2.80.3-1/glib-2.80.3.tar.xz -source_filename = glib-2.80.3.tar.xz -source_hash = 3947a0eaddd0f3613d0230bb246d0c69e46142c19022f5c4b1b2e3cba236d417 -wrapdb_version = 2.80.3-1 +[wrap-git] +directory = glib +url = https://github.com/VitoVan/glib +revision = wasm-calm-2.76.1 +depth = 1 [provide] dependency_names = gthread-2.0, gobject-2.0, gmodule-no-export-2.0, gmodule-export-2.0, gmodule-2.0, glib-2.0, gio-2.0, gio-windows-2.0, gio-unix-2.0 From eb4bb4c78d064e2e2ca4515beb18f9a75fdaddb2 Mon Sep 17 00:00:00 2001 From: yanovskyy Date: Sun, 16 Jun 2024 11:34:11 +0200 Subject: [PATCH 04/10] applying wasm32 patch for libffi Signed-off-by: yanovskyy --- subprojects/libffi.wrap | 1 + 1 file changed, 1 insertion(+) diff --git a/subprojects/libffi.wrap b/subprojects/libffi.wrap index cab3b81..b9bb03b 100644 --- a/subprojects/libffi.wrap +++ b/subprojects/libffi.wrap @@ -6,6 +6,7 @@ source_hash = d66c56ad259a82cf2a9dfc408b32bf5da52371500b84745f7fb8b645712df676 patch_filename = libffi_3.4.4-4_patch.zip patch_url = https://wrapdb.mesonbuild.com/v2/libffi_3.4.4-4/get_patch patch_hash = 6babcedb6949383986f1b240a99cd2219a029d62421996d518865a2de855d35a +diff_files = libffi-wasm-3.4.4.patch source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libffi_3.4.4-4/libffi-3.4.4.tar.gz wrapdb_version = 3.4.4-4 From 8e986b0d33bfdbf4cf4ee8748fab6b10058bc080 Mon Sep 17 00:00:00 2001 From: yanovskyy Date: Sun, 16 Jun 2024 11:35:00 +0200 Subject: [PATCH 05/10] skip pcre2 for emscripten and added other op for glib Signed-off-by: yanovskyy --- deps/meson.build | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/deps/meson.build b/deps/meson.build index 456f8fd..c1b64ff 100644 --- a/deps/meson.build +++ b/deps/meson.build @@ -89,19 +89,34 @@ subproject( 'build_codec_apps=false', ], ) + + +host_system = host_machine.system() + +# When trying to do with wasm32, +# this happen with pcre2, "Problem encountered: Your configuration is not supported" + +if host_system != 'emscripten' subproject( 'pcre2', - default_options : [ + default_options: [ 'grep=false', 'test=false', ], ) +endif + subproject( 'glib', default_options : [ - 'introspection=disabled', + #'introspection=disabled', 'nls=disabled', 'tests=false', + 'selinux=disabled', + 'xattr=false', + 'libmount=disabled', + 'nls=disabled', + 'force_fallback_for=pcr2, gvdb', ], ) subproject( @@ -148,4 +163,4 @@ openslide = subproject( 'default_library=shared', 'doc=disabled', ], -) +) \ No newline at end of file From 2db8b45ddc22f8edeca009661075103da0c9cf9c Mon Sep 17 00:00:00 2001 From: yanovskyy Date: Sat, 10 Aug 2024 21:22:54 +0200 Subject: [PATCH 06/10] switch glib dep with patch Signed-off-by: yanovskyy --- subprojects/glib.wrap | 12 +- subprojects/packagefiles/glib.patch | 5642 +++++++++++++++++++++++++++ 2 files changed, 5649 insertions(+), 5 deletions(-) create mode 100644 subprojects/packagefiles/glib.patch diff --git a/subprojects/glib.wrap b/subprojects/glib.wrap index e115792..027ce6f 100644 --- a/subprojects/glib.wrap +++ b/subprojects/glib.wrap @@ -1,8 +1,10 @@ -[wrap-git] -directory = glib -url = https://github.com/VitoVan/glib -revision = wasm-calm-2.76.1 -depth = 1 +[wrap-file] +directory = glib-2.80.4 +source_url = https://download.gnome.org/sources/glib/2.80/glib-2.80.4.tar.xz +source_filename = glib-2.80.4.tar.xz +source_hash = 24e029c5dfc9b44e4573697adf33078a9827c48938555004b3b9096fa4ea034f +diff_files = glib.patch + [provide] dependency_names = gthread-2.0, gobject-2.0, gmodule-no-export-2.0, gmodule-export-2.0, gmodule-2.0, glib-2.0, gio-2.0, gio-windows-2.0, gio-unix-2.0 diff --git a/subprojects/packagefiles/glib.patch b/subprojects/packagefiles/glib.patch new file mode 100644 index 0000000..1f97af1 --- /dev/null +++ b/subprojects/packagefiles/glib.patch @@ -0,0 +1,5642 @@ +From 0d18ac470a217219cd6123ea2d9348e0ce6456bb Mon Sep 17 00:00:00 2001 +From: Kleis Auke Wolthuizen +Date: Tue, 8 Oct 2019 11:30:00 +0200 +Subject: [PATCH 01/10] Do not build tools + +We're only interested in the libraries. + +Upstream-Status: Inappropriate [disable feature] +This patch is just for our convenience. +--- + gio/meson.build | 137 -------------------------------------------- + glib/meson.build | 2 +- + gobject/meson.build | 5 -- + meson.build | 3 - + 4 files changed, 1 insertion(+), 146 deletions(-) + +diff --git a/gio/meson.build b/gio/meson.build +index 59c2b0fc023..30b411fad40 100644 +--- a/gio/meson.build ++++ b/gio/meson.build +@@ -404,20 +404,6 @@ if host_system != 'windows' + contenttype_sources += files('gcontenttype.c') + unix_sources += files('gdesktopappinfo.c') + gio_unix_include_headers += files('gdesktopappinfo.h') +- launch_desktop_sources = files('gio-launch-desktop.c') +- +- if host_system == 'linux' +- launch_desktop_sources += files('../glib/gjournal-private.c') +- endif +- +- gio_launch_desktop = executable('gio-launch-desktop', launch_desktop_sources, +- include_directories : glibinc, +- install : true, +- install_dir : multiarch_libexecdir, +- install_tag : 'bin', +- c_args : gio_c_args, +- # intl.lib is not compatible with SAFESEH +- link_args : noseh_link_args) + endif + + subdir('xdgmime') +@@ -962,119 +948,6 @@ gconstructor_as_data_h = custom_target('gconstructor_as_data.h', + output : ['gconstructor_as_data.h'], + command : [python, '@INPUT0@', '@INPUT1@', 'gconstructor_code', '@OUTPUT@']) + +-# Several installed executables +-gio_tool_sources = [ +- 'gio-tool.c', +- 'gio-tool.h', +- 'gio-tool-cat.c', +- 'gio-tool-copy.c', +- 'gio-tool-info.c', +- 'gio-tool-launch.c', +- 'gio-tool-list.c', +- 'gio-tool-mime.c', +- 'gio-tool-mkdir.c', +- 'gio-tool-monitor.c', +- 'gio-tool-mount.c', +- 'gio-tool-move.c', +- 'gio-tool-open.c', +- 'gio-tool-rename.c', +- 'gio-tool-remove.c', +- 'gio-tool-save.c', +- 'gio-tool-set.c', +- 'gio-tool-trash.c', +- 'gio-tool-tree.c', +-] +- +-gio_tool = executable('gio', gio_tool_sources, +- install : true, +- install_tag : 'bin', +- c_args : gio_c_args, +- # intl.lib is not compatible with SAFESEH +- link_args : noseh_link_args, +- dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) +- +-executable('gresource', 'gresource-tool.c', +- install : true, +- install_tag : 'bin', +- # intl.lib is not compatible with SAFESEH +- link_args : noseh_link_args, +- dependencies : [libelf, libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) +- +-gio_querymodules = executable('gio-querymodules', 'gio-querymodules.c', 'giomodule-priv.c', +- install : true, +- install_dir : multiarch_bindir, +- install_tag : 'bin', +- c_args : gio_c_args, +- # intl.lib is not compatible with SAFESEH +- link_args : noseh_link_args, +- dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) +- +-glib_compile_schemas = executable('glib-compile-schemas', +- ['glib-compile-schemas.c'], +- install : true, +- install_dir : multiarch_bindir, +- install_tag : 'bin', +- # intl.lib is not compatible with SAFESEH +- link_args : noseh_link_args, +- dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep, gvdb_dep]) +- +-glib_compile_resources = executable('glib-compile-resources', +- [gconstructor_as_data_h, 'glib-compile-resources.c'], +- install : true, +- install_tag : 'bin-devel', +- c_args : gio_c_args, +- # intl.lib is not compatible with SAFESEH +- link_args : noseh_link_args, +- dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep, gvdb_dep]) +-install_data('gresource.dtd', +- install_dir: get_option('datadir') / dtds_subdir, +- install_tag: 'devel', +-) +- +-# Cannot override those programs in cross compilation case because they are +-# native executables that cannot be run on the build machine. +-# See https://gitlab.gnome.org/GNOME/glib/issues/1859. +-if meson.can_run_host_binaries() +- meson.override_find_program('glib-compile-schemas', glib_compile_schemas) +- meson.override_find_program('glib-compile-resources', glib_compile_resources) +- meson.override_find_program('gio-querymodules', gio_querymodules) +-endif +- +-executable('gsettings', 'gsettings-tool.c', +- install : true, +- install_tag : 'bin', +- c_args : gio_c_args, +- # intl.lib is not compatible with SAFESEH +- link_args : noseh_link_args, +- dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) +-install_data('gschema.dtd', +- install_dir : get_option('datadir') / schemas_subdir, +- install_tag : 'devel', +-) +- +-install_data(['gschema.loc', 'gschema.its'], +- install_dir : get_option('datadir') / 'gettext' / 'its', +- install_tag : 'devel', +-) +- +-executable('gdbus', 'gdbus-tool.c', +- install : true, +- install_tag : 'bin', +- c_args : gio_c_args, +- # intl.lib is not compatible with SAFESEH +- link_args : noseh_link_args, +- dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) +- +-if host_system != 'windows' and not glib_have_cocoa +- executable('gapplication', 'gapplication-tool.c', +- install : true, +- install_tag : 'bin', +- c_args : gio_c_args, +- # intl.lib is not compatible with SAFESEH +- link_args : noseh_link_args, +- dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) +-endif +- + if enable_systemtap + gio_stp = configure_file(input : 'gio.stp.in', + output : '@0@.stp'.format(libgio.full_path().split('/').get(-1)), +@@ -1084,16 +957,6 @@ if enable_systemtap + ) + endif + +-if multiarch_bindir != get_option('bindir') +- foreach exe : ['gio-querymodules', 'glib-compile-schemas'] +- install_symlink( +- exe, +- install_dir : get_option('bindir'), +- pointing_to : get_option('prefix') / multiarch_bindir / exe, +- ) +- endforeach +-endif +- + if build_tests + subdir('tests') + endif +diff --git a/glib/meson.build b/glib/meson.build +index d2efebadce8..f4944d5f343 100644 +--- a/glib/meson.build ++++ b/glib/meson.build +@@ -487,7 +487,7 @@ if host_system == 'windows' + include_directories : configinc, + dependencies : [libglib_dep]) + endif +-else ++elif host_system != 'emscripten' + gtester = executable('gtester', 'gtester.c', + install : true, + install_tag : 'bin-devel', +diff --git a/gobject/meson.build b/gobject/meson.build +index 2129aaf8a66..0cf39253dc3 100644 +--- a/gobject/meson.build ++++ b/gobject/meson.build +@@ -170,11 +170,6 @@ libgobject_dep = declare_dependency(link_with : libgobject, + ) + meson.override_dependency('gobject-2.0', libgobject_dep) + +-gobject_query = executable('gobject-query', 'gobject-query.c', +- install : true, +- install_tag : 'bin-devel', +- dependencies : [libglib_dep, libgobject_dep]) +- + install_data('gobject_gdb.py', + install_dir : glib_pkgdatadir / 'gdb', + install_tag : 'devel', +diff --git a/meson.build b/meson.build +index 7534542091a..a38fb12514e 100644 +--- a/meson.build ++++ b/meson.build +@@ -2571,9 +2571,6 @@ subdir('gobject') + subdir('gthread') + subdir('gmodule') + subdir('gio') +-subdir('girepository') +-subdir('fuzzing') +-subdir('tests') + + # xgettext is optional (on Windows for instance) + if find_program('xgettext', required : get_option('nls')).found() + +From 8b6b4992c8c1f8216ae3ebcc1c5c16901827c33d Mon Sep 17 00:00:00 2001 +From: Kleis Auke Wolthuizen +Date: Wed, 13 Jul 2022 09:44:36 +0200 +Subject: [PATCH 02/10] Remove GRegex pre-emptively + +Unused by libvips or any of the libraries it relies on. + +Upstream-Status: Inappropriate [disable feature] +Upstream may still depend on GRegex. +--- + gio/gsettingsschema.c | 57 +--------------------------------------- + glib/glib-autocleanups.h | 2 -- + glib/glib.h | 1 - + glib/meson.build | 11 +------- + gobject/gboxed.c | 3 --- + gobject/glib-types.h | 9 ------- + meson.build | 40 ---------------------------- + 7 files changed, 2 insertions(+), 121 deletions(-) + +diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c +index b1918657da6..7b9328d4843 100644 +--- a/gio/gsettingsschema.c ++++ b/gio/gsettingsschema.c +@@ -548,62 +548,7 @@ start_element (GMarkupParseContext *context, + static gchar * + normalise_whitespace (const gchar *orig) + { +- /* We normalise by the same rules as in intltool: +- * +- * sub cleanup { +- * s/^\s+//; +- * s/\s+$//; +- * s/\s+/ /g; +- * return $_; +- * } +- * +- * $message = join "\n\n", map &cleanup, split/\n\s*\n+/, $message; +- * +- * Where \s is an ascii space character. +- * +- * We aim for ease of implementation over efficiency -- this code is +- * not run in normal applications. +- */ +- static GRegex *cleanup[3]; +- static GRegex *splitter; +- gchar **lines; +- gchar *result; +- gint i; +- +- if (g_once_init_enter_pointer (&splitter)) +- { +- GRegex *s; +- +- cleanup[0] = g_regex_new ("^\\s+", G_REGEX_DEFAULT, +- G_REGEX_MATCH_DEFAULT, NULL); +- cleanup[1] = g_regex_new ("\\s+$", G_REGEX_DEFAULT, +- G_REGEX_MATCH_DEFAULT, NULL); +- cleanup[2] = g_regex_new ("\\s+", G_REGEX_DEFAULT, +- G_REGEX_MATCH_DEFAULT, NULL); +- s = g_regex_new ("\\n\\s*\\n+", G_REGEX_DEFAULT, +- G_REGEX_MATCH_DEFAULT, NULL); +- +- g_once_init_leave_pointer (&splitter, s); +- } +- +- lines = g_regex_split (splitter, orig, 0); +- for (i = 0; lines[i]; i++) +- { +- gchar *a, *b, *c; +- +- a = g_regex_replace_literal (cleanup[0], lines[i], -1, 0, "", 0, 0); +- b = g_regex_replace_literal (cleanup[1], a, -1, 0, "", 0, 0); +- c = g_regex_replace_literal (cleanup[2], b, -1, 0, " ", 0, 0); +- g_free (lines[i]); +- g_free (a); +- g_free (b); +- lines[i] = c; +- } +- +- result = g_strjoinv ("\n\n", lines); +- g_strfreev (lines); +- +- return result; ++ return orig; + } + + static void +diff --git a/glib/glib-autocleanups.h b/glib/glib-autocleanups.h +index 68be87c84a3..24e74472883 100644 +--- a/glib/glib-autocleanups.h ++++ b/glib/glib-autocleanups.h +@@ -75,8 +75,6 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GPatternSpec, g_pattern_spec_free) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GQueue, g_queue_free) + G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GQueue, g_queue_clear) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRand, g_rand_free) +-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRegex, g_regex_unref) +-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMatchInfo, g_match_info_unref) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GScanner, g_scanner_destroy) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSequence, g_sequence_free) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSList, g_slist_free) +diff --git a/glib/glib.h b/glib/glib.h +index 40e501997aa..d107dabc6f8 100644 +--- a/glib/glib.h ++++ b/glib/glib.h +@@ -75,7 +75,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/glib/meson.build b/glib/meson.build +index f4944d5f343..86e801a8346 100644 +--- a/glib/meson.build ++++ b/glib/meson.build +@@ -220,7 +220,6 @@ glib_sub_headers = files( + 'grcbox.h', + 'grefcount.h', + 'grefstring.h', +- 'gregex.h', + 'gscanner.h', + 'gsequence.h', + 'gshell.h', +@@ -314,7 +313,6 @@ glib_sources += files( + 'grcbox.c', + 'grefcount.c', + 'grefstring.c', +- 'gregex.c', + 'gscanner.c', + 'gsequence.c', + 'gshell.c', +@@ -400,13 +398,7 @@ else + glib_dtrace_hdr = [] + endif + +-pcre2_static_args = [] +- +-if use_pcre2_static_flag +- pcre2_static_args = ['-DPCRE2_STATIC'] +-endif +- +-glib_c_args = ['-DG_LOG_DOMAIN="GLib"'] + glib_c_args_internal + pcre2_static_args ++glib_c_args = ['-DG_LOG_DOMAIN="GLib"'] + glib_c_args_internal + libglib = library('glib-2.0', + glib_dtrace_obj, glib_dtrace_hdr, + sources : [glib_deprecated_sources, glib_sources], +@@ -425,7 +417,6 @@ libglib = library('glib-2.0', + libm, + librt, + libsysprof_capture_dep, +- pcre2, + platform_deps, + thread_dep, + ], +diff --git a/gobject/gboxed.c b/gobject/gboxed.c +index 04cededa0bd..63a4f2f8116 100644 +--- a/gobject/gboxed.c ++++ b/gobject/gboxed.c +@@ -121,9 +121,6 @@ G_DEFINE_BOXED_TYPE (GByteArray, g_byte_array, g_byte_array_ref, g_byte_array_un + G_DEFINE_BOXED_TYPE (GBytes, g_bytes, g_bytes_ref, g_bytes_unref) + G_DEFINE_BOXED_TYPE (GTree, g_tree, g_tree_ref, g_tree_unref) + +-G_DEFINE_BOXED_TYPE (GRegex, g_regex, g_regex_ref, g_regex_unref) +-G_DEFINE_BOXED_TYPE (GMatchInfo, g_match_info, g_match_info_ref, g_match_info_unref) +- + #define g_variant_type_get_type g_variant_type_get_gtype + G_DEFINE_BOXED_TYPE (GVariantType, g_variant_type, g_variant_type_copy, g_variant_type_free) + #undef g_variant_type_get_type +diff --git a/gobject/glib-types.h b/gobject/glib-types.h +index e31baf144b5..239f7ba7000 100644 +--- a/gobject/glib-types.h ++++ b/gobject/glib-types.h +@@ -88,15 +88,6 @@ typedef gsize GType; + */ + #define G_TYPE_HASH_TABLE (g_hash_table_get_type ()) + +-/** +- * G_TYPE_REGEX: +- * +- * The #GType for a boxed type holding a #GRegex reference. +- * +- * Since: 2.14 +- */ +-#define G_TYPE_REGEX (g_regex_get_type ()) +- + /** + * G_TYPE_MATCH_INFO: + * +diff --git a/meson.build b/meson.build +index a38fb12514e..50f40a5f2a4 100644 +--- a/meson.build ++++ b/meson.build +@@ -2170,46 +2170,6 @@ else + libiconv = dependency('iconv') + endif + +-pcre2_req = '>=10.32' +- +-# Pick up pcre from the system, or if "--force-fallback-for libpcre2-8" was specified +-pcre2 = dependency('libpcre2-8', version: pcre2_req, required: false, default_options: ['default_library=static']) +-if not pcre2.found() +- if cc.get_id() == 'msvc' or cc.get_id() == 'clang-cl' +- # MSVC: Search for the PCRE2 library by the configuration, which corresponds +- # to the output of CMake builds of PCRE2. Note that debugoptimized +- # is really a Release build with .PDB files. +- if vs_crt == 'debug' +- pcre2 = cc.find_library('pcre2d-8', required : false) +- else +- pcre2 = cc.find_library('pcre2-8', required : false) +- endif +- endif +-endif +- +-# Try again with the fallback +-if not pcre2.found() +- pcre2 = dependency('libpcre2-8', version: pcre2_req, allow_fallback: true, default_options: ['default_library=static']) +- assert(pcre2.type_name() == 'internal') +- # static flags are automatically enabled by the subproject if it's built +- # with default_library=static +- use_pcre2_static_flag = false +-elif host_system == 'windows' and pcre2.type_name() != 'internal' +- pcre2_static = cc.links('''#define PCRE2_STATIC +- #define PCRE2_CODE_UNIT_WIDTH 8 +- #include +- int main() { +- void *p = NULL; +- pcre2_code_free(p); +- return 0; +- }''', +- dependencies: pcre2, +- name : 'Windows system PCRE2 is a static build') +- use_pcre2_static_flag = pcre2_static +-else +- use_pcre2_static_flag = false +-endif +- + # Import the gvdb sources as a subproject to avoid having the copylib in-tree + subproject('gvdb') + gvdb_dep = dependency('gvdb') + +From 87a40d9d88cf66169227c9c7f6d302c3130adac7 Mon Sep 17 00:00:00 2001 +From: Kleis Auke Wolthuizen +Date: Tue, 23 Aug 2022 10:29:57 +0200 +Subject: [PATCH 03/10] Disable NLS + +Upstream-Status: Inappropriate [disable feature] +This patch is just for our convenience. +--- + glib/gi18n-lib.h | 15 +++------------ + 1 file changed, 3 insertions(+), 12 deletions(-) + +diff --git a/glib/gi18n-lib.h b/glib/gi18n-lib.h +index fe9e79dbd96..8597f90d1de 100644 +--- a/glib/gi18n-lib.h ++++ b/glib/gi18n-lib.h +@@ -20,19 +20,10 @@ + #ifndef __G_I18N_LIB_H__ + #define __G_I18N_LIB_H__ + +-#include +- +-#include +-#include +- +-#ifndef GETTEXT_PACKAGE +-#error You must define GETTEXT_PACKAGE before including gi18n-lib.h. Did you forget to include config.h? +-#endif +- +-#define _(String) ((char *) g_dgettext (GETTEXT_PACKAGE, String)) +-#define Q_(String) g_dpgettext (GETTEXT_PACKAGE, String, 0) ++#define _(String) (String) ++#define Q_(String) (String) + #define N_(String) (String) +-#define C_(Context,String) g_dpgettext (GETTEXT_PACKAGE, Context "\004" String, strlen (Context) + 1) ++#define C_(Context,String) (String) + #define NC_(Context, String) (String) + + #endif /* __G_I18N_LIB_H__ */ + +From 07086699bbcefcf4ecd22e1453f8f2406fdec05c Mon Sep 17 00:00:00 2001 +From: Kleis Auke Wolthuizen +Date: Wed, 18 Sep 2019 15:00:00 +0200 +Subject: [PATCH 04/10] Emscripten doesn't always define + __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + +See: +https://github.com/llvm/llvm-project/commit/d227c3b68cf5c236902c9ff4fdf8b719c9a3dd26 +--- + meson.build | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/meson.build b/meson.build +index 50f40a5f2a4..c953b8e343c 100644 +--- a/meson.build ++++ b/meson.build +@@ -2021,8 +2021,8 @@ atomicdefine = ''' + # We know that we can always use real ("lock free") atomic operations with MSVC + if cc.get_id() == 'msvc' or cc.get_id() == 'clang-cl' or cc.links(atomictest, name : 'atomic ops') + have_atomic_lock_free = true +- if cc.get_id() == 'gcc' and not cc.compiles(atomicdefine, name : 'atomic ops define') +- # Old gcc release may provide ++ if (cc.get_id() == 'gcc' or host_system == 'emscripten') and not cc.compiles(atomicdefine, name : 'atomic ops define') ++ # Some old releases of GCC or Emscripten provides + # __sync_bool_compare_and_swap but doesn't define + # __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + glib_conf.set('__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4', true) + +From 3d6fcd4a4749f050704cd30cf424bfc8048a18e8 Mon Sep 17 00:00:00 2001 +From: Kleis Auke Wolthuizen +Date: Wed, 18 Sep 2019 15:20:00 +0200 +Subject: [PATCH 05/10] posix_spawn isn't usable in WASM + +--- + meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/meson.build b/meson.build +index c953b8e343c..78612d289eb 100644 +--- a/meson.build ++++ b/meson.build +@@ -828,7 +828,7 @@ if host_system != 'windows' and cc.has_function('posix_memalign', prefix: '#incl + endif + + # Check that posix_spawn() is usable; must use header +-if cc.has_function('posix_spawn', prefix : '#include ') ++if host_system != 'emscripten' and cc.has_function('posix_spawn', prefix : '#include ') + glib_conf.set('HAVE_POSIX_SPAWN', 1) + endif + + +From 9fa5a9982ec0a30fc1334c90df6494df6b2baf66 Mon Sep 17 00:00:00 2001 +From: Kleis Auke Wolthuizen +Date: Wed, 18 Sep 2019 15:40:00 +0200 +Subject: [PATCH 06/10] Network libs are not available in WASM + +--- + gio/meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/gio/meson.build b/gio/meson.build +index 30b411fad40..9cad15151a7 100644 +--- a/gio/meson.build ++++ b/gio/meson.build +@@ -39,7 +39,7 @@ endif + + network_libs = [ ] + network_args = [ ] +-if host_system != 'windows' ++if host_system not in ['windows', 'emscripten'] + # res_query() + res_query_test = '''#include + int main (int argc, char ** argv) { + +From e19a72d46646045f6cb83a70f46c9f0a4968e0de Mon Sep 17 00:00:00 2001 +From: Kleis Auke Wolthuizen +Date: Wed, 22 Apr 2020 12:11:28 +0200 +Subject: [PATCH 07/10] Ensure separate checks are also done for Emscripten + +--- + meson.build | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/meson.build b/meson.build +index 78612d289eb..aac86e3d22c 100644 +--- a/meson.build ++++ b/meson.build +@@ -542,7 +542,7 @@ foreach m : struct_members + endforeach + + # Compiler flags +-if cc.get_id() == 'gcc' or cc.get_id() == 'clang' ++if cc.get_id() == 'gcc' or cc.get_id() == 'clang' or cc.get_id() == 'emscripten' + warning_common_args = [ + '-Wduplicated-branches', + '-Wimplicit-fallthrough', +@@ -1727,10 +1727,10 @@ g_sizet_compatibility = { + 'long long': sizet_size == long_long_size, + } + +-# Do separate checks for gcc/clang (and ignore other compilers for now), since +-# we need to explicitly pass -Werror to the compilers. ++# Do separate checks for gcc/clang/emscripten (and ignore other compilers for now), ++# since we need to explicitly pass -Werror to the compilers. + # FIXME: https://github.com/mesonbuild/meson/issues/5399 +-if cc.get_id() == 'gcc' or cc.get_id() == 'clang' ++if cc.get_id() == 'gcc' or cc.get_id() == 'clang' or cc.get_id() == 'emscripten' + foreach type_name, size_compatibility : g_sizet_compatibility + g_sizet_compatibility += { type_name: size_compatibility and + cc.compiles( + +From 6a19d4c5642beaa3d72d6c5943959030d62cc801 Mon Sep 17 00:00:00 2001 +From: Kleis Auke Wolthuizen +Date: Tue, 13 Apr 2021 15:30:00 +0200 +Subject: [PATCH 08/10] Use vsnpintf/snprintf/printf from musl libc + +The C99 semantics of these functions is well supported in musl libc. + +Note: can also be set with these properties in the Meson cross file: +have_c99_vsnprintf = true +have_c99_snprintf = true +have_unix98_printf = true +--- + meson.build | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/meson.build b/meson.build +index aac86e3d22c..b184db2e485 100644 +--- a/meson.build ++++ b/meson.build +@@ -1160,9 +1160,9 @@ if host_system == 'windows' and (cc.get_id() == 'msvc' or cc.get_id() == 'clang- + glib_conf.set('HAVE_C99_SNPRINTF', false) + glib_conf.set('HAVE_C99_VSNPRINTF', false) + glib_conf.set('HAVE_UNIX98_PRINTF', false) +-elif not cc_can_run and host_system in ['ios', 'darwin'] +- # All these are true when compiling natively on macOS, so we should use good +- # defaults when building for iOS and tvOS. ++elif not cc_can_run and host_system in ['ios', 'darwin', 'emscripten'] ++ # All these are true when compiling natively on macOS, or when compiling with ++ # Emscripten (which uses musl libc internally). + glib_conf.set('HAVE_C99_SNPRINTF', true) + glib_conf.set('HAVE_C99_VSNPRINTF', true) + glib_conf.set('HAVE_UNIX98_PRINTF', true) + +From b8d81ef4ee1b1050e00898a3a500e06580136cad Mon Sep 17 00:00:00 2001 +From: Kleis Auke Wolthuizen +Date: Wed, 24 Aug 2022 21:55:32 +0200 +Subject: [PATCH 09/10] Add support for WebAssembly + +- Exclude unix specific files. +- Add Wasm-specific platform definition. +- Use `.wasm` as shared module suffix. +- Disable subprocess, spawn, signal, pipe, and stdin usage. +- Implement `g_get_os_info(G_OS_INFO_KEY_NAME)`. +- Implement `g_time_zone_new_identifier(NULL)`. +- Implement `g_get_num_processors()`. +--- + gio/gappinfo.c | 4 +- + gio/gapplicationcommandline.c | 4 +- + gio/gcontenttype-wasm.c | 211 ++++++++++++++++++++++++++++++++++ + gio/gdbusprivate.c | 18 +-- + gio/gdesktopappinfo.c | 6 +- + gio/gfile.c | 2 +- + gio/giomodule.c | 6 +- + gio/gkeyfilesettingsbackend.c | 2 +- + gio/glocalfile.c | 39 +++++-- + gio/glocalfileinfo.c | 8 +- + gio/glocalfileinfo.h | 2 +- + gio/glocalfileinputstream.c | 14 ++- + gio/glocalfilemonitor.c | 4 +- + gio/glocalfileoutputstream.c | 20 ++-- + gio/glocalvfs.c | 6 +- + gio/gportalsupport.c | 14 +++ + gio/gresourcefile.c | 2 + + gio/gsocket.c | 18 +-- + gio/gsocketcontrolmessage.c | 2 +- + gio/gsocketinputstream.c | 8 +- + gio/gsocketoutputstream.c | 8 +- + gio/gsubprocess.c | 52 +++++---- + gio/gtestdbus.c | 20 +++- + gio/gthreadedresolver.c | 12 +- + gio/gunixconnection.c | 2 +- + gio/gunixfdlist.c | 4 + + gio/meson.build | 8 +- + glib/gbacktrace.c | 4 +- + glib/gmain.c | 58 +++++----- + glib/gspawn-wasm.c | 164 ++++++++++++++++++++++++++ + glib/gthread.c | 8 +- + glib/gtimezone.c | 12 +- + glib/gutils.c | 7 +- + glib/gwakeup.c | 29 +++++ + glib/meson.build | 3 +- + gobject/gsourceclosure.c | 24 ++-- + meson.build | 5 + + 37 files changed, 662 insertions(+), 148 deletions(-) + create mode 100644 gio/gcontenttype-wasm.c + create mode 100644 glib/gspawn-wasm.c + +diff --git a/gio/gappinfo.c b/gio/gappinfo.c +index 652cae6e1a9..8e7f17a97b8 100644 +--- a/gio/gappinfo.c ++++ b/gio/gappinfo.c +@@ -1020,7 +1020,7 @@ g_app_info_launch_default_for_uri (const char *uri, + g_object_unref (app_info); + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + if (!res && glib_should_use_portal ()) + { + const char *parent_window = NULL; +@@ -1072,7 +1072,7 @@ launch_default_for_uri_portal_open_uri_cb (GObject *object, + static void + launch_default_for_uri_portal_open_uri (GTask *task, GError *error) + { +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + LaunchDefaultForUriData *data = g_task_get_task_data (task); + GCancellable *cancellable = g_task_get_cancellable (task); + +diff --git a/gio/gapplicationcommandline.c b/gio/gapplicationcommandline.c +index b3a6d00b42c..ffb682d2831 100644 +--- a/gio/gapplicationcommandline.c ++++ b/gio/gapplicationcommandline.c +@@ -295,7 +295,9 @@ g_application_command_line_real_printerr_literal (GApplicationCommandLine *cmdli + static GInputStream * + g_application_command_line_real_get_stdin (GApplicationCommandLine *cmdline) + { +-#ifdef G_OS_UNIX ++#ifdef G_PLATFORM_WASM ++ return NULL; ++#elif defined(G_OS_UNIX) + return g_unix_input_stream_new (0, FALSE); + #else + return g_win32_input_stream_new (GetStdHandle (STD_INPUT_HANDLE), FALSE); +diff --git a/gio/gcontenttype-wasm.c b/gio/gcontenttype-wasm.c +new file mode 100644 +index 00000000000..082888cde22 +--- /dev/null ++++ b/gio/gcontenttype-wasm.c +@@ -0,0 +1,211 @@ ++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ ++ ++/* GIO - GLib Input, Output and Streaming Library ++ * ++ * Copyright (C) 2023 Kleis Auke Wolthuizen ++ * ++ * SPDX-License-Identifier: LGPL-2.1-or-later ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General ++ * Public License along with this library; if not, see . ++ */ ++ ++#include "config.h" ++#include ++#include "gcontenttype.h" ++#include "glibintl.h" ++ ++/*< private >*/ ++void ++g_content_type_set_mime_dirs (const gchar * const *dirs) ++{ ++ /* noop on WebAssembly */ ++} ++ ++/*< private >*/ ++const gchar * const * ++g_content_type_get_mime_dirs (void) ++{ ++ const gchar * const *mime_dirs = { NULL }; ++ return mime_dirs; ++} ++ ++gboolean ++g_content_type_equals (const gchar *type1, ++ const gchar *type2) ++{ ++ g_return_val_if_fail (type1 != NULL, FALSE); ++ g_return_val_if_fail (type2 != NULL, FALSE); ++ ++ if (g_ascii_strcasecmp (type1, type2) == 0) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++gboolean ++g_content_type_is_a (const gchar *type, ++ const gchar *supertype) ++{ ++ g_return_val_if_fail (type != NULL, FALSE); ++ g_return_val_if_fail (supertype != NULL, FALSE); ++ ++ if (g_content_type_equals (type, supertype)) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++gboolean ++g_content_type_is_mime_type (const gchar *type, ++ const gchar *mime_type) ++{ ++ gchar *content_type; ++ gboolean ret; ++ ++ g_return_val_if_fail (type != NULL, FALSE); ++ g_return_val_if_fail (mime_type != NULL, FALSE); ++ ++ content_type = g_content_type_from_mime_type (mime_type); ++ ret = g_content_type_is_a (type, content_type); ++ g_free (content_type); ++ ++ return ret; ++} ++ ++gboolean ++g_content_type_is_unknown (const gchar *type) ++{ ++ g_return_val_if_fail (type != NULL, FALSE); ++ ++ return strcmp ("*", type) == 0; ++} ++ ++gchar * ++g_content_type_get_description (const gchar *type) ++{ ++ return g_strdup (_("Unknown type")); ++} ++ ++gchar * ++g_content_type_get_mime_type (const gchar *type) ++{ ++ return g_strdup ("application/octet-stream"); ++} ++ ++GIcon * ++g_content_type_get_icon (const gchar *type) ++{ ++ return NULL; ++} ++ ++GIcon * ++g_content_type_get_symbolic_icon (const gchar *type) ++{ ++ return NULL; ++} ++ ++gchar * ++g_content_type_get_generic_icon_name (const gchar *type) ++{ ++ return NULL; ++} ++ ++gboolean ++g_content_type_can_be_executable (const gchar *type) ++{ ++ g_return_val_if_fail (type != NULL, FALSE); ++ ++ return strcmp (type, ".wasm") == 0; ++} ++ ++static gboolean ++looks_like_text (const guchar *data, ++ gsize data_size) ++{ ++ gsize i; ++ guchar c; ++ for (i = 0; i < data_size; i++) ++ { ++ c = data[i]; ++ if (g_ascii_iscntrl (c) && !g_ascii_isspace (c) && c != '\b') ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++gchar * ++g_content_type_from_mime_type (const gchar *mime_type) ++{ ++ return g_strdup ("*"); ++} ++ ++gchar * ++g_content_type_guess (const gchar *filename, ++ const guchar *data, ++ gsize data_size, ++ gboolean *result_uncertain) ++{ ++ char *basename; ++ char *type; ++ char *dot; ++ size_t i; ++ ++ type = NULL; ++ ++ if (result_uncertain) ++ *result_uncertain = FALSE; ++ ++ /* our test suite and potentially other code used -1 in the past, which is ++ * not documented and not allowed; guard against that */ ++ g_return_val_if_fail (data_size != (gsize) -1, g_strdup ("*")); ++ ++ if (filename) ++ { ++ i = strlen (filename); ++ if (i > 0 && filename[i - 1] == G_DIR_SEPARATOR) ++ { ++ type = g_strdup ("inode/directory"); ++ if (result_uncertain) ++ *result_uncertain = TRUE; ++ } ++ else ++ { ++ basename = g_path_get_basename (filename); ++ dot = strrchr (basename, '.'); ++ if (dot) ++ type = g_strdup (dot); ++ g_free (basename); ++ } ++ } ++ ++ if (type) ++ return type; ++ ++ if (data && looks_like_text (data, data_size)) ++ return g_strdup (".txt"); ++ ++ return g_strdup ("*"); ++} ++ ++GList * ++g_content_types_get_registered (void) ++{ ++ return NULL; ++} ++ ++gchar ** ++g_content_type_guess_for_tree (GFile *root) ++{ ++ return NULL; ++} +diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c +index 28083e4ed77..039363b2014 100644 +--- a/gio/gdbusprivate.c ++++ b/gio/gdbusprivate.c +@@ -48,7 +48,7 @@ + #include "gsocketoutputstream.h" + #include "gtask.h" + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include "gunixfdmessage.h" + #include "gunixconnection.h" + #include "gunixcredentialsmessage.h" +@@ -600,7 +600,7 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, + if (FALSE) + { + } +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + else if (G_IS_UNIX_FD_MESSAGE (control_message)) + { + GUnixFDMessage *fd_message; +@@ -770,7 +770,7 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, + goto out; + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + if (worker->read_fd_list != NULL) + { + g_dbus_message_set_unix_fd_list (message, worker->read_fd_list); +@@ -970,7 +970,7 @@ write_message_async_cb (GObject *source_object, + * write-lock is not held on entry + * output_pending is PENDING_WRITE on entry + */ +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static gboolean + on_socket_ready (GSocket *socket, + GIOCondition condition, +@@ -992,7 +992,7 @@ static void + write_message_continue_writing (MessageToWriteData *data) + { + GOutputStream *ostream; +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + GUnixFDList *fd_list; + #endif + +@@ -1003,7 +1003,7 @@ write_message_continue_writing (MessageToWriteData *data) + * like @data is not always freed on every code path in this function. */ + + ostream = g_io_stream_get_output_stream (data->worker->stream); +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + fd_list = g_dbus_message_get_unix_fd_list (data->message); + #endif + +@@ -1013,7 +1013,7 @@ write_message_continue_writing (MessageToWriteData *data) + if (FALSE) + { + } +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + else if (G_IS_SOCKET_OUTPUT_STREAM (ostream) && data->total_written == 0) + { + GOutputVector vector; +@@ -1100,7 +1100,7 @@ write_message_continue_writing (MessageToWriteData *data) + #endif + else + { +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + if (data->total_written == 0 && fd_list != NULL) + { + /* We were trying to write byte 0 of the message, which needs +@@ -1125,7 +1125,7 @@ write_message_continue_writing (MessageToWriteData *data) + write_message_async_cb, + data); /* steal @data */ + } +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + out: + #endif + ; +diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c +index 87db7a97a1e..7d36b6a3401 100644 +--- a/gio/gdesktopappinfo.c ++++ b/gio/gdesktopappinfo.c +@@ -42,7 +42,7 @@ + + #include "gcontenttypeprivate.h" + #include "gdesktopappinfo.h" +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include "glib-unix.h" + #endif + #include "gfile.h" +@@ -58,7 +58,7 @@ + #include "glocalfilemonitor.h" + #include "gutilsprivate.h" + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include "gdocumentportal.h" + #endif + +@@ -3275,7 +3275,7 @@ g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo *info, + + g_return_val_if_fail (info != NULL, FALSE); + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + app_id = g_desktop_app_info_get_string (info, "X-Flatpak"); + if (app_id && *app_id) + { +diff --git a/gio/gfile.c b/gio/gfile.c +index d52262f13f7..9b3d24e6c53 100644 +--- a/gio/gfile.c ++++ b/gio/gfile.c +@@ -58,7 +58,7 @@ + + #include "gfile.h" + #include "glib/gstdio.h" +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include "glib-unix.h" + #endif + #include "gvfs.h" +diff --git a/gio/giomodule.c b/gio/giomodule.c +index 1e1495528bb..c080aed5bef 100644 +--- a/gio/giomodule.c ++++ b/gio/giomodule.c +@@ -1085,7 +1085,7 @@ extern GType g_memory_monitor_portal_get_type (void); + extern GType g_memory_monitor_win32_get_type (void); + extern GType g_power_profile_monitor_dbus_get_type (void); + +-#ifdef G_OS_UNIX ++#ifdef G_OS_UNIX && !defined(G_PLATFORM_WASM) + extern GType g_fdo_notification_backend_get_type (void); + extern GType g_gtk_notification_backend_get_type (void); + extern GType g_portal_notification_backend_get_type (void); +@@ -1180,7 +1180,7 @@ _g_io_modules_ensure_extension_points_registered (void) + + if (g_once_init_enter (®istered_extensions)) + { +-#if defined(G_OS_UNIX) && !defined(__APPLE__) ++#if defined(G_OS_UNIX) && !defined(__APPLE__) && !defined(G_PLATFORM_WASM) + #if !GLIB_CHECK_VERSION (3, 0, 0) + ep = g_io_extension_point_register (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME); + g_io_extension_point_set_required_type (ep, G_TYPE_DESKTOP_APP_INFO_LOOKUP); +@@ -1351,7 +1351,7 @@ _g_io_modules_ensure_loaded (void) + g_type_ensure (g_nextstep_settings_backend_get_type ()); + g_type_ensure (g_osx_app_info_get_type ()); + #endif +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + g_type_ensure (_g_unix_volume_monitor_get_type ()); + g_type_ensure (g_debug_controller_dbus_get_type ()); + g_type_ensure (g_fdo_notification_backend_get_type ()); +diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c +index a86c4d913c0..d279b84d430 100644 +--- a/gio/gkeyfilesettingsbackend.c ++++ b/gio/gkeyfilesettingsbackend.c +@@ -79,7 +79,7 @@ typedef struct + GFileMonitor *dir_monitor; + } GKeyfileSettingsBackend; + +-#ifdef G_OS_WIN32 ++#if defined(G_OS_WIN32) || defined(G_PLATFORM_WASM) + #define EXTENSION_PRIORITY 10 + #else + #define EXTENSION_PRIORITY (glib_should_use_portal () && !glib_has_dconf_access_in_sandbox () ? 110 : 10) +diff --git a/gio/glocalfile.c b/gio/glocalfile.c +index ceb888ad8db..099df4d2762 100644 +--- a/gio/glocalfile.c ++++ b/gio/glocalfile.c +@@ -27,7 +27,7 @@ + #include + #include + #include +-#if G_OS_UNIX ++#ifdef G_OS_UNIX + #include + #include + #endif +@@ -69,7 +69,7 @@ + #include + #include + #include "glibintl.h" +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include "glib-unix.h" + #include "gportalsupport.h" + #include "gtrashportal.h" +@@ -758,7 +758,7 @@ get_fs_type (long f_type) + } + #endif + +-#ifndef G_OS_WIN32 ++#if !defined(G_OS_WIN32) && !defined(G_PLATFORM_WASM) + + G_LOCK_DEFINE_STATIC(mount_info_hash); + static GHashTable *mount_info_hash = NULL; +@@ -1102,6 +1102,7 @@ g_local_file_query_filesystem_info (GFile *file, + g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, fstype); + #endif /* G_OS_WIN32 */ + ++#ifndef G_PLATFORM_WASM + if (g_file_attribute_matcher_matches (attribute_matcher, + G_FILE_ATTRIBUTE_FILESYSTEM_READONLY) || + g_file_attribute_matcher_matches (attribute_matcher, +@@ -1113,6 +1114,7 @@ g_local_file_query_filesystem_info (GFile *file, + get_mount_info (info, local->filename, attribute_matcher); + #endif /* G_OS_WIN32 */ + } ++#endif /* !G_PLATFORM_WASM */ + + g_file_attribute_matcher_unref (attribute_matcher); + +@@ -1124,6 +1126,7 @@ g_local_file_find_enclosing_mount (GFile *file, + GCancellable *cancellable, + GError **error) + { ++#ifndef G_PLATFORM_WASM + GLocalFile *local = G_LOCAL_FILE (file); + GStatBuf buf; + char *mountpoint; +@@ -1142,6 +1145,7 @@ g_local_file_find_enclosing_mount (GFile *file, + return mount; + + error: ++#endif + g_set_io_error (error, + /* Translators: This is an error message when trying to find + * the enclosing (user visible) mount of a file, but none +@@ -1525,7 +1529,7 @@ g_local_file_delete (GFile *file, + return TRUE; + } + +-#ifndef G_OS_WIN32 ++#if !defined(G_OS_WIN32) && !defined(G_PLATFORM_WASM) + + static char * + strip_trailing_slashes (const char *path) +@@ -1934,7 +1938,6 @@ _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev) + return res; + } + +-#ifndef G_OS_WIN32 + gboolean + _g_local_file_is_lost_found_dir (const char *path, dev_t path_dev) + { +@@ -1973,7 +1976,6 @@ _g_local_file_is_lost_found_dir (const char *path, dev_t path_dev) + g_free (mount_dir); + return ret; + } +-#endif + + static gboolean + g_local_file_trash (GFile *file, +@@ -2348,7 +2350,7 @@ g_local_file_trash (GFile *file, + + return TRUE; + } +-#else /* G_OS_WIN32 */ ++#elif defined(G_OS_WIN32) + gboolean + _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev) + { +@@ -2394,7 +2396,24 @@ g_local_file_trash (GFile *file, + g_free (wfilename); + return success; + } +-#endif /* G_OS_WIN32 */ ++#else /* G_PLATFORM_WASM */ ++gboolean ++_g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev) ++{ ++ return FALSE; ++} ++ ++static gboolean ++g_local_file_trash (GFile *file, ++ GCancellable *cancellable, ++ GError **error) ++{ ++ g_set_io_error (error, ++ _("g_local_file_trash is no-op on WebAssembly"), ++ file, ENOTSUP); ++ return FALSE; ++} ++#endif /* G_PLATFORM_WASM */ + + static gboolean + g_local_file_make_directory (GFile *file, +@@ -2598,7 +2617,7 @@ g_local_file_move (GFile *source, + return TRUE; + } + +-#ifdef G_OS_WIN32 ++#if defined(G_OS_WIN32) || defined(G_PLATFORM_WASM) + + gboolean + g_local_file_is_nfs_home (const gchar *filename) +@@ -2662,7 +2681,7 @@ g_local_file_is_nfs_home (const gchar *filename) + + return FALSE; + } +-#endif /* !G_OS_WIN32 */ ++#endif /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + + static GFileMonitor* + g_local_file_monitor_dir (GFile *file, +diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c +index 2df7c91e522..7aa6418fef1 100644 +--- a/gio/glocalfileinfo.c ++++ b/gio/glocalfileinfo.c +@@ -62,8 +62,10 @@ + + #ifdef G_OS_UNIX + #include ++#ifndef G_PLATFORM_WASM + #include "glib-unix.h" +-#endif ++#endif /* !G_PLATFORM_WASM */ ++#endif /* G_OS_UNIX */ + + #include "glib-private.h" + +@@ -1342,7 +1344,7 @@ get_content_type (const char *basename, + + content_type = g_content_type_guess (basename, NULL, 0, &result_uncertain); + +-#if !defined(G_OS_WIN32) && !defined(__APPLE__) ++#if !defined(G_OS_WIN32) && !defined(__APPLE__) && !defined(G_PLATFORM_WASM) + if (!fast && result_uncertain && path != NULL) + { + /* Sniff the first 16KiB of the file (sometimes less, if xdgmime +@@ -2000,6 +2002,7 @@ _g_local_file_info_get (const char *basename, + if (stat_ok) + set_info_from_stat (info, &statbuf, attribute_matcher); + ++#ifndef G_PLATFORM_WASM + #ifndef G_OS_WIN32 + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_IS_HIDDEN)) +@@ -2035,6 +2038,7 @@ _g_local_file_info_get (const char *basename, + + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_IS_BACKUP, FALSE); + #endif ++#endif /* !G_PLATFORM_WASM */ + + symlink_target = NULL; + if (is_symlink) +diff --git a/gio/glocalfileinfo.h b/gio/glocalfileinfo.h +index b098b1980bf..e250119d024 100644 +--- a/gio/glocalfileinfo.h ++++ b/gio/glocalfileinfo.h +@@ -348,7 +348,7 @@ inline static guint32 _g_stat_mtim_nsec (const GLocalFileStat *buf) { return 0 + + gboolean _g_local_file_has_trash_dir (const char *dirname, + dev_t dir_dev); +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + gboolean _g_local_file_is_lost_found_dir (const char *path, + dev_t path_dev); + #endif +diff --git a/gio/glocalfileinputstream.c b/gio/glocalfileinputstream.c +index 933f317147e..33e848f8782 100644 +--- a/gio/glocalfileinputstream.c ++++ b/gio/glocalfileinputstream.c +@@ -37,9 +37,11 @@ + + #ifdef G_OS_UNIX + #include ++#ifndef G_PLATFORM_WASM + #include "glib-unix.h" + #include "gfiledescriptorbased.h" +-#endif ++#endif /* !G_PLATFORM_WASM */ ++#endif /* G_OS_UNIX */ + + #ifdef G_OS_WIN32 + #include +@@ -50,12 +52,12 @@ struct _GLocalFileInputStreamPrivate { + guint do_close : 1; + }; + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); + #endif + + #define g_local_file_input_stream_get_type _g_local_file_input_stream_get_type +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + G_DEFINE_TYPE_WITH_CODE (GLocalFileInputStream, g_local_file_input_stream, G_TYPE_FILE_INPUT_STREAM, + G_ADD_PRIVATE (GLocalFileInputStream) + G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED, +@@ -84,7 +86,7 @@ static GFileInfo *g_local_file_input_stream_query_info (GFileInputStream *strea + const char *attributes, + GCancellable *cancellable, + GError **error); +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static int g_local_file_input_stream_get_fd (GFileDescriptorBased *stream); + #endif + +@@ -109,7 +111,7 @@ g_local_file_input_stream_class_init (GLocalFileInputStreamClass *klass) + file_stream_class->query_info = g_local_file_input_stream_query_info; + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void + g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) + { +@@ -297,7 +299,7 @@ g_local_file_input_stream_query_info (GFileInputStream *stream, + error); + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static int + g_local_file_input_stream_get_fd (GFileDescriptorBased *fd_based) + { +diff --git a/gio/glocalfilemonitor.c b/gio/glocalfilemonitor.c +index 8de40793945..acf3e0291a4 100644 +--- a/gio/glocalfilemonitor.c ++++ b/gio/glocalfilemonitor.c +@@ -742,7 +742,7 @@ g_local_file_monitor_set_property (GObject *object, guint prop_id, + g_object_notify (object, "rate-limit"); + } + +-#ifndef G_OS_WIN32 ++#if !defined(G_OS_WIN32) && !defined(G_PLATFORM_WASM) + static void + g_local_file_monitor_mounts_changed (GUnixMountMonitor *mount_monitor, + gpointer user_data) +@@ -792,7 +792,7 @@ g_local_file_monitor_start (GLocalFileMonitor *local_monitor, + + if (is_directory && !class->mount_notify && (flags & G_FILE_MONITOR_WATCH_MOUNTS)) + { +-#ifdef G_OS_WIN32 ++#if defined(G_OS_WIN32) || defined(G_PLATFORM_WASM) + /*claim everything was mounted */ + local_monitor->was_mounted = TRUE; + #else +diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c +index 6875811d0d7..efe2e2c612d 100644 +--- a/gio/glocalfileoutputstream.c ++++ b/gio/glocalfileoutputstream.c +@@ -44,9 +44,11 @@ + + #ifdef G_OS_UNIX + #include ++#ifndef G_PLATFORM_WASM + #include "gfiledescriptorbased.h" + #include +-#endif ++#endif /* !G_PLATFORM_WASM */ ++#endif /* G_OS_UNIX */ + + #include "glib-private.h" + #include "gioprivate.h" +@@ -81,12 +83,12 @@ struct _GLocalFileOutputStreamPrivate { + int fd; + }; + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); + #endif + + #define g_local_file_output_stream_get_type _g_local_file_output_stream_get_type +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + G_DEFINE_TYPE_WITH_CODE (GLocalFileOutputStream, g_local_file_output_stream, G_TYPE_FILE_OUTPUT_STREAM, + G_ADD_PRIVATE (GLocalFileOutputStream) + G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED, +@@ -108,7 +110,7 @@ static gssize g_local_file_output_stream_write (GOutputStream *s + gsize count, + GCancellable *cancellable, + GError **error); +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static gboolean g_local_file_output_stream_writev (GOutputStream *stream, + const GOutputVector *vectors, + gsize n_vectors, +@@ -136,7 +138,7 @@ static gboolean g_local_file_output_stream_truncate (GFileOutputStream *s + goffset size, + GCancellable *cancellable, + GError **error); +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static int g_local_file_output_stream_get_fd (GFileDescriptorBased *stream); + #endif + +@@ -165,7 +167,7 @@ g_local_file_output_stream_class_init (GLocalFileOutputStreamClass *klass) + gobject_class->finalize = g_local_file_output_stream_finalize; + + stream_class->write_fn = g_local_file_output_stream_write; +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + stream_class->writev_fn = g_local_file_output_stream_writev; + #endif + stream_class->close_fn = g_local_file_output_stream_close; +@@ -178,7 +180,7 @@ g_local_file_output_stream_class_init (GLocalFileOutputStreamClass *klass) + file_stream_class->truncate_fn = g_local_file_output_stream_truncate; + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void + g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) + { +@@ -234,7 +236,7 @@ g_local_file_output_stream_write (GOutputStream *stream, + * things, that each chunk is the size of a whole page and in memory aligned + * to a page. We can't possibly guarantee that in GLib. + */ +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + /* Macro to check if struct iovec and GOutputVector have the same ABI */ + #define G_OUTPUT_VECTOR_IS_IOVEC (sizeof (struct iovec) == sizeof (GOutputVector) && \ + G_SIZEOF_MEMBER (struct iovec, iov_base) == G_SIZEOF_MEMBER (GOutputVector, buffer) && \ +@@ -1333,7 +1335,7 @@ _g_local_file_output_stream_get_fd (GLocalFileOutputStream *stream) + return stream->priv->fd; + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static int + g_local_file_output_stream_get_fd (GFileDescriptorBased *fd_based) + { +diff --git a/gio/glocalvfs.c b/gio/glocalvfs.c +index 7266ee0f833..7c330d026a3 100644 +--- a/gio/glocalvfs.c ++++ b/gio/glocalvfs.c +@@ -28,7 +28,7 @@ + #include "gvfs.h" + #include + #include +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include "glib-unix.h" + #include + #endif +@@ -134,7 +134,7 @@ g_local_vfs_parse_name (GVfs *vfs, + { + if (*parse_name == '~') + { +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + const char *user_start; + user_start = parse_name + 1; + #endif +@@ -145,7 +145,7 @@ g_local_vfs_parse_name (GVfs *vfs, + + user_end = parse_name; + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + if (user_end == user_start) + user_prefix = g_strdup (g_get_home_dir ()); + else +diff --git a/gio/gportalsupport.c b/gio/gportalsupport.c +index b002e93f697..4bfcede7bc6 100644 +--- a/gio/gportalsupport.c ++++ b/gio/gportalsupport.c +@@ -29,6 +29,7 @@ static gboolean use_portal; + static gboolean network_available; + static gboolean dconf_access; + ++#ifndef G_PLATFORM_WASM + #ifdef G_PORTAL_SUPPORT_TEST + static const char *snapctl = "snapctl"; + #else +@@ -136,21 +137,29 @@ sandbox_info_read (void) + + g_once_init_leave (&sandbox_info_is_read, 1); + } ++#endif + + gboolean + glib_should_use_portal (void) + { ++#ifdef G_PLATFORM_WASM ++ return FALSE; ++#else + sandbox_info_read (); + + if (sandbox_type == G_SANDBOX_TYPE_SNAP) + return snap_plug_is_connected ("desktop"); + + return use_portal; ++#endif + } + + gboolean + glib_network_available_in_sandbox (void) + { ++#ifdef G_PLATFORM_WASM ++ return FALSE; ++#else + sandbox_info_read (); + + if (sandbox_type == G_SANDBOX_TYPE_SNAP) +@@ -164,15 +173,20 @@ glib_network_available_in_sandbox (void) + } + + return network_available; ++#endif + } + + gboolean + glib_has_dconf_access_in_sandbox (void) + { ++#ifdef G_PLATFORM_WASM ++ return FALSE; ++#else + sandbox_info_read (); + + if (sandbox_type == G_SANDBOX_TYPE_SNAP) + return snap_plug_is_connected ("gsettings"); + + return dconf_access; ++#endif + } +diff --git a/gio/gresourcefile.c b/gio/gresourcefile.c +index 1621839cf73..6066ae2151e 100644 +--- a/gio/gresourcefile.c ++++ b/gio/gresourcefile.c +@@ -516,6 +516,7 @@ g_resource_file_query_info (GFile *file, + g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR); + g_file_info_set_size (info, size); + ++#ifndef G_PLATFORM_WASM + if ((_g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) || + ((~resource_flags & G_RESOURCE_FLAGS_COMPRESSED) && + _g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE))) && +@@ -530,6 +531,7 @@ g_resource_file_query_info (GFile *file, + g_bytes_unref (bytes); + } + else ++#endif + content_type = NULL; + + if (content_type) +diff --git a/gio/gsocket.c b/gio/gsocket.c +index c2ddadeaf00..58bbe5c77ac 100644 +--- a/gio/gsocket.c ++++ b/gio/gsocket.c +@@ -31,7 +31,7 @@ + + #include "gsocket.h" + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include "glib-unix.h" + #endif + +@@ -54,7 +54,7 @@ + # include + #endif + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include + #endif + +@@ -606,9 +606,9 @@ g_socket_details_from_fd (GSocket *socket) + static void + socket_set_nonblock (int fd) + { +-#ifndef G_OS_WIN32 ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + GError *error = NULL; +-#else ++#elif defined(G_OS_WIN32) + gulong arg; + #endif + +@@ -616,13 +616,13 @@ socket_set_nonblock (int fd) + * nonblocking automatically in certain operations. This way we make + * things work the same on all platforms. + */ +-#ifndef G_OS_WIN32 ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + if (!g_unix_set_fd_nonblocking (fd, TRUE, &error)) + { + g_warning ("Error setting socket to nonblocking mode: %s", error->message); + g_clear_error (&error); + } +-#else ++#elif defined(G_OS_WIN32) + arg = TRUE; + + if (ioctlsocket (fd, FIONBIO, &arg) == SOCKET_ERROR) +@@ -4242,7 +4242,9 @@ socket_source_dispatch (GSource *source, + events = G_IO_NVAL; + else + events = update_condition (socket_source->socket); +-#else ++#elif defined(G_PLATFORM_WASM) ++ events = G_IO_NVAL; ++#elif defined(G_OS_UNIX) + if (g_socket_is_closed (socket_source->socket)) + { + if (socket_source->fd_tag) +@@ -4380,7 +4382,7 @@ socket_source_new (GSocket *socket, + socket_source->pollfd.events = condition; + socket_source->pollfd.revents = 0; + g_source_add_poll (source, &socket_source->pollfd); +-#else ++#elif defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + socket_source->fd_tag = g_source_add_unix_fd (source, socket->priv->fd, condition); + #endif + +diff --git a/gio/gsocketcontrolmessage.c b/gio/gsocketcontrolmessage.c +index d79bd742803..1287ff902c1 100644 +--- a/gio/gsocketcontrolmessage.c ++++ b/gio/gsocketcontrolmessage.c +@@ -176,7 +176,7 @@ g_socket_control_message_deserialize (int level, + guint i; + + /* Ensure we know about the built in types */ +-#ifndef G_OS_WIN32 ++#if !defined(G_OS_WIN32) && !defined(G_PLATFORM_WASM) + g_type_ensure (G_TYPE_UNIX_CREDENTIALS_MESSAGE); + g_type_ensure (G_TYPE_UNIX_FD_MESSAGE); + #endif +diff --git a/gio/gsocketinputstream.c b/gio/gsocketinputstream.c +index 7a15f512db9..fbfbb641bb0 100644 +--- a/gio/gsocketinputstream.c ++++ b/gio/gsocketinputstream.c +@@ -42,13 +42,13 @@ struct _GSocketInputStreamPrivate + }; + + static void g_socket_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface); +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void g_socket_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); + #endif + + #define g_socket_input_stream_get_type _g_socket_input_stream_get_type + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + G_DEFINE_TYPE_WITH_CODE (GSocketInputStream, g_socket_input_stream, G_TYPE_INPUT_STREAM, + G_ADD_PRIVATE (GSocketInputStream) + G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, g_socket_input_stream_pollable_iface_init) +@@ -168,7 +168,7 @@ g_socket_input_stream_pollable_read_nonblocking (GPollableInputStream *pollable + NULL, error); + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static int + g_socket_input_stream_get_fd (GFileDescriptorBased *fd_based) + { +@@ -196,7 +196,7 @@ g_socket_input_stream_class_init (GSocketInputStreamClass *klass) + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void + g_socket_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) + { +diff --git a/gio/gsocketoutputstream.c b/gio/gsocketoutputstream.c +index a5b4c353250..36ea413c165 100644 +--- a/gio/gsocketoutputstream.c ++++ b/gio/gsocketoutputstream.c +@@ -47,13 +47,13 @@ struct _GSocketOutputStreamPrivate + }; + + static void g_socket_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface); +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void g_socket_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); + #endif + + #define g_socket_output_stream_get_type _g_socket_output_stream_get_type + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + G_DEFINE_TYPE_WITH_CODE (GSocketOutputStream, g_socket_output_stream, G_TYPE_OUTPUT_STREAM, + G_ADD_PRIVATE (GSocketOutputStream) + G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM, g_socket_output_stream_pollable_iface_init) +@@ -223,7 +223,7 @@ g_socket_output_stream_pollable_create_source (GPollableOutputStream *pollable, + return pollable_source; + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static int + g_socket_output_stream_get_fd (GFileDescriptorBased *fd_based) + { +@@ -252,7 +252,7 @@ g_socket_output_stream_class_init (GSocketOutputStreamClass *klass) + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void + g_socket_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) + { +diff --git a/gio/gsubprocess.c b/gio/gsubprocess.c +index 6af94db8042..8a6bd06b14c 100644 +--- a/gio/gsubprocess.c ++++ b/gio/gsubprocess.c +@@ -91,7 +91,7 @@ + #include "glib-private.h" + + #include +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include + #include + #include +@@ -104,6 +104,14 @@ + #include + #include "giowin32-priv.h" + #endif ++#ifdef G_PLATFORM_WASM ++#include ++#include ++#include ++#include ++#include ++#include ++#endif + + #ifndef O_BINARY + #define O_BINARY 0 +@@ -186,7 +194,9 @@ platform_input_stream_from_spawn_fd (gint fd) + if (fd < 0) + return NULL; + +-#ifdef G_OS_UNIX ++#ifdef G_PLATFORM_WASM ++ return NULL; ++#elif defined(G_OS_UNIX) + return g_unix_input_stream_new (fd, TRUE); + #else + return g_win32_input_stream_new_from_fd (fd, TRUE); +@@ -199,14 +209,16 @@ platform_output_stream_from_spawn_fd (gint fd) + if (fd < 0) + return NULL; + +-#ifdef G_OS_UNIX ++#ifdef G_PLATFORM_WASM ++ return NULL; ++#elif defined(G_OS_UNIX) + return g_unix_output_stream_new (fd, TRUE); + #else + return g_win32_output_stream_new_from_fd (fd, TRUE); + #endif + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static gint + unix_open_file (const char *filename, + gint mode, +@@ -300,7 +312,7 @@ initable_init (GInitable *initable, + gint *pipe_ptrs[3] = { NULL, NULL, NULL }; + gint pipe_fds[3] = { -1, -1, -1 }; + gint close_fds[3] = { -1, -1, -1 }; +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + gint stdin_fd = -1, stdout_fd = -1, stderr_fd = -1; + #endif + GSpawnFlags spawn_flags = 0; +@@ -323,7 +335,7 @@ initable_init (GInitable *initable, + spawn_flags |= G_SPAWN_CHILD_INHERITS_STDIN; + else if (self->flags & G_SUBPROCESS_FLAGS_STDIN_PIPE) + pipe_ptrs[0] = &pipe_fds[0]; +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + else if (self->launcher) + { + if (self->launcher->stdin_fd != -1) +@@ -342,7 +354,7 @@ initable_init (GInitable *initable, + spawn_flags |= G_SPAWN_STDOUT_TO_DEV_NULL; + else if (self->flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE) + pipe_ptrs[1] = &pipe_fds[1]; +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + else if (self->launcher) + { + if (self->launcher->stdout_fd != -1) +@@ -361,7 +373,7 @@ initable_init (GInitable *initable, + spawn_flags |= G_SPAWN_STDERR_TO_DEV_NULL; + else if (self->flags & G_SUBPROCESS_FLAGS_STDERR_PIPE) + pipe_ptrs[2] = &pipe_fds[2]; +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + else if (self->flags & G_SUBPROCESS_FLAGS_STDERR_MERGE) + /* This will work because stderr gets set up after stdout. */ + stderr_fd = 1; +@@ -397,7 +409,7 @@ initable_init (GInitable *initable, + (const gchar * const *) self->argv, + (const gchar * const *) (self->launcher ? self->launcher->envp : NULL), + spawn_flags, +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + self->launcher ? self->launcher->child_setup_func : NULL, + self->launcher ? self->launcher->child_setup_user_data : NULL, + stdin_fd, stdout_fd, stderr_fd, +@@ -441,7 +453,7 @@ initable_init (GInitable *initable, + g_source_unref (source); + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + out: + #endif + /* we don't need this past init... */ +@@ -961,7 +973,7 @@ g_subprocess_wait_check_finish (GSubprocess *subprocess, + g_spawn_check_wait_status (subprocess->status, error); + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + typedef struct + { + GSubprocess *subprocess; +@@ -1056,9 +1068,9 @@ g_subprocess_force_exit (GSubprocess *subprocess) + { + g_return_if_fail (G_IS_SUBPROCESS (subprocess)); + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + g_subprocess_dispatch_signal (subprocess, SIGKILL); +-#else ++#elif defined(G_OS_WIN32) + TerminateProcess (subprocess->pid, 1); + #endif + } +@@ -1113,7 +1125,7 @@ g_subprocess_get_successful (GSubprocess *subprocess) + g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), FALSE); + g_return_val_if_fail (subprocess->pid == 0, FALSE); + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + return WIFEXITED (subprocess->status) && WEXITSTATUS (subprocess->status) == 0; + #else + return subprocess->status == 0; +@@ -1142,7 +1154,7 @@ g_subprocess_get_if_exited (GSubprocess *subprocess) + g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), FALSE); + g_return_val_if_fail (subprocess->pid == 0, FALSE); + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + return WIFEXITED (subprocess->status); + #else + return TRUE; +@@ -1172,7 +1184,7 @@ g_subprocess_get_exit_status (GSubprocess *subprocess) + g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), 1); + g_return_val_if_fail (subprocess->pid == 0, 1); + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + g_return_val_if_fail (WIFEXITED (subprocess->status), 1); + + return WEXITSTATUS (subprocess->status); +@@ -1202,7 +1214,7 @@ g_subprocess_get_if_signaled (GSubprocess *subprocess) + g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), FALSE); + g_return_val_if_fail (subprocess->pid == 0, FALSE); + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + return WIFSIGNALED (subprocess->status); + #else + return FALSE; +@@ -1231,12 +1243,12 @@ g_subprocess_get_term_sig (GSubprocess *subprocess) + g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), 0); + g_return_val_if_fail (subprocess->pid == 0, 0); + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + g_return_val_if_fail (WIFSIGNALED (subprocess->status), 0); + + return WTERMSIG (subprocess->status); + #else +- g_critical ("g_subprocess_get_term_sig() called on Windows, where " ++ g_critical ("g_subprocess_get_term_sig() called on Windows or Wasm, where " + "g_subprocess_get_if_signaled() always returns FALSE..."); + return 0; + #endif +@@ -1451,7 +1463,7 @@ g_subprocess_communicate_internal (GSubprocess *subprocess, + { + g_assert (stdin_buf != NULL); + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + /* We're doing async writes to the pipe, and the async write mechanism assumes + * that streams polling as writable do SOME progress (possibly partial) and then + * stop, but never block. +diff --git a/gio/gtestdbus.c b/gio/gtestdbus.c +index 29727e2e132..24caf661c77 100644 +--- a/gio/gtestdbus.c ++++ b/gio/gtestdbus.c +@@ -48,7 +48,7 @@ + + #include "glibintl.h" + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include "glib-unix.h" + #include "glib-unixprivate.h" + #endif +@@ -148,7 +148,7 @@ _g_test_watcher_remove_pid (GPid pid) + will be killed anyway */ + } + +-#else ++#elif defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + + #define ADD_PID_FORMAT "add pid %d\n" + #define REMOVE_PID_FORMAT "remove pid %d\n" +@@ -327,6 +327,20 @@ _g_test_watcher_remove_pid (GPid pid) + g_free (command); + } + ++#else ++ ++static void ++_g_test_watcher_add_pid (GPid pid) ++{ ++ /* no-op */ ++} ++ ++static void ++_g_test_watcher_remove_pid (GPid pid) ++{ ++ /* no-op */ ++} ++ + #endif + + /* -------------------------------------------------------------------------- */ +@@ -597,7 +611,7 @@ static gboolean + make_pipe (gint pipe_fds[2], + GError **error) + { +-#if defined(G_OS_UNIX) ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + return g_unix_open_pipe (pipe_fds, O_CLOEXEC, error); + #elif defined(G_OS_WIN32) + if (_pipe (pipe_fds, 4096, _O_BINARY) < 0) +diff --git a/gio/gthreadedresolver.c b/gio/gthreadedresolver.c +index b8588e77e15..cef6c03e409 100644 +--- a/gio/gthreadedresolver.c ++++ b/gio/gthreadedresolver.c +@@ -1275,7 +1275,7 @@ do_lookup_records (const gchar *rrname, + { + GList *records; + +-#if defined(G_OS_UNIX) ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + gint len = 512; + gint herr; + GByteArray *answer; +@@ -1340,7 +1340,8 @@ do_lookup_records (const gchar *rrname, + + #endif /* HAVE_RES_NQUERY */ + +-#else ++ return g_steal_pointer (&records); ++#elif defined(G_OS_WIN32) + + DNS_STATUS status; + DNS_RECORDA *results = NULL; +@@ -1359,9 +1360,12 @@ do_lookup_records (const gchar *rrname, + if (results != NULL) + DnsRecordListFree (results, DnsFreeRecordList); + +-#endif +- + return g_steal_pointer (&records); ++#else ++ g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, ++ _("do_lookup_records is no-op on WebAssembly")); ++ return NULL; ++#endif + } + + static GList * +diff --git a/gio/gunixconnection.c b/gio/gunixconnection.c +index 94a92e3c454..e2c3a814585 100644 +--- a/gio/gunixconnection.c ++++ b/gio/gunixconnection.c +@@ -141,7 +141,7 @@ g_unix_connection_receive_fd (GUnixConnection *connection, + GCancellable *cancellable, + GError **error) + { +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + GSocketControlMessage **scms; + gint *fds, nfd, fd, nscm; + GUnixFDMessage *fdmsg; +diff --git a/gio/gunixfdlist.c b/gio/gunixfdlist.c +index 88a5a5f8a8b..d2c2f730862 100644 +--- a/gio/gunixfdlist.c ++++ b/gio/gunixfdlist.c +@@ -45,6 +45,10 @@ + #include "glib/glib-private.h" + #include "glib/gstdio.h" + ++#ifdef G_OS_UNIX ++#include /* dup() */ ++#endif ++ + #ifdef G_OS_WIN32 + #include + #endif +diff --git a/gio/meson.build b/gio/meson.build +index 9cad15151a7..c75847175f1 100644 +--- a/gio/meson.build ++++ b/gio/meson.build +@@ -352,7 +352,7 @@ gdbus_daemon_sources = [ + gdbus_daemon_generated, + ] + +-if host_system != 'windows' ++if host_system not in ['windows', 'emscripten'] + unix_sources = files( + 'gfiledescriptorbased.c', + 'giounix-private.c', +@@ -417,7 +417,7 @@ if host_system != 'windows' + 'gnetworkmonitornm.c', + ) + endif +-else ++elif host_system == 'windows' + win32_sources += files('gwin32appinfo.c') + contenttype_sources += files('gcontenttype-win32.c') + platform_deps += [cc.find_library('shlwapi'), +@@ -459,6 +459,8 @@ else + 'gwin32outputstream.h', + ) + install_headers(gio_win32_include_headers, subdir : 'gio-win32-2.0/gio') ++elif host_system == 'emscripten' ++ contenttype_sources += files('gcontenttype-wasm.c') + endif + + gio_base_sources = files( +@@ -899,7 +901,7 @@ if host_system == 'windows' + description : 'Windows specific headers for glib I/O library', + ) + meson.override_dependency('gio-windows-2.0', libgio_dep) +-else ++elif host_system != 'emscripten' + pkg.generate(requires : ['gobject-2.0', 'gio-2.0'], + subdirs : ['gio-unix-2.0'], + version : glib_version, +diff --git a/glib/gbacktrace.c b/glib/gbacktrace.c +index 0f81502e508..226871af4af 100644 +--- a/glib/gbacktrace.c ++++ b/glib/gbacktrace.c +@@ -260,7 +260,7 @@ g_on_error_query (const gchar *prg_name) + void + g_on_error_stack_trace (const gchar *prg_name) + { +-#if defined(G_OS_UNIX) ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + pid_t pid; + gchar buf[16]; + const gchar *args[5] = { DEBUGGER, NULL, NULL, NULL, NULL }; +@@ -302,9 +302,11 @@ g_on_error_stack_trace (const gchar *prg_name) + break; + } + #else ++#ifdef G_OS_WIN32 + if (IsDebuggerPresent ()) + G_BREAKPOINT (); + else ++#endif + g_abort (); + #endif + } +diff --git a/glib/gmain.c b/glib/gmain.c +index 6d56ab3e8df..2b9e47cb13d 100644 +--- a/glib/gmain.c ++++ b/glib/gmain.c +@@ -48,7 +48,7 @@ + #define G_MAIN_POLL_DEBUG + #endif + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include "glib-unix.h" + #include + #ifdef HAVE_EVENTFD +@@ -250,9 +250,9 @@ struct _GChildWatchSource + /* @poll is always used on Windows. + * On Unix, poll.fd will be negative if PIDFD is unavailable. */ + GPollFD poll; +-#ifndef G_OS_WIN32 ++#if !defined(G_OS_WIN32) && !defined(G_PLATFORM_WASM) + gboolean child_maybe_exited; /* (atomic) */ +-#endif /* G_OS_WIN32 */ ++#endif /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + }; + + struct _GUnixSignalWatchSource +@@ -359,11 +359,11 @@ static gboolean g_child_watch_dispatch (GSource *source, + gpointer user_data); + static void g_child_watch_finalize (GSource *source); + +-#ifndef G_OS_WIN32 ++#if !defined(G_OS_WIN32) && !defined(G_PLATFORM_WASM) + static void unref_unix_signal_handler_unlocked (int signum); + #endif + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void g_unix_signal_handler (int signum); + static gboolean g_unix_signal_watch_prepare (GSource *source, + gint *timeout); +@@ -384,7 +384,7 @@ static void block_source (GSource *source); + + static GMainContext *glib_worker_context; + +-#ifndef G_OS_WIN32 ++#if !defined(G_OS_WIN32) && !defined(G_PLATFORM_WASM) + + + /* UNIX signals work by marking one of these variables then waking the +@@ -425,7 +425,7 @@ GSourceFuncs g_unix_signal_funcs = + g_unix_signal_watch_finalize, + NULL, NULL + }; +-#endif /* !G_OS_WIN32 */ ++#endif /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + G_LOCK_DEFINE_STATIC (main_context_list); + static GSList *main_context_list = NULL; + +@@ -2595,7 +2595,7 @@ g_clear_handle_id (guint *tag_ptr, + } + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + /** + * g_source_add_unix_fd: + * @source: a #GSource +@@ -2777,7 +2777,7 @@ g_source_query_unix_fd (GSource *source, + + return poll_fd->revents; + } +-#endif /* G_OS_UNIX */ ++#endif /* G_OS_UNIX && !G_PLATFORM_WASM */ + + /** + * g_get_current_time: +@@ -5372,9 +5372,9 @@ static gboolean + g_child_watch_prepare (GSource *source, + gint *timeout) + { +-#ifdef G_OS_WIN32 ++#if defined(G_OS_WIN32) || defined(G_PLATFORM_WASM) + return FALSE; +-#else /* G_OS_WIN32 */ ++#else /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + { + GChildWatchSource *child_watch_source; + +@@ -5385,7 +5385,7 @@ g_child_watch_prepare (GSource *source, + + return g_atomic_int_get (&child_watch_source->child_maybe_exited); + } +-#endif /* G_OS_WIN32 */ ++#endif /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + } + + static gboolean +@@ -5396,9 +5396,9 @@ g_child_watch_check (GSource *source) + + child_watch_source = (GChildWatchSource *) source; + +-#ifdef G_OS_WIN32 ++#if defined(G_OS_WIN32) || defined(G_PLATFORM_WASM) + child_exited = !!(child_watch_source->poll.revents & G_IO_IN); +-#else /* G_OS_WIN32 */ ++#else /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + #ifdef HAVE_PIDFD + if (child_watch_source->poll.fd >= 0) + { +@@ -5407,7 +5407,7 @@ g_child_watch_check (GSource *source) + } + #endif /* HAVE_PIDFD */ + child_exited = g_atomic_int_get (&child_watch_source->child_maybe_exited); +-#endif /* G_OS_WIN32 */ ++#endif /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + + return child_exited; + } +@@ -5415,7 +5415,7 @@ g_child_watch_check (GSource *source) + static void + g_child_watch_finalize (GSource *source) + { +-#ifndef G_OS_WIN32 ++#if !defined(G_OS_WIN32) && !defined(G_PLATFORM_WASM) + GChildWatchSource *child_watch_source = (GChildWatchSource *) source; + + if (child_watch_source->poll.fd >= 0) +@@ -5428,10 +5428,10 @@ g_child_watch_finalize (GSource *source) + unix_child_watches = g_slist_remove (unix_child_watches, source); + unref_unix_signal_handler_unlocked (SIGCHLD); + G_UNLOCK (unix_signal_lock); +-#endif /* G_OS_WIN32 */ ++#endif /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + } + +-#ifndef G_OS_WIN32 ++#if !defined(G_OS_WIN32) && !defined(G_PLATFORM_WASM) + + static void + wake_source (GSource *source) +@@ -5761,7 +5761,9 @@ g_child_watch_dispatch (GSource *source, + else + wait_status = child_status; + } +-#else /* G_OS_WIN32 */ ++#elif defined(G_PLATFORM_WASM) /* !G_OS_WIN32 */ ++ wait_status = -1; ++#else /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + { + gboolean child_exited = FALSE; + +@@ -5845,7 +5847,7 @@ g_child_watch_dispatch (GSource *source, + } + } + } +-#endif /* G_OS_WIN32 */ ++#endif /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + + if (!callback) + { +@@ -5860,7 +5862,7 @@ g_child_watch_dispatch (GSource *source, + return FALSE; + } + +-#ifndef G_OS_WIN32 ++#if !defined(G_OS_WIN32) && !defined(G_PLATFORM_WASM) + + static void + g_unix_signal_handler (int signum) +@@ -5881,7 +5883,7 @@ g_unix_signal_handler (int signum) + errno = saved_errno; + } + +-#endif /* !G_OS_WIN32 */ ++#endif /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + + /** + * g_child_watch_source_new: +@@ -5954,12 +5956,12 @@ g_child_watch_source_new (GPid pid) + + child_watch_source->pid = pid; + +-#ifdef G_OS_WIN32 ++#if defined(G_OS_WIN32) || defined(G_PLATFORM_WASM) + child_watch_source->poll.fd = (gintptr) pid; + child_watch_source->poll.events = G_IO_IN; + + g_source_add_poll (source, &child_watch_source->poll); +-#else /* !G_OS_WIN32 */ ++#else /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + + #ifdef HAVE_PIDFD + /* Use a pidfd, if possible, to avoid having to install a global SIGCHLD +@@ -5994,7 +5996,7 @@ g_child_watch_source_new (GPid pid) + ref_unix_signal_handler_unlocked (SIGCHLD); + unix_child_watches = g_slist_prepend (unix_child_watches, child_watch_source); + G_UNLOCK (unix_signal_lock); +-#endif /* !G_OS_WIN32 */ ++#endif /* !G_OS_WIN32 && !G_PLATFORM_WASM */ + + return source; + } +@@ -6441,7 +6443,7 @@ glib_worker_main (gpointer data) + { + g_main_context_iteration (glib_worker_context, TRUE); + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + if (g_atomic_int_get (&any_unix_signal_pending)) + dispatch_unix_signals (); + #endif +@@ -6458,7 +6460,7 @@ g_get_worker_context (void) + if (g_once_init_enter (&initialised)) + { + /* mask all signals in the worker thread */ +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + sigset_t prev_mask; + sigset_t all; + +@@ -6467,7 +6469,7 @@ g_get_worker_context (void) + #endif + glib_worker_context = g_main_context_new (); + g_thread_new ("gmain", glib_worker_main, NULL); +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + pthread_sigmask (SIG_SETMASK, &prev_mask, NULL); + #endif + g_once_init_leave (&initialised, TRUE); +diff --git a/glib/gspawn-wasm.c b/glib/gspawn-wasm.c +new file mode 100644 +index 00000000000..da1da95aa66 +--- /dev/null ++++ b/glib/gspawn-wasm.c +@@ -0,0 +1,164 @@ ++/* gspawn-wasm.c - Process launching on WebAssembly, no-op implementation ++ * ++ * Copyright (C) 2022 Kleis Auke Wolthuizen ++ * ++ * SPDX-License-Identifier: LGPL-2.1-or-later ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, see . ++ */ ++ ++#include "config.h" ++ ++#include "glib.h" ++#include "glibintl.h" ++#include "gspawn.h" ++ ++G_DEFINE_QUARK (g-exec-error-quark, g_spawn_error) ++G_DEFINE_QUARK (g-spawn-exit-error-quark, g_spawn_exit_error) ++ ++gboolean ++g_spawn_async (const gchar *working_directory, ++ gchar **argv, ++ gchar **envp, ++ GSpawnFlags flags, ++ GSpawnChildSetupFunc child_setup, ++ gpointer user_data, ++ GPid *child_pid, ++ GError **error) ++{ ++ g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, ++ _("g_spawn_async is no-op on WebAssembly")); ++ return FALSE; ++} ++ ++gboolean ++g_spawn_async_with_pipes (const gchar *working_directory, ++ gchar **argv, ++ gchar **envp, ++ GSpawnFlags flags, ++ GSpawnChildSetupFunc child_setup, ++ gpointer user_data, ++ GPid *child_pid, ++ gint *standard_input, ++ gint *standard_output, ++ gint *standard_error, ++ GError **error) ++{ ++ g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, ++ _("g_spawn_async_with_pipes is no-op on WebAssembly")); ++ return FALSE; ++} ++ ++gboolean ++g_spawn_async_with_pipes_and_fds (const gchar *working_directory, ++ const gchar * const *argv, ++ const gchar * const *envp, ++ GSpawnFlags flags, ++ GSpawnChildSetupFunc child_setup, ++ gpointer user_data, ++ gint stdin_fd, ++ gint stdout_fd, ++ gint stderr_fd, ++ const gint *source_fds, ++ const gint *target_fds, ++ gsize n_fds, ++ GPid *child_pid_out, ++ gint *stdin_pipe_out, ++ gint *stdout_pipe_out, ++ gint *stderr_pipe_out, ++ GError **error) ++{ ++ g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, ++ _("g_spawn_async_with_pipes_and_fds is no-op on WebAssembly")); ++ return FALSE; ++} ++ ++gboolean ++g_spawn_async_with_fds (const gchar *working_directory, ++ gchar **argv, ++ gchar **envp, ++ GSpawnFlags flags, ++ GSpawnChildSetupFunc child_setup, ++ gpointer user_data, ++ GPid *child_pid, ++ gint stdin_fd, ++ gint stdout_fd, ++ gint stderr_fd, ++ GError **error) ++{ ++ g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, ++ _("g_spawn_async_with_fds is no-op on WebAssembly")); ++ return FALSE; ++} ++ ++gboolean ++g_spawn_sync (const gchar *working_directory, ++ gchar **argv, ++ gchar **envp, ++ GSpawnFlags flags, ++ GSpawnChildSetupFunc child_setup, ++ gpointer user_data, ++ gchar **standard_output, ++ gchar **standard_error, ++ gint *wait_status, ++ GError **error) ++{ ++ g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, ++ _("g_spawn_sync is no-op on WebAssembly")); ++ return FALSE; ++} ++ ++gboolean ++g_spawn_command_line_sync (const gchar *command_line, ++ gchar **standard_output, ++ gchar **standard_error, ++ gint *wait_status, ++ GError **error) ++{ ++ g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, ++ _("g_spawn_command_line_sync is no-op on WebAssembly")); ++ return FALSE; ++} ++ ++gboolean ++g_spawn_command_line_async (const gchar *command_line, ++ GError **error) ++{ ++ g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, ++ _("g_spawn_command_line_async is no-op on WebAssembly")); ++ return FALSE; ++} ++ ++gboolean ++g_spawn_check_wait_status (gint wait_status, ++ GError **error) ++{ ++ g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, ++ _("g_spawn_check_wait_status is no-op on WebAssembly")); ++ return FALSE; ++} ++ ++gboolean ++g_spawn_check_exit_status (gint wait_status, ++ GError **error) ++{ ++ g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, ++ _("g_spawn_check_exit_status is no-op on WebAssembly")); ++ return FALSE; ++} ++ ++void ++g_spawn_close_pid (GPid pid) ++{ ++} +diff --git a/glib/gthread.c b/glib/gthread.c +index b39acc475c1..e53611a579e 100644 +--- a/glib/gthread.c ++++ b/glib/gthread.c +@@ -60,6 +60,10 @@ + #include + #endif /* G_OS_WIN32 */ + ++#ifdef G_PLATFORM_WASM ++#include ++#endif /*G_PLATFORM_WASM*/ ++ + #include "gslice.h" + #include "gstrfuncs.h" + #include "gtestutils.h" +@@ -1064,7 +1068,9 @@ g_thread_self (void) + guint + g_get_num_processors (void) + { +-#ifdef G_OS_WIN32 ++#ifdef G_PLATFORM_WASM ++ return emscripten_num_logical_cores(); ++#elif defined(G_OS_WIN32) + unsigned int count; + SYSTEM_INFO sysinfo; + DWORD_PTR process_cpus; +diff --git a/glib/gtimezone.c b/glib/gtimezone.c +index 0c3cae3f7af..a90c8657818 100644 +--- a/glib/gtimezone.c ++++ b/glib/gtimezone.c +@@ -204,7 +204,7 @@ static GTimeZone *tz_local = NULL; + there's no point in getting carried + away. */ + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static GTimeZone *parse_footertz (const gchar *, size_t); + #endif + +@@ -504,7 +504,7 @@ zone_identifier_illumos (void) + } + #endif /* defined(__sun) && defined(__SRVR) */ + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + /* + * returns the path to the top of the Olson zoneinfo timezone hierarchy. + */ +@@ -1696,7 +1696,7 @@ rules_from_identifier (const gchar *identifier, + return create_ruleset_from_rule (rules, &tzr); + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static GTimeZone * + parse_footertz (const gchar *footer, size_t footerlen) + { +@@ -1855,7 +1855,9 @@ g_time_zone_new_identifier (const gchar *identifier) + else + { + G_LOCK (tz_default); +-#ifdef G_OS_UNIX ++#ifdef G_PLATFORM_WASM ++ resolved_identifier = g_strdup ("UTC0"); ++#elif defined (G_OS_UNIX) + resolved_identifier = zone_identifier_unix (); + #elif defined (G_OS_WIN32) + resolved_identifier = windows_default_tzname (); +@@ -1895,7 +1897,7 @@ g_time_zone_new_identifier (const gchar *identifier) + + if (tz->t_info == NULL) + { +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + GBytes *zoneinfo = zone_info_unix (identifier, resolved_identifier); + if (zoneinfo != NULL) + { +diff --git a/glib/gutils.c b/glib/gutils.c +index bb88c76b2ad..0365375ab30 100644 +--- a/glib/gutils.c ++++ b/glib/gutils.c +@@ -1522,7 +1522,7 @@ get_windows_version (gboolean with_windows) + } + #endif + +-#if defined (G_OS_UNIX) && !defined (__APPLE__) ++#if defined (G_OS_UNIX) && !defined (__APPLE__) && !defined (G_PLATFORM_WASM) + static gchar * + get_os_info_from_os_release (const gchar *key_name, + const gchar *buffer) +@@ -1679,6 +1679,11 @@ g_get_os_info (const gchar *key_name) + return g_strdup ("macOS"); + else + return NULL; ++#elif defined (G_PLATFORM_WASM) ++ if (g_strcmp0 (key_name, G_OS_INFO_KEY_NAME) == 0) ++ return g_strdup ("wasm"); ++ else ++ return NULL; + #elif defined (G_OS_UNIX) + const gchar * const os_release_files[] = { "/etc/os-release", "/usr/lib/os-release" }; + gsize i; +diff --git a/glib/gwakeup.c b/glib/gwakeup.c +index 82080421621..1f6140e00ef 100644 +--- a/glib/gwakeup.c ++++ b/glib/gwakeup.c +@@ -110,16 +110,24 @@ g_wakeup_free (GWakeup *wakeup) + + #else + ++#ifdef G_PLATFORM_WASM ++#ifdef GLIB_COMPILATION ++#include "gmessages.h" ++#endif ++#else /* !G_PLATFORM_WASM */ + #include "glib-unix.h" + #include + + #if defined (HAVE_EVENTFD) + #include + #endif ++#endif /*G_PLATFORM_WASM*/ + + struct _GWakeup + { ++#ifndef G_PLATFORM_WASM + gint fds[2]; ++#endif + }; + + /*< private > +@@ -136,6 +144,10 @@ struct _GWakeup + GWakeup * + g_wakeup_new (void) + { ++#ifdef G_PLATFORM_WASM ++ g_error ("g_wakeup_new is no-op on WebAssembly"); ++ return NULL; ++#else + GError *error = NULL; + GWakeup *wakeup; + +@@ -166,6 +178,7 @@ g_wakeup_new (void) + g_error ("Set pipes non-blocking for GWakeup: %s", error->message); + + return wakeup; ++#endif + } + + /*< private > +@@ -184,8 +197,12 @@ void + g_wakeup_get_pollfd (GWakeup *wakeup, + GPollFD *poll_fd) + { ++#ifdef G_PLATFORM_WASM ++ g_error ("g_wakeup_get_pollfd is no-op on WebAssembly"); ++#else + poll_fd->fd = wakeup->fds[0]; + poll_fd->events = G_IO_IN; ++#endif + } + + /*< private > +@@ -205,6 +222,9 @@ g_wakeup_get_pollfd (GWakeup *wakeup, + void + g_wakeup_acknowledge (GWakeup *wakeup) + { ++#ifdef G_PLATFORM_WASM ++ g_error ("g_wakeup_acknowledge is no-op on WebAssembly"); ++#else + int res; + + if (wakeup->fds[1] == -1) +@@ -225,6 +245,7 @@ g_wakeup_acknowledge (GWakeup *wakeup) + res = read (wakeup->fds[0], &value, sizeof (value)); + while (res == sizeof (value) || G_UNLIKELY (res == -1 && errno == EINTR)); + } ++#endif + } + + /*< private > +@@ -244,6 +265,9 @@ g_wakeup_acknowledge (GWakeup *wakeup) + void + g_wakeup_signal (GWakeup *wakeup) + { ++#ifdef G_PLATFORM_WASM ++ g_error ("g_wakeup_signal is no-op on WebAssembly"); ++#else + int res; + + if (wakeup->fds[1] == -1) +@@ -266,6 +290,7 @@ g_wakeup_signal (GWakeup *wakeup) + res = write (wakeup->fds[1], &one, sizeof one); + while (G_UNLIKELY (res == -1 && errno == EINTR)); + } ++#endif + } + + /*< private > +@@ -280,12 +305,16 @@ g_wakeup_signal (GWakeup *wakeup) + void + g_wakeup_free (GWakeup *wakeup) + { ++#ifdef G_PLATFORM_WASM ++ g_error ("g_wakeup_free is no-op on WebAssembly"); ++#else + close (wakeup->fds[0]); + + if (wakeup->fds[1] != -1) + close (wakeup->fds[1]); + + g_slice_free (GWakeup, wakeup); ++#endif + } + + #endif /* !_WIN32 */ +diff --git a/glib/meson.build b/glib/meson.build +index 86e801a8346..5c63a4d9a29 100644 +--- a/glib/meson.build ++++ b/glib/meson.build +@@ -368,9 +368,10 @@ if host_system == 'windows' + if cc.get_id() == 'msvc' or cc.get_id() == 'clang-cl' + glib_sources += files('dirent/wdirent.c') + endif ++elif host_system == 'emscripten' ++ glib_sources += files('gspawn-wasm.c') + else + glib_sources += files('glib-unix.c', 'gspawn.c', 'giounix.c') +- platform_deps = [] + endif + + if host_system == 'linux' +diff --git a/gobject/gsourceclosure.c b/gobject/gsourceclosure.c +index 3ca5e45f9a3..84117485c06 100644 +--- a/gobject/gsourceclosure.c ++++ b/gobject/gsourceclosure.c +@@ -25,7 +25,7 @@ + #include "gmarshal.h" + #include "gvalue.h" + #include "gvaluetypes.h" +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + #include "glib-unix.h" + #endif + +@@ -119,7 +119,7 @@ g_child_watch_closure_callback (GPid pid, + + g_value_init (&result_value, G_TYPE_BOOLEAN); + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + g_value_init (¶ms[0], G_TYPE_ULONG); + g_value_set_ulong (¶ms[0], pid); + #endif +@@ -141,7 +141,7 @@ g_child_watch_closure_callback (GPid pid, + return result; + } + +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static gboolean + g_unix_fd_source_closure_callback (int fd, + GIOCondition condition, +@@ -199,16 +199,18 @@ closure_callback_get (gpointer cb_data, + + if (!closure_callback) + { +- if (source->source_funcs == &g_io_watch_funcs) +- closure_callback = (GSourceFunc)io_watch_closure_callback; +- else if (source->source_funcs == &g_child_watch_funcs) ++ if (source->source_funcs == &g_child_watch_funcs) + closure_callback = (GSourceFunc)g_child_watch_closure_callback; +-#ifdef G_OS_UNIX ++#ifndef G_PLATFORM_WASM ++ else if (source->source_funcs == &g_io_watch_funcs) ++ closure_callback = (GSourceFunc)io_watch_closure_callback; ++#endif ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + else if (source->source_funcs == &g_unix_fd_source_funcs) + closure_callback = (GSourceFunc)g_unix_fd_source_closure_callback; + #endif + else if (source->source_funcs == &g_timeout_funcs || +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + source->source_funcs == &g_unix_signal_funcs || + #endif + source->source_funcs == &g_idle_funcs) +@@ -251,12 +253,14 @@ g_source_set_closure (GSource *source, + g_return_if_fail (closure != NULL); + + if (!source->source_funcs->closure_callback && +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + source->source_funcs != &g_unix_fd_source_funcs && + source->source_funcs != &g_unix_signal_funcs && + #endif + source->source_funcs != &g_child_watch_funcs && ++#ifndef G_PLATFORM_WASM + source->source_funcs != &g_io_watch_funcs && ++#endif + source->source_funcs != &g_timeout_funcs && + source->source_funcs != &g_idle_funcs) + { +@@ -276,7 +280,7 @@ g_source_set_closure (GSource *source, + if (marshal) + g_closure_set_marshal (closure, marshal); + else if (source->source_funcs == &g_idle_funcs || +-#ifdef G_OS_UNIX ++#if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + source->source_funcs == &g_unix_signal_funcs || + #endif + source->source_funcs == &g_timeout_funcs) +diff --git a/meson.build b/meson.build +index b184db2e485..5b42281ecfc 100644 +--- a/meson.build ++++ b/meson.build +@@ -333,6 +333,9 @@ if host_system == 'windows' + elif host_system == 'cygwin' + glib_os = '''#define G_OS_UNIX + #define G_WITH_CYGWIN''' ++elif host_system == 'emscripten' ++ glib_os = '''#define G_OS_UNIX ++#define G_PLATFORM_WASM''' + else + glib_os = '#define G_OS_UNIX' + endif +@@ -1815,6 +1818,8 @@ glibconfig_conf.set('gssizebits', ssizet_size * 8) + # XXX: https://gitlab.gnome.org/GNOME/glib/issues/1413 + if host_system == 'windows' + g_module_suffix = 'dll' ++elif host_system == 'emscripten' ++ g_module_suffix = 'wasm' + else + g_module_suffix = 'so' + endif + +From f4e716a0fbd817dd94c8d349e30eb4dd812ce37e Mon Sep 17 00:00:00 2001 +From: Kleis Auke Wolthuizen +Date: Fri, 20 Sep 2019 16:05:00 +0200 +Subject: [PATCH 10/10] Fix function pointer cast issues + +It is undefined behavior in C and C++ to cast a function pointer +to another type and call it that way. This does work in most native +platforms, however, despite it being UB, but in WASM it can fail. + +See: +https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html +--- + gio/gapplication.c | 18 ++++++--- + gio/gbufferedinputstream.c | 6 ++- + gio/gbufferedoutputstream.c | 6 ++- + gio/gbytesicon.c | 12 ++++-- + gio/gcharsetconverter.c | 12 ++++-- + gio/gconverterinputstream.c | 7 ++-- + gio/gconverteroutputstream.c | 6 ++- + gio/gdataoutputstream.c | 6 ++- + gio/gdbusactiongroup.c | 12 ++++-- + gio/gdbusconnection.c | 12 ++++-- + gio/gdbusdaemon.c | 12 ++++-- + gio/gdbusobjectmanagerclient.c | 18 ++++++--- + gio/gdbusproxy.c | 18 ++++++--- + gio/gdbusserver.c | 6 ++- + gio/gdebugcontrollerdbus.c | 12 ++++-- + gio/gdesktopappinfo.c | 6 ++- + gio/gdummyfile.c | 6 ++- + gio/gdummyproxyresolver.c | 6 ++- + gio/gdummytlsbackend.c | 36 +++++++++++------ + gio/gemblem.c | 6 ++- + gio/gemblemedicon.c | 6 ++- + gio/gfileicon.c | 12 ++++-- + gio/gfileinputstream.c | 6 ++- + gio/gfileiostream.c | 6 ++- + gio/gfileoutputstream.c | 6 ++- + gio/ghttpproxy.c | 6 ++- + gio/ginetaddressmask.c | 6 ++- + gio/ginetsocketaddress.c | 6 ++- + gio/gliststore.c | 6 ++- + gio/glocalfile.c | 6 ++- + gio/glocalfileinputstream.c | 6 ++- + gio/glocalfileoutputstream.c | 6 ++- + gio/gmemoryinputstream.c | 12 ++++-- + gio/gmemorymonitordbus.c | 12 ++++-- + gio/gmemorymonitorportal.c | 12 ++++-- + gio/gmemorymonitorwin32.c | 12 ++++-- + gio/gmemoryoutputstream.c | 12 ++++-- + gio/gnetworkaddress.c | 6 ++- + gio/gnetworkmonitorbase.c | 12 ++++-- + gio/gnetworkmonitornetlink.c | 12 ++++-- + gio/gnetworkmonitornm.c | 12 ++++-- + gio/gnetworkmonitorportal.c | 12 ++++-- + gio/gnetworkservice.c | 6 ++- + gio/gosxappinfo.m | 6 ++- + gio/gpowerprofilemonitordbus.c | 12 ++++-- + gio/gpowerprofilemonitorportal.c | 12 ++++-- + gio/gpropertyaction.c | 6 ++- + gio/gproxyresolverportal.c | 6 ++- + gio/gresourcefile.c | 6 ++- + gio/gsettings.c | 6 ++- + gio/gsimpleaction.c | 6 ++- + gio/gsimpleactiongroup.c | 12 ++++-- + gio/gsimpleasyncresult.c | 6 ++- + gio/gsimpleproxyresolver.c | 6 ++- + gio/gsocket.c | 12 ++++-- + gio/gsocketaddress.c | 6 ++- + gio/gsocketinputstream.c | 12 ++++-- + gio/gsocketoutputstream.c | 12 ++++-- + gio/gsocks4aproxy.c | 6 ++- + gio/gsocks5proxy.c | 6 ++- + gio/gsubprocess.c | 6 ++- + gio/gtask.c | 6 ++- + gio/gthemedicon.c | 6 ++- + gio/gunixinputstream.c | 12 ++++-- + gio/gunixmount.c | 6 ++- + gio/gunixoutputstream.c | 12 ++++-- + gio/gunixsocketaddress.c | 6 ++- + gio/gunixvolume.c | 6 ++- + gio/gwin32appinfo.c | 6 ++- + gio/gwin32mount.c | 6 ++- + gio/gwin32networkmonitor.c | 12 ++++-- + gio/gwin32registrykey.c | 6 ++- + gio/gzlibcompressor.c | 6 ++- + gio/gzlibdecompressor.c | 6 ++- + gio/win32/gwinhttpfile.c | 6 ++- + gobject/gobject.c | 6 ++- + gobject/gparam.h | 3 +- + gobject/gparamspecs.c | 66 +++++++++++++++++++++----------- + gobject/gtype.h | 26 +++++++++---- + gobject/gtypemodule.c | 3 +- + gobject/gtypemodule.h | 8 ++-- + 81 files changed, 519 insertions(+), 260 deletions(-) + +diff --git a/gio/gapplication.c b/gio/gapplication.c +index b7d2870e995..1128d211352 100644 +--- a/gio/gapplication.c ++++ b/gio/gapplication.c +@@ -290,8 +290,10 @@ enum + + static guint g_application_signals[NR_SIGNALS]; + +-static void g_application_action_group_iface_init (GActionGroupInterface *); +-static void g_application_action_map_iface_init (GActionMapInterface *); ++static void g_application_action_group_iface_init (GActionGroupInterface *iface, ++ gpointer iface_data); ++static void g_application_action_map_iface_init (GActionMapInterface *iface, ++ gpointer iface_data); + G_DEFINE_TYPE_WITH_CODE (GApplication, g_application, G_TYPE_OBJECT, + G_ADD_PRIVATE (GApplication) + G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_application_action_group_iface_init) +@@ -317,7 +319,8 @@ typedef struct + } GApplicationExportedActions; + + static GType g_application_exported_actions_get_type (void); +-static void g_application_exported_actions_iface_init (GRemoteActionGroupInterface *iface); ++static void g_application_exported_actions_iface_init (GRemoteActionGroupInterface *iface, ++ gpointer iface_data); + G_DEFINE_TYPE_WITH_CODE (GApplicationExportedActions, g_application_exported_actions, G_TYPE_SIMPLE_ACTION_GROUP, + G_IMPLEMENT_INTERFACE (G_TYPE_REMOTE_ACTION_GROUP, g_application_exported_actions_iface_init)) + +@@ -361,7 +364,8 @@ g_application_exported_actions_init (GApplicationExportedActions *actions) + } + + static void +-g_application_exported_actions_iface_init (GRemoteActionGroupInterface *iface) ++g_application_exported_actions_iface_init (GRemoteActionGroupInterface *iface, ++ gpointer iface_data) + { + iface->activate_action_full = g_application_exported_actions_activate_action_full; + iface->change_action_state_full = g_application_exported_actions_change_action_state_full; +@@ -2872,7 +2876,8 @@ g_application_remove_action (GActionMap *action_map, + } + + static void +-g_application_action_group_iface_init (GActionGroupInterface *iface) ++g_application_action_group_iface_init (GActionGroupInterface *iface, ++ gpointer iface_data) + { + iface->list_actions = g_application_list_actions; + iface->query_action = g_application_query_action; +@@ -2881,7 +2886,8 @@ g_application_action_group_iface_init (GActionGroupInterface *iface) + } + + static void +-g_application_action_map_iface_init (GActionMapInterface *iface) ++g_application_action_map_iface_init (GActionMapInterface *iface, ++ gpointer iface_data) + { + iface->lookup_action = g_application_lookup_action; + iface->add_action = g_application_add_action; +diff --git a/gio/gbufferedinputstream.c b/gio/gbufferedinputstream.c +index 64cb293ef35..f89aa8152a0 100644 +--- a/gio/gbufferedinputstream.c ++++ b/gio/gbufferedinputstream.c +@@ -111,7 +111,8 @@ static gssize g_buffered_input_stream_real_fill_finish (GBufferedInputStream *s + GAsyncResult *result, + GError **error); + +-static void g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface); ++static void g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data); + static goffset g_buffered_input_stream_tell (GSeekable *seekable); + static gboolean g_buffered_input_stream_can_seek (GSeekable *seekable); + static gboolean g_buffered_input_stream_seek (GSeekable *seekable, +@@ -301,7 +302,8 @@ g_buffered_input_stream_finalize (GObject *object) + } + + static void +-g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface) ++g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data) + { + iface->tell = g_buffered_input_stream_tell; + iface->can_seek = g_buffered_input_stream_can_seek; +diff --git a/gio/gbufferedoutputstream.c b/gio/gbufferedoutputstream.c +index f82b10f1149..dc0198c425b 100644 +--- a/gio/gbufferedoutputstream.c ++++ b/gio/gbufferedoutputstream.c +@@ -103,7 +103,8 @@ static gboolean g_buffered_output_stream_close_finish (GOutputStream *str + GAsyncResult *result, + GError **error); + +-static void g_buffered_output_stream_seekable_iface_init (GSeekableIface *iface); ++static void g_buffered_output_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data); + static goffset g_buffered_output_stream_tell (GSeekable *seekable); + static gboolean g_buffered_output_stream_can_seek (GSeekable *seekable); + static gboolean g_buffered_output_stream_seek (GSeekable *seekable, +@@ -350,7 +351,8 @@ g_buffered_output_stream_init (GBufferedOutputStream *stream) + } + + static void +-g_buffered_output_stream_seekable_iface_init (GSeekableIface *iface) ++g_buffered_output_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data) + { + iface->tell = g_buffered_output_stream_tell; + iface->can_seek = g_buffered_output_stream_can_seek; +diff --git a/gio/gbytesicon.c b/gio/gbytesicon.c +index 37c242afbce..e22e9e055eb 100644 +--- a/gio/gbytesicon.c ++++ b/gio/gbytesicon.c +@@ -56,8 +56,10 @@ enum + PROP_BYTES + }; + +-static void g_bytes_icon_icon_iface_init (GIconIface *iface); +-static void g_bytes_icon_loadable_icon_iface_init (GLoadableIconIface *iface); ++static void g_bytes_icon_icon_iface_init (GIconIface *iface, ++ gpointer iface_data); ++static void g_bytes_icon_loadable_icon_iface_init (GLoadableIconIface *iface, ++ gpointer iface_data); + G_DEFINE_TYPE_WITH_CODE (GBytesIcon, g_bytes_icon, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ICON, g_bytes_icon_icon_iface_init) + G_IMPLEMENT_INTERFACE (G_TYPE_LOADABLE_ICON, g_bytes_icon_loadable_icon_iface_init)) +@@ -205,7 +207,8 @@ g_bytes_icon_serialize (GIcon *icon) + } + + static void +-g_bytes_icon_icon_iface_init (GIconIface *iface) ++g_bytes_icon_icon_iface_init (GIconIface *iface, ++ gpointer iface_data) + { + iface->hash = g_bytes_icon_hash; + iface->equal = g_bytes_icon_equal; +@@ -258,7 +261,8 @@ g_bytes_icon_load_finish (GLoadableIcon *icon, + } + + static void +-g_bytes_icon_loadable_icon_iface_init (GLoadableIconIface *iface) ++g_bytes_icon_loadable_icon_iface_init (GLoadableIconIface *iface, ++ gpointer iface_data) + { + iface->load = g_bytes_icon_load; + iface->load_async = g_bytes_icon_load_async; +diff --git a/gio/gcharsetconverter.c b/gio/gcharsetconverter.c +index c9437e1bd47..d38045e40c2 100644 +--- a/gio/gcharsetconverter.c ++++ b/gio/gcharsetconverter.c +@@ -45,8 +45,10 @@ enum { + * [struct@GLib.IConv]. + */ + +-static void g_charset_converter_iface_init (GConverterIface *iface); +-static void g_charset_converter_initable_iface_init (GInitableIface *iface); ++static void g_charset_converter_iface_init (GConverterIface *iface, ++ gpointer iface_data); ++static void g_charset_converter_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + struct _GCharsetConverter + { +@@ -433,7 +435,8 @@ g_charset_converter_get_num_fallbacks (GCharsetConverter *converter) + } + + static void +-g_charset_converter_iface_init (GConverterIface *iface) ++g_charset_converter_iface_init (GConverterIface *iface, ++ gpointer iface_data) + { + iface->convert = g_charset_converter_convert; + iface->reset = g_charset_converter_reset; +@@ -478,7 +481,8 @@ g_charset_converter_initable_init (GInitable *initable, + } + + static void +-g_charset_converter_initable_iface_init (GInitableIface *iface) ++g_charset_converter_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_charset_converter_initable_init; + } +diff --git a/gio/gconverterinputstream.c b/gio/gconverterinputstream.c +index c74ec29f38c..afa51313723 100644 +--- a/gio/gconverterinputstream.c ++++ b/gio/gconverterinputstream.c +@@ -90,8 +90,8 @@ static gssize g_converter_input_stream_read_nonblocking (GPollableInputStream + static GSource *g_converter_input_stream_create_source (GPollableInputStream *stream, + GCancellable *cancellable); + +-static void g_converter_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface); +- ++static void g_converter_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface, ++ gpointer iface_data); + G_DEFINE_TYPE_WITH_CODE (GConverterInputStream, + g_converter_input_stream, + G_TYPE_FILTER_INPUT_STREAM, +@@ -129,7 +129,8 @@ g_converter_input_stream_class_init (GConverterInputStreamClass *klass) + } + + static void +-g_converter_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface) ++g_converter_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface, ++ gpointer iface_data) + { + iface->can_poll = g_converter_input_stream_can_poll; + iface->is_readable = g_converter_input_stream_is_readable; +diff --git a/gio/gconverteroutputstream.c b/gio/gconverteroutputstream.c +index 1877b0e4ea2..942d5f750ca 100644 +--- a/gio/gconverteroutputstream.c ++++ b/gio/gconverteroutputstream.c +@@ -105,7 +105,8 @@ static gssize g_converter_output_stream_write_nonblocking (GPollableOutputStre + static GSource *g_converter_output_stream_create_source (GPollableOutputStream *stream, + GCancellable *cancellable); + +-static void g_converter_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface); ++static void g_converter_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GConverterOutputStream, + g_converter_output_stream, +@@ -145,7 +146,8 @@ g_converter_output_stream_class_init (GConverterOutputStreamClass *klass) + } + + static void +-g_converter_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface) ++g_converter_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface, ++ gpointer iface_data) + { + iface->can_poll = g_converter_output_stream_can_poll; + iface->is_writable = g_converter_output_stream_is_writable; +diff --git a/gio/gdataoutputstream.c b/gio/gdataoutputstream.c +index f183f96268e..fe8ced0be59 100644 +--- a/gio/gdataoutputstream.c ++++ b/gio/gdataoutputstream.c +@@ -55,7 +55,8 @@ static void g_data_output_stream_get_property (GObject *object, + GValue *value, + GParamSpec *pspec); + +-static void g_data_output_stream_seekable_iface_init (GSeekableIface *iface); ++static void g_data_output_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data); + static goffset g_data_output_stream_tell (GSeekable *seekable); + static gboolean g_data_output_stream_can_seek (GSeekable *seekable); + static gboolean g_data_output_stream_seek (GSeekable *seekable, +@@ -155,7 +156,8 @@ g_data_output_stream_init (GDataOutputStream *stream) + } + + static void +-g_data_output_stream_seekable_iface_init (GSeekableIface *iface) ++g_data_output_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data) + { + iface->tell = g_data_output_stream_tell; + iface->can_seek = g_data_output_stream_can_seek; +diff --git a/gio/gdbusactiongroup.c b/gio/gdbusactiongroup.c +index 0bd53112165..060f1478a5e 100644 +--- a/gio/gdbusactiongroup.c ++++ b/gio/gdbusactiongroup.c +@@ -122,8 +122,10 @@ action_info_new_from_iter (GVariantIter *iter) + return info; + } + +-static void g_dbus_action_group_remote_iface_init (GRemoteActionGroupInterface *iface); +-static void g_dbus_action_group_iface_init (GActionGroupInterface *iface); ++static void g_dbus_action_group_remote_iface_init (GRemoteActionGroupInterface *iface, ++ gpointer iface_data); ++static void g_dbus_action_group_iface_init (GActionGroupInterface *iface, ++ gpointer iface_data); + G_DEFINE_TYPE_WITH_CODE (GDBusActionGroup, g_dbus_action_group, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_dbus_action_group_iface_init) + G_IMPLEMENT_INTERFACE (G_TYPE_REMOTE_ACTION_GROUP, g_dbus_action_group_remote_iface_init)) +@@ -450,14 +452,16 @@ g_dbus_action_group_class_init (GDBusActionGroupClass *class) + } + + static void +-g_dbus_action_group_remote_iface_init (GRemoteActionGroupInterface *iface) ++g_dbus_action_group_remote_iface_init (GRemoteActionGroupInterface *iface, ++ gpointer iface_data) + { + iface->activate_action_full = g_dbus_action_group_activate_action_full; + iface->change_action_state_full = g_dbus_action_group_change_action_state_full; + } + + static void +-g_dbus_action_group_iface_init (GActionGroupInterface *iface) ++g_dbus_action_group_iface_init (GActionGroupInterface *iface, ++ gpointer iface_data) + { + iface->list_actions = g_dbus_action_group_list_actions; + iface->query_action = g_dbus_action_group_query_action; +diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c +index 42134a601b0..8f0045d04a1 100644 +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -505,8 +505,10 @@ static void schedule_method_call (GDBusConnection *connection, + + static guint signals[LAST_SIGNAL] = { 0 }; + +-static void initable_iface_init (GInitableIface *initable_iface); +-static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface); ++static void initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data); ++static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GDBusConnection, g_dbus_connection, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init) +@@ -2668,7 +2670,8 @@ initable_init (GInitable *initable, + } + + static void +-initable_iface_init (GInitableIface *initable_iface) ++initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data) + { + initable_iface->init = initable_init; + } +@@ -2676,7 +2679,8 @@ initable_iface_init (GInitableIface *initable_iface) + /* ---------------------------------------------------------------------------------------------------- */ + + static void +-async_initable_iface_init (GAsyncInitableIface *async_initable_iface) ++async_initable_iface_init (GAsyncInitableIface *async_initable_iface, ++ gpointer iface_data) + { + /* Use default */ + } +diff --git a/gio/gdbusdaemon.c b/gio/gdbusdaemon.c +index 3474b7091d1..11dc9eb20c3 100644 +--- a/gio/gdbusdaemon.c ++++ b/gio/gdbusdaemon.c +@@ -90,8 +90,10 @@ enum + static guint g_dbus_daemon_signals[NR_SIGNALS]; + + +-static void initable_iface_init (GInitableIface *initable_iface); +-static void g_dbus_daemon_iface_init (_GFreedesktopDBusIface *iface); ++static void initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data); ++static void g_dbus_daemon_iface_init (_GFreedesktopDBusIface *iface, ++ gpointer iface_data); + + #define g_dbus_daemon_get_type _g_dbus_daemon_get_type + G_DEFINE_TYPE_WITH_CODE (GDBusDaemon, g_dbus_daemon, _G_TYPE_FREEDESKTOP_DBUS_SKELETON, +@@ -1700,7 +1702,8 @@ g_dbus_daemon_class_init (GDBusDaemonClass *klass) + } + + static void +-g_dbus_daemon_iface_init (_GFreedesktopDBusIface *iface) ++g_dbus_daemon_iface_init (_GFreedesktopDBusIface *iface, ++ gpointer iface_data) + { + iface->handle_add_match = handle_add_match; + iface->handle_get_connection_selinux_security_context = handle_get_connection_selinux_security_context; +@@ -1722,7 +1725,8 @@ g_dbus_daemon_iface_init (_GFreedesktopDBusIface *iface) + } + + static void +-initable_iface_init (GInitableIface *initable_iface) ++initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data) + { + initable_iface->init = initable_init; + } +diff --git a/gio/gdbusobjectmanagerclient.c b/gio/gdbusobjectmanagerclient.c +index cb35d066934..c12177e201e 100644 +--- a/gio/gdbusobjectmanagerclient.c ++++ b/gio/gdbusobjectmanagerclient.c +@@ -177,9 +177,12 @@ enum + + static guint signals[LAST_SIGNAL] = { 0 }; + +-static void initable_iface_init (GInitableIface *initable_iface); +-static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface); +-static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface); ++static void initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data); ++static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface, ++ gpointer iface_data); ++static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT, + G_ADD_PRIVATE (GDBusObjectManagerClient) +@@ -1500,13 +1503,15 @@ initable_init (GInitable *initable, + } + + static void +-initable_iface_init (GInitableIface *initable_iface) ++initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data) + { + initable_iface->init = initable_init; + } + + static void +-async_initable_iface_init (GAsyncInitableIface *async_initable_iface) ++async_initable_iface_init (GAsyncInitableIface *async_initable_iface, ++ gpointer iface_data) + { + /* for now, just use default: run GInitable code in thread */ + } +@@ -1847,7 +1852,8 @@ g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager) + + + static void +-dbus_object_manager_interface_init (GDBusObjectManagerIface *iface) ++dbus_object_manager_interface_init (GDBusObjectManagerIface *iface, ++ gpointer iface_data) + { + iface->get_object_path = g_dbus_object_manager_client_get_object_path; + iface->get_objects = g_dbus_object_manager_client_get_objects; +diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c +index 5d9a637c355..a4b3b84ba7d 100644 +--- a/gio/gdbusproxy.c ++++ b/gio/gdbusproxy.c +@@ -179,9 +179,12 @@ enum + + static guint signals[LAST_SIGNAL] = {0}; + +-static void dbus_interface_iface_init (GDBusInterfaceIface *dbus_interface_iface); +-static void initable_iface_init (GInitableIface *initable_iface); +-static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface); ++static void dbus_interface_iface_init (GDBusInterfaceIface *dbus_interface_iface, ++ gpointer iface_data); ++static void initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data); ++static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GDBusProxy, g_dbus_proxy, G_TYPE_OBJECT, + G_ADD_PRIVATE (GDBusProxy) +@@ -1826,7 +1829,8 @@ async_initable_init_finish (GAsyncInitable *initable, + } + + static void +-async_initable_iface_init (GAsyncInitableIface *async_initable_iface) ++async_initable_iface_init (GAsyncInitableIface *async_initable_iface, ++ gpointer iface_data) + { + async_initable_iface->init_async = async_initable_init_async; + async_initable_iface->init_finish = async_initable_init_finish; +@@ -1913,7 +1917,8 @@ initable_init (GInitable *initable, + } + + static void +-initable_iface_init (GInitableIface *initable_iface) ++initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data) + { + initable_iface->init = initable_init; + } +@@ -3168,7 +3173,8 @@ _g_dbus_proxy_set_object (GDBusInterface *interface, + } + + static void +-dbus_interface_iface_init (GDBusInterfaceIface *dbus_interface_iface) ++dbus_interface_iface_init (GDBusInterfaceIface *dbus_interface_iface, ++ gpointer iface_data) + { + dbus_interface_iface->get_info = _g_dbus_proxy_get_info; + dbus_interface_iface->get_object = _g_dbus_proxy_get_object; +diff --git a/gio/gdbusserver.c b/gio/gdbusserver.c +index 4e23e52e4be..891a3c8be65 100644 +--- a/gio/gdbusserver.c ++++ b/gio/gdbusserver.c +@@ -158,7 +158,8 @@ enum + + static guint _signals[LAST_SIGNAL] = {0}; + +-static void initable_iface_init (GInitableIface *initable_iface); ++static void initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GDBusServer, g_dbus_server, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)) +@@ -1163,7 +1164,8 @@ initable_init (GInitable *initable, + + + static void +-initable_iface_init (GInitableIface *initable_iface) ++initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data) + { + initable_iface->init = initable_init; + } +diff --git a/gio/gdebugcontrollerdbus.c b/gio/gdebugcontrollerdbus.c +index 03dd1be98ad..cc22d5ab6e2 100644 +--- a/gio/gdebugcontrollerdbus.c ++++ b/gio/gdebugcontrollerdbus.c +@@ -161,8 +161,10 @@ static GDBusInterfaceInfo *org_gtk_Debugging; + + #define G_DEBUG_CONTROLLER_DBUS_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable)) + +-static void g_debug_controller_dbus_iface_init (GDebugControllerInterface *iface); +-static void g_debug_controller_dbus_initable_iface_init (GInitableIface *iface); ++static void g_debug_controller_dbus_iface_init (GDebugControllerInterface *iface, ++ gpointer iface_data); ++static void g_debug_controller_dbus_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + static gboolean g_debug_controller_dbus_authorize_default (GDebugControllerDBus *self, + GDBusMethodInvocation *invocation); + +@@ -615,12 +617,14 @@ g_debug_controller_dbus_class_init (GDebugControllerDBusClass *klass) + } + + static void +-g_debug_controller_dbus_iface_init (GDebugControllerInterface *iface) ++g_debug_controller_dbus_iface_init (GDebugControllerInterface *iface, ++ gpointer iface_data) + { + } + + static void +-g_debug_controller_dbus_initable_iface_init (GInitableIface *iface) ++g_debug_controller_dbus_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_debug_controller_dbus_initable_init; + } +diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c +index 7d36b6a3401..4512a2b6111 100644 +--- a/gio/gdesktopappinfo.c ++++ b/gio/gdesktopappinfo.c +@@ -87,7 +87,8 @@ enum { + PROP_FILENAME + }; + +-static void g_desktop_app_info_iface_init (GAppInfoIface *iface); ++static void g_desktop_app_info_iface_init (GAppInfoIface *iface, ++ gpointer iface_data); + static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info, + GError **error); + static gboolean g_desktop_app_info_load_file (GDesktopAppInfo *self); +@@ -4378,7 +4379,8 @@ g_app_info_create_from_commandline (const char *commandline, + /* GAppInfo interface init */ + + static void +-g_desktop_app_info_iface_init (GAppInfoIface *iface) ++g_desktop_app_info_iface_init (GAppInfoIface *iface, ++ gpointer iface_data) + { + iface->dup = g_desktop_app_info_dup; + iface->equal = g_desktop_app_info_equal; +diff --git a/gio/gdummyfile.c b/gio/gdummyfile.c +index 4ec352c6e41..36d55ceeaf2 100644 +--- a/gio/gdummyfile.c ++++ b/gio/gdummyfile.c +@@ -33,7 +33,8 @@ + #include "gfile.h" + + +-static void g_dummy_file_file_iface_init (GFileIface *iface); ++static void g_dummy_file_file_iface_init (GFileIface *iface, ++ gpointer iface_data); + + typedef struct { + char *scheme; +@@ -398,7 +399,8 @@ g_dummy_file_get_uri_scheme (GFile *file) + + + static void +-g_dummy_file_file_iface_init (GFileIface *iface) ++g_dummy_file_file_iface_init (GFileIface *iface, ++ gpointer iface_data) + { + iface->dup = g_dummy_file_dup; + iface->hash = g_dummy_file_hash; +diff --git a/gio/gdummyproxyresolver.c b/gio/gdummyproxyresolver.c +index 1cac1db746f..fe354166f08 100644 +--- a/gio/gdummyproxyresolver.c ++++ b/gio/gdummyproxyresolver.c +@@ -38,7 +38,8 @@ struct _GDummyProxyResolver { + GObject parent_instance; + }; + +-static void g_dummy_proxy_resolver_iface_init (GProxyResolverInterface *iface); ++static void g_dummy_proxy_resolver_iface_init (GProxyResolverInterface *iface, ++ gpointer iface_data); + + #define g_dummy_proxy_resolver_get_type _g_dummy_proxy_resolver_get_type + G_DEFINE_TYPE_WITH_CODE (GDummyProxyResolver, g_dummy_proxy_resolver, G_TYPE_OBJECT, +@@ -127,7 +128,8 @@ g_dummy_proxy_resolver_class_init (GDummyProxyResolverClass *resolver_class) + } + + static void +-g_dummy_proxy_resolver_iface_init (GProxyResolverInterface *iface) ++g_dummy_proxy_resolver_iface_init (GProxyResolverInterface *iface, ++ gpointer iface_data) + { + iface->is_supported = g_dummy_proxy_resolver_is_supported; + iface->lookup = g_dummy_proxy_resolver_lookup; +diff --git a/gio/gdummytlsbackend.c b/gio/gdummytlsbackend.c +index 4c69f1d010a..05c374ce3e0 100644 +--- a/gio/gdummytlsbackend.c ++++ b/gio/gdummytlsbackend.c +@@ -53,7 +53,8 @@ struct _GDummyTlsBackend { + GTlsDatabase *database; + }; + +-static void g_dummy_tls_backend_iface_init (GTlsBackendInterface *iface); ++static void g_dummy_tls_backend_iface_init (GTlsBackendInterface *iface, ++ gpointer iface_data); + + #define g_dummy_tls_backend_get_type _g_dummy_tls_backend_get_type + G_DEFINE_TYPE_WITH_CODE (GDummyTlsBackend, g_dummy_tls_backend, G_TYPE_OBJECT, +@@ -105,7 +106,8 @@ g_dummy_tls_backend_get_default_database (GTlsBackend *backend) + } + + static void +-g_dummy_tls_backend_iface_init (GTlsBackendInterface *iface) ++g_dummy_tls_backend_iface_init (GTlsBackendInterface *iface, ++ gpointer iface_data) + { + iface->get_certificate_type = _g_dummy_tls_certificate_get_type; + iface->get_client_connection_type = _g_dummy_tls_connection_get_type; +@@ -140,7 +142,8 @@ enum + PROP_CERT_ISSUER + }; + +-static void g_dummy_tls_certificate_initable_iface_init (GInitableIface *iface); ++static void g_dummy_tls_certificate_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + #define g_dummy_tls_certificate_get_type _g_dummy_tls_certificate_get_type + G_DEFINE_TYPE_WITH_CODE (GDummyTlsCertificate, g_dummy_tls_certificate, G_TYPE_TLS_CERTIFICATE, +@@ -199,7 +202,8 @@ g_dummy_tls_certificate_initable_init (GInitable *initable, + } + + static void +-g_dummy_tls_certificate_initable_iface_init (GInitableIface *iface) ++g_dummy_tls_certificate_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_dummy_tls_certificate_initable_init; + } +@@ -242,7 +246,8 @@ enum + PROP_CONN_NEGOTIATED_PROTOCOL, + }; + +-static void g_dummy_tls_connection_initable_iface_init (GInitableIface *iface); ++static void g_dummy_tls_connection_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + #define g_dummy_tls_connection_get_type _g_dummy_tls_connection_get_type + G_DEFINE_TYPE_WITH_CODE (GDummyTlsConnection, g_dummy_tls_connection, G_TYPE_TLS_CONNECTION, +@@ -325,7 +330,8 @@ g_dummy_tls_connection_initable_init (GInitable *initable, + } + + static void +-g_dummy_tls_connection_initable_iface_init (GInitableIface *iface) ++g_dummy_tls_connection_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_dummy_tls_connection_initable_init; + } +@@ -363,7 +369,8 @@ enum + PROP_DTLS_CONN_AUTHENTICATION_MODE, + }; + +-static void g_dummy_dtls_connection_initable_iface_init (GInitableIface *iface); ++static void g_dummy_dtls_connection_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + #define g_dummy_dtls_connection_get_type _g_dummy_dtls_connection_get_type + G_DEFINE_TYPE_WITH_CODE (GDummyDtlsConnection, g_dummy_dtls_connection, G_TYPE_OBJECT, +@@ -427,7 +434,8 @@ g_dummy_dtls_connection_initable_init (GInitable *initable, + } + + static void +-g_dummy_dtls_connection_initable_iface_init (GInitableIface *iface) ++g_dummy_dtls_connection_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_dummy_dtls_connection_initable_init; + } +@@ -453,8 +461,10 @@ enum + PROP_ANCHORS, + }; + +-static void g_dummy_tls_database_file_database_iface_init (GTlsFileDatabaseInterface *iface); +-static void g_dummy_tls_database_initable_iface_init (GInitableIface *iface); ++static void g_dummy_tls_database_file_database_iface_init (GTlsFileDatabaseInterface *iface, ++ gpointer iface_data); ++static void g_dummy_tls_database_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + #define g_dummy_tls_database_get_type _g_dummy_tls_database_get_type + G_DEFINE_TYPE_WITH_CODE (GDummyTlsDatabase, g_dummy_tls_database, G_TYPE_TLS_DATABASE, +@@ -502,7 +512,8 @@ g_dummy_tls_database_init (GDummyTlsDatabase *database) + } + + static void +-g_dummy_tls_database_file_database_iface_init (GTlsFileDatabaseInterface *iface) ++g_dummy_tls_database_file_database_iface_init (GTlsFileDatabaseInterface *iface, ++ gpointer iface_data) + { + } + +@@ -517,7 +528,8 @@ g_dummy_tls_database_initable_init (GInitable *initable, + } + + static void +-g_dummy_tls_database_initable_iface_init (GInitableIface *iface) ++g_dummy_tls_database_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_dummy_tls_database_initable_init; + } +diff --git a/gio/gemblem.c b/gio/gemblem.c +index dc032672e07..e328e1c4d01 100644 +--- a/gio/gemblem.c ++++ b/gio/gemblem.c +@@ -41,7 +41,8 @@ + * supported. More may be added in the future. + */ + +-static void g_emblem_iface_init (GIconIface *iface); ++static void g_emblem_iface_init (GIconIface *iface, ++ gpointer iface_data); + + struct _GEmblem + { +@@ -378,7 +379,8 @@ g_emblem_serialize (GIcon *icon) + } + + static void +-g_emblem_iface_init (GIconIface *iface) ++g_emblem_iface_init (GIconIface *iface, ++ gpointer iface_data) + { + iface->hash = g_emblem_hash; + iface->equal = g_emblem_equal; +diff --git a/gio/gemblemedicon.c b/gio/gemblemedicon.c +index 9415c0b9d46..9c69169ea00 100644 +--- a/gio/gemblemedicon.c ++++ b/gio/gemblemedicon.c +@@ -55,7 +55,8 @@ struct _GEmblemedIconPrivate { + + static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; + +-static void g_emblemed_icon_icon_iface_init (GIconIface *iface); ++static void g_emblemed_icon_icon_iface_init (GIconIface *iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GEmblemedIcon, g_emblemed_icon, G_TYPE_OBJECT, + G_ADD_PRIVATE (GEmblemedIcon) +@@ -461,7 +462,8 @@ g_emblemed_icon_serialize (GIcon *icon) + } + + static void +-g_emblemed_icon_icon_iface_init (GIconIface *iface) ++g_emblemed_icon_icon_iface_init (GIconIface *iface, ++ gpointer iface_data) + { + iface->hash = g_emblemed_icon_hash; + iface->equal = g_emblemed_icon_equal; +diff --git a/gio/gfileicon.c b/gio/gfileicon.c +index d796ed43f44..8162f229fee 100644 +--- a/gio/gfileicon.c ++++ b/gio/gfileicon.c +@@ -41,8 +41,10 @@ + * It implements [iface@Gio.LoadableIcon]. + */ + +-static void g_file_icon_icon_iface_init (GIconIface *iface); +-static void g_file_icon_loadable_icon_iface_init (GLoadableIconIface *iface); ++static void g_file_icon_icon_iface_init (GIconIface *iface, ++ gpointer iface_data); ++static void g_file_icon_loadable_icon_iface_init (GLoadableIconIface *iface, ++ gpointer iface_data); + static void g_file_icon_load_async (GLoadableIcon *icon, + int size, + GCancellable *cancellable, +@@ -276,7 +278,8 @@ g_file_icon_serialize (GIcon *icon) + } + + static void +-g_file_icon_icon_iface_init (GIconIface *iface) ++g_file_icon_icon_iface_init (GIconIface *iface, ++ gpointer iface_data) + { + iface->hash = g_file_icon_hash; + iface->equal = g_file_icon_equal; +@@ -356,7 +359,8 @@ g_file_icon_load_finish (GLoadableIcon *icon, + } + + static void +-g_file_icon_loadable_icon_iface_init (GLoadableIconIface *iface) ++g_file_icon_loadable_icon_iface_init (GLoadableIconIface *iface, ++ gpointer iface_data) + { + iface->load = g_file_icon_load; + iface->load_async = g_file_icon_load_async; +diff --git a/gio/gfileinputstream.c b/gio/gfileinputstream.c +index f71beb5bb3c..bd62a7b2447 100644 +--- a/gio/gfileinputstream.c ++++ b/gio/gfileinputstream.c +@@ -46,7 +46,8 @@ + * To position a file input stream, use [vfunc@Gio.Seekable.seek]. + **/ + +-static void g_file_input_stream_seekable_iface_init (GSeekableIface *iface); ++static void g_file_input_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data); + static goffset g_file_input_stream_seekable_tell (GSeekable *seekable); + static gboolean g_file_input_stream_seekable_can_seek (GSeekable *seekable); + static gboolean g_file_input_stream_seekable_seek (GSeekable *seekable, +@@ -87,7 +88,8 @@ g_file_input_stream_class_init (GFileInputStreamClass *klass) + } + + static void +-g_file_input_stream_seekable_iface_init (GSeekableIface *iface) ++g_file_input_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data) + { + iface->tell = g_file_input_stream_seekable_tell; + iface->can_seek = g_file_input_stream_seekable_can_seek; +diff --git a/gio/gfileiostream.c b/gio/gfileiostream.c +index 4a030c0932b..ac491ddbfa9 100644 +--- a/gio/gfileiostream.c ++++ b/gio/gfileiostream.c +@@ -59,7 +59,8 @@ + * Since: 2.22 + **/ + +-static void g_file_io_stream_seekable_iface_init (GSeekableIface *iface); ++static void g_file_io_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data); + static goffset g_file_io_stream_seekable_tell (GSeekable *seekable); + static gboolean g_file_io_stream_seekable_can_seek (GSeekable *seekable); + static gboolean g_file_io_stream_seekable_seek (GSeekable *seekable, +@@ -92,7 +93,8 @@ G_DEFINE_TYPE_WITH_CODE (GFileIOStream, g_file_io_stream, G_TYPE_IO_STREAM, + g_file_io_stream_seekable_iface_init)) + + static void +-g_file_io_stream_seekable_iface_init (GSeekableIface *iface) ++g_file_io_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data) + { + iface->tell = g_file_io_stream_seekable_tell; + iface->can_seek = g_file_io_stream_seekable_can_seek; +diff --git a/gio/gfileoutputstream.c b/gio/gfileoutputstream.c +index 786d037c361..bb724050ab3 100644 +--- a/gio/gfileoutputstream.c ++++ b/gio/gfileoutputstream.c +@@ -51,7 +51,8 @@ + * stream, use [method@Gio.Seekable.truncate]. + **/ + +-static void g_file_output_stream_seekable_iface_init (GSeekableIface *iface); ++static void g_file_output_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data); + static goffset g_file_output_stream_seekable_tell (GSeekable *seekable); + static gboolean g_file_output_stream_seekable_can_seek (GSeekable *seekable); + static gboolean g_file_output_stream_seekable_seek (GSeekable *seekable, +@@ -91,7 +92,8 @@ g_file_output_stream_class_init (GFileOutputStreamClass *klass) + } + + static void +-g_file_output_stream_seekable_iface_init (GSeekableIface *iface) ++g_file_output_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data) + { + iface->tell = g_file_output_stream_seekable_tell; + iface->can_seek = g_file_output_stream_seekable_can_seek; +diff --git a/gio/ghttpproxy.c b/gio/ghttpproxy.c +index 605a7299415..28e36747138 100644 +--- a/gio/ghttpproxy.c ++++ b/gio/ghttpproxy.c +@@ -53,7 +53,8 @@ struct _GHttpProxyClass + GObjectClass parent_class; + }; + +-static void g_http_proxy_iface_init (GProxyInterface *proxy_iface); ++static void g_http_proxy_iface_init (GProxyInterface *proxy_iface, ++ gpointer iface_data); + + #define g_http_proxy_get_type _g_http_proxy_get_type + G_DEFINE_TYPE_WITH_CODE (GHttpProxy, g_http_proxy, G_TYPE_OBJECT, +@@ -379,7 +380,8 @@ g_http_proxy_class_init (GHttpProxyClass *class) + } + + static void +-g_http_proxy_iface_init (GProxyInterface *proxy_iface) ++g_http_proxy_iface_init (GProxyInterface *proxy_iface, ++ gpointer iface_data) + { + proxy_iface->connect = g_http_proxy_connect; + proxy_iface->connect_async = g_http_proxy_connect_async; +diff --git a/gio/ginetaddressmask.c b/gio/ginetaddressmask.c +index 1431b94358e..ec262dcb71d 100644 +--- a/gio/ginetaddressmask.c ++++ b/gio/ginetaddressmask.c +@@ -47,7 +47,8 @@ struct _GInetAddressMaskPrivate + guint length; + }; + +-static void g_inet_address_mask_initable_iface_init (GInitableIface *iface); ++static void g_inet_address_mask_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GInetAddressMask, g_inet_address_mask, G_TYPE_OBJECT, + G_ADD_PRIVATE (GInetAddressMask) +@@ -238,7 +239,8 @@ g_inet_address_mask_initable_init (GInitable *initable, + } + + static void +-g_inet_address_mask_initable_iface_init (GInitableIface *iface) ++g_inet_address_mask_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_inet_address_mask_initable_init; + } +diff --git a/gio/ginetsocketaddress.c b/gio/ginetsocketaddress.c +index c17bd1497e1..1d705f61f58 100644 +--- a/gio/ginetsocketaddress.c ++++ b/gio/ginetsocketaddress.c +@@ -51,7 +51,8 @@ struct _GInetSocketAddressPrivate + guint32 scope_id; + }; + +-static void g_inet_socket_address_connectable_iface_init (GSocketConnectableIface *iface); ++static void g_inet_socket_address_connectable_iface_init (GSocketConnectableIface *iface, ++ gpointer iface_data); + static gchar *g_inet_socket_address_connectable_to_string (GSocketConnectable *connectable); + + G_DEFINE_TYPE_WITH_CODE (GInetSocketAddress, g_inet_socket_address, G_TYPE_SOCKET_ADDRESS, +@@ -311,7 +312,8 @@ g_inet_socket_address_class_init (GInetSocketAddressClass *klass) + } + + static void +-g_inet_socket_address_connectable_iface_init (GSocketConnectableIface *iface) ++g_inet_socket_address_connectable_iface_init (GSocketConnectableIface *iface, ++ gpointer iface_data) + { + GSocketConnectableIface *parent_iface = g_type_interface_peek_parent (iface); + +diff --git a/gio/gliststore.c b/gio/gliststore.c +index 41450f6c304..9cfa53016d0 100644 +--- a/gio/gliststore.c ++++ b/gio/gliststore.c +@@ -58,7 +58,8 @@ enum + N_PROPERTIES + }; + +-static void g_list_store_iface_init (GListModelInterface *iface); ++static void g_list_store_iface_init (GListModelInterface *iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GListStore, g_list_store, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, g_list_store_iface_init)); +@@ -219,7 +220,8 @@ g_list_store_get_item (GListModel *list, + } + + static void +-g_list_store_iface_init (GListModelInterface *iface) ++g_list_store_iface_init (GListModelInterface *iface, ++ gpointer iface_data) + { + iface->get_item_type = g_list_store_get_item_type; + iface->get_n_items = g_list_store_get_n_items; +diff --git a/gio/glocalfile.c b/gio/glocalfile.c +index 099df4d2762..35dd746d4ae 100644 +--- a/gio/glocalfile.c ++++ b/gio/glocalfile.c +@@ -102,7 +102,8 @@ + #endif + + +-static void g_local_file_file_iface_init (GFileIface *iface); ++static void g_local_file_file_iface_init (GFileIface *iface, ++ gpointer iface_data); + + static GFileAttributeInfoList *local_writable_attributes = NULL; + static GFileAttributeInfoList *local_writable_namespaces = NULL; +@@ -3060,7 +3061,8 @@ g_local_file_measure_disk_usage (GFile *file, + } + + static void +-g_local_file_file_iface_init (GFileIface *iface) ++g_local_file_file_iface_init (GFileIface *iface, ++ gpointer iface_data) + { + iface->dup = g_local_file_dup; + iface->hash = g_local_file_hash; +diff --git a/gio/glocalfileinputstream.c b/gio/glocalfileinputstream.c +index 33e848f8782..b0229f492a9 100644 +--- a/gio/glocalfileinputstream.c ++++ b/gio/glocalfileinputstream.c +@@ -53,7 +53,8 @@ struct _GLocalFileInputStreamPrivate { + }; + + #if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) +-static void g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); ++static void g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data); + #endif + + #define g_local_file_input_stream_get_type _g_local_file_input_stream_get_type +@@ -113,7 +114,8 @@ g_local_file_input_stream_class_init (GLocalFileInputStreamClass *klass) + + #if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void +-g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) ++g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data) + { + iface->get_fd = g_local_file_input_stream_get_fd; + } +diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c +index efe2e2c612d..7e0440461aa 100644 +--- a/gio/glocalfileoutputstream.c ++++ b/gio/glocalfileoutputstream.c +@@ -84,7 +84,8 @@ struct _GLocalFileOutputStreamPrivate { + }; + + #if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) +-static void g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); ++static void g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data); + #endif + + #define g_local_file_output_stream_get_type _g_local_file_output_stream_get_type +@@ -182,7 +183,8 @@ g_local_file_output_stream_class_init (GLocalFileOutputStreamClass *klass) + + #if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void +-g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) ++g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data) + { + iface->get_fd = g_local_file_output_stream_get_fd; + } +diff --git a/gio/gmemoryinputstream.c b/gio/gmemoryinputstream.c +index de164542d87..f017c37cfc5 100644 +--- a/gio/gmemoryinputstream.c ++++ b/gio/gmemoryinputstream.c +@@ -77,7 +77,8 @@ static gboolean g_memory_input_stream_close_finish (GInputStream *stream + GAsyncResult *result, + GError **error); + +-static void g_memory_input_stream_seekable_iface_init (GSeekableIface *iface); ++static void g_memory_input_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data); + static goffset g_memory_input_stream_tell (GSeekable *seekable); + static gboolean g_memory_input_stream_can_seek (GSeekable *seekable); + static gboolean g_memory_input_stream_seek (GSeekable *seekable, +@@ -91,7 +92,8 @@ static gboolean g_memory_input_stream_truncate (GSeekable *seek + GCancellable *cancellable, + GError **error); + +-static void g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface); ++static void g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface, ++ gpointer iface_data); + static gboolean g_memory_input_stream_is_readable (GPollableInputStream *stream); + static GSource *g_memory_input_stream_create_source (GPollableInputStream *stream, + GCancellable *cancellable); +@@ -142,7 +144,8 @@ g_memory_input_stream_finalize (GObject *object) + } + + static void +-g_memory_input_stream_seekable_iface_init (GSeekableIface *iface) ++g_memory_input_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data) + { + iface->tell = g_memory_input_stream_tell; + iface->can_seek = g_memory_input_stream_can_seek; +@@ -152,7 +155,8 @@ g_memory_input_stream_seekable_iface_init (GSeekableIface *iface) + } + + static void +-g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface) ++g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface, ++ gpointer iface_data) + { + iface->is_readable = g_memory_input_stream_is_readable; + iface->create_source = g_memory_input_stream_create_source; +diff --git a/gio/gmemorymonitordbus.c b/gio/gmemorymonitordbus.c +index 37542f75c6f..995b7bf9688 100644 +--- a/gio/gmemorymonitordbus.c ++++ b/gio/gmemorymonitordbus.c +@@ -33,8 +33,10 @@ + + #define G_MEMORY_MONITOR_DBUS_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable)) + +-static void g_memory_monitor_dbus_iface_init (GMemoryMonitorInterface *iface); +-static void g_memory_monitor_dbus_initable_iface_init (GInitableIface *iface); ++static void g_memory_monitor_dbus_iface_init (GMemoryMonitorInterface *iface, ++ gpointer iface_data); ++static void g_memory_monitor_dbus_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + struct _GMemoryMonitorDBus + { +@@ -176,12 +178,14 @@ g_memory_monitor_dbus_class_init (GMemoryMonitorDBusClass *nl_class) + } + + static void +-g_memory_monitor_dbus_iface_init (GMemoryMonitorInterface *monitor_iface) ++g_memory_monitor_dbus_iface_init (GMemoryMonitorInterface *monitor_iface, ++ gpointer iface_data) + { + } + + static void +-g_memory_monitor_dbus_initable_iface_init (GInitableIface *iface) ++g_memory_monitor_dbus_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_memory_monitor_dbus_initable_init; + } +diff --git a/gio/gmemorymonitorportal.c b/gio/gmemorymonitorportal.c +index 1517d61a9ff..235d45a935e 100644 +--- a/gio/gmemorymonitorportal.c ++++ b/gio/gmemorymonitorportal.c +@@ -29,8 +29,10 @@ + + #define G_MEMORY_MONITOR_PORTAL_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable)) + +-static void g_memory_monitor_portal_iface_init (GMemoryMonitorInterface *iface); +-static void g_memory_monitor_portal_initable_iface_init (GInitableIface *iface); ++static void g_memory_monitor_portal_iface_init (GMemoryMonitorInterface *iface, ++ gpointer iface_data); ++static void g_memory_monitor_portal_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + struct _GMemoryMonitorPortal + { +@@ -143,12 +145,14 @@ g_memory_monitor_portal_class_init (GMemoryMonitorPortalClass *nl_class) + } + + static void +-g_memory_monitor_portal_iface_init (GMemoryMonitorInterface *monitor_iface) ++g_memory_monitor_portal_iface_init (GMemoryMonitorInterface *monitor_iface, ++ gpointer iface_data) + { + } + + static void +-g_memory_monitor_portal_initable_iface_init (GInitableIface *iface) ++g_memory_monitor_portal_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_memory_monitor_portal_initable_init; + } +diff --git a/gio/gmemorymonitorwin32.c b/gio/gmemorymonitorwin32.c +index 83fef504fb5..36d5ff0eaa7 100644 +--- a/gio/gmemorymonitorwin32.c ++++ b/gio/gmemorymonitorwin32.c +@@ -35,8 +35,10 @@ G_DECLARE_FINAL_TYPE (GMemoryMonitorWin32, g_memory_monitor_win32, G, MEMORY_MON + + #define G_MEMORY_MONITOR_WIN32_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable)) + +-static void g_memory_monitor_win32_iface_init (GMemoryMonitorInterface *iface); +-static void g_memory_monitor_win32_initable_iface_init (GInitableIface *iface); ++static void g_memory_monitor_win32_iface_init (GMemoryMonitorInterface *iface, ++ gpointer iface_data); ++static void g_memory_monitor_win32_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + struct _GMemoryMonitorWin32 + { +@@ -252,12 +254,14 @@ g_memory_monitor_win32_class_init (GMemoryMonitorWin32Class *nl_class) + } + + static void +-g_memory_monitor_win32_iface_init (GMemoryMonitorInterface *monitor_iface) ++g_memory_monitor_win32_iface_init (GMemoryMonitorInterface *monitor_iface, ++ gpointer iface_data) + { + } + + static void +-g_memory_monitor_win32_initable_iface_init (GInitableIface *iface) ++g_memory_monitor_win32_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_memory_monitor_win32_initable_init; + } +diff --git a/gio/gmemoryoutputstream.c b/gio/gmemoryoutputstream.c +index bf080852c1d..31dcfcb468f 100644 +--- a/gio/gmemoryoutputstream.c ++++ b/gio/gmemoryoutputstream.c +@@ -96,7 +96,8 @@ static gboolean g_memory_output_stream_close_finish (GOutputStream *strea + GAsyncResult *result, + GError **error); + +-static void g_memory_output_stream_seekable_iface_init (GSeekableIface *iface); ++static void g_memory_output_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data); + static goffset g_memory_output_stream_tell (GSeekable *seekable); + static gboolean g_memory_output_stream_can_seek (GSeekable *seekable); + static gboolean g_memory_output_stream_seek (GSeekable *seekable, +@@ -114,7 +115,8 @@ static gboolean g_memory_output_stream_is_writable (GPollableOutputStream + static GSource *g_memory_output_stream_create_source (GPollableOutputStream *stream, + GCancellable *cancellable); + +-static void g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface); ++static void g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GMemoryOutputStream, g_memory_output_stream, G_TYPE_OUTPUT_STREAM, + G_ADD_PRIVATE (GMemoryOutputStream) +@@ -211,7 +213,8 @@ g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass) + } + + static void +-g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface) ++g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface, ++ gpointer iface_data) + { + iface->is_writable = g_memory_output_stream_is_writable; + iface->create_source = g_memory_output_stream_create_source; +@@ -300,7 +303,8 @@ g_memory_output_stream_finalize (GObject *object) + } + + static void +-g_memory_output_stream_seekable_iface_init (GSeekableIface *iface) ++g_memory_output_stream_seekable_iface_init (GSeekableIface *iface, ++ gpointer iface_data) + { + iface->tell = g_memory_output_stream_tell; + iface->can_seek = g_memory_output_stream_can_seek; +diff --git a/gio/gnetworkaddress.c b/gio/gnetworkaddress.c +index adff705189d..00435f0d2aa 100644 +--- a/gio/gnetworkaddress.c ++++ b/gio/gnetworkaddress.c +@@ -85,7 +85,8 @@ static void g_network_address_get_property (GObject *object, + GValue *value, + GParamSpec *pspec); + +-static void g_network_address_connectable_iface_init (GSocketConnectableIface *iface); ++static void g_network_address_connectable_iface_init (GSocketConnectableIface *iface, ++ gpointer iface_data); + static GSocketAddressEnumerator *g_network_address_connectable_enumerate (GSocketConnectable *connectable); + static GSocketAddressEnumerator *g_network_address_connectable_proxy_enumerate (GSocketConnectable *connectable); + static gchar *g_network_address_connectable_to_string (GSocketConnectable *connectable); +@@ -160,7 +161,8 @@ g_network_address_class_init (GNetworkAddressClass *klass) + } + + static void +-g_network_address_connectable_iface_init (GSocketConnectableIface *connectable_iface) ++g_network_address_connectable_iface_init (GSocketConnectableIface *connectable_iface, ++ gpointer iface_data) + { + connectable_iface->enumerate = g_network_address_connectable_enumerate; + connectable_iface->proxy_enumerate = g_network_address_connectable_proxy_enumerate; +diff --git a/gio/gnetworkmonitorbase.c b/gio/gnetworkmonitorbase.c +index 78e26344477..ab9b8830507 100644 +--- a/gio/gnetworkmonitorbase.c ++++ b/gio/gnetworkmonitorbase.c +@@ -33,8 +33,10 @@ + #include "gtask.h" + #include "glibintl.h" + +-static void g_network_monitor_base_iface_init (GNetworkMonitorInterface *iface); +-static void g_network_monitor_base_initable_iface_init (GInitableIface *iface); ++static void g_network_monitor_base_iface_init (GNetworkMonitorInterface *iface, ++ gpointer iface_data); ++static void g_network_monitor_base_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + enum + { +@@ -345,7 +347,8 @@ g_network_monitor_base_can_reach_finish (GNetworkMonitor *monitor, + } + + static void +-g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface) ++g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface, ++ gpointer iface_data) + { + monitor_iface->can_reach = g_network_monitor_base_can_reach; + monitor_iface->can_reach_async = g_network_monitor_base_can_reach_async; +@@ -367,7 +370,8 @@ g_network_monitor_base_initable_init (GInitable *initable, + } + + static void +-g_network_monitor_base_initable_iface_init (GInitableIface *iface) ++g_network_monitor_base_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_network_monitor_base_initable_init; + } +diff --git a/gio/gnetworkmonitornetlink.c b/gio/gnetworkmonitornetlink.c +index 9d4b0f9c572..64ce26e5fc2 100644 +--- a/gio/gnetworkmonitornetlink.c ++++ b/gio/gnetworkmonitornetlink.c +@@ -42,8 +42,10 @@ + #include + + static GInitableIface *initable_parent_iface; +-static void g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *iface); +-static void g_network_monitor_netlink_initable_iface_init (GInitableIface *iface); ++static void g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *iface, ++ gpointer iface_data); ++static void g_network_monitor_netlink_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + struct _GNetworkMonitorNetlinkPrivate + { +@@ -502,12 +504,14 @@ g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass *nl_class) + } + + static void +-g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *monitor_iface) ++g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *monitor_iface, ++ gpointer iface_data) + { + } + + static void +-g_network_monitor_netlink_initable_iface_init (GInitableIface *iface) ++g_network_monitor_netlink_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + initable_parent_iface = g_type_interface_peek_parent (iface); + +diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c +index 207d50d5e3d..22eea24f193 100644 +--- a/gio/gnetworkmonitornm.c ++++ b/gio/gnetworkmonitornm.c +@@ -34,8 +34,10 @@ + #include "gnetworkmonitor.h" + #include "gdbusproxy.h" + +-static void g_network_monitor_nm_iface_init (GNetworkMonitorInterface *iface); +-static void g_network_monitor_nm_initable_iface_init (GInitableIface *iface); ++static void g_network_monitor_nm_iface_init (GNetworkMonitorInterface *iface, ++ gpointer iface_data); ++static void g_network_monitor_nm_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + enum + { +@@ -365,12 +367,14 @@ g_network_monitor_nm_class_init (GNetworkMonitorNMClass *nl_class) + } + + static void +-g_network_monitor_nm_iface_init (GNetworkMonitorInterface *monitor_iface) ++g_network_monitor_nm_iface_init (GNetworkMonitorInterface *monitor_iface, ++ gpointer iface_data) + { + } + + static void +-g_network_monitor_nm_initable_iface_init (GInitableIface *iface) ++g_network_monitor_nm_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_network_monitor_nm_initable_init; + } +diff --git a/gio/gnetworkmonitorportal.c b/gio/gnetworkmonitorportal.c +index f48d3e6f03b..36389383cd8 100644 +--- a/gio/gnetworkmonitorportal.c ++++ b/gio/gnetworkmonitorportal.c +@@ -27,8 +27,10 @@ + #include "gportalsupport.h" + + static GInitableIface *initable_parent_iface; +-static void g_network_monitor_portal_iface_init (GNetworkMonitorInterface *iface); +-static void g_network_monitor_portal_initable_iface_init (GInitableIface *iface); ++static void g_network_monitor_portal_iface_init (GNetworkMonitorInterface *iface, ++ gpointer iface_data); ++static void g_network_monitor_portal_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + enum + { +@@ -613,7 +615,8 @@ g_network_monitor_portal_can_reach_finish (GNetworkMonitor *monitor, + } + + static void +-g_network_monitor_portal_iface_init (GNetworkMonitorInterface *monitor_iface) ++g_network_monitor_portal_iface_init (GNetworkMonitorInterface *monitor_iface, ++ gpointer iface_data) + { + monitor_iface->can_reach = g_network_monitor_portal_can_reach; + monitor_iface->can_reach_async = g_network_monitor_portal_can_reach_async; +@@ -621,7 +624,8 @@ g_network_monitor_portal_iface_init (GNetworkMonitorInterface *monitor_iface) + } + + static void +-g_network_monitor_portal_initable_iface_init (GInitableIface *iface) ++g_network_monitor_portal_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + initable_parent_iface = g_type_interface_peek_parent (iface); + +diff --git a/gio/gnetworkservice.c b/gio/gnetworkservice.c +index 39c9df1b963..069557010da 100644 +--- a/gio/gnetworkservice.c ++++ b/gio/gnetworkservice.c +@@ -79,7 +79,8 @@ static void g_network_service_get_property (GObject *object, + GValue *value, + GParamSpec *pspec); + +-static void g_network_service_connectable_iface_init (GSocketConnectableIface *iface); ++static void g_network_service_connectable_iface_init (GSocketConnectableIface *iface, ++ gpointer iface_data); + static GSocketAddressEnumerator *g_network_service_connectable_enumerate (GSocketConnectable *connectable); + static GSocketAddressEnumerator *g_network_service_connectable_proxy_enumerate (GSocketConnectable *connectable); + static gchar *g_network_service_connectable_to_string (GSocketConnectable *connectable); +@@ -172,7 +173,8 @@ g_network_service_class_init (GNetworkServiceClass *klass) + } + + static void +-g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_iface) ++g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_iface, ++ gpointer iface_data) + { + connectable_iface->enumerate = g_network_service_connectable_enumerate; + connectable_iface->proxy_enumerate = g_network_service_connectable_proxy_enumerate; +diff --git a/gio/gosxappinfo.m b/gio/gosxappinfo.m +index 50b08e0be9b..9b587d92acd 100644 +--- a/gio/gosxappinfo.m ++++ b/gio/gosxappinfo.m +@@ -41,7 +41,8 @@ + * Note that `` is unique to OSX. + */ + +-static void g_osx_app_info_iface_init (GAppInfoIface *iface); ++static void g_osx_app_info_iface_init (GAppInfoIface *iface, ++ gpointer iface_data); + static const char *g_osx_app_info_get_id (GAppInfo *appinfo); + + struct _GOsxAppInfo +@@ -550,7 +551,8 @@ + } + + static void +-g_osx_app_info_iface_init (GAppInfoIface *iface) ++g_osx_app_info_iface_init (GAppInfoIface *iface, ++ gpointer iface_data) + { + iface->dup = g_osx_app_info_dup; + iface->equal = g_osx_app_info_equal; +diff --git a/gio/gpowerprofilemonitordbus.c b/gio/gpowerprofilemonitordbus.c +index ac6f8a88c7a..ffd66d5ed9f 100644 +--- a/gio/gpowerprofilemonitordbus.c ++++ b/gio/gpowerprofilemonitordbus.c +@@ -34,8 +34,10 @@ + + #define G_POWER_PROFILE_MONITOR_DBUS_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable)) + +-static void g_power_profile_monitor_dbus_iface_init (GPowerProfileMonitorInterface *iface); +-static void g_power_profile_monitor_dbus_initable_iface_init (GInitableIface *iface); ++static void g_power_profile_monitor_dbus_iface_init (GPowerProfileMonitorInterface *iface, ++ gpointer iface_data); ++static void g_power_profile_monitor_dbus_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + struct _GPowerProfileMonitorDBus + { +@@ -233,12 +235,14 @@ g_power_profile_monitor_dbus_class_init (GPowerProfileMonitorDBusClass *nl_class + } + + static void +-g_power_profile_monitor_dbus_iface_init (GPowerProfileMonitorInterface *monitor_iface) ++g_power_profile_monitor_dbus_iface_init (GPowerProfileMonitorInterface *monitor_iface, ++ gpointer iface_data) + { + } + + static void +-g_power_profile_monitor_dbus_initable_iface_init (GInitableIface *iface) ++g_power_profile_monitor_dbus_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_power_profile_monitor_dbus_initable_init; + } +diff --git a/gio/gpowerprofilemonitorportal.c b/gio/gpowerprofilemonitorportal.c +index 0c69ed9b522..3ba794aeeed 100644 +--- a/gio/gpowerprofilemonitorportal.c ++++ b/gio/gpowerprofilemonitorportal.c +@@ -31,8 +31,10 @@ + + #define G_POWER_PROFILE_MONITOR_PORTAL_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable)) + +-static void g_power_profile_monitor_portal_iface_init (GPowerProfileMonitorInterface *iface); +-static void g_power_profile_monitor_portal_initable_iface_init (GInitableIface *iface); ++static void g_power_profile_monitor_portal_iface_init (GPowerProfileMonitorInterface *iface, ++ gpointer iface_data); ++static void g_power_profile_monitor_portal_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + typedef enum + { +@@ -180,12 +182,14 @@ g_power_profile_monitor_portal_class_init (GPowerProfileMonitorPortalClass *nl_c + } + + static void +-g_power_profile_monitor_portal_iface_init (GPowerProfileMonitorInterface *monitor_iface) ++g_power_profile_monitor_portal_iface_init (GPowerProfileMonitorInterface *monitor_iface, ++ gpointer iface_data) + { + } + + static void +-g_power_profile_monitor_portal_initable_iface_init (GInitableIface *iface) ++g_power_profile_monitor_portal_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_power_profile_monitor_portal_initable_init; + } +diff --git a/gio/gpropertyaction.c b/gio/gpropertyaction.c +index 6b671f54bf5..61a0f045888 100644 +--- a/gio/gpropertyaction.c ++++ b/gio/gpropertyaction.c +@@ -98,7 +98,8 @@ struct _GPropertyAction + + typedef GObjectClass GPropertyActionClass; + +-static void g_property_action_iface_init (GActionInterface *iface); ++static void g_property_action_iface_init (GActionInterface *iface, ++ gpointer iface_data); + G_DEFINE_TYPE_WITH_CODE (GPropertyAction, g_property_action, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, g_property_action_iface_init)) + +@@ -437,7 +438,8 @@ g_property_action_init (GPropertyAction *property) + } + + void +-g_property_action_iface_init (GActionInterface *iface) ++g_property_action_iface_init (GActionInterface *iface, ++ gpointer iface_data) + { + iface->get_name = g_property_action_get_name; + iface->get_parameter_type = g_property_action_get_parameter_type; +diff --git a/gio/gproxyresolverportal.c b/gio/gproxyresolverportal.c +index ec803b9c412..a25e6e8ccb1 100644 +--- a/gio/gproxyresolverportal.c ++++ b/gio/gproxyresolverportal.c +@@ -33,7 +33,8 @@ struct _GProxyResolverPortal { + gboolean network_available; + }; + +-static void g_proxy_resolver_portal_iface_init (GProxyResolverInterface *iface); ++static void g_proxy_resolver_portal_iface_init (GProxyResolverInterface *iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GProxyResolverPortal, g_proxy_resolver_portal, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER, +@@ -201,7 +202,8 @@ g_proxy_resolver_portal_class_init (GProxyResolverPortalClass *resolver_class) + } + + static void +-g_proxy_resolver_portal_iface_init (GProxyResolverInterface *iface) ++g_proxy_resolver_portal_iface_init (GProxyResolverInterface *iface, ++ gpointer iface_data) + { + iface->is_supported = g_proxy_resolver_portal_is_supported; + iface->lookup = g_proxy_resolver_portal_lookup; +diff --git a/gio/gresourcefile.c b/gio/gresourcefile.c +index 6066ae2151e..6efe0550016 100644 +--- a/gio/gresourcefile.c ++++ b/gio/gresourcefile.c +@@ -68,7 +68,8 @@ struct _GResourceFileEnumeratorClass + typedef struct _GResourceFileEnumerator GResourceFileEnumerator; + typedef struct _GResourceFileEnumeratorClass GResourceFileEnumeratorClass; + +-static void g_resource_file_file_iface_init (GFileIface *iface); ++static void g_resource_file_file_iface_init (GFileIface *iface, ++ gpointer iface_data); + + static GFileAttributeInfoList *resource_writable_attributes = NULL; + static GFileAttributeInfoList *resource_writable_namespaces = NULL; +@@ -667,7 +668,8 @@ g_resource_file_set_display_name (GFile *file, + } + + static void +-g_resource_file_file_iface_init (GFileIface *iface) ++g_resource_file_file_iface_init (GFileIface *iface, ++ gpointer iface_data) + { + iface->dup = g_resource_file_dup; + iface->hash = g_resource_file_hash; +diff --git a/gio/gsettings.c b/gio/gsettings.c +index a14ba809481..9f4ae47fb5e 100644 +--- a/gio/gsettings.c ++++ b/gio/gsettings.c +@@ -3142,7 +3142,8 @@ typedef struct + typedef GObjectClass GSettingsActionClass; + + static GType g_settings_action_get_type (void); +-static void g_settings_action_iface_init (GActionInterface *iface); ++static void g_settings_action_iface_init (GActionInterface *iface, ++ gpointer iface_data); + G_DEFINE_TYPE_WITH_CODE (GSettingsAction, g_settings_action, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, g_settings_action_iface_init)) + +@@ -3299,7 +3300,8 @@ g_settings_action_init (GSettingsAction *gsa) + } + + static void +-g_settings_action_iface_init (GActionInterface *iface) ++g_settings_action_iface_init (GActionInterface *iface, ++ gpointer iface_data) + { + iface->get_name = g_settings_action_get_name; + iface->get_parameter_type = g_settings_action_get_parameter_type; +diff --git a/gio/gsimpleaction.c b/gio/gsimpleaction.c +index 6e3080bec97..de2524f05bd 100644 +--- a/gio/gsimpleaction.c ++++ b/gio/gsimpleaction.c +@@ -48,7 +48,8 @@ struct _GSimpleAction + + typedef GObjectClass GSimpleActionClass; + +-static void g_simple_action_iface_init (GActionInterface *iface); ++static void g_simple_action_iface_init (GActionInterface *iface, ++ gpointer iface_data); + G_DEFINE_TYPE_WITH_CODE (GSimpleAction, g_simple_action, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, g_simple_action_iface_init)) + +@@ -337,7 +338,8 @@ g_simple_action_init (GSimpleAction *simple) + } + + void +-g_simple_action_iface_init (GActionInterface *iface) ++g_simple_action_iface_init (GActionInterface *iface, ++ gpointer iface_data) + { + iface->get_name = g_simple_action_get_name; + iface->get_parameter_type = g_simple_action_get_parameter_type; +diff --git a/gio/gsimpleactiongroup.c b/gio/gsimpleactiongroup.c +index cd768a0a1af..3ebc01b192d 100644 +--- a/gio/gsimpleactiongroup.c ++++ b/gio/gsimpleactiongroup.c +@@ -42,8 +42,10 @@ struct _GSimpleActionGroupPrivate + GHashTable *table; /* string -> GAction */ + }; + +-static void g_simple_action_group_iface_init (GActionGroupInterface *); +-static void g_simple_action_group_map_iface_init (GActionMapInterface *); ++static void g_simple_action_group_iface_init (GActionGroupInterface *iface, ++ gpointer iface_data); ++static void g_simple_action_group_map_iface_init (GActionMapInterface *iface, ++ gpointer iface_data); + G_DEFINE_TYPE_WITH_CODE (GSimpleActionGroup, + g_simple_action_group, G_TYPE_OBJECT, + G_ADD_PRIVATE (GSimpleActionGroup) +@@ -274,7 +276,8 @@ g_simple_action_group_class_init (GSimpleActionGroupClass *class) + } + + static void +-g_simple_action_group_iface_init (GActionGroupInterface *iface) ++g_simple_action_group_iface_init (GActionGroupInterface *iface, ++ gpointer iface_data) + { + iface->list_actions = g_simple_action_group_list_actions; + iface->query_action = g_simple_action_group_query_action; +@@ -283,7 +286,8 @@ g_simple_action_group_iface_init (GActionGroupInterface *iface) + } + + static void +-g_simple_action_group_map_iface_init (GActionMapInterface *iface) ++g_simple_action_group_map_iface_init (GActionMapInterface *iface, ++ gpointer iface_data) + { + iface->add_action = g_simple_action_group_add_action; + iface->remove_action = g_simple_action_group_remove_action; +diff --git a/gio/gsimpleasyncresult.c b/gio/gsimpleasyncresult.c +index ef5492f8e9e..2ce78569854 100644 +--- a/gio/gsimpleasyncresult.c ++++ b/gio/gsimpleasyncresult.c +@@ -205,7 +205,8 @@ + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + +-static void g_simple_async_result_async_result_iface_init (GAsyncResultIface *iface); ++static void g_simple_async_result_async_result_iface_init (GAsyncResultIface *iface, ++ gpointer iface_data); + + struct _GSimpleAsyncResult + { +@@ -464,7 +465,8 @@ g_simple_async_result_is_tagged (GAsyncResult *res, + } + + static void +-g_simple_async_result_async_result_iface_init (GAsyncResultIface *iface) ++g_simple_async_result_async_result_iface_init (GAsyncResultIface *iface, ++ gpointer iface_data) + { + iface->get_user_data = g_simple_async_result_get_user_data; + iface->get_source_object = g_simple_async_result_get_source_object; +diff --git a/gio/gsimpleproxyresolver.c b/gio/gsimpleproxyresolver.c +index 41136527f05..33669d44bbe 100644 +--- a/gio/gsimpleproxyresolver.c ++++ b/gio/gsimpleproxyresolver.c +@@ -61,7 +61,8 @@ struct _GSimpleProxyResolverPrivate { + GSimpleProxyResolverDomain *ignore_domains; + }; + +-static void g_simple_proxy_resolver_iface_init (GProxyResolverInterface *iface); ++static void g_simple_proxy_resolver_iface_init (GProxyResolverInterface *iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GSimpleProxyResolver, g_simple_proxy_resolver, G_TYPE_OBJECT, + G_ADD_PRIVATE (GSimpleProxyResolver) +@@ -477,7 +478,8 @@ g_simple_proxy_resolver_class_init (GSimpleProxyResolverClass *resolver_class) + } + + static void +-g_simple_proxy_resolver_iface_init (GProxyResolverInterface *iface) ++g_simple_proxy_resolver_iface_init (GProxyResolverInterface *iface, ++ gpointer iface_data) + { + iface->lookup = g_simple_proxy_resolver_lookup; + iface->lookup_async = g_simple_proxy_resolver_lookup_async; +diff --git a/gio/gsocket.c b/gio/gsocket.c +index 58bbe5c77ac..84d60ae6c00 100644 +--- a/gio/gsocket.c ++++ b/gio/gsocket.c +@@ -159,12 +159,14 @@ + * Since: 2.22 + */ + +-static void g_socket_initable_iface_init (GInitableIface *iface); ++static void g_socket_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + static gboolean g_socket_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error); + +-static void g_socket_datagram_based_iface_init (GDatagramBasedInterface *iface); ++static void g_socket_datagram_based_iface_init (GDatagramBasedInterface *iface, ++ gpointer iface_data); + static gint g_socket_datagram_based_receive_messages (GDatagramBased *self, + GInputMessage *messages, + guint num_messages, +@@ -1169,13 +1171,15 @@ g_socket_class_init (GSocketClass *klass) + } + + static void +-g_socket_initable_iface_init (GInitableIface *iface) ++g_socket_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_socket_initable_init; + } + + static void +-g_socket_datagram_based_iface_init (GDatagramBasedInterface *iface) ++g_socket_datagram_based_iface_init (GDatagramBasedInterface *iface, ++ gpointer iface_data) + { + iface->receive_messages = g_socket_datagram_based_receive_messages; + iface->send_messages = g_socket_datagram_based_send_messages; +diff --git a/gio/gsocketaddress.c b/gio/gsocketaddress.c +index 09cb9abbe95..8d46fbd7e1e 100644 +--- a/gio/gsocketaddress.c ++++ b/gio/gsocketaddress.c +@@ -59,7 +59,8 @@ enum + PROP_FAMILY + }; + +-static void g_socket_address_connectable_iface_init (GSocketConnectableIface *iface); ++static void g_socket_address_connectable_iface_init (GSocketConnectableIface *iface, ++ gpointer iface_data); + static GSocketAddressEnumerator *g_socket_address_connectable_enumerate (GSocketConnectable *connectable); + static GSocketAddressEnumerator *g_socket_address_connectable_proxy_enumerate (GSocketConnectable *connectable); + +@@ -125,7 +126,8 @@ g_socket_address_class_init (GSocketAddressClass *klass) + } + + static void +-g_socket_address_connectable_iface_init (GSocketConnectableIface *connectable_iface) ++g_socket_address_connectable_iface_init (GSocketConnectableIface *connectable_iface, ++ gpointer iface_data) + { + connectable_iface->enumerate = g_socket_address_connectable_enumerate; + connectable_iface->proxy_enumerate = g_socket_address_connectable_proxy_enumerate; +diff --git a/gio/gsocketinputstream.c b/gio/gsocketinputstream.c +index fbfbb641bb0..81fa563f88e 100644 +--- a/gio/gsocketinputstream.c ++++ b/gio/gsocketinputstream.c +@@ -41,9 +41,11 @@ struct _GSocketInputStreamPrivate + gsize count; + }; + +-static void g_socket_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface); ++static void g_socket_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface, ++ gpointer iface_data); + #if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) +-static void g_socket_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); ++static void g_socket_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data); + #endif + + #define g_socket_input_stream_get_type _g_socket_input_stream_get_type +@@ -198,14 +200,16 @@ g_socket_input_stream_class_init (GSocketInputStreamClass *klass) + + #if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void +-g_socket_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) ++g_socket_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data) + { + iface->get_fd = g_socket_input_stream_get_fd; + } + #endif + + static void +-g_socket_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface) ++g_socket_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface, ++ gpointer iface_data) + { + iface->is_readable = g_socket_input_stream_pollable_is_readable; + iface->create_source = g_socket_input_stream_pollable_create_source; +diff --git a/gio/gsocketoutputstream.c b/gio/gsocketoutputstream.c +index 36ea413c165..a2d8a46b22f 100644 +--- a/gio/gsocketoutputstream.c ++++ b/gio/gsocketoutputstream.c +@@ -46,9 +46,11 @@ struct _GSocketOutputStreamPrivate + gsize count; + }; + +-static void g_socket_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface); ++static void g_socket_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface, ++ gpointer iface_data); + #if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) +-static void g_socket_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); ++static void g_socket_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data); + #endif + + #define g_socket_output_stream_get_type _g_socket_output_stream_get_type +@@ -254,14 +256,16 @@ g_socket_output_stream_class_init (GSocketOutputStreamClass *klass) + + #if defined(G_OS_UNIX) && !defined(G_PLATFORM_WASM) + static void +-g_socket_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) ++g_socket_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data) + { + iface->get_fd = g_socket_output_stream_get_fd; + } + #endif + + static void +-g_socket_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface) ++g_socket_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface, ++ gpointer iface_data) + { + iface->is_writable = g_socket_output_stream_pollable_is_writable; + iface->create_source = g_socket_output_stream_pollable_create_source; +diff --git a/gio/gsocks4aproxy.c b/gio/gsocks4aproxy.c +index 3dad118eb78..e4a1306e689 100644 +--- a/gio/gsocks4aproxy.c ++++ b/gio/gsocks4aproxy.c +@@ -50,7 +50,8 @@ + #define SOCKS4_REP_NO_IDENT 92 + #define SOCKS4_REP_BAD_IDENT 93 + +-static void g_socks4a_proxy_iface_init (GProxyInterface *proxy_iface); ++static void g_socks4a_proxy_iface_init (GProxyInterface *proxy_iface, ++ gpointer iface_data); + + #define g_socks4a_proxy_get_type _g_socks4a_proxy_get_type + G_DEFINE_TYPE_WITH_CODE (GSocks4aProxy, g_socks4a_proxy, G_TYPE_OBJECT, +@@ -451,7 +452,8 @@ g_socks4a_proxy_class_init (GSocks4aProxyClass *class) + } + + static void +-g_socks4a_proxy_iface_init (GProxyInterface *proxy_iface) ++g_socks4a_proxy_iface_init (GProxyInterface *proxy_iface, ++ gpointer iface_data) + { + proxy_iface->connect = g_socks4a_proxy_connect; + proxy_iface->connect_async = g_socks4a_proxy_connect_async; +diff --git a/gio/gsocks5proxy.c b/gio/gsocks5proxy.c +index 71ac107dafb..73640c4b71f 100644 +--- a/gio/gsocks5proxy.c ++++ b/gio/gsocks5proxy.c +@@ -82,7 +82,8 @@ struct _GSocks5ProxyClass + GObjectClass parent_class; + }; + +-static void g_socks5_proxy_iface_init (GProxyInterface *proxy_iface); ++static void g_socks5_proxy_iface_init (GProxyInterface *proxy_iface, ++ gpointer iface_data); + + #define g_socks5_proxy_get_type _g_socks5_proxy_get_type + G_DEFINE_TYPE_WITH_CODE (GSocks5Proxy, g_socks5_proxy, G_TYPE_OBJECT, +@@ -1101,7 +1102,8 @@ g_socks5_proxy_class_init (GSocks5ProxyClass *class) + } + + static void +-g_socks5_proxy_iface_init (GProxyInterface *proxy_iface) ++g_socks5_proxy_iface_init (GProxyInterface *proxy_iface, ++ gpointer iface_data) + { + proxy_iface->connect = g_socks5_proxy_connect; + proxy_iface->connect_async = g_socks5_proxy_connect_async; +diff --git a/gio/gsubprocess.c b/gio/gsubprocess.c +index 8a6bd06b14c..5ef4a269624 100644 +--- a/gio/gsubprocess.c ++++ b/gio/gsubprocess.c +@@ -149,7 +149,8 @@ + * via the worker thread so that we don't race with waitpid() and + * accidentally send a signal to an already-reaped child. + */ +-static void initable_iface_init (GInitableIface *initable_iface); ++static void initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data); + + typedef GObjectClass GSubprocessClass; + +@@ -495,7 +496,8 @@ g_subprocess_init (GSubprocess *self) + } + + static void +-initable_iface_init (GInitableIface *initable_iface) ++initable_iface_init (GInitableIface *initable_iface, ++ gpointer iface_data) + { + initable_iface->init = initable_init; + } +diff --git a/gio/gtask.c b/gio/gtask.c +index e6815e2d05d..f2633a54a9d 100644 +--- a/gio/gtask.c ++++ b/gio/gtask.c +@@ -623,7 +623,8 @@ typedef enum + PROP_COMPLETED = 1, + } GTaskProperty; + +-static void g_task_async_result_iface_init (GAsyncResultIface *iface); ++static void g_task_async_result_iface_init (GAsyncResultIface *iface, ++ gpointer iface_data); + static void g_task_thread_pool_init (void); + + G_DEFINE_TYPE_WITH_CODE (GTask, g_task, G_TYPE_OBJECT, +@@ -2503,7 +2504,8 @@ g_task_is_tagged (GAsyncResult *res, + } + + static void +-g_task_async_result_iface_init (GAsyncResultIface *iface) ++g_task_async_result_iface_init (GAsyncResultIface *iface, ++ gpointer iface_data) + { + iface->get_user_data = g_task_get_user_data; + iface->get_source_object = g_task_ref_source_object; +diff --git a/gio/gthemedicon.c b/gio/gthemedicon.c +index 1d6aacdf198..1efc5123ca4 100644 +--- a/gio/gthemedicon.c ++++ b/gio/gthemedicon.c +@@ -44,7 +44,8 @@ + * themes that inherit other themes. + **/ + +-static void g_themed_icon_icon_iface_init (GIconIface *iface); ++static void g_themed_icon_icon_iface_init (GIconIface *iface, ++ gpointer iface_data); + + struct _GThemedIcon + { +@@ -613,7 +614,8 @@ g_themed_icon_serialize (GIcon *icon) + } + + static void +-g_themed_icon_icon_iface_init (GIconIface *iface) ++g_themed_icon_icon_iface_init (GIconIface *iface, ++ gpointer iface_data) + { + iface->hash = g_themed_icon_hash; + iface->equal = g_themed_icon_equal; +diff --git a/gio/gunixinputstream.c b/gio/gunixinputstream.c +index 210decd67f1..13560798316 100644 +--- a/gio/gunixinputstream.c ++++ b/gio/gunixinputstream.c +@@ -64,8 +64,10 @@ struct _GUnixInputStreamPrivate { + guint can_poll : 1; + }; + +-static void g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface); +-static void g_unix_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); ++static void g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface, ++ gpointer iface_data); ++static void g_unix_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GUnixInputStream, g_unix_input_stream, G_TYPE_INPUT_STREAM, + G_ADD_PRIVATE (GUnixInputStream) +@@ -152,7 +154,8 @@ g_unix_input_stream_class_init (GUnixInputStreamClass *klass) + } + + static void +-g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface) ++g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface, ++ gpointer iface_data) + { + iface->can_poll = g_unix_input_stream_pollable_can_poll; + iface->is_readable = g_unix_input_stream_pollable_is_readable; +@@ -160,7 +163,8 @@ g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface) + } + + static void +-g_unix_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) ++g_unix_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data) + { + iface->get_fd = (int (*) (GFileDescriptorBased *))g_unix_input_stream_get_fd; + } +diff --git a/gio/gunixmount.c b/gio/gunixmount.c +index ec6c57353b7..a4764389227 100644 +--- a/gio/gunixmount.c ++++ b/gio/gunixmount.c +@@ -63,7 +63,8 @@ struct _GUnixMount { + gboolean can_eject; + }; + +-static void g_unix_mount_mount_iface_init (GMountIface *iface); ++static void g_unix_mount_mount_iface_init (GMountIface *iface, ++ gpointer iface_data); + + #define g_unix_mount_get_type _g_unix_mount_get_type + G_DEFINE_TYPE_WITH_CODE (GUnixMount, g_unix_mount, G_TYPE_OBJECT, +@@ -379,7 +380,8 @@ g_unix_mount_eject_finish (GMount *mount, + } + + static void +-g_unix_mount_mount_iface_init (GMountIface *iface) ++g_unix_mount_mount_iface_init (GMountIface *iface, ++ gpointer iface_data) + { + iface->get_root = g_unix_mount_get_root; + iface->get_name = g_unix_mount_get_name; +diff --git a/gio/gunixoutputstream.c b/gio/gunixoutputstream.c +index 96d9e952ee8..63fc280f02c 100644 +--- a/gio/gunixoutputstream.c ++++ b/gio/gunixoutputstream.c +@@ -66,8 +66,10 @@ struct _GUnixOutputStreamPrivate { + guint can_poll : 1; + }; + +-static void g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface); +-static void g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface); ++static void g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface, ++ gpointer iface_data); ++static void g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data); + + G_DEFINE_TYPE_WITH_CODE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM, + G_ADD_PRIVATE (GUnixOutputStream) +@@ -151,7 +153,8 @@ g_unix_output_stream_class_init (GUnixOutputStreamClass *klass) + } + + static void +-g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface) ++g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface, ++ gpointer iface_data) + { + iface->can_poll = g_unix_output_stream_pollable_can_poll; + iface->is_writable = g_unix_output_stream_pollable_is_writable; +@@ -160,7 +163,8 @@ g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface) + } + + static void +-g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface) ++g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface, ++ gpointer iface_data) + { + iface->get_fd = (int (*) (GFileDescriptorBased *))g_unix_output_stream_get_fd; + } +diff --git a/gio/gunixsocketaddress.c b/gio/gunixsocketaddress.c +index 3d1a26e1e08..c2c3d85616c 100644 +--- a/gio/gunixsocketaddress.c ++++ b/gio/gunixsocketaddress.c +@@ -80,7 +80,8 @@ struct _GUnixSocketAddressPrivate + GUnixSocketAddressType address_type; + }; + +-static void g_unix_socket_address_connectable_iface_init (GSocketConnectableIface *iface); ++static void g_unix_socket_address_connectable_iface_init (GSocketConnectableIface *iface, ++ gpointer iface_data); + static gchar *g_unix_socket_address_connectable_to_string (GSocketConnectable *connectable); + + G_DEFINE_TYPE_WITH_CODE (GUnixSocketAddress, g_unix_socket_address, G_TYPE_SOCKET_ADDRESS, +@@ -329,7 +330,8 @@ g_unix_socket_address_class_init (GUnixSocketAddressClass *klass) + } + + static void +-g_unix_socket_address_connectable_iface_init (GSocketConnectableIface *iface) ++g_unix_socket_address_connectable_iface_init (GSocketConnectableIface *iface, ++ gpointer iface_data) + { + GSocketConnectableIface *parent_iface = g_type_interface_peek_parent (iface); + +diff --git a/gio/gunixvolume.c b/gio/gunixvolume.c +index 67374570b7c..0862c3c3b95 100644 +--- a/gio/gunixvolume.c ++++ b/gio/gunixvolume.c +@@ -61,7 +61,8 @@ struct _GUnixVolume { + GIcon *symbolic_icon; + }; + +-static void g_unix_volume_volume_iface_init (GVolumeIface *iface); ++static void g_unix_volume_volume_iface_init (GVolumeIface *iface, ++ gpointer iface_data); + + #define g_unix_volume_get_type _g_unix_volume_get_type + G_DEFINE_TYPE_WITH_CODE (GUnixVolume, g_unix_volume, G_TYPE_OBJECT, +@@ -421,7 +422,8 @@ g_unix_volume_enumerate_identifiers (GVolume *volume) + } + + static void +-g_unix_volume_volume_iface_init (GVolumeIface *iface) ++g_unix_volume_volume_iface_init (GVolumeIface *iface, ++ gpointer iface_data) + { + iface->get_name = g_unix_volume_get_name; + iface->get_icon = g_unix_volume_get_icon; +diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c +index f177878466a..c30e1942d42 100644 +--- a/gio/gwin32appinfo.c ++++ b/gio/gwin32appinfo.c +@@ -4059,7 +4059,8 @@ gio_win32_appinfo_init (gboolean do_wait) + } + + +-static void g_win32_app_info_iface_init (GAppInfoIface *iface); ++static void g_win32_app_info_iface_init (GAppInfoIface *iface, ++ gpointer iface_data); + + struct _GWin32AppInfo + { +@@ -5724,7 +5725,8 @@ g_app_info_create_from_commandline (const char *commandline, + /* GAppInfo interface init */ + + static void +-g_win32_app_info_iface_init (GAppInfoIface *iface) ++g_win32_app_info_iface_init (GAppInfoIface *iface, ++ gpointer iface_data) + { + iface->dup = g_win32_app_info_dup; + iface->equal = g_win32_app_info_equal; +diff --git a/gio/gwin32mount.c b/gio/gwin32mount.c +index 98560259b77..9a495d2c3e1 100644 +--- a/gio/gwin32mount.c ++++ b/gio/gwin32mount.c +@@ -97,7 +97,8 @@ struct _GWin32Mount { + gboolean can_eject; + }; + +-static void g_win32_mount_mount_iface_init (GMountIface *iface); ++static void g_win32_mount_mount_iface_init (GMountIface *iface, ++ gpointer iface_data) + + #define g_win32_mount_get_type _g_win32_mount_get_type + G_DEFINE_TYPE_WITH_CODE (GWin32Mount, g_win32_mount, G_TYPE_OBJECT, +@@ -525,7 +526,8 @@ g_win32_mount_eject_finish (GMount *mount, + } + + static void +-g_win32_mount_mount_iface_init (GMountIface *iface) ++g_win32_mount_mount_iface_init (GMountIface *iface, ++ gpointer iface_data) + { + iface->get_root = g_win32_mount_get_root; + iface->get_name = g_win32_mount_get_name; +diff --git a/gio/gwin32networkmonitor.c b/gio/gwin32networkmonitor.c +index e219225f0bd..836cfee06a6 100644 +--- a/gio/gwin32networkmonitor.c ++++ b/gio/gwin32networkmonitor.c +@@ -46,8 +46,10 @@ + #include "gioerror.h" + + static GInitableIface *initable_parent_iface; +-static void g_win32_network_monitor_iface_init (GNetworkMonitorInterface *iface); +-static void g_win32_network_monitor_initable_iface_init (GInitableIface *iface); ++static void g_win32_network_monitor_iface_init (GNetworkMonitorInterface *iface, ++ gpointer iface_data); ++static void g_win32_network_monitor_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + + struct _GWin32NetworkMonitorPrivate + { +@@ -328,12 +330,14 @@ g_win32_network_monitor_class_init (GWin32NetworkMonitorClass *win_class) + } + + static void +-g_win32_network_monitor_iface_init (GNetworkMonitorInterface *monitor_iface) ++g_win32_network_monitor_iface_init (GNetworkMonitorInterface *monitor_iface, ++ gpointer iface_data) + { + } + + static void +-g_win32_network_monitor_initable_iface_init (GInitableIface *iface) ++g_win32_network_monitor_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + initable_parent_iface = g_type_interface_peek_parent (iface); + +diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c +index bd83b38b5ec..bcc19cd7b84 100644 +--- a/gio/gwin32registrykey.c ++++ b/gio/gwin32registrykey.c +@@ -432,7 +432,8 @@ struct _GWin32RegistryKeyPrivate { + gpointer user_data; + }; + +-static void g_win32_registry_key_initable_iface_init (GInitableIface *iface); ++static void g_win32_registry_key_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data); + static gboolean g_win32_registry_key_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error); +@@ -539,7 +540,8 @@ g_win32_registry_key_new_w (const gunichar2 *path, + } + + static void +-g_win32_registry_key_initable_iface_init (GInitableIface *iface) ++g_win32_registry_key_initable_iface_init (GInitableIface *iface, ++ gpointer iface_data) + { + iface->init = g_win32_registry_key_initable_init; + } +diff --git a/gio/gzlibcompressor.c b/gio/gzlibcompressor.c +index 00bde8fe2f8..99e1c712527 100644 +--- a/gio/gzlibcompressor.c ++++ b/gio/gzlibcompressor.c +@@ -49,7 +49,8 @@ enum { + * compresses data using zlib. + */ + +-static void g_zlib_compressor_iface_init (GConverterIface *iface); ++static void g_zlib_compressor_iface_init (GConverterIface *iface, ++ gpointer iface_data); + + struct _GZlibCompressor + { +@@ -434,7 +435,8 @@ g_zlib_compressor_convert (GConverter *converter, + } + + static void +-g_zlib_compressor_iface_init (GConverterIface *iface) ++g_zlib_compressor_iface_init (GConverterIface *iface, ++ gpointer iface_data) + { + iface->convert = g_zlib_compressor_convert; + iface->reset = g_zlib_compressor_reset; +diff --git a/gio/gzlibdecompressor.c b/gio/gzlibdecompressor.c +index dbe126d3c67..0b114ec6ebc 100644 +--- a/gio/gzlibdecompressor.c ++++ b/gio/gzlibdecompressor.c +@@ -48,7 +48,8 @@ enum { + * decompresses data compressed with zlib. + */ + +-static void g_zlib_decompressor_iface_init (GConverterIface *iface); ++static void g_zlib_decompressor_iface_init (GConverterIface *iface, ++ gpointer iface_data); + + typedef struct { + gz_header gzheader; +@@ -407,7 +408,8 @@ g_zlib_decompressor_convert (GConverter *converter, + } + + static void +-g_zlib_decompressor_iface_init (GConverterIface *iface) ++g_zlib_decompressor_iface_init (GConverterIface *iface, ++ gpointer iface_data) + { + iface->convert = g_zlib_decompressor_convert; + iface->reset = g_zlib_decompressor_reset; +diff --git a/gio/win32/gwinhttpfile.c b/gio/win32/gwinhttpfile.c +index 605c28460c8..e0769cdaacb 100644 +--- a/gio/win32/gwinhttpfile.c ++++ b/gio/win32/gwinhttpfile.c +@@ -37,7 +37,8 @@ + + #include "glibintl.h" + +-static void g_winhttp_file_file_iface_init (GFileIface *iface); ++static void g_winhttp_file_file_iface_init (GFileIface *iface, ++ gpointer iface_data); + + #define g_winhttp_file_get_type _g_winhttp_file_get_type + G_DEFINE_TYPE_WITH_CODE (GWinHttpFile, g_winhttp_file, G_TYPE_OBJECT, +@@ -769,7 +770,8 @@ g_winhttp_file_move (GFile *source, + #endif + + static void +-g_winhttp_file_file_iface_init (GFileIface *iface) ++g_winhttp_file_file_iface_init (GFileIface *iface, ++ gpointer iface_data) + { + iface->dup = g_winhttp_file_dup; + iface->hash = g_winhttp_file_hash; +diff --git a/gobject/gobject.c b/gobject/gobject.c +index 7ec5902b6e4..c54c59defda 100644 +--- a/gobject/gobject.c ++++ b/gobject/gobject.c +@@ -170,7 +170,8 @@ G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, qdata) == G_STRUCT_OFFSET(GObjectReal, + /* --- prototypes --- */ + static void g_object_base_class_init (GObjectClass *class); + static void g_object_base_class_finalize (GObjectClass *class); +-static void g_object_do_class_init (GObjectClass *class); ++static void g_object_do_class_init (GObjectClass *class, ++ gpointer class_data); + static void g_object_init (GObject *object, + GObjectClass *class); + static GObject* g_object_constructor (GType type, +@@ -970,7 +971,8 @@ g_object_base_class_finalize (GObjectClass *class) + } + + static void +-g_object_do_class_init (GObjectClass *class) ++g_object_do_class_init (GObjectClass *class, ++ gpointer class_data) + { + quark_closure_array = g_quark_from_static_string ("GObject-closure-array"); + quark_weak_notifies = g_quark_from_static_string ("GObject-weak-notifies"); +diff --git a/gobject/gparam.h b/gobject/gparam.h +index 89374fec0c3..5f1329567ac 100644 +--- a/gobject/gparam.h ++++ b/gobject/gparam.h +@@ -389,7 +389,8 @@ struct _GParamSpecTypeInfo + /* type system portion */ + guint16 instance_size; /* obligatory */ + guint16 n_preallocs; /* optional */ +- void (*instance_init) (GParamSpec *pspec); /* optional */ ++ void (*instance_init) (GParamSpec *pspec, /* optional */ ++ gpointer class_data); + + /* class portion */ + GType value_type; /* obligatory */ +diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c +index cf50df74fb5..fa0cc0dd2b2 100644 +--- a/gobject/gparamspecs.c ++++ b/gobject/gparamspecs.c +@@ -43,7 +43,8 @@ + + /* --- param spec functions --- */ + static void +-param_char_init (GParamSpec *pspec) ++param_char_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecChar *cspec = G_PARAM_SPEC_CHAR (pspec); + +@@ -82,7 +83,8 @@ param_char_validate (GParamSpec *pspec, + } + + static void +-param_uchar_init (GParamSpec *pspec) ++param_uchar_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecUChar *uspec = G_PARAM_SPEC_UCHAR (pspec); + +@@ -148,7 +150,8 @@ param_boolean_validate (GParamSpec *pspec, + } + + static void +-param_int_init (GParamSpec *pspec) ++param_int_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecInt *ispec = G_PARAM_SPEC_INT (pspec); + +@@ -198,7 +201,8 @@ param_int_values_cmp (GParamSpec *pspec, + } + + static void +-param_uint_init (GParamSpec *pspec) ++param_uint_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecUInt *uspec = G_PARAM_SPEC_UINT (pspec); + +@@ -248,7 +252,8 @@ param_uint_values_cmp (GParamSpec *pspec, + } + + static void +-param_long_init (GParamSpec *pspec) ++param_long_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecLong *lspec = G_PARAM_SPEC_LONG (pspec); + +@@ -303,7 +308,8 @@ param_long_values_cmp (GParamSpec *pspec, + } + + static void +-param_ulong_init (GParamSpec *pspec) ++param_ulong_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecULong *uspec = G_PARAM_SPEC_ULONG (pspec); + +@@ -357,7 +363,8 @@ param_ulong_values_cmp (GParamSpec *pspec, + } + + static void +-param_int64_init (GParamSpec *pspec) ++param_int64_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecInt64 *lspec = G_PARAM_SPEC_INT64 (pspec); + +@@ -407,7 +414,8 @@ param_int64_values_cmp (GParamSpec *pspec, + } + + static void +-param_uint64_init (GParamSpec *pspec) ++param_uint64_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecUInt64 *uspec = G_PARAM_SPEC_UINT64 (pspec); + +@@ -457,7 +465,8 @@ param_uint64_values_cmp (GParamSpec *pspec, + } + + static void +-param_unichar_init (GParamSpec *pspec) ++param_unichar_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecUnichar *uspec = G_PARAM_SPEC_UNICHAR (pspec); + +@@ -506,7 +515,8 @@ param_unichar_values_cmp (GParamSpec *pspec, + } + + static void +-param_enum_init (GParamSpec *pspec) ++param_enum_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecEnum *espec = G_PARAM_SPEC_ENUM (pspec); + +@@ -561,7 +571,8 @@ param_enum_validate (GParamSpec *pspec, + } + + static void +-param_flags_init (GParamSpec *pspec) ++param_flags_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecFlags *fspec = G_PARAM_SPEC_FLAGS (pspec); + +@@ -616,7 +627,8 @@ param_flags_validate (GParamSpec *pspec, + } + + static void +-param_float_init (GParamSpec *pspec) ++param_float_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecFloat *fspec = G_PARAM_SPEC_FLOAT (pspec); + +@@ -669,7 +681,8 @@ param_float_values_cmp (GParamSpec *pspec, + } + + static void +-param_double_init (GParamSpec *pspec) ++param_double_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecDouble *dspec = G_PARAM_SPEC_DOUBLE (pspec); + +@@ -722,7 +735,8 @@ param_double_values_cmp (GParamSpec *pspec, + } + + static void +-param_string_init (GParamSpec *pspec) ++param_string_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecString *sspec = G_PARAM_SPEC_STRING (pspec); + +@@ -853,7 +867,8 @@ param_string_values_cmp (GParamSpec *pspec, + } + + static void +-param_param_init (GParamSpec *pspec) ++param_param_init (GParamSpec *pspec, ++ gpointer class_data) + { + /* GParamSpecParam *spec = G_PARAM_SPEC_PARAM (pspec); */ + } +@@ -896,7 +911,8 @@ param_param_validate (GParamSpec *pspec, + } + + static void +-param_boxed_init (GParamSpec *pspec) ++param_boxed_init (GParamSpec *pspec, ++ gpointer class_data) + { + /* GParamSpecBoxed *bspec = G_PARAM_SPEC_BOXED (pspec); */ + } +@@ -922,7 +938,8 @@ param_boxed_values_cmp (GParamSpec *pspec, + } + + static void +-param_pointer_init (GParamSpec *pspec) ++param_pointer_init (GParamSpec *pspec, ++ gpointer class_data) + { + /* GParamSpecPointer *spec = G_PARAM_SPEC_POINTER (pspec); */ + } +@@ -948,7 +965,8 @@ param_pointer_values_cmp (GParamSpec *pspec, + } + + static void +-param_value_array_init (GParamSpec *pspec) ++param_value_array_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecValueArray *aspec = G_PARAM_SPEC_VALUE_ARRAY (pspec); + +@@ -1099,7 +1117,8 @@ param_value_array_values_cmp (GParamSpec *pspec, + } + + static void +-param_object_init (GParamSpec *pspec) ++param_object_init (GParamSpec *pspec, ++ gpointer class_data) + { + /* GParamSpecObject *ospec = G_PARAM_SPEC_OBJECT (pspec); */ + } +@@ -1154,7 +1173,8 @@ param_object_values_cmp (GParamSpec *pspec, + } + + static void +-param_override_init (GParamSpec *pspec) ++param_override_init (GParamSpec *pspec, ++ gpointer class_data) + { + /* GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec); */ + } +@@ -1212,7 +1232,8 @@ param_override_values_cmp (GParamSpec *pspec, + } + + static void +-param_gtype_init (GParamSpec *pspec) ++param_gtype_init (GParamSpec *pspec, ++ gpointer class_data) + { + } + +@@ -1267,7 +1288,8 @@ param_gtype_values_cmp (GParamSpec *pspec, + } + + static void +-param_variant_init (GParamSpec *pspec) ++param_variant_init (GParamSpec *pspec, ++ gpointer class_data) + { + GParamSpecVariant *vspec = G_PARAM_SPEC_VARIANT (pspec); + +diff --git a/gobject/gtype.h b/gobject/gtype.h +index a16da459325..6158dff51d4 100644 +--- a/gobject/gtype.h ++++ b/gobject/gtype.h +@@ -2108,7 +2108,7 @@ guint g_type_get_type_registration_serial (void); + */ + #define G_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init) { \ + const GInterfaceInfo g_implement_interface_info = { \ +- (GInterfaceInitFunc)(void (*)(void)) iface_init, NULL, NULL \ ++ (GInterfaceInitFunc) iface_init, NULL, NULL \ + }; \ + g_type_add_interface_static (g_define_type_id, TYPE_IFACE, &g_implement_interface_info); \ + } +@@ -2250,7 +2250,8 @@ guint g_type_get_type_registration_serial (void); + */ + #if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38 + #define _G_DEFINE_TYPE_EXTENDED_CLASS_INIT(TypeName, type_name) \ +-static void type_name##_class_intern_init (gpointer klass) \ ++static void type_name##_class_intern_init (gpointer klass, \ ++ gpointer class_data) \ + { \ + type_name##_parent_class = g_type_class_peek_parent (klass); \ + if (TypeName##_private_offset != 0) \ +@@ -2260,7 +2261,8 @@ static void type_name##_class_intern_init (gpointer klass) \ + + #else + #define _G_DEFINE_TYPE_EXTENDED_CLASS_INIT(TypeName, type_name) \ +-static void type_name##_class_intern_init (gpointer klass) \ ++static void type_name##_class_intern_init (gpointer klass, \ ++ gpointer class_data) \ + { \ + type_name##_parent_class = g_type_class_peek_parent (klass); \ + type_name##_class_init ((TypeName##Class*) klass); \ +@@ -2282,6 +2284,11 @@ static void type_name##_class_intern_init (gpointer klass) \ + \ + static void type_name##_init (TypeName *self); \ + static void type_name##_class_init (TypeName##Class *klass); \ ++static void type_name##_init_adapter (TypeName *self, \ ++ gpointer class_data) \ ++{ \ ++ type_name##_init (self); \ ++} \ + static GType type_name##_get_type_once (void); \ + static gpointer type_name##_parent_class = NULL; \ + static gint TypeName##_private_offset; \ +@@ -2319,9 +2326,9 @@ type_name##_get_type_once (void) \ + g_type_register_static_simple (TYPE_PARENT, \ + g_intern_static_string (#TypeName), \ + sizeof (TypeName##Class), \ +- (GClassInitFunc)(void (*)(void)) type_name##_class_intern_init, \ ++ (GClassInitFunc) type_name##_class_intern_init, \ + sizeof (TypeName), \ +- (GInstanceInitFunc)(void (*)(void)) type_name##_init, \ ++ (GInstanceInitFunc) type_name##_init_adapter, \ + (GTypeFlags) flags); \ + { /* custom code follows */ + #define _G_DEFINE_TYPE_EXTENDED_END() \ +@@ -2341,7 +2348,12 @@ type_name##_get_type_once (void) \ + * to avoid deprecation warnings with older GLIB_VERSION_MAX_ALLOWED */ + #define _G_DEFINE_INTERFACE_EXTENDED_BEGIN(TypeName, type_name, TYPE_PREREQ) \ + \ +-static void type_name##_default_init (TypeName##Interface *klass); \ ++static void type_name##_default_init (TypeName##Interface *klass); \ ++static void type_name##_default_init_adapter (TypeName##Interface *klass, \ ++ gpointer class_data) \ ++{ \ ++ type_name##_default_init (klass); \ ++} \ + \ + GType \ + type_name##_get_type (void) \ +@@ -2353,7 +2365,7 @@ type_name##_get_type (void) \ + g_type_register_static_simple (G_TYPE_INTERFACE, \ + g_intern_static_string (#TypeName), \ + sizeof (TypeName##Interface), \ +- (GClassInitFunc)(void (*)(void)) type_name##_default_init, \ ++ (GClassInitFunc) type_name##_default_init_adapter, \ + 0, \ + (GInstanceInitFunc)NULL, \ + (GTypeFlags) 0); \ +diff --git a/gobject/gtypemodule.c b/gobject/gtypemodule.c +index b7f61c67470..3b95ddfc32d 100644 +--- a/gobject/gtypemodule.c ++++ b/gobject/gtypemodule.c +@@ -134,7 +134,8 @@ g_type_module_class_init (GTypeModuleClass *class) + } + + static void +-g_type_module_iface_init (GTypePluginClass *iface) ++g_type_module_iface_init (GTypePluginClass *iface, ++ gpointer iface_data) + { + iface->use_plugin = g_type_module_use_plugin; + iface->unuse_plugin = (void (*) (GTypePlugin *))g_type_module_unuse; +diff --git a/gobject/gtypemodule.h b/gobject/gtypemodule.h +index fba714bc28c..f4ef0847802 100644 +--- a/gobject/gtypemodule.h ++++ b/gobject/gtypemodule.h +@@ -202,12 +202,12 @@ type_name##_register_type (GTypeModule *type_module) \ + sizeof (TypeName##Class), \ + (GBaseInitFunc) NULL, \ + (GBaseFinalizeFunc) NULL, \ +- (GClassInitFunc)(void (*)(void)) type_name##_class_intern_init, \ +- (GClassFinalizeFunc)(void (*)(void)) type_name##_class_finalize, \ ++ (GClassInitFunc) type_name##_class_intern_init, \ ++ (GClassFinalizeFunc) type_name##_class_finalize, \ + NULL, /* class_data */ \ + sizeof (TypeName), \ + 0, /* n_preallocs */ \ +- (GInstanceInitFunc)(void (*)(void)) type_name##_init, \ ++ (GInstanceInitFunc) type_name##_init_adapter, \ + NULL /* value_table */ \ + }; \ + type_name##_type_id = g_type_module_register_type (type_module, \ +@@ -237,7 +237,7 @@ type_name##_register_type (GTypeModule *type_module) \ + */ + #define G_IMPLEMENT_INTERFACE_DYNAMIC(TYPE_IFACE, iface_init) { \ + const GInterfaceInfo g_implement_interface_info = { \ +- (GInterfaceInitFunc)(void (*)(void)) iface_init, NULL, NULL \ ++ (GInterfaceInitFunc) iface_init, NULL, NULL \ + }; \ + g_type_module_add_interface (type_module, g_define_type_id, TYPE_IFACE, &g_implement_interface_info); \ + } From e1f3519413fba02c8a619b2c5ffa7f54dbbed2e7 Mon Sep 17 00:00:00 2001 From: yanovskyy Date: Sun, 11 Aug 2024 23:21:31 +0200 Subject: [PATCH 07/10] emscripten fixed compilation error - removed gmodule for gdk-pixbuf - refactored a bit Signed-off-by: yanovskyy --- .vscode/settings.json | 10 +++++++++ deps/meson.build | 21 ++++++++++++------- machines/cross-emscripten.ini | 2 ++ subprojects/gdk-pixbuf.wrap | 2 +- .../packagefiles/gdk-pixbuf-gmodule.patch | 14 +++++++++++++ 5 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 subprojects/packagefiles/gdk-pixbuf-gmodule.patch diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0f7d0f8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "C_Cpp.default.configurationProvider": "mesonbuild.mesonbuild", + "C_Cpp.default.compileCommands": "/home/yanovskyy/Documents/projects/openslide-bin/builddir/compile_commands.json", + "files.associations": { + "*.tsx": "typescriptreact", + "*.y": "yacc", + "*.sh": "jinja-shell", + "openslide-private.h": "c" + } +} \ No newline at end of file diff --git a/deps/meson.build b/deps/meson.build index c1b64ff..5fd0e13 100644 --- a/deps/meson.build +++ b/deps/meson.build @@ -106,19 +106,26 @@ subproject( ) endif -subproject( - 'glib', - default_options : [ - #'introspection=disabled', - 'nls=disabled', - 'tests=false', +glib_options = [ + 'introspection=disabled', + 'nls=disabled', + 'tests=false', +] +if host_system == 'emscripten' + glib_options += [ 'selinux=disabled', 'xattr=false', 'libmount=disabled', 'nls=disabled', 'force_fallback_for=pcr2, gvdb', - ], + ] +endif + +subproject( + 'glib', + default_options : glib_options, ) + subproject( 'gdk-pixbuf', default_options : [ diff --git a/machines/cross-emscripten.ini b/machines/cross-emscripten.ini index 1d7477c..40274cb 100644 --- a/machines/cross-emscripten.ini +++ b/machines/cross-emscripten.ini @@ -19,6 +19,8 @@ python_platform_tag = 'wasm32' # Ensure that '-s PTHREAD_POOL_SIZE=*' is not injected into .pc files c_thread_count = 0 cpp_thread_count = 0 +c_args = '-matomics -mbulk-memory' +cpp_args = '-matomics -mbulk-memory' [host_machine] system = 'emscripten' diff --git a/subprojects/gdk-pixbuf.wrap b/subprojects/gdk-pixbuf.wrap index dfbb923..dfc992b 100644 --- a/subprojects/gdk-pixbuf.wrap +++ b/subprojects/gdk-pixbuf.wrap @@ -7,7 +7,7 @@ source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/gdk wrapdb_version = 2.42.12-1 # https://gitlab.gnome.org/GNOME/gdk-pixbuf/-/merge_requests/158 -diff_files = gdk-pixbuf-intl.patch +diff_files = gdk-pixbuf-intl.patch, gdk-pixbuf-gmodule.patch [provide] gdk-pixbuf-2.0 = gdkpixbuf_dep diff --git a/subprojects/packagefiles/gdk-pixbuf-gmodule.patch b/subprojects/packagefiles/gdk-pixbuf-gmodule.patch new file mode 100644 index 0000000..76c2dd1 --- /dev/null +++ b/subprojects/packagefiles/gdk-pixbuf-gmodule.patch @@ -0,0 +1,14 @@ +diff --git a/meson.build b/meson.build +index 3eb3fcc..c69e4ac 100644 +--- a/meson.build ++++ b/meson.build +@@ -235,6 +235,9 @@ if gmodule_dep.type_name() == 'pkgconfig' + else + build_modules = subproject('glib').get_variable('g_module_impl') != '0' + endif ++if host_system == 'emscripten' ++ build_modules = false ++endif + gdk_pixbuf_conf.set('USE_GMODULE', build_modules) + + # Check which loaders should be built into gdk-pixbuf From fee48ab5fe48f59816988aa168b935a878605076 Mon Sep 17 00:00:00 2001 From: yanovskyy Date: Sun, 11 Aug 2024 23:25:10 +0200 Subject: [PATCH 08/10] fix end of lines to cross emcc config Signed-off-by: yanovskyy --- machines/cross-emscripten.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machines/cross-emscripten.ini b/machines/cross-emscripten.ini index 40274cb..ec24aee 100644 --- a/machines/cross-emscripten.ini +++ b/machines/cross-emscripten.ini @@ -26,4 +26,4 @@ cpp_args = '-matomics -mbulk-memory' system = 'emscripten' cpu_family = 'wasm32' cpu = 'wasm32' -endian = 'little' \ No newline at end of file +endian = 'little' From a5c520ce0a819ef9b115ea9ca10b3ba6e88d4f5b Mon Sep 17 00:00:00 2001 From: yanovskyy Date: Sun, 11 Aug 2024 23:26:38 +0200 Subject: [PATCH 09/10] removed .vscode and put into .gitignore Signed-off-by: yanovskyy --- .gitattributes | 1 + .vscode/settings.json | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitattributes b/.gitattributes index 576c714..1531f0a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,3 +8,4 @@ /.github/workflows export-ignore /.pre-commit-config.yaml export-ignore /pyproject.toml export-ignore +/.vscode export-ignore diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 0f7d0f8..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "C_Cpp.default.configurationProvider": "mesonbuild.mesonbuild", - "C_Cpp.default.compileCommands": "/home/yanovskyy/Documents/projects/openslide-bin/builddir/compile_commands.json", - "files.associations": { - "*.tsx": "typescriptreact", - "*.y": "yacc", - "*.sh": "jinja-shell", - "openslide-private.h": "c" - } -} \ No newline at end of file From 1659b642b14d99537cdc51ff60a1d8e3298d7708 Mon Sep 17 00:00:00 2001 From: yanovskyy Date: Sun, 11 Aug 2024 23:29:38 +0200 Subject: [PATCH 10/10] added newline for meson build Signed-off-by: yanovskyy --- deps/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/meson.build b/deps/meson.build index 5fd0e13..16bf7e0 100644 --- a/deps/meson.build +++ b/deps/meson.build @@ -170,4 +170,4 @@ openslide = subproject( 'default_library=shared', 'doc=disabled', ], -) \ No newline at end of file +)