diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..d7653807 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,63 @@ +name: Build + +on: + push: + pull_request: + +jobs: + build: + # Just the dtk ci without versions (for now) + + # This is a *private* build container. + # See docs/github_actions.md for more information. + container: ghcr.io/punpckhdq/halo-build:main + + runs-on: ubuntu-latest + strategy: + fail-fast: false + + steps: + # Checkout the repository + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + + # Set Git config + - name: Git config + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + + # Normalize file mod times + - name: Restore timestamps + run: | + uv run https://raw.githubusercontent.com/MestreLion/git-tools/refs/tags/v2022.12/git-restore-mtime \ + --merge --commit-time + + # Copy the original files to the workspace + - name: Prepare + run: cp -a /orig/* . + + # Restore cached files + - name: Cache build + uses: actions/cache@v4 + with: + path: | + build + .ninja_deps + .ninja_log + key: ${{ runner.os }}-${{ github.sha }} + restore-keys: ${{ runner.os }}- + + # Build the project + - name: Build + run: | + python configure.py + ninja all_source progress build/report.json + + # Upload progress report + - name: Upload report + uses: actions/upload-artifact@v4 + with: + name: report + path: build/report.json diff --git a/configure.py b/configure.py index b2295a07..5c754811 100644 --- a/configure.py +++ b/configure.py @@ -27,6 +27,7 @@ from tools.project_x86 import ( SolutionConfig, calculate_progress, generate_build, + is_windows, ) import os # arguments @@ -56,6 +57,13 @@ parser.add_argument( type=Path, help="path to ninja binary (optional)", ) +if not is_windows(): + parser.add_argument( + "--wrapper", + metavar="BINARY", + type=Path, + help="path to wibo or wine (optional)", + ) args = parser.parse_args() @@ -105,10 +113,13 @@ sln.baserom = build_config["baserom"] sln.objdiff_path = args.objdiff sln.csplit_path = args.csplit sln.ninja_path = args.ninja +if not is_windows(): + sln.wrapper = args.wrapper # Tool versions sln.objdiff_tag = "v3.3.1" -sln.csplit_tag = "v0.0.1" +sln.csplit_tag = "v0.0.2" +sln.wibo_tag = "1.0.0" sln.projects = [] for build_project in build_config["projects"]: diff --git a/tools/project_x86.py b/tools/project_x86.py index 2309e7b9..e3fd7608 100644 --- a/tools/project_x86.py +++ b/tools/project_x86.py @@ -113,6 +113,8 @@ class SolutionConfig: self.csplit_path: Optional[Path] = None # If None, download self.objdiff_tag: Optional[str] = None # Git tag self.objdiff_path: Optional[Path] = None # If None, download + self.wibo_tag: Optional[str] = None # Git tag + self.wrapper: Optional[Path] = None # If None, download wibo on Linux # Project config self.baserom: Optional[Path] = None @@ -148,6 +150,26 @@ class SolutionConfig: for proj in self.projects: proj.validate() + # Gets the wrapper to use for compiler commands, if set. + def compiler_wrapper(self) -> Optional[Path]: + wrapper = self.wrapper + + if self.use_wibo(): + wrapper = self.build_dir / "tools" / "wibo" + if not is_windows() and wrapper is None: + wrapper = Path("wine") + + return wrapper + + # Determines whether or not to use wibo as the compiler wrapper. + def use_wibo(self) -> bool: + return ( + self.wibo_tag is not None + and (sys.platform == "linux" or sys.platform == "darwin") + and platform.machine() in ("i386", "x86_64", "aarch64", "arm64") + and self.wrapper is None + ) + def is_windows() -> bool: return os.name == "nt" @@ -226,6 +248,24 @@ def generate_build_ninja(sln: SolutionConfig) -> None: else: sys.exit("SolutionConfig.csplit_tag missing") + wrapper = sln.compiler_wrapper() + if wrapper is not None and sln.use_wibo(): + n.build( + outputs=wrapper, + rule="download_tool", + implicit=download_tool, + variables={ + "tool": "wibo", + "tag": sln.wibo_tag, + }, + ) + + wrapper_implicit: Optional[Path] = None + if wrapper is not None and (wrapper.exists() or sln.use_wibo()): + wrapper_implicit = wrapper + + wrapper_cmd = f"{wrapper} " if wrapper else "" + n.newline() ### @@ -244,7 +284,7 @@ def generate_build_ninja(sln: SolutionConfig) -> None: ### n.rule( name="cl", - command="xbox/bin/vc7/CL.Exe /nologo /c $cflags /Fo$out $in", + command=f"{wrapper_cmd}xbox/bin/vc7/CL.Exe /nologo /c $cflags /Fo$out $in", description="CL $out", ) n.newline() @@ -274,6 +314,7 @@ def generate_build_ninja(sln: SolutionConfig) -> None: rule="cl", variables={"cflags": cflags}, inputs=obj.file_path, + implicit=wrapper_implicit ) base_object_targets.extend(proj_base_object_targets) n.build(