diff --git a/buildstream/_options/optionarch.py b/buildstream/_options/optionarch.py index 1d8509cf202e4af1ed233a9436e123002e1180e8..0e2963c8465753ba85ea03bc5bd66018ae38fd0f 100644 --- a/buildstream/_options/optionarch.py +++ b/buildstream/_options/optionarch.py @@ -17,6 +17,8 @@ # Authors: # Tristan Van Berkom <tristan.vanberkom@codethink.co.uk> +from .. import _yaml +from .._exceptions import LoadError, LoadErrorReason, PlatformError from .._platform import Platform from .optionenum import OptionEnum @@ -41,7 +43,34 @@ class OptionArch(OptionEnum): super(OptionArch, self).load(node, allow_default_definition=False) def load_default_value(self, node): - return Platform.get_host_arch() + arch = Platform.get_host_arch() + + default_value = None + + for index, value in enumerate(self.values): + try: + canonical_value = Platform.canonicalize_arch(value) + if default_value is None and canonical_value == arch: + default_value = value + # Do not terminate the loop early to ensure we validate + # all values in the list. + except PlatformError as e: + provenance = _yaml.node_get_provenance(node, key='values', indices=[index]) + prefix = "" + if provenance: + prefix = "{}: ".format(provenance) + raise LoadError(LoadErrorReason.INVALID_DATA, + "{}Invalid value for {} option '{}': {}" + .format(prefix, self.OPTION_TYPE, self.name, e)) + + if default_value is None: + # Host architecture is not supported by the project. + # Do not raise an error here as the user may override it. + # If the user does not override it, an error will be raised + # by resolve()/validate(). + default_value = arch + + return default_value def resolve(self): diff --git a/buildstream/_platform/platform.py b/buildstream/_platform/platform.py index 42b360ff868c8e106ae13de95cc7856db71138ad..73ed571fe35c5c34a8e08d32a9cc324604cc1b0e 100644 --- a/buildstream/_platform/platform.py +++ b/buildstream/_platform/platform.py @@ -77,20 +77,17 @@ class Platform(): def get_host_os(): return os.uname()[0] - # get_host_arch(): + # canonicalize_arch(): # - # This returns the architecture of the host machine. The possible values - # map from uname -m in order to be a OS independent list. + # This returns the canonical, OS-independent architecture name + # or raises a PlatformError if the architecture is unknown. # - # Returns: - # (string): String representing the architecture @staticmethod - def get_host_arch(): - # get the hardware identifier from uname - uname_machine = os.uname()[4] - uname_to_arch = { + def canonicalize_arch(arch): + aliases = { + "aarch32": "aarch32", "aarch64": "aarch64", - "aarch64_be": "aarch64-be", + "aarch64-be": "aarch64-be", "amd64": "x86-64", "arm": "aarch32", "armv8l": "aarch64", @@ -99,17 +96,34 @@ class Platform(): "i486": "x86-32", "i586": "x86-32", "i686": "x86-32", + "power-isa-be": "power-isa-be", + "power-isa-le": "power-isa-le", "ppc64": "power-isa-be", "ppc64le": "power-isa-le", "sparc": "sparc-v9", "sparc64": "sparc-v9", - "x86_64": "x86-64" + "sparc-v9": "sparc-v9", + "x86-32": "x86-32", + "x86-64": "x86-64" } + try: - return uname_to_arch[uname_machine] + return aliases[arch.replace('_', '-')] except KeyError: - raise PlatformError("uname gave unsupported machine architecture: {}" - .format(uname_machine)) + raise PlatformError("Unknown architecture: {}".format(arch)) + + # get_host_arch(): + # + # This returns the architecture of the host machine. The possible values + # map from uname -m in order to be a OS independent list. + # + # Returns: + # (string): String representing the architecture + @staticmethod + def get_host_arch(): + # get the hardware identifier from uname + uname_machine = os.uname()[4] + return Platform.canonicalize_arch(uname_machine) ################################################################## # Sandbox functions # diff --git a/buildstream/element.py b/buildstream/element.py index 3bfe622752351516ac843df7118fa758428bf3c8..c5fbf772cbf637c9af67c75d56d685f253baf851 100644 --- a/buildstream/element.py +++ b/buildstream/element.py @@ -2441,11 +2441,17 @@ class Element(Plugin): # Sandbox config, unlike others, has fixed members so we should validate them _yaml.node_validate(sandbox_config, ['build-uid', 'build-gid', 'build-os', 'build-arch']) + build_arch = self.node_get_member(sandbox_config, str, 'build-arch', default=None) + if build_arch: + build_arch = Platform.canonicalize_arch(build_arch) + else: + build_arch = host_arch + return SandboxConfig( self.node_get_member(sandbox_config, int, 'build-uid'), self.node_get_member(sandbox_config, int, 'build-gid'), self.node_get_member(sandbox_config, str, 'build-os', default=host_os), - self.node_get_member(sandbox_config, str, 'build-arch', default=host_arch)) + build_arch) # This makes a special exception for the split rules, which # elements may extend but whos defaults are defined in the project. diff --git a/tests/format/option-arch-alias/element.bst b/tests/format/option-arch-alias/element.bst new file mode 100644 index 0000000000000000000000000000000000000000..92ebfb134caef74aa9338bfb767d81484b5d7061 --- /dev/null +++ b/tests/format/option-arch-alias/element.bst @@ -0,0 +1,8 @@ +kind: autotools +variables: + result: "Nothing" + (?): + - machine_arch == "arm": + result: "Army" + - machine_arch == "x86_64": + result: "X86-64y" diff --git a/tests/format/option-arch-alias/project.conf b/tests/format/option-arch-alias/project.conf new file mode 100644 index 0000000000000000000000000000000000000000..47f0945c9744c780ccaae367d51e3215a04674b6 --- /dev/null +++ b/tests/format/option-arch-alias/project.conf @@ -0,0 +1,9 @@ +name: test + +options: + machine_arch: + type: arch + description: The machine architecture + values: + - arm + - x86_64 diff --git a/tests/format/option-arch-unknown/element.bst b/tests/format/option-arch-unknown/element.bst new file mode 100644 index 0000000000000000000000000000000000000000..c4376715b6c61acd85c4d10b82351fb974893f7d --- /dev/null +++ b/tests/format/option-arch-unknown/element.bst @@ -0,0 +1,10 @@ +kind: autotools +variables: + result: "Nothing" + (?): + - machine_arch == "aarch32": + result: "Army" + - machine_arch == "aarch64": + result: "Aarchy" + - machine_arch == "x86-128": + result: "X86-128y" diff --git a/tests/format/option-arch-unknown/project.conf b/tests/format/option-arch-unknown/project.conf new file mode 100644 index 0000000000000000000000000000000000000000..0827ec38786066a0a0cc860c51cf26e95584dead --- /dev/null +++ b/tests/format/option-arch-unknown/project.conf @@ -0,0 +1,10 @@ +name: test + +options: + machine_arch: + type: arch + description: The machine architecture + values: + - aarch32 + - aarch64 + - x86-128 diff --git a/tests/format/optionarch.py b/tests/format/optionarch.py index 901b6e2da6fd2b41774bc0d8d1706e59824c4ef4..09f9c07c9ba2169a496bcce76da6ec3464579948 100644 --- a/tests/format/optionarch.py +++ b/tests/format/optionarch.py @@ -75,3 +75,47 @@ def test_unsupported_arch(cli, datafiles): ]) result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_DATA) + + +@pytest.mark.datafiles(DATA_DIR) +def test_alias(cli, datafiles): + + with override_uname_arch("arm"): + project = os.path.join(datafiles.dirname, datafiles.basename, 'option-arch-alias') + result = cli.run(project=project, silent=True, args=[ + 'show', + '--deps', 'none', + '--format', '%{vars}', + 'element.bst' + ]) + + result.assert_success() + + +@pytest.mark.datafiles(DATA_DIR) +def test_unknown_host_arch(cli, datafiles): + + with override_uname_arch("x86_128"): + project = os.path.join(datafiles.dirname, datafiles.basename, 'option-arch') + result = cli.run(project=project, silent=True, args=[ + 'show', + '--deps', 'none', + '--format', '%{vars}', + 'element.bst' + ]) + + result.assert_main_error(ErrorDomain.PLATFORM, None) + + +@pytest.mark.datafiles(DATA_DIR) +def test_unknown_project_arch(cli, datafiles): + + project = os.path.join(datafiles.dirname, datafiles.basename, 'option-arch-unknown') + result = cli.run(project=project, silent=True, args=[ + 'show', + '--deps', 'none', + '--format', '%{vars}', + 'element.bst' + ]) + + result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_DATA)