PageRenderTime 37ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/admin/nt/dist-build/build-dep-zips.py

https://gitlab.com/freesoftware/emacs
Python | 276 lines | 253 code | 8 blank | 15 comment | 1 complexity | bd8b154225b7d52f341d5df42995f755 MD5 | raw file
  1. #!/usr/bin/python3
  2. ## Copyright (C) 2017-2022 Free Software Foundation, Inc.
  3. ## This file is part of GNU Emacs.
  4. ## GNU Emacs is free software: you can redistribute it and/or modify
  5. ## it under the terms of the GNU General Public License as published by
  6. ## the Free Software Foundation, either version 3 of the License, or
  7. ## (at your option) any later version.
  8. ## GNU Emacs is distributed in the hope that it will be useful,
  9. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ## GNU General Public License for more details.
  12. ## You should have received a copy of the GNU General Public License
  13. ## along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
  14. import argparse
  15. import os
  16. import shutil
  17. import re
  18. import functools
  19. import operator
  20. from subprocess import check_output
  21. ## Constants
  22. EMACS_MAJOR_VERSION="28"
  23. # This list derives from the features we want Emacs to compile with.
  24. PKG_REQ='''mingw-w64-x86_64-giflib
  25. mingw-w64-x86_64-gnutls
  26. mingw-w64-x86_64-harfbuzz
  27. mingw-w64-x86_64-jansson
  28. mingw-w64-x86_64-lcms2
  29. mingw-w64-x86_64-libjpeg-turbo
  30. mingw-w64-x86_64-libpng
  31. mingw-w64-x86_64-librsvg
  32. mingw-w64-x86_64-libtiff
  33. mingw-w64-x86_64-libxml2
  34. mingw-w64-x86_64-xpm-nox'''.split()
  35. DLL_REQ='''libgif
  36. libgnutls
  37. libharfbuzz
  38. libjansson
  39. liblcms2
  40. libturbojpeg
  41. libpng
  42. librsvg
  43. libtiff
  44. libxml
  45. libXpm'''.split()
  46. ## Options
  47. DRY_RUN=False
  48. def check_output_maybe(*args,**kwargs):
  49. if(DRY_RUN):
  50. print("Calling: {}{}".format(args,kwargs))
  51. else:
  52. return check_output(*args,**kwargs)
  53. ## DLL Capture
  54. def gather_deps():
  55. os.mkdir("x86_64")
  56. os.chdir("x86_64")
  57. for dep in full_dll_dependency():
  58. check_output_maybe(["cp /mingw64/bin/{}*.dll .".format(dep)],
  59. shell=True)
  60. print("Zipping")
  61. check_output_maybe("zip -9r ../emacs-{}-{}deps.zip *"
  62. .format(EMACS_MAJOR_VERSION, DATE),
  63. shell=True)
  64. os.chdir("../")
  65. ## Return all Emacs dependencies
  66. def full_dll_dependency():
  67. deps = [dll_dependency(dep) for dep in DLL_REQ]
  68. return set(sum(deps, []) + DLL_REQ)
  69. ## Dependencies for a given DLL
  70. def dll_dependency(dll):
  71. output = check_output(["/mingw64/bin/ntldd", "--recursive",
  72. "/mingw64/bin/{}*.dll".format(dll)]).decode("utf-8")
  73. ## munge output
  74. return ntldd_munge(output)
  75. def ntldd_munge(out):
  76. deps = out.splitlines()
  77. rtn = []
  78. for dep in deps:
  79. ## Output looks something like this
  80. ## KERNEL32.dll => C:\Windows\SYSTEM32\KERNEL32.dll (0x0000000002a30000)
  81. ## libwinpthread-1.dll => C:\msys64\mingw64\bin\libwinpthread-1.dll (0x0000000000090000)
  82. ## if it's the former, we want it, if its the later we don't
  83. splt = dep.split()
  84. if len(splt) > 2 and "msys64" in splt[2]:
  85. print("Adding dep", splt[0])
  86. rtn.append(splt[0].split(".")[0])
  87. return rtn
  88. #### Source Capture
  89. ## Packages to fiddle with
  90. ## Source for gcc-libs is part of gcc
  91. SKIP_SRC_PKGS=["mingw-w64-gcc-libs"]
  92. SKIP_DEP_PKGS=frozenset(["mingw-w64-x86_64-glib2"])
  93. MUNGE_SRC_PKGS={"mingw-w64-libwinpthread-git":"mingw-w64-winpthreads-git"}
  94. MUNGE_DEP_PKGS={
  95. "mingw-w64-x86_64-libwinpthread":"mingw-w64-x86_64-libwinpthread-git",
  96. "mingw-w64-x86_64-libtre": "mingw-w64-x86_64-libtre-git",
  97. }
  98. ## Currently no packages seem to require this!
  99. ARCH_PKGS=[]
  100. SRC_REPO="https://repo.msys2.org/mingw/sources"
  101. def immediate_deps(pkgs):
  102. package_info = check_output(["pacman", "-Si"] + pkgs).decode("utf-8").splitlines()
  103. ## Extract the packages listed for "Depends On:" lines.
  104. dependencies = [line.split(":")[1].split() for line in package_info
  105. if line.startswith("Depends On")]
  106. ## Flatten dependency lists from multiple packages into one list.
  107. dependencies = functools.reduce(operator.iconcat, dependencies, [])
  108. ## Remove > signs TODO can we get any other punctuation here?
  109. dependencies = [d.split(">")[0] for d in dependencies if d]
  110. dependencies = [d for d in dependencies if not d == "None"]
  111. dependencies = [MUNGE_DEP_PKGS.get(d, d) for d in dependencies]
  112. return dependencies
  113. ## Extract all the msys2 packages that are dependencies of our direct dependencies
  114. def extract_deps():
  115. print( "Extracting deps" )
  116. # Get a list of all dependencies needed for packages mentioned above.
  117. pkgs = set(PKG_REQ)
  118. newdeps = pkgs
  119. print("adding...")
  120. while True:
  121. subdeps = frozenset(immediate_deps(list(newdeps)))
  122. newdeps = subdeps - SKIP_DEP_PKGS - pkgs
  123. if not newdeps:
  124. break
  125. print('\n'.join(newdeps))
  126. pkgs |= newdeps
  127. return list(pkgs)
  128. def download_source(tarball):
  129. print("Acquiring {}...".format(tarball))
  130. if not os.path.exists("../emacs-src-cache/{}".format(tarball)):
  131. print("Downloading {}...".format(tarball))
  132. check_output_maybe(
  133. "wget -a ../download.log -O ../emacs-src-cache/{} {}/{}"
  134. .format(tarball, SRC_REPO, tarball),
  135. shell=True
  136. )
  137. print("Downloading {}... done".format(tarball))
  138. print("Copying {} from local".format(tarball))
  139. shutil.copyfile("../emacs-src-cache/{}".format(tarball),
  140. "{}".format(tarball))
  141. ## Fetch all the source code
  142. def gather_source(deps):
  143. if not os.path.exists("emacs-src-cache"):
  144. os.mkdir("emacs-src-cache")
  145. os.mkdir("emacs-src")
  146. os.chdir("emacs-src")
  147. for pkg in deps:
  148. pkg_name_and_version= \
  149. check_output(["pacman","-Q", pkg]).decode("utf-8").strip()
  150. ## Produces output like:
  151. ## mingw-w64-x86_64-zlib 2.43.2
  152. pkg_name_components = pkg_name_and_version.split()
  153. pkg_name=pkg_name_components[0]
  154. pkg_version=pkg_name_components[1]
  155. ## source pkgs don't have an architecture in them
  156. pkg_name = re.sub(r"x86_64-","",pkg_name)
  157. if(pkg_name in SKIP_SRC_PKGS):
  158. continue
  159. ## Switch names if necessary
  160. pkg_name = MUNGE_SRC_PKGS.get(pkg_name,pkg_name)
  161. tarball = "{}-{}.src.tar.gz".format(pkg_name,pkg_version)
  162. download_source(tarball)
  163. print("Zipping")
  164. check_output_maybe("zip -9 ../emacs-{}-{}deps-mingw-w64-src.zip *"
  165. .format(EMACS_MAJOR_VERSION,DATE),
  166. shell=True)
  167. os.chdir("..")
  168. def clean():
  169. print("Cleaning")
  170. os.path.isdir("emacs-src") and shutil.rmtree("emacs-src")
  171. os.path.isdir("x86_64") and shutil.rmtree("x86_64")
  172. os.path.isfile("download.log") and os.remove("download.log")
  173. if(os.environ["MSYSTEM"] != "MSYS"):
  174. print("Run this script in an MSYS-shell!")
  175. exit(1)
  176. parser = argparse.ArgumentParser()
  177. parser.add_argument("-s", help="snapshot build",
  178. action="store_true")
  179. parser.add_argument("-r", help="source code only",
  180. action="store_true")
  181. parser.add_argument("-c", help="clean only",
  182. action="store_true")
  183. parser.add_argument("-d", help="dry run",
  184. action="store_true")
  185. parser.add_argument("-l", help="list dependencies only",
  186. action="store_true")
  187. args = parser.parse_args()
  188. do_all=not (args.c or args.r)
  189. DRY_RUN=args.d
  190. if( args.l ):
  191. print("List of dependencies")
  192. print( deps )
  193. exit(0)
  194. if args.s:
  195. DATE="{}-".format(check_output(["date", "+%Y-%m-%d"]).decode("utf-8").strip())
  196. else:
  197. DATE=""
  198. if( do_all):
  199. gather_deps()
  200. if( do_all or args.r ):
  201. deps=extract_deps()
  202. gather_source(deps)
  203. if( args.c ):
  204. clean()