plugins: make test/example plugins work on windows
Generate a qemu_plugin_api.lib delay import lib on windows, for windows qemu plugins to link against. Implement an example dll load fail hook to link up the API functions correctly when a plugin is loaded on windows. Update the build scripts for the test and example plugins to use these things. Signed-off-by: Greg Manning <gmanning@rapitasystems.com> Acked-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20231102172053.17692-3-gmanning@rapitasystems.com> [AJB: use find_program for dlltool, s/Windows/windows/] Cc: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20231106185112.2755262-15-alex.bennee@linaro.org>
This commit is contained in:
parent
fb691b8cba
commit
330fe3b03f
3
configure
vendored
3
configure
vendored
@ -1666,6 +1666,9 @@ fi
|
||||
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
|
||||
|
@ -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
|
||||
|
34
contrib/plugins/win32_linker.c
Normal file
34
contrib/plugins/win32_linker.c
Normal file
@ -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;
|
||||
}
|
||||
|
@ -14,6 +14,25 @@ if not enable_modules
|
||||
endif
|
||||
|
||||
if get_option('plugins')
|
||||
if targetos == 'windows'
|
||||
dlltool = find_program('dlltool', required: true)
|
||||
|
||||
# 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
|
||||
|
Loading…
Reference in New Issue
Block a user