Skip to content

Commit

Permalink
Add a --sysroot-install-dir-targets flag for jenkins-cheri-build
Browse files Browse the repository at this point in the history
When target tarballs have been unpacked to the sysroot for use as
dependencies we need to tell jenkins-cheri-build not to assume they're
installed in the output root directory ($WORKSPACE/tarball). Sadly this
means piling more code into the existing hack.

Note that jenkins-cheri-build currently has the strange "feature" that
it always /opt/<suffix> regardless of what the target normally has, and
so we need to preserve this but relative to the sysroot, rather than
just not override the directory in the first place. This suffix also
includes the -for-<arch>-rootfs if present, unlike normal cheribuild.
  • Loading branch information
jrtc27 committed Sep 11, 2024
1 parent 648ff0a commit 3e952d2
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 31 deletions.
4 changes: 4 additions & 0 deletions pycheribuild/config/jenkinsconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ def __init__(self, loader: ConfigLoaderBase, available_targets: "list[str]") ->
"sysroot-extra-archives",
help="Addition archives to extract within the sysroot",
)
self.sysroot_install_dir_targets = loader.add_commandline_only_list_option(
"sysroot-install-dir-targets",
help="Targets for which to use the sysroot/rootfs rather than the output path",
)
self.keep_install_dir = loader.add_commandline_only_bool_option(
"keep-install-dir", help="Don't delete the install dir prior to build"
)
Expand Down
44 changes: 36 additions & 8 deletions pycheribuild/jenkins_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,52 @@
import inspect
from pathlib import Path

from .config.chericonfig import CheriConfig
from .config.jenkinsconfig import CheriConfig, JenkinsConfig
from .config.loader import CommandLineConfigOption
from .config.target_info import AbstractProject
from .projects.project import Project
from .targets import MultiArchTargetAlias, SimpleTargetAlias, Target, target_manager
from .utils import status_update
from .utils import fatal_error, status_update


def jenkins_override_install_dirs_hack(cheri_config: CheriConfig, install_prefix: Path):
expected_install_path = Path(f"{cheri_config.output_root}{install_prefix}")
# Ugly workaround to override all install dirs to go to the tarball
all_targets = [
x
for x in target_manager.targets(cheri_config)
if not isinstance(x, (SimpleTargetAlias, MultiArchTargetAlias)) and issubclass(x.project_class, Project)
]
if isinstance(cheri_config, JenkinsConfig):
sysroot_targets = [
target_manager.get_chosen_target(cheri_config, target_name)
for target_name in cheri_config.sysroot_install_dir_targets
]
else:
sysroot_targets = []

for target in sysroot_targets:
if target.xtarget.is_native():
fatal_error("Cannot use non-existent sysroot for native target", target.name, pretend=False)

def expected_install_root(target):
if target in sysroot_targets:
project = target._try_get_project()
if project is None:
target_info = target.xtarget.create_target_info(AbstractProject(cheri_config))
else:
target_info = project.target_info
sysroot_dir = target_info.sysroot_dir
return sysroot_dir
else:
return cheri_config.output_root

def expected_install_path(target):
root_dir = expected_install_root(target)
return Path(f"{root_dir}{install_prefix}")

for target in all_targets:
cls = target.project_class
cls._default_install_dir_fn = expected_install_path
cls._default_install_dir_fn = expected_install_path(target)

