diff --git a/generate-rpm-note.sh b/generate-rpm-note.sh index edf5cb1..ed84aae 100755 --- a/generate-rpm-note.sh +++ b/generate-rpm-note.sh @@ -1,66 +1,24 @@ -#!/bin/bash - -readonly=1 -insert_after=1 - -pad_string() { - for _ in $(seq "$1"); do - printf ' BYTE(0x00)' - done -} - -write_string() { - text="$1" - prefix="$2" - label="$3" - total="$4" - - printf "%s/* %s: '%s' */" "$prefix" "$label" "$text" - for i in $(seq ${#text}); do - if (( i % 4 == 1 )); then - printf '\n%s' "$prefix" - else - printf ' ' - fi - printf 'BYTE(0x%02x)' "'${text:i-1:1}" - done - - pad_string $(( total - ${#text} )) - printf '\n' -} - -write_script() { - value_len=$(( (${#1} + 3) / 4 * 4 )) - [ -n "$readonly" ] && readonly_attr='(READONLY) ' - - printf 'SECTIONS\n{\n' - printf ' .note.package %s: ALIGN(4) {\n' "$readonly_attr" - # Note that for the binary fields we use the native 4 bytes type, to avoid - # endianness issues. - printf ' LONG(0x0004) /* Length of Owner including NUL */\n' - printf ' LONG(0x%04x) /* Length of Value including NUL */\n' \ - ${value_len} - printf ' LONG(0xcafe1a7e) /* Note ID */\n' - - printf " BYTE(0x46) BYTE(0x44) BYTE(0x4f) BYTE(0x00) /* Owner: 'FDO' */\n" - - write_string "$1" ' ' 'Value' "$value_len" - - printf ' }\n}\n' - [ -n "$insert_after" ] && printf 'INSERT AFTER .note.gnu.build-id;\n' - : -} - -if [ "$1" == "--readonly=no" ]; then - shift - readonly= -fi - -if [ "$1" == "--insert-after=no" ]; then - shift - insert_after= -fi +#!/bin/sh +# SPDX-License-Identifier: 0BSD +# Prints a quoted --package-metadata string suitable for being used from an RPM +# macro in a way that gets correctly propagated down to the linker. cpe="$(cat /usr/lib/system-release-cpe)" -json="$(printf '{"type":"rpm","name":"%s","version":"%s","architecture":"%s","osCpe":"%s"}' "$1" "$2" "$3" "$cpe")" -write_script "$json" + +# We need to print the escapes as-is, so single quote echo, but also print the +# variables, so do it in multiple lines. +# The many quotes are necessary so that the compiler gets: +# -Xlinker "--package-metadata={\"type\":\"rpm\",\"name\":\"foo\",\"version\":\"bar\",\"architecture\":\"baz\",\"osCpe\":\"barbaz\"}" +# This way the inner quotes make it into the parsed string, and the outer quotes +# ensure the { } do not get expanded. -Xlinker instead of -Wl allows to use commas. +echo -n '-Xlinker \"--package-metadata={\\\"type\\\":\\\"rpm\\\",\\\"name\\\":\\\"' +echo -n "$1" +echo -n '\\\",\\\"version\\\":\\\"' +echo -n "$2" +echo -n '\\\",\\\"architecture\\\":\\\"' +echo -n "$3" +echo -n '\\\",\\\"osCpe\\\":\\\"' +echo -n "$cpe" +# Yes, the closing bracket needs to be escaped, otherwise it gets duplicated: +# "--package-metadata={\"type\":\"rpm\",\"name\":\"foo\",\"version\":\"bar\",\"architecture\":\"baz\",\"osCpe\":\"barbaz\"}"} +echo -n '\\\"\}\"' diff --git a/macros.package-notes-srpm b/macros.package-notes-srpm index 213d051..c7db29c 100644 --- a/macros.package-notes-srpm +++ b/macros.package-notes-srpm @@ -7,49 +7,26 @@ # To opt out of the use of this feature completely, include this in # the spec file: # -# %undefine _package_note_file +# %undefine _package_note_flags # -# The other macros can be undefined too to replace parts of the -# functionality. If %_generate_package_note_file is undefined, the -# linker script will not be generated, but the link flags may still -# refer to it. This may be useful if the default generation method is -# insufficient and a different mechanism will be used to generate -# %_package_note_file. If %_package_note_flags is undefined, the -# linker argument that injects the script will not be added to -# %build_ldfags, but the linker script would still be generated. - -# The name of the file with the linker script. If %{buildsubdir} is -# defined, the file will be placed therein. Otherwise, one level up, -# directly in %{_builddir}. -# -# Note that %{version}-%{release} used here might be redefined from -# the "primary" values when subpackages with different version-release -# are specified. The contents of the script use the shell variable -# $RPM_PACKAGE_NAME, $RPM_PACKAGE_VERSION, $RPM_PACKAGE_RELEASE, -# and $RPM_ARCH that are set early and seem to always contain the "primary" -# values for the main package. -%_package_note_file %{_builddir}%{?buildsubdir:/%{buildsubdir}}/.package_note-%{name}-%{version}-%{release}.%{_arch}.ld - # Which linker will be used? This should be either "bfd", "gold", or -# "lld". Unfortunately linkers other than bfd do not support some of -# the options that we'd like to use, so if this is set to anything -# other than "bfd", note insertion is disabled. +# "mold". Unfortunately "lld" does not support the --package-metadata flag so +# the note insertion is disabled when using it. # # (The default linker for clang on armv7hl is lld.) %_package_note_linker %["%_target_cpu" == "armv7hl" && "%{toolchain}" == "clang" ? "lld" : "bfd"] -# Whether to specify the READONLY attribute for the inserted -# section. We generally want this, but binutils <= 2.37 and other -# linkers do not support it. -%_package_note_readonly %["%_package_note_linker" == "bfd"?"1":"0"] +# These are defined for backwards compatibility. Do not use. +%_package_note_file 1 +%_generate_package_note_file %{nil} # Overall status: 1 if looks like we can insert the note, 0 otherwise -%_package_note_status %[0%{?_package_note_file:1} && 0%{?name:1} && "%_target_cpu" != "noarch" && "%_package_note_linker" == "bfd" ? 1 : 0] +%_package_note_status %[0%{?_package_note_file:1} && 0%{?name:1} && "%_target_cpu" != "noarch" && "%_package_note_linker" != "lld" ? 1 : 0] -# The linker flags to be passed to the compiler to insert the notes section. -%_package_note_flags %[%_package_note_status?"-Wl,%["%_package_note_linker" != "lld"?"-dT":"-T"],%{_package_note_file}":""] +# The linker flags to be passed to the compiler to insert the notes section will be created by the spec file, +# to avoid issues with quoting and escaping across different build systems and shells. +%_package_note_flags %[%_package_note_status?"-specs=/usr/lib/rpm/redhat/redhat-package-notes":""] -# The command to actually generate the linker script that inserts the -# notes file. This command is automatically used as part of the build -# preamble. -%_generate_package_note_file %[%_package_note_status?"if [ -f %{_rpmconfigdir}/generate-rpm-note.sh ]; then %{_rpmconfigdir}/generate-rpm-note.sh %[0%{?_package_note_readonly}?"":"--readonly=no "]${RPM_PACKAGE_NAME:?} ${RPM_PACKAGE_VERSION:?}-${RPM_PACKAGE_RELEASE:?} ${RPM_ARCH:?} >%{_package_note_file}; fi":""] +# Passing linker flags inline via -Xlinker causes autotools failures, as libtool eats the escaped quotes +#%_package_note_json %(%{_rpmconfigdir}/generate-rpm-note.sh %name %version %_arch) +#%_package_note_flags %[%_package_note_status?"%_package_note_json":""] diff --git a/package-notes.spec b/package-notes.spec index e7f26a1..03d9a22 100644 --- a/package-notes.spec +++ b/package-notes.spec @@ -1,21 +1,14 @@ Name: package-notes -Version: 0.4 +Version: 0.5 Release: %autorelease -Summary: Generate a linker script to insert .note.package section - -%global forgeurl https://github.com/systemd/package-notes -%forgemeta - -License: CC0 -URL: %{forgeurl} -Source0: %{forgesource} +Summary: Generate LDFLAGS to insert .note.package section +License: 0BSD +Source0: redhat-package-notes.in Source1: generate-rpm-note.sh Source2: macros.package-notes-srpm BuildArch: noarch -BuildRequires: python3-devel -Requires: python3dist(simplejson) %description This package provides a generator of linker scripts that insert a section with @@ -24,33 +17,31 @@ for. %package srpm-macros Summary: %{summary} +Obsoletes: package-notes < 0.5 +# Those are minimum versions that implement --package-metadata +Conflicts: binutils < 2.38-23 +Conflicts: binutils-gold < 2.38-23 +Conflicts: mold < 1.3.0 %description srpm-macros -RPM macros to inject a linker script into link flags and a helper to generate -a script that inserts a section with an ELF note with a JSON payload that -describes the package the binary was built for. +RPM macros to insert a section with an ELF note with a JSON payload that +describes the package the binary was built for via compiler spec file. %prep -%autosetup - -%build # nothing to do -%install -install -Dt %{buildroot}%{_bindir}/ generate-package-notes -install -m0644 -Dt %{buildroot}%{_mandir}/man1/ debian/generate-package-notes.1 +%build +sed "s|@OSCPE@|$(cat /usr/lib/system-release-cpe)|" %{SOURCE0} > redhat-package-notes -# A partial reimplementation without Python +%install +install -Dt %{buildroot}%{_rpmconfigdir}/redhat/ redhat-package-notes install -Dt %{buildroot}%{_rpmconfigdir}/ %{SOURCE1} install -m0644 -Dt %{buildroot}%{_rpmmacrodir}/ %{SOURCE2} -%files -%{_bindir}/generate-package-notes -%{_mandir}/man1/generate-package-notes.1* - %files srpm-macros %{_rpmconfigdir}/generate-rpm-note.sh %{_rpmmacrodir}/macros.package-notes-srpm +%{_rpmconfigdir}/redhat/redhat-package-notes %changelog %autochangelog diff --git a/redhat-package-notes.in b/redhat-package-notes.in new file mode 100644 index 0000000..3a19b1b --- /dev/null +++ b/redhat-package-notes.in @@ -0,0 +1,2 @@ +*link: ++ --package-metadata={\"type\":\"rpm\",\"name\":\"%:getenv(RPM_PACKAGE_NAME \",\"version\":\"%:getenv(RPM_PACKAGE_VERSION -%:getenv(RPM_PACKAGE_RELEASE \",\"architecture\":\"%:getenv(RPM_ARCH \",\"osCpe\":\"@OSCPE@\"})))) diff --git a/sources b/sources index 180591a..e69de29 100644 --- a/sources +++ b/sources @@ -1 +0,0 @@ -SHA512 (package-notes-0.4.tar.gz) = 97a36e4125db99bca02e02eac5d2f823ae38e4c8a083a624f5f72f8d4a4c80fcfb24c8d15bbb922e0f28f5d6da97a87789a881a26aa02e2c1034c485a8866735