@@ -1662,6 +1662,9 @@ echo "CFLAGS=${CFLAGS-$default_cflags} $EXTRA_CFLAGS" >> contrib/plugins/$config
if test "$targetos" = darwin; then
echo "CONFIG_DARWIN=y" >> contrib/plugins/$config_host_mak
fi
+if test "$targetos" = windows; then
+ echo "CONFIG_WIN32=y" >> contrib/plugins/$config_host_mak
+fi
# tests/tcg configuration
(config_host_mak=tests/tcg/config-host.mak
new file mode 100644
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023, Greg Manning <gmanning@rapitasystems.com>
+ *
+ * This hook, __pfnDliFailureHook2, is documented in the microsoft documentation here:
+ * https://learn.microsoft.com/en-us/cpp/build/reference/error-handling-and-notification
+ * It gets called when a delay-loaded DLL encounters various errors.
+ * We handle the specific case of a DLL looking for a "qemu.exe",
+ * and give it the running executable (regardless of what it is named).
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include <Windows.h>
+#include <delayimp.h>
+
+FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli);
+
+
+PfnDliHook __pfnDliFailureHook2 = dll_failure_hook;
+
+FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli) {
+ if (dliNotify == dliFailLoadLib) {
+ /* If the failing request was for qemu.exe, ... */
+ if (strcmp(pdli->szDll, "qemu.exe") == 0) {
+ /* Then pass back a pointer to the top level module. */
+ HMODULE top = GetModuleHandle(NULL);
+ return (FARPROC) top;
+ }
+ }
+ /* Otherwise we can't do anything special. */
+ return 0;
+}
+
@@ -22,7 +22,14 @@ NAMES += hwprofile
NAMES += cache
NAMES += drcov
-SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
+ifeq ($(CONFIG_WIN32),y)
+SO_SUFFIX := .dll
+LDLIBS += $(shell $(PKG_CONFIG) --libs glib-2.0)
+else
+SO_SUFFIX := .so
+endif
+
+SONAMES := $(addsuffix $(SO_SUFFIX),$(addprefix lib,$(NAMES)))
# The main QEMU uses Glib extensively so it's perfectly fine to use it
# in plugins (which many example do).
@@ -35,15 +42,20 @@ all: $(SONAMES)
%.o: %.c
$(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<
-lib%.so: %.o
-ifeq ($(CONFIG_DARWIN),y)
+ifeq ($(CONFIG_WIN32),y)
+lib%$(SO_SUFFIX): %.o win32_linker.o ../../plugins/qemu_plugin_api.lib
+ $(CC) -shared -o $@ $^ $(LDLIBS)
+else ifeq ($(CONFIG_DARWIN),y)
+lib%$(SO_SUFFIX): %.o
$(CC) -bundle -Wl,-undefined,dynamic_lookup -o $@ $^ $(LDLIBS)
else
+lib%$(SO_SUFFIX): %.o
$(CC) -shared -o $@ $^ $(LDLIBS)
endif
+
clean:
- rm -f *.o *.so *.d
+ rm -f *.o *$(SO_SUFFIX) *.d
rm -Rf .libs
.PHONY: all clean
@@ -14,6 +14,23 @@ if not enable_modules
endif
if get_option('plugins')
+ if targetos == 'windows'
+ # Generate a .lib file for plugins to link against.
+ # First, create a .def file listing all the symbols a plugin should expect to have
+ # available in qemu
+ win32_plugin_def = configure_file(
+ input: files('qemu-plugins.symbols'),
+ output: 'qemu_plugin_api.def',
+ capture: true,
+ command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
+ # then use dlltool to assemble a delaylib.
+ win32_qemu_plugin_api_lib = configure_file(
+ input: win32_plugin_def,
+ output: 'qemu_plugin_api.lib',
+ command: ['dlltool', '--input-def', '@INPUT@',
+ '--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
+ )
+ endif
specific_ss.add(files(
'loader.c',
'core.c',
@@ -1,9 +1,17 @@
t = []
if get_option('plugins')
foreach i : ['bb', 'empty', 'insn', 'mem', 'syscall']
- t += shared_module(i, files(i + '.c'),
- include_directories: '../../include/qemu',
- dependencies: glib)
+ if targetos == 'windows'
+ t += shared_module(i, files(i + '.c') + '../../contrib/plugins/win32_linker.c',
+ include_directories: '../../include/qemu',
+ objects: [win32_qemu_plugin_api_lib],
+ dependencies: glib)
+
+ else
+ t += shared_module(i, files(i + '.c'),
+ include_directories: '../../include/qemu',
+ dependencies: glib)
+ endif
endforeach
endif
if t.length() > 0