Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright (C) 2020 Red Hat, Inc. |
| 4 | # |
| 5 | # SPDX-License-Identifier: GPL-2.0-or-later |
| 6 | |
| 7 | import argparse |
| 8 | import glob |
| 9 | import os |
| 10 | import shutil |
| 11 | import subprocess |
| 12 | import tempfile |
| 13 | |
| 14 | |
| 15 | def signcode(path): |
| 16 | cmd = os.environ.get("SIGNCODE") |
| 17 | if not cmd: |
| 18 | return |
| 19 | subprocess.run([cmd, path]) |
| 20 | |
Bin Meng | a3c1e64 | 2022-09-08 21:28:13 +0800 | [diff] [blame] | 21 | def find_deps(exe_or_dll, search_path, analyzed_deps): |
| 22 | deps = [exe_or_dll] |
| 23 | output = subprocess.check_output(["objdump", "-p", exe_or_dll], text=True) |
| 24 | output = output.split("\n") |
| 25 | for line in output: |
| 26 | if not line.startswith("\tDLL Name: "): |
| 27 | continue |
| 28 | |
| 29 | dep = line.split("DLL Name: ")[1].strip() |
| 30 | if dep in analyzed_deps: |
| 31 | continue |
| 32 | |
| 33 | dll = os.path.join(search_path, dep) |
| 34 | if not os.path.exists(dll): |
| 35 | # assume it's a Windows provided dll, skip it |
| 36 | continue |
| 37 | |
| 38 | analyzed_deps.add(dep) |
| 39 | # locate the dll dependencies recursively |
| 40 | rdeps = find_deps(dll, search_path, analyzed_deps) |
| 41 | deps.extend(rdeps) |
| 42 | |
| 43 | return deps |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 44 | |
| 45 | def main(): |
| 46 | parser = argparse.ArgumentParser(description="QEMU NSIS build helper.") |
| 47 | parser.add_argument("outfile") |
| 48 | parser.add_argument("prefix") |
| 49 | parser.add_argument("srcdir") |
Bin Meng | a3c1e64 | 2022-09-08 21:28:13 +0800 | [diff] [blame] | 50 | parser.add_argument("dlldir") |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 51 | parser.add_argument("cpu") |
| 52 | parser.add_argument("nsisargs", nargs="*") |
| 53 | args = parser.parse_args() |
| 54 | |
Bin Meng | 93dbca2 | 2022-09-08 21:28:12 +0800 | [diff] [blame] | 55 | # canonicalize the Windows native prefix path |
| 56 | prefix = os.path.splitdrive(args.prefix)[1] |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 57 | destdir = tempfile.mkdtemp() |
| 58 | try: |
Bin Meng | 7f8c044 | 2022-09-08 21:28:11 +0800 | [diff] [blame] | 59 | subprocess.run(["make", "install", "DESTDIR=" + destdir]) |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 60 | with open( |
Bin Meng | 93dbca2 | 2022-09-08 21:28:12 +0800 | [diff] [blame] | 61 | os.path.join(destdir + prefix, "system-emulations.nsh"), "w" |
Peter Maydell | c087963 | 2022-03-05 10:57:43 +0000 | [diff] [blame] | 62 | ) as nsh, open( |
Bin Meng | 93dbca2 | 2022-09-08 21:28:12 +0800 | [diff] [blame] | 63 | os.path.join(destdir + prefix, "system-mui-text.nsh"), "w" |
Peter Maydell | c087963 | 2022-03-05 10:57:43 +0000 | [diff] [blame] | 64 | ) as muinsh: |
Peter Maydell | e422d92 | 2022-03-05 10:57:41 +0000 | [diff] [blame] | 65 | for exe in sorted(glob.glob( |
Bin Meng | 93dbca2 | 2022-09-08 21:28:12 +0800 | [diff] [blame] | 66 | os.path.join(destdir + prefix, "qemu-system-*.exe") |
Peter Maydell | e422d92 | 2022-03-05 10:57:41 +0000 | [diff] [blame] | 67 | )): |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 68 | exe = os.path.basename(exe) |
| 69 | arch = exe[12:-4] |
| 70 | nsh.write( |
| 71 | """ |
| 72 | Section "{0}" Section_{0} |
| 73 | SetOutPath "$INSTDIR" |
| 74 | File "${{BINDIR}}\\{1}" |
| 75 | SectionEnd |
| 76 | """.format( |
| 77 | arch, exe |
| 78 | ) |
| 79 | ) |
Peter Maydell | c087963 | 2022-03-05 10:57:43 +0000 | [diff] [blame] | 80 | if arch.endswith('w'): |
| 81 | desc = arch[:-1] + " emulation (GUI)." |
| 82 | else: |
| 83 | desc = arch + " emulation." |
| 84 | |
| 85 | muinsh.write( |
| 86 | """ |
| 87 | !insertmacro MUI_DESCRIPTION_TEXT ${{Section_{0}}} "{1}" |
| 88 | """.format(arch, desc)) |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 89 | |
Bin Meng | a3c1e64 | 2022-09-08 21:28:13 +0800 | [diff] [blame] | 90 | search_path = args.dlldir |
| 91 | print("Searching '%s' for the dependent dlls ..." % search_path) |
| 92 | dlldir = os.path.join(destdir + prefix, "dll") |
| 93 | os.mkdir(dlldir) |
| 94 | |
Bin Meng | 93dbca2 | 2022-09-08 21:28:12 +0800 | [diff] [blame] | 95 | for exe in glob.glob(os.path.join(destdir + prefix, "*.exe")): |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 96 | signcode(exe) |
| 97 | |
Bin Meng | a3c1e64 | 2022-09-08 21:28:13 +0800 | [diff] [blame] | 98 | # find all dll dependencies |
| 99 | deps = set(find_deps(exe, search_path, set())) |
| 100 | deps.remove(exe) |
| 101 | |
| 102 | # copy all dlls to the DLLDIR |
| 103 | for dep in deps: |
| 104 | dllfile = os.path.join(dlldir, os.path.basename(dep)) |
| 105 | if (os.path.exists(dllfile)): |
| 106 | continue |
| 107 | print("Copying '%s' to '%s'" % (dep, dllfile)) |
| 108 | shutil.copy(dep, dllfile) |
| 109 | |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 110 | makensis = [ |
| 111 | "makensis", |
| 112 | "-V2", |
| 113 | "-NOCD", |
| 114 | "-DSRCDIR=" + args.srcdir, |
Bin Meng | 93dbca2 | 2022-09-08 21:28:12 +0800 | [diff] [blame] | 115 | "-DBINDIR=" + destdir + prefix, |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 116 | ] |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 117 | if args.cpu == "x86_64": |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 118 | makensis += ["-DW64"] |
Bin Meng | a3c1e64 | 2022-09-08 21:28:13 +0800 | [diff] [blame] | 119 | makensis += ["-DDLLDIR=" + dlldir] |
Marc-André Lureau | 8adfeba | 2020-08-26 15:04:19 +0400 | [diff] [blame] | 120 | |
| 121 | makensis += ["-DOUTFILE=" + args.outfile] + args.nsisargs |
| 122 | subprocess.run(makensis) |
| 123 | signcode(args.outfile) |
| 124 | finally: |
| 125 | shutil.rmtree(destdir) |
| 126 | |
| 127 | |
| 128 | if __name__ == "__main__": |
| 129 | main() |