diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ec76291f1..59f20920c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -332,7 +332,9 @@ vs2017-x64: - win32-ps needs: [] script: - - .gitlab-ci/test-msvc.bat + # FIXME: These should use --wrap-mode=nodownload but the Windows CI machines + # aren’t currently set up for that. + - .gitlab-ci/test-msvc.bat ${MESON_COMMON_OPTIONS} --wrap-mode=default artifacts: reports: junit: "_build/${env:CI_JOB_NAME}-report.xml" @@ -347,6 +349,25 @@ vs2017-x64: - _build/gthread/libgthread-2.0-0.dll - _build/gobject/libgobject-2.0-0.dll +vs2017-x64-static: + extends: .only-default + stage: build + tags: + - win32-ps + needs: [] + script: + # FIXME: These should use --wrap-mode=nodownload but the Windows CI machines + # aren’t currently set up for that. + - .gitlab-ci/test-msvc.bat ${MESON_COMMON_OPTIONS} --wrap-mode=default --default-library=static + artifacts: + reports: + junit: "_build/${env:CI_JOB_NAME}-report.xml" + name: "glib-${env:CI_JOB_NAME}-${env:CI_COMMIT_REF_NAME}" + when: always + paths: + - _build/meson-logs + - "_build/${env:CI_JOB_NAME}-report.xml" + freebsd-12-x86_64: stage: build only: diff --git a/.gitlab-ci/test-msvc.bat b/.gitlab-ci/test-msvc.bat index aeb09664f..1a6924bd2 100644 --- a/.gitlab-ci/test-msvc.bat +++ b/.gitlab-ci/test-msvc.bat @@ -2,11 +2,18 @@ :: vcvarsall.bat sets various env vars like PATH, INCLUDE, LIB, LIBPATH for the :: specified build architecture call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x64 -@echo on + +:: Remove quotes from script args +setlocal enabledelayedexpansion +set args= +for %%x in (%*) do ( + set args=!args! %%~x +) +set args=%args:~1% :: FIXME: make warnings fatal pip3 install --upgrade --user meson==0.52.0 || goto :error -meson _build || goto :error +meson %args% _build || goto :error ninja -C _build || goto :error :: FIXME: dont ignore test errors diff --git a/gio/giomodule.c b/gio/giomodule.c index 90af75118..1e202d3ee 100644 --- a/gio/giomodule.c +++ b/gio/giomodule.c @@ -68,6 +68,10 @@ #include #endif +#define __GLIB_H_INSIDE__ +#include "gconstructor.h" +#undef __GLIB_H_INSIDE__ + /** * SECTION:giomodule * @short_description: Loadable GIO Modules @@ -1103,7 +1107,7 @@ extern GType _g_win32_network_monitor_get_type (void); static HMODULE gio_dll = NULL; -#ifdef DLL_EXPORT +#ifndef GLIB_STATIC_COMPILATION BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, @@ -1123,8 +1127,40 @@ DllMain (HINSTANCE hinstDLL, return TRUE; } +#elif defined(G_HAS_CONSTRUCTORS) /* && G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION */ +extern void glib_win32_init (void); +extern void gobject_win32_init (void); + +#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(giomodule_init_ctor) #endif +G_DEFINE_CONSTRUCTOR (giomodule_init_ctor) + +static void +giomodule_init_ctor (void) +{ + /* When built dynamically, module initialization is done through DllMain + * function which is called when the dynamic library is loaded by the glib + * module AFTER loading gobject. So, in dynamic configuration glib and + * gobject are always initialized BEFORE gio. + * + * When built statically, initialization mechanism relies on hooking + * functions to the CRT section directly at compilation time. As we don't + * control how each compilation unit will be built and in which order, we + * obtain the same kind of issue as the "static initialization order fiasco". + * In this case, we must ensure explicitly that glib and gobject are always + * well initialized BEFORE gio. + */ + glib_win32_init (); + gobject_win32_init (); + gio_win32_appinfo_init (FALSE); +} + +#else /* G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION && !G_HAS_CONSTRUCTORS */ +#error Your platform/compiler is missing constructor support +#endif /* GLIB_STATIC_COMPILATION */ + void * _g_io_win32_get_module (void) { @@ -1136,7 +1172,7 @@ _g_io_win32_get_module (void) return gio_dll; } -#endif +#endif /* G_PLATFORM_WIN32 */ void _g_io_modules_ensure_extension_points_registered (void) diff --git a/gio/tests/modules/symbol-visibility.h b/gio/tests/modules/symbol-visibility.h index f9f8826ce..e83894444 100644 --- a/gio/tests/modules/symbol-visibility.h +++ b/gio/tests/modules/symbol-visibility.h @@ -3,11 +3,15 @@ /* This is the same check that's done in configure to create config.h */ #ifdef _WIN32 -# ifdef _MSC_VER -# define GLIB_TEST_EXPORT_SYMBOL __declspec(dllexport) extern -# else -# define GLIB_TEST_EXPORT_SYMBOL __attribute__((visibility("default"))) __declspec(dllexport) extern -# endif +#ifdef GLIB_STATIC_COMPILATION +#define GLIB_TEST_EXPORT_SYMBOL extern +#else +#ifdef _MSC_VER +#define GLIB_TEST_EXPORT_SYMBOL __declspec(dllexport) extern +#else +#define GLIB_TEST_EXPORT_SYMBOL __attribute__ ((visibility ("default"))) __declspec(dllexport) extern +#endif +#endif /* Matches GCC and Clang */ #elif defined(__GNUC__) && (__GNUC__ >= 4) # define GLIB_TEST_EXPORT_SYMBOL __attribute__((visibility("default"))) extern diff --git a/glib/gconstructor.h b/glib/gconstructor.h index 407202167..17c46699a 100644 --- a/glib/gconstructor.h +++ b/glib/gconstructor.h @@ -1,3 +1,30 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 . + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __G_CONSTRUCTOR_H__ +#define __G_CONSTRUCTOR_H__ + /* If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and destructors, in a usable way, including e.g. on library unload. If not you're on @@ -28,6 +55,7 @@ #elif defined (_MSC_VER) && (_MSC_VER >= 1500) /* Visual studio 2008 and later has _Pragma */ +#include "gslist.h" #include #define G_HAS_CONSTRUCTORS 1 @@ -120,3 +148,4 @@ #endif #endif /* __GTK_DOC_IGNORE__ */ +#endif /* __G_CONSTRUCTOR_H__ */ diff --git a/glib/glib-init.c b/glib/glib-init.c index 2958fb5be..e7b4984e6 100644 --- a/glib/glib-init.c +++ b/glib/glib-init.c @@ -340,14 +340,48 @@ glib_init (void) g_error_init (); } -#if defined (G_OS_WIN32) +#ifdef G_PLATFORM_WIN32 + +HMODULE glib_dll = NULL; +void glib_win32_init (void); + +void +glib_win32_init (void) +{ + /* May be called more than once in static compilation mode */ + static gboolean win32_already_init = FALSE; + if (!win32_already_init) + { + win32_already_init = TRUE; + + g_crash_handler_win32_init (); +#ifdef THREADS_WIN32 + g_thread_win32_init (); +#endif + + g_clock_win32_init (); + glib_init (); + /* must go after glib_init */ + g_console_win32_init (); + } +} + +static void +glib_win32_deinit (gboolean detach_thread) +{ +#ifdef THREADS_WIN32 + if (detach_thread) + g_thread_win32_process_detach (); +#endif + g_crash_handler_win32_deinit (); +} + +#ifndef GLIB_STATIC_COMPILATION BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); -HMODULE glib_dll; - BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, @@ -357,14 +391,7 @@ DllMain (HINSTANCE hinstDLL, { case DLL_PROCESS_ATTACH: glib_dll = hinstDLL; - g_crash_handler_win32_init (); - g_clock_win32_init (); -#ifdef THREADS_WIN32 - g_thread_win32_init (); -#endif - glib_init (); - /* must go after glib_init */ - g_console_win32_init (); + glib_win32_init (); break; case DLL_THREAD_DETACH: @@ -374,11 +401,7 @@ DllMain (HINSTANCE hinstDLL, break; case DLL_PROCESS_DETACH: -#ifdef THREADS_WIN32 - if (lpvReserved == NULL) - g_thread_win32_process_detach (); -#endif - g_crash_handler_win32_deinit (); + glib_win32_deinit (lpvReserved == NULL); break; default: @@ -389,7 +412,35 @@ DllMain (HINSTANCE hinstDLL, return TRUE; } -#elif defined (G_HAS_CONSTRUCTORS) +#elif defined(G_HAS_CONSTRUCTORS) /* && G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION */ +#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(glib_init_ctor) +#endif +#ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(glib_init_dtor) +#endif + +G_DEFINE_CONSTRUCTOR (glib_init_ctor) + +static void +glib_init_ctor (void) +{ + glib_win32_init (); +} + +G_DEFINE_DESTRUCTOR (glib_init_dtor) + +static void +glib_init_dtor (void) +{ + glib_win32_deinit (FALSE); +} + +#else /* G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION && !G_HAS_CONSTRUCTORS */ +#error Your platform/compiler is missing constructor support +#endif /* GLIB_STATIC_COMPILATION */ + +#elif defined(G_HAS_CONSTRUCTORS) /* && !G_PLATFORM_WIN32 */ #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(glib_init_ctor) @@ -402,6 +453,6 @@ glib_init_ctor (void) glib_init (); } -#else +#else /* !G_PLATFORM_WIN32 && !G_HAS_CONSTRUCTORS */ # error Your platform/compiler is missing constructor support -#endif +#endif /* G_PLATFORM_WIN32 */ diff --git a/glib/glibconfig.h.in b/glib/glibconfig.h.in index 873cb0314..e66748d95 100644 --- a/glib/glibconfig.h.in +++ b/glib/glibconfig.h.in @@ -20,6 +20,8 @@ #mesondefine GLIB_STATIC_COMPILATION #mesondefine GOBJECT_STATIC_COMPILATION +#mesondefine G_INTL_STATIC_COMPILATION +#mesondefine FFI_STATIC_BUILD G_BEGIN_DECLS diff --git a/glib/gthread-win32.c b/glib/gthread-win32.c index 4cac46d6b..e7a4cde7b 100644 --- a/glib/gthread-win32.c +++ b/glib/gthread-win32.c @@ -422,6 +422,28 @@ g_system_thread_free (GRealThread *thread) void g_system_thread_exit (void) { + /* In static compilation, DllMain doesn't exist and so DLL_THREAD_DETACH + * case is never called and thread destroy notifications are not triggered. + * To ensure that notifications are correctly triggered in static + * compilation mode, we call directly the "detach" function here right + * before terminating the thread. + * As all win32 threads initialized through the glib API are run through + * the same proxy function g_thread_win32_proxy() which calls systematically + * g_system_thread_exit() when finishing, we obtain the same behavior as + * with dynamic compilation. + * + * WARNING: unfortunately this mechanism cannot work with threads created + * directly from the Windows API using CreateThread() or _beginthread/ex(). + * It only works with threads created by using the glib API with + * g_system_thread_new(). If users need absolutely to use a thread NOT + * created with glib API under Windows and in static compilation mode, they + * should not use glib functions within their thread or they may encounter + * memory leaks when the thread finishes. + */ +#ifdef GLIB_STATIC_COMPILATION + g_thread_win32_thread_detach (); +#endif + _endthreadex (0); } @@ -610,7 +632,7 @@ SetThreadName (DWORD dwThreadID, typedef HRESULT (WINAPI *pSetThreadDescription) (HANDLE hThread, PCWSTR lpThreadDescription); static pSetThreadDescription SetThreadDescriptionFunc = NULL; -HMODULE kernel32_module = NULL; +static HMODULE kernel32_module = NULL; static gboolean g_thread_win32_load_library (void) diff --git a/glib/tests/private.c b/glib/tests/private.c index 5e89b35e2..ec256d8de 100644 --- a/glib/tests/private.c +++ b/glib/tests/private.c @@ -146,6 +146,14 @@ test_private3 (void) thread = (HANDLE) _beginthreadex (NULL, 0, private3_func, NULL, 0, &ignore); WaitForSingleObject (thread, INFINITE); CloseHandle (thread); + + /* FIXME: with static compilation on Windows this test will fail because + * it is mixing up glib threads with Microsoft native thread API. See + * comment in gthread-win32.c for g_system_thread_exit() implementation. + * Fix is not straightforward, possible solution could be to use FLS + * functions (instead of TLS) as proposed in + * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1655 + */ } #else { diff --git a/gobject/gtype.c b/gobject/gtype.c index 26ec30b7b..071429934 100644 --- a/gobject/gtype.c +++ b/gobject/gtype.c @@ -4521,7 +4521,23 @@ gobject_init (void) _g_signal_init (); } -#if defined (G_OS_WIN32) +#ifdef G_PLATFORM_WIN32 + +void gobject_win32_init (void); + +void +gobject_win32_init (void) +{ + /* May be called more than once in static compilation mode */ + static gboolean win32_already_init = FALSE; + if (!win32_already_init) + { + win32_already_init = TRUE; + gobject_init (); + } +} + +#ifndef GLIB_STATIC_COMPILATION BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, @@ -4535,7 +4551,7 @@ DllMain (HINSTANCE hinstDLL, switch (fdwReason) { case DLL_PROCESS_ATTACH: - gobject_init (); + gobject_win32_init (); break; default: @@ -4546,21 +4562,55 @@ DllMain (HINSTANCE hinstDLL, return TRUE; } -#elif defined (G_HAS_CONSTRUCTORS) +#elif defined(G_HAS_CONSTRUCTORS) /* && G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION */ +extern void glib_win32_init (void); + #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(gobject_init_ctor) #endif + G_DEFINE_CONSTRUCTOR(gobject_init_ctor) +static void +gobject_init_ctor (void) +{ + /* When built dynamically, module initialization is done through DllMain + * function which is called when the dynamic library is loaded by the glib + * module. So, in dynamic configuration glib is always initialized BEFORE + * gobject. + * + * When built statically, initialization mechanism relies on hooking + * functions to the CRT section directly at compilation time. As we don't + * control how each compilation unit will be built and in which order, we + * obtain the same kind of issue as the "static initialization order fiasco". + * In this case, we must ensure explicitly that glib is always well + * initialized BEFORE gobject. + */ + glib_win32_init (); + gobject_win32_init (); +} + +#else /* G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION && !G_HAS_CONSTRUCTORS */ +# error Your platform/compiler is missing constructor support +#endif /* GLIB_STATIC_COMPILATION */ + +#elif defined(G_HAS_CONSTRUCTORS) /* && !G_PLATFORM_WIN32 */ + +#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(gobject_init_ctor) +#endif + +G_DEFINE_CONSTRUCTOR (gobject_init_ctor) + static void gobject_init_ctor (void) { gobject_init (); } -#else -# error Your platform/compiler is missing constructor support -#endif +#else /* !G_PLATFORM_WIN32 && !G_HAS_CONSTRUCTORS */ +#error Your platform/compiler is missing constructor support +#endif /* G_PLATFORM_WIN32 */ /** * g_type_class_add_private: diff --git a/meson.build b/meson.build index 082ab630f..299f832f8 100644 --- a/meson.build +++ b/meson.build @@ -214,8 +214,10 @@ if get_option('default_library') != 'static' endif if get_option('default_library') == 'static' - glibconfig_conf.set('GLIB_STATIC_COMPILATION', '1') - glibconfig_conf.set('GOBJECT_STATIC_COMPILATION', '1') + glibconfig_conf.set('GLIB_STATIC_COMPILATION', '1') + glibconfig_conf.set('GOBJECT_STATIC_COMPILATION', '1') + glibconfig_conf.set('G_INTL_STATIC_COMPILATION', '1') + glibconfig_conf.set('FFI_STATIC_BUILD', '1') endif # Cygwin glib port maintainers made it clear diff --git a/subprojects/zlib.wrap b/subprojects/zlib.wrap index ff9ab6680..c49c1d90c 100644 --- a/subprojects/zlib.wrap +++ b/subprojects/zlib.wrap @@ -1,10 +1,11 @@ [wrap-file] directory = zlib-1.2.11 - source_url = https://zlib.net/fossils/zlib-1.2.11.tar.gz source_filename = zlib-1.2.11.tar.gz source_hash = c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 +patch_filename = zlib_1.2.11-6_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.2.11-6/get_patch +patch_hash = f7c24c5698ce787294910ad431f94088102d35ddaf88542d04add1e54afa9212 -patch_url = https://github.com/mesonbuild/zlib/releases/download/1.2.11-3/zlib.zip -patch_filename = zlib-1.2.11-3-wrap.zip -patch_hash = f07dc491ab3d05daf00632a0591e2ae61b470615b5b73bcf9b3f061fff65cff0 +[provide] +zlib = zlib_dep diff --git a/tests/module-test.c b/tests/module-test.c index 62473d29d..a74bc74d4 100644 --- a/tests/module-test.c +++ b/tests/module-test.c @@ -101,8 +101,12 @@ main (int argc, if (!module_self) g_error ("error: %s", g_module_error ()); + /* On Windows static compilation mode, glib API symbols are not + * exported dynamically by definition. */ +#if !defined(G_PLATFORM_WIN32) || !defined(GLIB_STATIC_COMPILATION) if (!g_module_symbol (module_self, "g_module_close", (gpointer *) &f_self)) g_error ("error: %s", g_module_error ()); +#endif module_a = g_module_open_full (plugin_a, G_MODULE_BIND_LAZY, &error); g_assert_no_error (error);