xref: /qemu/scripts/nsis.py (revision a3c1e645)
18adfeba9SMarc-André Lureau#!/usr/bin/env python3
28adfeba9SMarc-André Lureau#
38adfeba9SMarc-André Lureau# Copyright (C) 2020 Red Hat, Inc.
48adfeba9SMarc-André Lureau#
58adfeba9SMarc-André Lureau# SPDX-License-Identifier: GPL-2.0-or-later
68adfeba9SMarc-André Lureau
78adfeba9SMarc-André Lureauimport argparse
88adfeba9SMarc-André Lureauimport glob
98adfeba9SMarc-André Lureauimport os
108adfeba9SMarc-André Lureauimport shutil
118adfeba9SMarc-André Lureauimport subprocess
128adfeba9SMarc-André Lureauimport tempfile
138adfeba9SMarc-André Lureau
148adfeba9SMarc-André Lureau
158adfeba9SMarc-André Lureaudef signcode(path):
168adfeba9SMarc-André Lureau    cmd = os.environ.get("SIGNCODE")
178adfeba9SMarc-André Lureau    if not cmd:
188adfeba9SMarc-André Lureau        return
198adfeba9SMarc-André Lureau    subprocess.run([cmd, path])
208adfeba9SMarc-André Lureau
21*a3c1e645SBin Mengdef find_deps(exe_or_dll, search_path, analyzed_deps):
22*a3c1e645SBin Meng    deps = [exe_or_dll]
23*a3c1e645SBin Meng    output = subprocess.check_output(["objdump", "-p", exe_or_dll], text=True)
24*a3c1e645SBin Meng    output = output.split("\n")
25*a3c1e645SBin Meng    for line in output:
26*a3c1e645SBin Meng        if not line.startswith("\tDLL Name: "):
27*a3c1e645SBin Meng            continue
28*a3c1e645SBin Meng
29*a3c1e645SBin Meng        dep = line.split("DLL Name: ")[1].strip()
30*a3c1e645SBin Meng        if dep in analyzed_deps:
31*a3c1e645SBin Meng            continue
32*a3c1e645SBin Meng
33*a3c1e645SBin Meng        dll = os.path.join(search_path, dep)
34*a3c1e645SBin Meng        if not os.path.exists(dll):
35*a3c1e645SBin Meng            # assume it's a Windows provided dll, skip it
36*a3c1e645SBin Meng            continue
37*a3c1e645SBin Meng
38*a3c1e645SBin Meng        analyzed_deps.add(dep)
39*a3c1e645SBin Meng        # locate the dll dependencies recursively
40*a3c1e645SBin Meng        rdeps = find_deps(dll, search_path, analyzed_deps)
41*a3c1e645SBin Meng        deps.extend(rdeps)
42*a3c1e645SBin Meng
43*a3c1e645SBin Meng    return deps
448adfeba9SMarc-André Lureau
458adfeba9SMarc-André Lureaudef main():
468adfeba9SMarc-André Lureau    parser = argparse.ArgumentParser(description="QEMU NSIS build helper.")
478adfeba9SMarc-André Lureau    parser.add_argument("outfile")
488adfeba9SMarc-André Lureau    parser.add_argument("prefix")
498adfeba9SMarc-André Lureau    parser.add_argument("srcdir")
50*a3c1e645SBin Meng    parser.add_argument("dlldir")
518adfeba9SMarc-André Lureau    parser.add_argument("cpu")
528adfeba9SMarc-André Lureau    parser.add_argument("nsisargs", nargs="*")
538adfeba9SMarc-André Lureau    args = parser.parse_args()
548adfeba9SMarc-André Lureau
5593dbca2cSBin Meng    # canonicalize the Windows native prefix path
5693dbca2cSBin Meng    prefix = os.path.splitdrive(args.prefix)[1]
578adfeba9SMarc-André Lureau    destdir = tempfile.mkdtemp()
588adfeba9SMarc-André Lureau    try:
597f8c0440SBin Meng        subprocess.run(["make", "install", "DESTDIR=" + destdir])
608adfeba9SMarc-André Lureau        with open(
6193dbca2cSBin Meng            os.path.join(destdir + prefix, "system-emulations.nsh"), "w"
62c0879637SPeter Maydell        ) as nsh, open(
6393dbca2cSBin Meng            os.path.join(destdir + prefix, "system-mui-text.nsh"), "w"
64c0879637SPeter Maydell        ) as muinsh:
65e422d92aSPeter Maydell            for exe in sorted(glob.glob(
6693dbca2cSBin Meng                os.path.join(destdir + prefix, "qemu-system-*.exe")
67e422d92aSPeter Maydell            )):
688adfeba9SMarc-André Lureau                exe = os.path.basename(exe)
698adfeba9SMarc-André Lureau                arch = exe[12:-4]
708adfeba9SMarc-André Lureau                nsh.write(
718adfeba9SMarc-André Lureau                    """
728adfeba9SMarc-André Lureau                Section "{0}" Section_{0}
738adfeba9SMarc-André Lureau                SetOutPath "$INSTDIR"
748adfeba9SMarc-André Lureau                File "${{BINDIR}}\\{1}"
758adfeba9SMarc-André Lureau                SectionEnd
768adfeba9SMarc-André Lureau                """.format(
778adfeba9SMarc-André Lureau                        arch, exe
788adfeba9SMarc-André Lureau                    )
798adfeba9SMarc-André Lureau                )
80c0879637SPeter Maydell                if arch.endswith('w'):
81c0879637SPeter Maydell                    desc = arch[:-1] + " emulation (GUI)."
82c0879637SPeter Maydell                else:
83c0879637SPeter Maydell                    desc = arch + " emulation."
84c0879637SPeter Maydell
85c0879637SPeter Maydell                muinsh.write(
86c0879637SPeter Maydell                    """
87c0879637SPeter Maydell                !insertmacro MUI_DESCRIPTION_TEXT ${{Section_{0}}} "{1}"
88c0879637SPeter Maydell                """.format(arch, desc))
898adfeba9SMarc-André Lureau
90*a3c1e645SBin Meng        search_path = args.dlldir
91*a3c1e645SBin Meng        print("Searching '%s' for the dependent dlls ..." % search_path)
92*a3c1e645SBin Meng        dlldir = os.path.join(destdir + prefix, "dll")
93*a3c1e645SBin Meng        os.mkdir(dlldir)
94*a3c1e645SBin Meng
9593dbca2cSBin Meng        for exe in glob.glob(os.path.join(destdir + prefix, "*.exe")):
968adfeba9SMarc-André Lureau            signcode(exe)
978adfeba9SMarc-André Lureau
98*a3c1e645SBin Meng            # find all dll dependencies
99*a3c1e645SBin Meng            deps = set(find_deps(exe, search_path, set()))
100*a3c1e645SBin Meng            deps.remove(exe)
101*a3c1e645SBin Meng
102*a3c1e645SBin Meng            # copy all dlls to the DLLDIR
103*a3c1e645SBin Meng            for dep in deps:
104*a3c1e645SBin Meng                dllfile = os.path.join(dlldir, os.path.basename(dep))
105*a3c1e645SBin Meng                if (os.path.exists(dllfile)):
106*a3c1e645SBin Meng                    continue
107*a3c1e645SBin Meng                print("Copying '%s' to '%s'" % (dep, dllfile))
108*a3c1e645SBin Meng                shutil.copy(dep, dllfile)
109*a3c1e645SBin Meng
1108adfeba9SMarc-André Lureau        makensis = [
1118adfeba9SMarc-André Lureau            "makensis",
1128adfeba9SMarc-André Lureau            "-V2",
1138adfeba9SMarc-André Lureau            "-NOCD",
1148adfeba9SMarc-André Lureau            "-DSRCDIR=" + args.srcdir,
11593dbca2cSBin Meng            "-DBINDIR=" + destdir + prefix,
1168adfeba9SMarc-André Lureau        ]
1178adfeba9SMarc-André Lureau        if args.cpu == "x86_64":
1188adfeba9SMarc-André Lureau            makensis += ["-DW64"]
119*a3c1e645SBin Meng        makensis += ["-DDLLDIR=" + dlldir]
1208adfeba9SMarc-André Lureau
1218adfeba9SMarc-André Lureau        makensis += ["-DOUTFILE=" + args.outfile] + args.nsisargs
1228adfeba9SMarc-André Lureau        subprocess.run(makensis)
1238adfeba9SMarc-André Lureau        signcode(args.outfile)
1248adfeba9SMarc-André Lureau    finally:
1258adfeba9SMarc-André Lureau        shutil.rmtree(destdir)
1268adfeba9SMarc-André Lureau
1278adfeba9SMarc-André Lureau
1288adfeba9SMarc-André Lureauif __name__ == "__main__":
1298adfeba9SMarc-André Lureau    main()
130