您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

97 行
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:]))