Target.instantiating_targets_should_warn = False
# Now that we have set the _install_dir member, override the prefix/destdir after instantiating.
Expand All @@ -66,15 +94,15 @@ def jenkins_override_install_dirs_hack(cheri_config: CheriConfig, install_prefix
status_update("Install directory for", cls.target, "was specified on commandline:", from_cmdline)
project._install_dir = from_cmdline
else:
project._install_dir = cheri_config.output_root
project._install_dir = expected_install_root(target)
project._check_install_dir_conflict = False
# Using "/" as the install prefix results inconsistently prefixing some paths with '/usr/'.
# To avoid this, just use the full install path as the prefix.
if install_prefix == Path("/"):
project._install_prefix = expected_install_path
project._install_prefix = expected_install_path(target)
project.destdir = Path("/")
else:
project._install_prefix = install_prefix
project.destdir = cheri_config.output_root
assert project.real_install_root_dir == expected_install_path
project.destdir = expected_install_root(target)
assert project.real_install_root_dir == expected_install_path(target)
assert isinstance(inspect.getattr_static(project, "_install_dir"), Path)
50 changes: 27 additions & 23 deletions pycheribuild/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ def get_real_target(
) -> "Target":
return self

def _try_get_project(self) -> "Optional[SimpleProject]":
return self.__project

def _get_or_create_project_no_setup(
self, _: Optional[CrossCompileTarget], config, caller: "Optional[AbstractProject]"
) -> "SimpleProject":
Expand Down Expand Up @@ -542,6 +545,29 @@ def run(self, config: CheriConfig, chosen_targets=None) -> None:
for target in chosen_targets:
target.execute(config)

def get_chosen_target(self, config, target_name) -> Target:
if target_name not in self._all_targets:
# See if it was a target alias without a default
if target_name in self._targets_for_command_line_options_only:
alias = self._targets_for_command_line_options_only[target_name]
errmsg = coloured(AnsiColour.red, "Target", target_name, "is ambiguous.")
suggestions = sorted([tgt.name for tgt in alias.derived_targets])
else:
import difflib

errmsg = coloured(AnsiColour.red, "Target", target_name, "does not exist.")
suggestions = difflib.get_close_matches(target_name, self.target_names(config))
if suggestions:
errmsg += " Did you mean " + " or ".join(coloured(AnsiColour.blue, s) for s in suggestions) + "?"
else:
errmsg += (
" See "
+ coloured(AnsiColour.yellow, os.path.basename(sys.argv[0]), "--list-targets")
+ " for the list of available targets."
)
sys.exit(errmsg)
return self.get_target(target_name, config=config, caller="cmdline parsing")

def get_all_chosen_targets(self, config) -> "list[Target]":
# check that all target dependencies are correct:
if os.getenv("CHERIBUILD_DEBUG"):
Expand All @@ -557,29 +583,7 @@ def get_all_chosen_targets(self, config) -> "list[Target]":
# assert self._all_targets["llvm"] < self._all_targets["all"]
# assert self._all_targets["disk-image"] > self._all_targets["qemu"]
# assert self._all_targets["sdk"] > self._all_targets["sdk-sysroot"]
explicitly_chosen_targets: "list[Target]" = []
for target_name in config.targets:
if target_name not in self._all_targets:
# See if it was a target alias without a default
if target_name in self._targets_for_command_line_options_only:
alias = self._targets_for_command_line_options_only[target_name]
errmsg = coloured(AnsiColour.red, "Target", target_name, "is ambiguous.")
suggestions = sorted([tgt.name for tgt in alias.derived_targets])
else:
import difflib

errmsg = coloured(AnsiColour.red, "Target", target_name, "does not exist.")
suggestions = difflib.get_close_matches(target_name, self.target_names(config))
if suggestions:
errmsg += " Did you mean " + " or ".join(coloured(AnsiColour.blue, s) for s in suggestions) + "?"
else:
errmsg += (
" See "
+ coloured(AnsiColour.yellow, os.path.basename(sys.argv[0]), "--list-targets")
+ " for the list of available targets."
)
sys.exit(errmsg)
explicitly_chosen_targets.append(self.get_target(target_name, config=config, caller="cmdline parsing"))
explicitly_chosen_targets = [self.get_chosen_target(config, target_name) for target_name in config.targets]
chosen_targets = self.get_all_targets(explicitly_chosen_targets, config)
for target in chosen_targets:
disabled = self.target_disabled_reason(target, config)
Expand Down

0 comments on commit 3e952d2

Please sign in to comment.