1
0
mirror of https://github.com/facebook/proxygen.git synced 2025-08-08 18:02:05 +03:00

Refactoring

Summary:
X-link: https://github.com/facebookincubator/zstrong/pull/897

Builder refactoring: instead of providing `install_dirs` to `build()`, `test()` etc., provide `loader` and `dep_manifests` when creating the builder. This is a cleaner API because we were computing `install_dirs` in multiple places before.

Furthermore this lets us do things that need to see the manifests of the dependencies, not just the list of `install_dirs`, such as treating direct dependencies differently from indirect dependencies (see D58244928).

Reviewed By: chadaustin

Differential Revision: D58200528

fbshipit-source-id: e52d35e84161b83ab49ab43099c3e3b9bb03f36e
This commit is contained in:
Simon Marlow
2024-06-26 17:02:17 -07:00
committed by Facebook GitHub Bot
parent 1c567ba69a
commit 6790282a52
6 changed files with 307 additions and 122 deletions

View File

@@ -29,6 +29,8 @@ if typing.TYPE_CHECKING:
class BuilderBase(object):
def __init__(
self,
loader,
dep_manifests, # manifests of dependencies
build_opts: "BuildOptions",
ctx,
manifest,
@@ -55,6 +57,9 @@ class BuilderBase(object):
self.build_opts = build_opts
self.manifest = manifest
self.final_install_prefix = final_install_prefix
self.loader = loader
self.dep_manifests = dep_manifests
self.install_dirs = [loader.get_project_install_dir(m) for m in dep_manifests]
def _get_cmd_prefix(self):
if self.build_opts.is_windows():
@@ -136,28 +141,28 @@ class BuilderBase(object):
os.chdir(old_wd)
patched_sentinel_file.touch()
def prepare(self, install_dirs, reconfigure: bool) -> None:
def prepare(self, reconfigure: bool) -> None:
print("Preparing %s..." % self.manifest.name)
reconfigure = self._reconfigure(reconfigure)
self._apply_patchfile()
self._prepare(install_dirs=install_dirs, reconfigure=reconfigure)
self._prepare(reconfigure=reconfigure)
def debug(self, install_dirs, reconfigure: bool) -> None:
def debug(self, reconfigure: bool) -> None:
reconfigure = self._reconfigure(reconfigure)
self._apply_patchfile()
self._prepare(install_dirs=install_dirs, reconfigure=reconfigure)
env = self._compute_env(install_dirs)
self._prepare(reconfigure=reconfigure)
env = self._compute_env()
print("Starting a shell in %s, ^D to exit..." % self.build_dir)
# TODO: print the command to run the build
shell = ["powershell.exe"] if sys.platform == "win32" else ["/bin/sh", "-i"]
self._run_cmd(shell, cwd=self.build_dir, env=env)
def build(self, install_dirs, reconfigure: bool) -> None:
def build(self, reconfigure: bool) -> None:
print("Building %s..." % self.manifest.name)
reconfigure = self._reconfigure(reconfigure)
self._apply_patchfile()
self._prepare(install_dirs=install_dirs, reconfigure=reconfigure)
self._build(install_dirs=install_dirs, reconfigure=reconfigure)
self._prepare(reconfigure=reconfigure)
self._build(reconfigure=reconfigure)
if self.build_opts.free_up_disk:
# don't clean --src-dir=. case as user may want to build again or run tests on the build
@@ -174,8 +179,8 @@ class BuilderBase(object):
# needs to be updated to include all of the directories containing the runtime
# library dependencies in order to run the binaries.
script_path = self.get_dev_run_script_path()
dep_munger = create_dyn_dep_munger(self.build_opts, install_dirs)
dep_dirs = self.get_dev_run_extra_path_dirs(install_dirs, dep_munger)
dep_munger = create_dyn_dep_munger(self.build_opts, self.install_dirs)
dep_dirs = self.get_dev_run_extra_path_dirs(dep_munger)
# pyre-fixme[16]: Optional type has no attribute `emit_dev_run_script`.
dep_munger.emit_dev_run_script(script_path, dep_dirs)
@@ -200,49 +205,47 @@ class BuilderBase(object):
)
)
def run_tests(
self, install_dirs, schedule_type, owner, test_filter, retry, no_testpilot
) -> None:
def run_tests(self, schedule_type, owner, test_filter, retry, no_testpilot) -> None:
"""Execute any tests that we know how to run. If they fail,
raise an exception."""
pass
def _prepare(self, install_dirs, reconfigure) -> None:
def _prepare(self, reconfigure) -> None:
"""Prepare the build. Useful when need to generate config,
but builder is not the primary build system.
e.g. cargo when called from cmake"""
pass
def _build(self, install_dirs, reconfigure) -> None:
def _build(self, reconfigure) -> None:
"""Perform the build.
install_dirs contains the list of installation directories for
the dependencies of this project.
reconfigure will be set to true if the fetcher determined
that the sources have changed in such a way that the build
system needs to regenerate its rules."""
pass
def _compute_env(self, install_dirs):
def _compute_env(self):
# CMAKE_PREFIX_PATH is only respected when passed through the
# environment, so we construct an appropriate path to pass down
return self.build_opts.compute_env_for_install_dirs(
install_dirs, env=self.env, manifest=self.manifest
self.install_dirs, env=self.env, manifest=self.manifest
)
def get_dev_run_script_path(self):
assert self.build_opts.is_windows()
return os.path.join(self.build_dir, "run.ps1")
def get_dev_run_extra_path_dirs(self, install_dirs, dep_munger=None):
def get_dev_run_extra_path_dirs(self, dep_munger=None):
assert self.build_opts.is_windows()
if dep_munger is None:
dep_munger = create_dyn_dep_munger(self.build_opts, install_dirs)
dep_munger = create_dyn_dep_munger(self.build_opts, self.install_dirs)
return dep_munger.compute_dependency_paths(self.build_dir)
class MakeBuilder(BuilderBase):
def __init__(
self,
loader,
dep_manifests,
build_opts,
ctx,
manifest,
@@ -254,7 +257,14 @@ class MakeBuilder(BuilderBase):
test_args,
) -> None:
super(MakeBuilder, self).__init__(
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
loader,
dep_manifests,
build_opts,
ctx,
manifest,
src_dir,
build_dir,
inst_dir,
)
self.build_args = build_args or []
self.install_args = install_args or []
@@ -267,9 +277,9 @@ class MakeBuilder(BuilderBase):
def _get_prefix(self):
return ["PREFIX=" + self.inst_dir, "prefix=" + self.inst_dir]
def _build(self, install_dirs, reconfigure) -> None:
def _build(self, reconfigure) -> None:
env = self._compute_env(install_dirs)
env = self._compute_env()
# Need to ensure that PREFIX is set prior to install because
# libbpf uses it when generating its pkg-config file.
@@ -292,20 +302,18 @@ class MakeBuilder(BuilderBase):
for file in glob.glob(srcpattern):
shutil.copy(file, libdir)
def run_tests(
self, install_dirs, schedule_type, owner, test_filter, retry, no_testpilot
) -> None:
def run_tests(self, schedule_type, owner, test_filter, retry, no_testpilot) -> None:
if not self.test_args:
return
env = self._compute_env(install_dirs)
env = self._compute_env()
cmd = [self._make_binary] + self.test_args + self._get_prefix()
self._run_cmd(cmd, env=env)
class CMakeBootStrapBuilder(MakeBuilder):
def _build(self, install_dirs, reconfigure) -> None:
def _build(self, reconfigure) -> None:
self._run_cmd(
[
"./bootstrap",
@@ -313,12 +321,14 @@ class CMakeBootStrapBuilder(MakeBuilder):
f"--parallel={self.num_jobs}",
]
)
super(CMakeBootStrapBuilder, self)._build(install_dirs, reconfigure)
super(CMakeBootStrapBuilder, self)._build(reconfigure)
class AutoconfBuilder(BuilderBase):
def __init__(
self,
loader,
dep_manifests,
build_opts,
ctx,
manifest,
@@ -329,7 +339,14 @@ class AutoconfBuilder(BuilderBase):
conf_env_args,
) -> None:
super(AutoconfBuilder, self).__init__(
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
loader,
dep_manifests,
build_opts,
ctx,
manifest,
src_dir,
build_dir,
inst_dir,
)
self.args = args or []
self.conf_env_args = conf_env_args or {}
@@ -338,11 +355,11 @@ class AutoconfBuilder(BuilderBase):
def _make_binary(self):
return self.manifest.get("build", "make_binary", "make", ctx=self.ctx)
def _build(self, install_dirs, reconfigure) -> None:
def _build(self, reconfigure) -> None:
configure_path = os.path.join(self.src_dir, "configure")
autogen_path = os.path.join(self.src_dir, "autogen.sh")
env = self._compute_env(install_dirs)
env = self._compute_env()
# Some configure scripts need additional env values passed derived from cmds
for k, cmd_args in self.conf_env_args.items():
@@ -383,12 +400,29 @@ class Iproute2Builder(BuilderBase):
# Thus, explicitly copy sources from src_dir to build_dir, build,
# and then install to inst_dir using DESTDIR
# lastly, also copy include from build_dir to inst_dir
def __init__(self, build_opts, ctx, manifest, src_dir, build_dir, inst_dir) -> None:
def __init__(
self,
loader,
dep_manifests,
build_opts,
ctx,
manifest,
src_dir,
build_dir,
inst_dir,
) -> None:
super(Iproute2Builder, self).__init__(
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
loader,
dep_manifests,
build_opts,
ctx,
manifest,
src_dir,
build_dir,
inst_dir,
)
def _build(self, install_dirs, reconfigure) -> None:
def _build(self, reconfigure) -> None:
configure_path = os.path.join(self.src_dir, "configure")
env = self.env.copy()
self._run_cmd([configure_path], env=env)
@@ -521,6 +555,8 @@ if __name__ == "__main__":
def __init__(
self,
loader,
dep_manifests,
build_opts,
ctx,
manifest,
@@ -528,12 +564,13 @@ if __name__ == "__main__":
build_dir,
inst_dir,
defines,
loader=None,
final_install_prefix=None,
extra_cmake_defines=None,
cmake_target="install",
) -> None:
super(CMakeBuilder, self).__init__(
loader,
dep_manifests,
build_opts,
ctx,
manifest,
@@ -694,10 +731,10 @@ if __name__ == "__main__":
return define_args
def _build(self, install_dirs, reconfigure: bool) -> None:
def _build(self, reconfigure: bool) -> None:
reconfigure = reconfigure or self._needs_reconfigure()
env = self._compute_env(install_dirs)
env = self._compute_env()
if not self.build_opts.is_windows() and self.final_install_prefix:
env["DESTDIR"] = self.inst_dir
@@ -740,9 +777,9 @@ if __name__ == "__main__":
)
def run_tests(
self, install_dirs, schedule_type, owner, test_filter, retry: int, no_testpilot
self, schedule_type, owner, test_filter, retry: int, no_testpilot
) -> None:
env = self._compute_env(install_dirs)
env = self._compute_env()
ctest = path_search(env, "ctest")
cmake = path_search(env, "cmake")
@@ -756,7 +793,7 @@ if __name__ == "__main__":
# since CMake will emit RPATH properly in the binary so they can find these
# dependencies.
if self.build_opts.is_windows():
path_entries = self.get_dev_run_extra_path_dirs(install_dirs)
path_entries = self.get_dev_run_extra_path_dirs()
path = env.get("PATH")
if path:
path_entries.insert(0, path)
@@ -853,7 +890,6 @@ if __name__ == "__main__":
env.set("http_proxy", "")
env.set("https_proxy", "")
runs = []
from sys import platform
with start_run(env["FBSOURCE_HASH"]) as run_id:
testpilot_args = [
@@ -957,12 +993,29 @@ if __name__ == "__main__":
class NinjaBootstrap(BuilderBase):
def __init__(self, build_opts, ctx, manifest, build_dir, src_dir, inst_dir) -> None:
def __init__(
self,
loader,
dep_manifests,
build_opts,
ctx,
manifest,
build_dir,
src_dir,
inst_dir,
) -> None:
super(NinjaBootstrap, self).__init__(
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
loader,
dep_manifests,
build_opts,
ctx,
manifest,
src_dir,
build_dir,
inst_dir,
)
def _build(self, install_dirs, reconfigure) -> None:
def _build(self, reconfigure) -> None:
self._run_cmd([sys.executable, "configure.py", "--bootstrap"], cwd=self.src_dir)
src_ninja = os.path.join(self.src_dir, "ninja")
dest_ninja = os.path.join(self.inst_dir, "bin/ninja")
@@ -974,20 +1027,37 @@ class NinjaBootstrap(BuilderBase):
class OpenSSLBuilder(BuilderBase):
def __init__(self, build_opts, ctx, manifest, build_dir, src_dir, inst_dir) -> None:
def __init__(
self,
loader,
dep_manifests,
build_opts,
ctx,
manifest,
build_dir,
src_dir,
inst_dir,
) -> None:
super(OpenSSLBuilder, self).__init__(
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
loader,
dep_manifests,
build_opts,
ctx,
manifest,
src_dir,
build_dir,
inst_dir,
)
def _build(self, install_dirs, reconfigure) -> None:
def _build(self, reconfigure) -> None:
configure = os.path.join(self.src_dir, "Configure")
# prefer to resolve the perl that we installed from
# our manifest on windows, but fall back to the system
# path on eg: darwin
env = self.env.copy()
for d in install_dirs:
bindir = os.path.join(d, "bin")
for m in self.dep_manifests:
bindir = os.path.join(self.loader.get_project_install_dir(m), "bin")
add_path_entry(env, "PATH", bindir, append=False)
perl = typing.cast(str, path_search(env, "perl", "perl"))
@@ -1037,7 +1107,16 @@ class OpenSSLBuilder(BuilderBase):
class Boost(BuilderBase):
def __init__(
self, build_opts, ctx, manifest, src_dir, build_dir, inst_dir, b2_args
self,
loader,
dep_manifests,
build_opts,
ctx,
manifest,
src_dir,
build_dir,
inst_dir,
b2_args,
) -> None:
children = os.listdir(src_dir)
assert len(children) == 1, "expected a single directory entry: %r" % (children,)
@@ -1045,12 +1124,19 @@ class Boost(BuilderBase):
assert boost_src.startswith("boost")
src_dir = os.path.join(src_dir, children[0])
super(Boost, self).__init__(
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
loader,
dep_manifests,
build_opts,
ctx,
manifest,
src_dir,
build_dir,
inst_dir,
)
self.b2_args = b2_args
def _build(self, install_dirs, reconfigure) -> None:
env = self._compute_env(install_dirs)
def _build(self, reconfigure) -> None:
env = self._compute_env()
linkage = ["static"]
if self.build_opts.is_windows() or self.build_opts.shared_libs:
linkage.append("shared")
@@ -1105,12 +1191,14 @@ class Boost(BuilderBase):
class NopBuilder(BuilderBase):
def __init__(self, build_opts, ctx, manifest, src_dir, inst_dir) -> None:
def __init__(
self, loader, dep_manifests, build_opts, ctx, manifest, src_dir, inst_dir
) -> None:
super(NopBuilder, self).__init__(
build_opts, ctx, manifest, src_dir, None, inst_dir
loader, dep_manifests, build_opts, ctx, manifest, src_dir, None, inst_dir
)
def build(self, install_dirs, reconfigure: bool) -> None:
def build(self, reconfigure: bool) -> None:
print("Installing %s -> %s" % (self.src_dir, self.inst_dir))
parent = os.path.dirname(self.inst_dir)
if not os.path.exists(parent):
@@ -1147,12 +1235,29 @@ class NopBuilder(BuilderBase):
class SqliteBuilder(BuilderBase):
def __init__(self, build_opts, ctx, manifest, src_dir, build_dir, inst_dir) -> None:
def __init__(
self,
loader,
dep_manifests,
build_opts,
ctx,
manifest,
src_dir,
build_dir,
inst_dir,
) -> None:
super(SqliteBuilder, self).__init__(
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
loader,
dep_manifests,
build_opts,
ctx,
manifest,
src_dir,
build_dir,
inst_dir,
)
def _build(self, install_dirs, reconfigure) -> None:
def _build(self, reconfigure) -> None:
for f in ["sqlite3.c", "sqlite3.h", "sqlite3ext.h"]:
src = os.path.join(self.src_dir, f)
dest = os.path.join(self.build_dir, f)
@@ -1191,7 +1296,7 @@ install(FILES sqlite3.h sqlite3ext.h DESTINATION include)
define_args = ["-D%s=%s" % (k, v) for (k, v) in defines.items()]
define_args += ["-G", "Ninja"]
env = self._compute_env(install_dirs)
env = self._compute_env()
# Resolve the cmake that we installed
cmake = path_search(env, "cmake")