From 923710b6d5b21d9b3fcecc7e6719cfa5a53de268 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Thu, 16 Jan 2025 16:02:54 +0000 Subject: [PATCH] plugins: enable linking with clang/lld MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Windows uses a special mechanism to enable plugins to work (DLL delay loading). Option for lld is different than ld. MSYS2 clang based environment use lld by default, so restricting to this config on Windows is safe, and will avoid false bug reports. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Tested-by: Stefan Weil Tested-by: Philippe Mathieu-Daudé Message-Id: <20250110203401.178532-4-pierrick.bouvier@linaro.org> Signed-off-by: Alex Bennée Message-Id: <20250116160306.1709518-26-alex.bennee@linaro.org> --- contrib/plugins/meson.build | 2 +- meson.build | 5 +++++ plugins/meson.build | 24 ++++++++++++++++++++---- tests/tcg/plugins/meson.build | 3 +-- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/contrib/plugins/meson.build b/contrib/plugins/meson.build index 63a32c2b4f0..484b9a808c8 100644 --- a/contrib/plugins/meson.build +++ b/contrib/plugins/meson.build @@ -12,7 +12,7 @@ if get_option('plugins') t += shared_module(i, files(i + '.c') + 'win32_linker.c', include_directories: '../../include/qemu', link_depends: [win32_qemu_plugin_api_lib], - link_args: ['-Lplugins', '-lqemu_plugin_api'], + link_args: win32_qemu_plugin_api_link_flags, dependencies: glib) else t += shared_module(i, files(i + '.c'), diff --git a/meson.build b/meson.build index da279cc1124..15a066043b7 100644 --- a/meson.build +++ b/meson.build @@ -377,6 +377,11 @@ elif host_os == 'sunos' qemu_common_flags += '-D__EXTENSIONS__' elif host_os == 'haiku' qemu_common_flags += ['-DB_USE_POSITIVE_POSIX_ERRORS', '-D_BSD_SOURCE', '-fPIC'] +elif host_os == 'windows' + # plugins use delaylib, and clang needs to be used with lld to make it work. + if compiler.get_id() == 'clang' and compiler.get_linker_id() != 'ld.lld' + error('On windows, you need to use lld with clang - use msys2 clang64/clangarm64 env') + endif endif # Choose instruction set (currently x86-only) diff --git a/plugins/meson.build b/plugins/meson.build index 98542e926f8..d60be2a4d6d 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -17,14 +17,15 @@ if not enable_modules capture: true, command: ['sed', '-ne', 's/^[[:space:]]*\\(qemu_.*\\);/_\\1/p', '@INPUT@']) emulator_link_args += ['-Wl,-exported_symbols_list,plugins/qemu-plugins-ld64.symbols'] + elif host_os == 'windows' and meson.get_compiler('c').get_id() == 'clang' + # LLVM/lld does not support exporting specific symbols. However, it works + # out of the box with dllexport/dllimport attribute we set in the code. else emulator_link_args += ['-Xlinker', '--dynamic-list=' + qemu_plugin_symbols.full_path()] endif endif if host_os == '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 @@ -33,12 +34,27 @@ if host_os == 'windows' output: 'qemu_plugin_api.def', capture: true, command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@']) + # then use dlltool to assemble a delaylib. + # The delaylib will have an "imaginary" name (qemu.exe), that is used by the + # linker file we add with plugins (win32_linker.c) to identify that we want + # to find missing symbols in current program. + win32_qemu_plugin_api_link_flags = ['-Lplugins', '-lqemu_plugin_api'] + if meson.get_compiler('c').get_id() == 'clang' + # With LLVM/lld, delaylib is specified at link time (-delayload) + dlltool = find_program('llvm-dlltool', required: true) + dlltool_cmd = [dlltool, '-d', '@INPUT@', '-l', '@OUTPUT@', '-D', 'qemu.exe'] + win32_qemu_plugin_api_link_flags += ['-Wl,-delayload=qemu.exe'] + else + # With gcc/ld, delay lib is built with a specific delay parameter. + dlltool = find_program('dlltool', required: true) + dlltool_cmd = [dlltool, '--input-def', '@INPUT@', + '--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe'] + endif win32_qemu_plugin_api_lib = configure_file( input: win32_plugin_def, output: 'libqemu_plugin_api.a', - command: [dlltool, '--input-def', '@INPUT@', - '--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe'] + command: dlltool_cmd ) endif specific_ss.add(files( diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build index f847849b1b7..87a17d67bd4 100644 --- a/tests/tcg/plugins/meson.build +++ b/tests/tcg/plugins/meson.build @@ -5,9 +5,8 @@ if get_option('plugins') t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c', include_directories: '../../../include/qemu', link_depends: [win32_qemu_plugin_api_lib], - link_args: ['-Lplugins', '-lqemu_plugin_api'], + link_args: win32_qemu_plugin_api_link_flags, dependencies: glib) - else t += shared_module(i, files(i + '.c'), include_directories: '../../../include/qemu', -- 2.39.5