| #!/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 |
| 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() |
| |
| # 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) |
| |
| 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", |
| "-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() |