Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions toolchain/mfc/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,38 @@ def get_install_binpath(self, case: Case) -> str:
return os.sep.join([self.get_install_dirpath(case), "bin", self.name])

def is_configured(self, case: Case) -> bool:
# We assume that if the CMakeCache.txt file exists, then the target is
# configured. (this isn't perfect, but it's good enough for now)
return os.path.isfile(os.sep.join([self.get_staging_dirpath(case), "CMakeCache.txt"]))
# CMake writes CMakeCache.txt before it generates the build system, so the
# cache alone does not mean the target is ready to build: a configure that
# was interrupted leaves the cache behind with no Makefile, and skipping
# configure on that basis fails later with "No rule to make target".
# Require the generator's build file too, asking the cache which generator
# it is rather than guessing. An unrecognized generator falls back to the
# cache alone, so this is never stricter than the old behaviour.
staging_dirpath = self.get_staging_dirpath(case)
cache_filepath = os.sep.join([staging_dirpath, "CMakeCache.txt"])
if not os.path.isfile(cache_filepath):
return False

generator = ""
with open(cache_filepath, "r") as f:
for line in f:
if line.startswith("CMAKE_GENERATOR:"):
generator = line.split("=", 1)[-1].strip()
break

if "Ninja" in generator:
return os.path.isfile(os.sep.join([staging_dirpath, "build.ninja"]))
if "Makefiles" in generator:
return os.path.isfile(os.sep.join([staging_dirpath, "Makefile"]))

return True

def is_installed(self, case: Case) -> bool:
# CMake writes an install manifest only after a successful install, so unlike
# CMakeCache.txt it is not left behind by a build that crashed. Multi-config
# generators name it install_manifest_<config>.txt, so match either form.
staging_dirpath = self.get_staging_dirpath(case)
return any(name.startswith("install_manifest") and name.endswith(".txt") for name in os.listdir(staging_dirpath)) if os.path.isdir(staging_dirpath) else False

def get_configuration_txt(self, case: Case) -> typing.Optional[dict]:
if not self.is_configured(case):
Expand Down Expand Up @@ -593,10 +622,12 @@ def __build_target(target: typing.Union[MFCTarget, str], case: input.MFCInputFil

history.add(target.name)

# Dependencies are pinned to fixed versions. If already configured
# (built & installed by a prior --deps-only step), skip entirely
# to avoid re-entering the superbuild (which may access the network).
if target.isDependency and target.is_configured(case):
# Dependencies are pinned to fixed versions, so skip one that a prior
# --deps-only step already installed, avoiding a re-entry into the superbuild
# (which may access the network). Gate on the install, not on the configure:
# a dependency build that crashed leaves CMakeCache.txt behind, and skipping
# on that would point CMAKE_PREFIX_PATH at an empty install tree forever.
if target.isDependency and target.is_installed(case):
return

for dep in target.requires.compute():
Expand Down
Loading