Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

97 lines
2.5KB

  1. import argparse
  2. from pathlib import Path
  3. import subprocess
  4. import os
  5. from typing import Sequence
  6. import sys
  7. import shutil
  8. BOOTSTRAP_PHASES = [
  9. 'bootstrap-p1',
  10. 'bootstrap-p2',
  11. ]
  12. HERE = Path(__file__).parent.absolute()
  13. PROJECT_ROOT = HERE.parent
  14. BUILD_DIR = PROJECT_ROOT / '_build'
  15. BOOTSTRAP_BASE_DIR = BUILD_DIR / '_bootstrap'
  16. PREBUILT_DIR = PROJECT_ROOT / '_prebuilt'
  17. EXE_SUFFIX = '.exe' if os.name == 'nt' else ''
  18. def _run_quiet(args) -> None:
  19. cmd = [str(s) for s in args]
  20. res = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  21. if res.returncode != 0:
  22. print(f'Subprocess command {cmd} failed '
  23. f'[{res.returncode}]:\n{res.stdout.decode()}')
  24. raise subprocess.CalledProcessError(res.returncode, cmd)
  25. def _clone_bootstrap_phase(ph: str) -> Path:
  26. print(f'Cloning: {ph}')
  27. bts_dir = BOOTSTRAP_BASE_DIR / ph
  28. if bts_dir.exists():
  29. shutil.rmtree(bts_dir)
  30. _run_quiet([
  31. 'git',
  32. 'clone',
  33. '--depth=1',
  34. f'--branch={ph}',
  35. f'file://{PROJECT_ROOT}',
  36. bts_dir,
  37. ])
  38. return bts_dir
  39. def _build_bootstrap_phase(ph: str, bts_dir: Path, args: argparse.Namespace) -> None:
  40. print(f'Running build: {ph} (Please wait a moment...)')
  41. env = os.environ.copy()
  42. env['DDS_BOOTSTRAP_PREV_EXE'] = str(PREBUILT_DIR / 'dds')
  43. subprocess.check_call(
  44. [
  45. sys.executable,
  46. '-u',
  47. str(bts_dir / 'tools/build.py'),
  48. f'--cxx={args.cxx}',
  49. ],
  50. env=env,
  51. )
  52. def _pull_executable(bts_dir: Path) -> Path:
  53. prebuild_dir = (PROJECT_ROOT / '_prebuilt')
  54. prebuild_dir.mkdir(exist_ok=True)
  55. generated = list(bts_dir.glob(f'_build/dds{EXE_SUFFIX}'))
  56. assert len(generated) == 1, repr(generated)
  57. exe, = generated
  58. dest = prebuild_dir / exe.name
  59. if dest.exists():
  60. dest.unlink()
  61. exe.rename(dest)
  62. return dest
  63. def _run_boot_phase(phase: str, args: argparse.Namespace) -> Path:
  64. bts_dir = _clone_bootstrap_phase(phase)
  65. _build_bootstrap_phase(phase, bts_dir, args)
  66. return _pull_executable(bts_dir)
  67. def main(argv: Sequence[str]) -> int:
  68. parser = argparse.ArgumentParser()
  69. parser.add_argument(
  70. '--cxx', help='The C++ compiler to use for the build', required=True)
  71. args = parser.parse_args(argv)
  72. for phase in BOOTSTRAP_PHASES:
  73. exe = _run_boot_phase(phase, args)
  74. print(f'A bootstrapped DDS executable has been generated: {exe}')
  75. return 0
  76. if __name__ == "__main__":
  77. sys.exit(main(sys.argv[1:]))