Skip to content

Commit 2d676f2

Browse files
committed
Proper compiler toolset abstraction
Setting CXX without setting the right AR as well turned out to be problematic on some setups.
1 parent 72d2e2e commit 2d676f2

3 files changed

Lines changed: 83 additions & 11 deletions

File tree

build_gn.py

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,108 @@
55
import sys
66
import stat
77
import shutil
8+
import argparse
89
import subprocess
910
from pathlib import Path
11+
from collections import namedtuple
1012

1113
PROJECT_DIR = Path(__file__).parent.resolve()
1214
SBUILD_DIR = PROJECT_DIR/"sbuild"
1315
GN_DIR = SBUILD_DIR/"gn"
1416
GN_REV = "3357c4f51b1a9e676378c695dd9c7e9911c35ee6"
1517

18+
1619
def log(*args, **kwargs):
1720
print(*args, **kwargs, file=sys.stderr)
1821

1922
def run_cmd(command, cwd, **kwargs):
2023
log(f"{command} (cwd={cwd})")
2124
return subprocess.run(command, cwd=cwd, check=True, **kwargs)
2225

23-
def make_executable(path):
26+
def _make_executable(path):
2427
path.chmod(path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
2528

26-
def build_gn():
29+
def _env_prepend(key, value, sep):
30+
tail = os.environ.get(key, "")
31+
if tail:
32+
tail = sep + tail
33+
os.environ[key] = value + tail
34+
35+
36+
CompilerToolset = namedtuple("CompilerToolset", ("CXX", "AR", "LD"), defaults=(None, ))
37+
38+
def build(toolset):
39+
2740
# GN's build system runs git commands that assume a full checkout
2841
# --depth 1 checkout would need a manually created sbuild/gn/out/last_commit_position.h and passing "--no-last-commit-position" to build/gen.py - probably not worth the trouble for now.
2942
SBUILD_DIR.mkdir(exist_ok=True)
3043
if not GN_DIR.exists():
3144
run_cmd(["git", "clone", "https://gn.googlesource.com/gn/"], cwd=SBUILD_DIR)
3245
run_cmd(["git", "checkout", GN_REV], cwd=GN_DIR)
33-
env = os.environ.copy()
34-
env["CXX"] = os.environ.get("CXX", "g++")
35-
run_cmd([sys.executable, "build/gen.py", "--no-static-libstdc++", "--allow-warnings"], cwd=GN_DIR, env=env)
46+
47+
env = os.environ
48+
if toolset:
49+
env = env.copy()
50+
env["CXX"] = toolset.CXX
51+
env["AR"] = toolset.AR
52+
env["LD"] = toolset.LD or toolset.CXX
53+
54+
args = [sys.executable, "build/gen.py", "--allow-warnings", "--no-static-libstdc++"]
55+
run_cmd(args, cwd=GN_DIR, env=env)
3656
# TODO on CI, build and run unittests
3757
run_cmd(["ninja", "-C", "out", "gn"], cwd=GN_DIR)
3858
target_path = PROJECT_DIR/"src"/"gn_dist"/"gn"
3959
shutil.copyfile(GN_DIR/"out"/"gn", target_path)
40-
make_executable(target_path)
60+
_make_executable(target_path)
61+
62+
63+
def assisted_build(compiler=None, toolprefix="", clang_path=None):
64+
65+
if compiler is None:
66+
compiler = "gcc"
67+
68+
if compiler == "gcc":
69+
toolset = CompilerToolset(CXX=toolprefix+"g++", AR=toolprefix+"ar")
70+
elif compiler == "clang":
71+
toolset = CompilerToolset(CXX="clang++", AR="llvm-ar")
72+
if clang_path:
73+
_env_prepend("PATH", str(clang_path/"bin"), os.pathsep)
74+
elif compiler == "custom":
75+
toolset = CompilerToolset(
76+
CXX=os.environ["CXX"], AR=os.environ["AR"], LD=os.environ.get("LD"),
77+
)
78+
else:
79+
assert False, compiler
80+
81+
build(toolset)
82+
83+
84+
def parse_args(argv):
85+
parser = argparse.ArgumentParser(
86+
description="GN build script",
87+
)
88+
parser.add_argument(
89+
"-c", "--compiler",
90+
choices=("gcc", "clang", "custom"),
91+
help = "The compiler to use.",
92+
)
93+
parser.add_argument(
94+
"--toolprefix",
95+
default = "",
96+
help = "(gcc only) Toolprefix to use.",
97+
)
98+
parser.add_argument(
99+
"--clang-path",
100+
type = lambda p: Path(p).expanduser().resolve(),
101+
help = "(clang only) Clang root dir to use.",
102+
)
103+
return parser.parse_args(argv)
104+
105+
106+
def main():
107+
args = parse_args(sys.argv[1:])
108+
assisted_build(**vars(args))
109+
41110

42111
if __name__ == "__main__":
43-
build_gn()
112+
main()

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,4 @@ before-all = [
6565
"bash ./utils/install-static-clang.sh",
6666
]
6767
inherit.environment = "append"
68-
environment.CXX = "clang++"
69-
environment.PATH = "/opt/clang/bin:$PATH"
68+
environment.BUILD_PARAMS = "-c clang --clang-path /opt/clang"

setup.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# SPDX-FileCopyrightText: 2026 geisserml <geisserml@gmail.com>
22
# SPDX-License-Identifier: BSD-3-Clause
33

4+
import os
45
import sys
6+
import shlex
57
from pathlib import Path
68
import setuptools
79
from setuptools.command.build_py import build_py
@@ -11,12 +13,14 @@
1113
from wheel.bdist_wheel import bdist_wheel
1214

1315
sys.path.insert(0, str(Path(__file__).parent))
14-
from build_gn import build_gn # local
16+
from build_gn import parse_args, assisted_build # local
1517

1618

1719
class BuildPyClass(build_py):
1820
def run(self):
19-
build_gn()
21+
build_params = os.environ.get("BUILD_PARAMS", "")
22+
args = parse_args(shlex.split(build_params))
23+
assisted_build(**vars(args))
2024
build_py.run(self)
2125

2226
class BdistWheelClass(bdist_wheel):

0 commit comments

Comments
 (0)