diff --git a/pkg/make_rpm.py b/pkg/make_rpm.py index e2ffca0a..76a2e51d 100644 --- a/pkg/make_rpm.py +++ b/pkg/make_rpm.py @@ -178,13 +178,14 @@ class RpmBuilder(object): RPMS_DIR = 'RPMS' DIRS = [SOURCE_DIR, BUILD_DIR, RPMS_DIR, TEMP_DIR] - def __init__(self, name, version, release, arch, rpmbuild_path, - source_date_epoch=None, + def __init__(self, name, version, release, arch, target_arch, + rpmbuild_path, source_date_epoch=None, debug=False): self.name = name self.version = helpers.GetFlagValue(version) self.release = helpers.GetFlagValue(release) self.arch = arch + self.target_arch = target_arch self.files = [] self.rpmbuild_path = FindRpmbuild(rpmbuild_path) self.rpm_path = None @@ -354,6 +355,10 @@ def CallRpmBuild(self, dirname, rpmbuild_args): '--buildroot=%s' % buildroot, ] # yapf: disable + # Target platform + if self.target_arch: + args += ['--target=%s' % self.target_arch] + # Macro-based RPM parameter substitution, if necessary inputs provided. if self.preamble_file: args += ['--define', 'build_rpm_options %s' % self.preamble_file] @@ -462,7 +467,10 @@ def main(argv): help='The release of the software being packaged.') parser.add_argument( '--arch', - help='The CPU architecture of the software being packaged.') + help='The CPU architecture of the machine on which it is built. ' + 'If the package is not architecture dependent, set this to "noarch".') + parser.add_argument('--target_arch', + help='The CPU architecture of the target platform the software being packaged for.') parser.add_argument('--spec_file', required=True, help='The file containing the RPM specification.') parser.add_argument('--out_file', required=True, @@ -501,7 +509,7 @@ def main(argv): try: builder = RpmBuilder(options.name, options.version, options.release, - options.arch, options.rpmbuild, + options.arch, options.target_arch, options.rpmbuild, source_date_epoch=options.source_date_epoch, debug=options.debug) builder.AddFiles(options.files) diff --git a/pkg/rpm_pfg.bzl b/pkg/rpm_pfg.bzl index 1e3450c1..596dc26d 100644 --- a/pkg/rpm_pfg.bzl +++ b/pkg/rpm_pfg.bzl @@ -142,7 +142,7 @@ def _make_absolute_if_not_already_or_is_macro(path): # this can be inlined easily. return path if path.startswith(("/", "%")) else "/" + path -#### Input processing helper functons. +#### Input processing helper functions. # TODO(nacl, #459): These are redundant with functions and structures in # pkg/private/pkg_files.bzl. We should really use the infrastructure provided @@ -251,7 +251,7 @@ def _pkg_rpm_impl(ctx): rpm_name, ctx.attr.version, ctx.attr.release, - ctx.attr.architecture, + ctx.attr.architecture if ctx.attr.architecture else ctx.attr.target_architecture, ) outputs, output_file, output_name = setup_output_files( @@ -432,6 +432,9 @@ def _pkg_rpm_impl(ctx): args.append("--out_file=" + output_file.path) + if ctx.attr.target_architecture: + args.append("--target_arch=" + ctx.attr.target_architecture) + # Add data files. if ctx.file.changelog: files.append(ctx.file.changelog) @@ -666,7 +669,7 @@ def _pkg_rpm_impl(ctx): output_groups = { "out": [default_file], "rpm": [output_file], - "changes": changes + "changes": changes, } return [ OutputGroupInfo(**output_groups), @@ -791,21 +794,30 @@ pkg_rpm = rule( # funny if it's not provided. The contents of the RPM are believed to # be set as expected, though. "architecture": attr.string( - doc = """Package architecture. + doc = """Host architecture. This currently sets the `BuildArch` tag, which influences the output architecture of the package. Typically, `BuildArch` only needs to be set when the package is - known to be cross-platform (e.g. written in an interpreted - language), or, less common, when it is known that the application is - only valid for specific architectures. + not architecture dependent (e.g. written in an interpreted + language). When no attribute is provided, this will default to your host's architecture. This is usually what you want. """, ), + "target_architecture": attr.string( + doc = """Package architecture. + + This currently sets the value for the "--target" argument to "rpmbuild" + to specify platform package is built for. + + When no attribute is provided, this will default to your host's + architecture. + """, + ), "license": attr.string( doc = """RPM "License" tag. diff --git a/tests/rpm/BUILD b/tests/rpm/BUILD index 5f91da8d..37f3f6ad 100644 --- a/tests/rpm/BUILD +++ b/tests/rpm/BUILD @@ -149,6 +149,19 @@ pkg_rpm( version = "1.1.1", ) +pkg_rpm( + name = "test_rpm_alien", + srcs = [ + ":test_pfg", + ], + target_architecture = "alien", + description = """pkg_rpm test rpm for alien target platform description""", + license = "Apache 2.0", + release = "2222", + summary = "pkg_rpm test rpm for alien target platform summary", + version = "1.1.1", +) + # Just like the above one, except the compression is changed. pkg_rpm( name = "test_rpm-bzip2", @@ -305,6 +318,7 @@ sh_library( testonly = True, srcs = [ ":test_rpm", + ":test_rpm_alien", ":test_rpm-bzip2", ":test_rpm_direct", ":test_rpm_manifest", diff --git a/tests/rpm/make_rpm_test.py b/tests/rpm/make_rpm_test.py index cb8608be..2a964a15 100644 --- a/tests/rpm/make_rpm_test.py +++ b/tests/rpm/make_rpm_test.py @@ -122,7 +122,7 @@ def testSetupWorkdir(self): with PrependPath([outer]): # Create the builder and exercise it. - builder = make_rpm.RpmBuilder('test', '1.0', '0', 'x86', None) + builder = make_rpm.RpmBuilder('test', '1.0', '0', 'x86', 'x86', None) # Create spec_file, test files. WriteFile('test.spec', 'Name: test', 'Version: 0.1', @@ -162,7 +162,7 @@ def testBuild(self): with PrependPath([outer]): # Create the builder and exercise it. - builder = make_rpm.RpmBuilder('test', '1.0', '0', 'x86', None) + builder = make_rpm.RpmBuilder('test', '1.0', '0', 'x86', 'x86', None) # Create spec_file, test files. WriteFile('test.spec', 'Name: test', 'Version: 0.1', diff --git a/tests/rpm/pkg_rpm_basic_test.py b/tests/rpm/pkg_rpm_basic_test.py index a152f064..21f2b6db 100644 --- a/tests/rpm/pkg_rpm_basic_test.py +++ b/tests/rpm/pkg_rpm_basic_test.py @@ -43,6 +43,8 @@ def setUp(self): self.runfiles = runfiles.Create() self.test_rpm_path = self.runfiles.Rlocation( "rules_pkg/tests/rpm/test_rpm.rpm") + self.test_rpm_alien_path = self.runfiles.Rlocation( + "rules_pkg/tests/rpm/test_rpm_alien.rpm") self.test_rpm_direct_path = self.runfiles.Rlocation( "rules_pkg/tests/rpm/test_rpm_direct.rpm") self.test_rpm_bzip2_path = self.runfiles.Rlocation( @@ -85,6 +87,25 @@ def test_basic_headers(self): output, expected, "RPM Tag {} does not match expected value".format(fieldname)) + def test_basic_headers_alien_target(self): + fields = { + "NAME": b"test_rpm_alien", + "VERSION": b"1.1.1", + "RELEASE": b"2222", + "ARCH": b"alien", + "GROUP": b"Unspecified", + "SUMMARY": b"pkg_rpm test rpm for alien target platform summary", + } + for fieldname, expected in fields.items(): + output = subprocess.check_output([ + "rpm", "-qp", "--queryformat", "%{" + fieldname + "}", + self.test_rpm_alien_path + ]) + + self.assertEqual( + output, expected, + "RPM Tag {} does not match expected value".format(fieldname)) + def test_contents(self): manifest_file = self.runfiles.Rlocation( "rules_pkg/tests/rpm/manifest.csv")