nsis.py 3.8 KB

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