Hi (adding Stefan Weil in CC, who currently provides Windows installer) On Thu, Sep 8, 2022 at 5:34 PM Bin Meng wrote: > From: Bin Meng > > At present packaging the required DLLs of QEMU executables is a > manual process, and error prone. > > Actually build/config-host.mak contains a GLIB_BINDIR variable > which is the directory where glib and other DLLs reside. This > works for both Windows native build and cross-build on Linux. > We can use it as the search directory for DLLs and automate > the whole DLL packaging process. > > Signed-off-by: Bin Meng > That seems reasonable to me, although packaging dependencies is not just about linked DLLs.. There are dynamic stuff, executables, data, legal docs etc etc. I have no clear picture how is everything really packaged in the installer tbh (I would recommend msys2 qemu installation at this point) anyhow, for the patch, as far as I am concerned: Reviewed-by: Marc-André Lureau --- > > meson.build | 1 + > scripts/nsis.py | 46 ++++++++++++++++++++++++++++++++++++++++++---- > 2 files changed, 43 insertions(+), 4 deletions(-) > > diff --git a/meson.build b/meson.build > index c2adb7caf4..4c03850f9f 100644 > --- a/meson.build > +++ b/meson.build > @@ -3657,6 +3657,7 @@ if host_machine.system() == 'windows' > '@OUTPUT@', > get_option('prefix'), > meson.current_source_dir(), > + config_host['GLIB_BINDIR'], > host_machine.cpu(), > '--', > '-DDISPLAYVERSION=' + meson.project_version(), > diff --git a/scripts/nsis.py b/scripts/nsis.py > index baa6ef9594..03ed7608a2 100644 > --- a/scripts/nsis.py > +++ b/scripts/nsis.py > @@ -18,12 +18,36 @@ def signcode(path): > return > subprocess.run([cmd, path]) > > +def find_deps(exe_or_dll, search_path, analyzed_deps): > + deps = [exe_or_dll] > + output = subprocess.check_output(["objdump", "-p", exe_or_dll], > text=True) > + output = output.split("\n") > + for line in output: > + if not line.startswith("\tDLL Name: "): > + continue > + > + dep = line.split("DLL Name: ")[1].strip() > + if dep in analyzed_deps: > + continue > + > + dll = os.path.join(search_path, dep) > + if not os.path.exists(dll): > + # assume it's a Windows provided dll, skip it > + continue > + > + analyzed_deps.add(dep) > + # locate the dll dependencies recursively > + rdeps = find_deps(dll, search_path, analyzed_deps) > + deps.extend(rdeps) > + > + return deps > > def main(): > parser = argparse.ArgumentParser(description="QEMU NSIS build > helper.") > parser.add_argument("outfile") > parser.add_argument("prefix") > parser.add_argument("srcdir") > + parser.add_argument("dlldir") > parser.add_argument("cpu") > parser.add_argument("nsisargs", nargs="*") > args = parser.parse_args() > @@ -63,9 +87,26 @@ def main(): > !insertmacro MUI_DESCRIPTION_TEXT ${{Section_{0}}} "{1}" > """.format(arch, desc)) > > + search_path = args.dlldir > + print("Searching '%s' for the dependent dlls ..." % search_path) > + dlldir = os.path.join(destdir + prefix, "dll") > + os.mkdir(dlldir) > + > for exe in glob.glob(os.path.join(destdir + prefix, "*.exe")): > signcode(exe) > > + # find all dll dependencies > + deps = set(find_deps(exe, search_path, set())) > + deps.remove(exe) > + > + # copy all dlls to the DLLDIR > + for dep in deps: > + dllfile = os.path.join(dlldir, os.path.basename(dep)) > + if (os.path.exists(dllfile)): > + continue > + print("Copying '%s' to '%s'" % (dep, dllfile)) > + shutil.copy(dep, dllfile) > + > makensis = [ > "makensis", > "-V2", > @@ -73,12 +114,9 @@ def main(): > "-DSRCDIR=" + args.srcdir, > "-DBINDIR=" + destdir + prefix, > ] > - dlldir = "w32" > if args.cpu == "x86_64": > - dlldir = "w64" > makensis += ["-DW64"] > - if os.path.exists(os.path.join(args.srcdir, "dll")): > - makensis += ["-DDLLDIR={0}/dll/{1}".format(args.srcdir, > dlldir)] > + makensis += ["-DDLLDIR=" + dlldir] > > makensis += ["-DOUTFILE=" + args.outfile] + args.nsisargs > subprocess.run(makensis) > -- > 2.34.1 > > > -- Marc-André Lureau