qemu/scripts/nsis.py
Stefan Weil b9eab5efc1 scripts/nsis.py: Run dependency check for each DLL file only once
Each DLL should only be checked once for dependencies, but
several hundred (781 in my test) unneeded checks were done.

Now the script is significantly faster (16 s in my build).

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-Id: <20250111215244.1680931-1-sw@weilnetz.de>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20250116160306.1709518-38-alex.bennee@linaro.org>
2025-01-17 10:46:15 +00:00

129 lines
3.8 KiB
Python

#!/usr/bin/env python3
#
# Copyright (C) 2020 Red Hat, Inc.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import argparse
import glob
import os
import shutil
import subprocess
import tempfile
def signcode(path):
cmd = os.environ.get("SIGNCODE")
if not cmd:
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
analyzed_deps, rdeps = find_deps(dll, search_path, analyzed_deps)
deps.extend(rdeps)
return analyzed_deps, 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()
# canonicalize the Windows native prefix path
prefix = os.path.splitdrive(args.prefix)[1]
destdir = tempfile.mkdtemp()
try:
subprocess.run(["make", "install", "DESTDIR=" + destdir])
with open(
os.path.join(destdir + prefix, "system-emulations.nsh"), "w"
) as nsh, open(
os.path.join(destdir + prefix, "system-mui-text.nsh"), "w"
) as muinsh:
for exe in sorted(glob.glob(
os.path.join(destdir + prefix, "qemu-system-*.exe")
)):
exe = os.path.basename(exe)
arch = exe[12:-4]
nsh.write(
"""
Section "{0}" Section_{0}
SetOutPath "$INSTDIR"
File "${{BINDIR}}\\{1}"
SectionEnd
""".format(
arch, exe
)
)
if arch.endswith('w'):
desc = arch[:-1] + " emulation (GUI)."
else:
desc = arch + " emulation."
muinsh.write(
"""
!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)
analyzed_deps = set()
for exe in glob.glob(os.path.join(destdir + prefix, "*.exe")):
signcode(exe)
# find all dll dependencies
analyzed_deps, deps = find_deps(exe, search_path, analyzed_deps)
deps = set(deps)
deps.remove(exe)
# copy all dlls to the DLLDIR
for dep in deps:
dllfile = os.path.join(dlldir, os.path.basename(dep))
print("Copying '%s' to '%s'" % (dep, dllfile))
shutil.copy(dep, dllfile)
makensis = [
"makensis",
"-V2",
"-NOCD",
"-DSRCDIR=" + args.srcdir,
"-DBINDIR=" + destdir + prefix,
]
if args.cpu == "x86_64":
makensis += ["-DW64"]
makensis += ["-DDLLDIR=" + dlldir]
makensis += ["-DOUTFILE=" + args.outfile] + args.nsisargs
subprocess.run(makensis)
signcode(args.outfile)
finally:
shutil.rmtree(destdir)
if __name__ == "__main__":
main()