選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

116 行
3.0KB

  1. import argparse
  2. from pathlib import Path
  3. import subprocess
  4. import os
  5. from typing import Sequence, NamedTuple
  6. import sys
  7. import shutil
  8. class BootstrapPhase(NamedTuple):
  9. ref: str
  10. nix_compiler: str
  11. win_compiler: str
  12. @property
  13. def platform_compiler(self):
  14. if os.name == 'nt':
  15. return self.win_compiler
  16. else:
  17. return self.nix_compiler
  18. BOOTSTRAP_PHASES = [
  19. BootstrapPhase('bootstrap-p1.2', 'g++-8', 'cl.exe'),
  20. BootstrapPhase('bootstrap-p4.2', 'g++-8', 'cl.exe'),
  21. BootstrapPhase('bootstrap-p5.2', 'g++-9', 'cl.exe'),
  22. BootstrapPhase('0.1.0-alpha.3', 'g++-9', 'cl.exe'),
  23. BootstrapPhase('0.1.0-alpha.4', 'g++-9', 'cl.exe'),
  24. ]
  25. HERE = Path(__file__).parent.absolute()
  26. PROJECT_ROOT = HERE.parent
  27. BUILD_DIR = PROJECT_ROOT / '_build'
  28. BOOTSTRAP_BASE_DIR = BUILD_DIR / '_bootstrap'
  29. PREBUILT_DIR = PROJECT_ROOT / '_prebuilt'
  30. EXE_SUFFIX = '.exe' if os.name == 'nt' else ''
  31. def _run_quiet(cmd, **kwargs) -> None:
  32. cmd = [str(s) for s in cmd]
  33. res = subprocess.run(
  34. cmd,
  35. stdout=subprocess.PIPE,
  36. stderr=subprocess.STDOUT,
  37. **kwargs,
  38. )
  39. if res.returncode != 0:
  40. print(f'Subprocess command {cmd} failed '
  41. f'[{res.returncode}]:\n{res.stdout.decode()}')
  42. raise subprocess.CalledProcessError(res.returncode, cmd)
  43. def _clone_bootstrap_phase(ref: str) -> Path:
  44. print(f'Clone revision: {ref}')
  45. bts_dir = BOOTSTRAP_BASE_DIR / ref
  46. if bts_dir.exists():
  47. shutil.rmtree(bts_dir)
  48. _run_quiet([
  49. 'git',
  50. 'clone',
  51. '--depth=1',
  52. f'--branch={ref}',
  53. f'file://{PROJECT_ROOT}',
  54. bts_dir,
  55. ])
  56. return bts_dir
  57. def _build_bootstrap_phase(ph: BootstrapPhase, bts_dir: Path) -> None:
  58. print(f'Build revision: {ph.ref} [This may take a moment]')
  59. env = os.environ.copy()
  60. env['DDS_BOOTSTRAP_PREV_EXE'] = str(PREBUILT_DIR / F'dds{EXE_SUFFIX}')
  61. _run_quiet(
  62. [
  63. sys.executable,
  64. '-u',
  65. str(bts_dir / 'tools/build.py'),
  66. f'--cxx={ph.platform_compiler}',
  67. ],
  68. env=env,
  69. cwd=bts_dir,
  70. )
  71. def _pull_executable(bts_dir: Path) -> Path:
  72. prebuild_dir = (PROJECT_ROOT / '_prebuilt')
  73. prebuild_dir.mkdir(exist_ok=True)
  74. generated = list(bts_dir.glob(f'_build/dds{EXE_SUFFIX}'))
  75. assert len(generated) == 1, repr(generated)
  76. exe, = generated
  77. dest = prebuild_dir / exe.name
  78. if dest.exists():
  79. dest.unlink()
  80. exe.rename(dest)
  81. return dest
  82. def _run_boot_phase(phase: BootstrapPhase) -> Path:
  83. bts_dir = _clone_bootstrap_phase(phase.ref)
  84. _build_bootstrap_phase(phase, bts_dir)
  85. return _pull_executable(bts_dir)
  86. def main() -> int:
  87. for idx, phase in enumerate(BOOTSTRAP_PHASES):
  88. print(f'Bootstrap phase [{idx+1}/{len(BOOTSTRAP_PHASES)}]')
  89. exe = _run_boot_phase(phase)
  90. print(f'A bootstrapped DDS executable has been generated: {exe}')
  91. return 0
  92. if __name__ == "__main__":
  93. sys.exit(main())