From efe6a367fbb47afbb04d256cbd5054bf57e4d293 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 27 Jan 2021 17:32:51 +0100 Subject: [PATCH 1/5] Add %bcond macro for defining build conditionals Fixes: https://github.com/rpm-software-management/rpm/issues/941 --- docs/manual/conditionalbuilds.md | 38 +++++++++++++++-- macros.in | 53 ++++++++++++++++------- tests/Makefile.am | 1 + tests/data/SPECS/bcondtest.spec | 33 +++++++++++++++ tests/rpmbuild.at | 73 ++++++++++++++++++++++++++++++++ 5 files changed, 179 insertions(+), 19 deletions(-) create mode 100644 tests/data/SPECS/bcondtest.spec diff --git a/docs/manual/conditionalbuilds.md b/docs/manual/conditionalbuilds.md index a64f87d9a8..a2d9139673 100644 --- a/docs/manual/conditionalbuilds.md +++ b/docs/manual/conditionalbuilds.md @@ -13,9 +13,38 @@ Here is an example of how to enable gnutls and disable openssl support: $ rpmbuild -ba newpackage.spec --with gnutls --without openssl ``` -## Enable `--with`/`--without` parameters +## Enable build conditionals -To use this feature in a spec file, add this to the beginning of the file: +To enable a build conditional in a spec file, use the `%bcond` macro at the +beginning of the file, specifying the name of the conditional and its default +value: + +``` +# To build with "gnutls" by default: +%bcond gnutls 1 +# To build without "gnutls" by default: +%bcond gnutls 0 +``` + +The default can be any numeric expression. +To pass a complex expression as a single argument, you can enclose it in +`%[...]` . + +``` +# Add `--with openssl` and `--without openssl`, with the default being the +# inverse of the gnutls setting: +%bcond openssl %{without gnutls} + +# Add `extra_tests` bcond, enabled by default if both of the other conditinals +# are enabled: +%bcond extra_tests %[%{with gnutls} && %{with sqlite}] +``` + + +### Enabling using `%bcond_with` and `%bcond_without` + +Build conditionals can also be enabled using the macros `%bcond_with` and +`%bcond_without`: ``` # add --with gnutls option, i.e. disable gnutls by default @@ -30,8 +59,9 @@ remainder of the spec file can be left unchanged. ## Check whether an option is enabled or disabled -To define `BuildRequires` depending on the command-line switch, you can use the -`%{with foo}` macro: +To make parts of the spec file conditional depending on the command-line +switch, you can use the `%{with foo}` macro or its counterpart, +`%{without foo}`: ``` %if %{with gnutls} diff --git a/macros.in b/macros.in index 22f675cdb5..1e2624842e 100644 --- a/macros.in +++ b/macros.in @@ -78,24 +78,33 @@ %defined() %{expand:%%{?%{1}:1}%%{!?%{1}:0}} %undefined() %{expand:%%{?%{1}:0}%%{!?%{1}:1}} -# Shorthand for %{defined with_...} +# Handle conditional builds. +# +# Shorthands for %{defined with_...}: %with() %{expand:%%{?with_%{1}:1}%%{!?with_%{1}:0}} %without() %{expand:%%{?with_%{1}:0}%%{!?with_%{1}:1}} -# Handle conditional builds. %bcond_with is for case when feature is -# default off and needs to be activated with --with ... command line -# switch. %bcond_without is for the dual case. -# -# %bcond_with foo defines symbol with_foo if --with foo was specified on -# command line. -# %bcond_without foo defines symbol with_foo if --without foo was *not* -# specified on command line. +# When checking conditions: never use without_foo, _with_foo nor _without_foo, +# only with_foo. This way changing default set of bconds for given spec is just +# a matter of changing single line in it and syntax is more readable. + +# To define a build condition, use: +# %bcond +# If is true, %bcond defines the symbol `with_` UNLESS the +# `--without ` command line switch is given. +# If is false, %bcond defines the symbol `with_` ONLY if the +# `--with ` command line switch is given. # -# For example (spec file): +# For example, in the following spec file: +# - "extra_fonts" is on, but can be deactivated by `--without extra_fonts` +# - "static" is off, but can be activated by `--with static` +# - "static_fonts" is on by default if both "extra_fonts" and "static" are, +# but can be overridden by `--with static_fonts`/`--without static_fonts`. # # (at the beginning) -# %bcond_with extra_fonts -# %bcond_without static +# %bcond extra_fonts 1 +# %bcond static 0 +# %bcond static_fonts %[%{with extra_fonts} && %{with static}] # (and later) # %if %{with extra_fonts} # ... @@ -108,17 +117,31 @@ # %if %{with static} # ... # %endif +# %if %{with static_fonts} +# ... +# %endif # %{?with_static: ... } # %{!?with_static: ... } # %{?with_extra_fonts: ... } # %{!?with_extra_fonts: ... } +# +%bcond() %{expand:%[ (%2) + ? "%{expand:%%{!?_without_%{1}:%%global with_%{1} 1}}" + : "%{expand:%%{?_with_%{1}:%%global with_%{1} 1}}" +]} +# Another way to define a bcond is %bcond_with and %bcond_without. +# %bcond_with corresponds to `%bcond ... 0`: the feature is off by default +# and needs to be activated with --with ... command line switch. +# %bcond_without is for the dual case. # -# The bottom line: never use without_foo, _with_foo nor _without_foo, only -# with_foo. This way changing default set of bconds for given spec is just -# a matter of changing single line in it and syntax is more readable. +# %bcond_with foo defines symbol with_foo if --with foo was specified on +# command line. +# %bcond_without foo defines symbol with_foo if --without foo was *not* +# specified on command line. %bcond_with() %{expand:%%{?_with_%{1}:%%global with_%{1} 1}} %bcond_without() %{expand:%%{!?_without_%{1}:%%global with_%{1} 1}} + # #============================================================================== # ---- Required rpmrc macros. diff --git a/tests/Makefile.am b/tests/Makefile.am index a41ce10de8..2977ddfb14 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -39,6 +39,7 @@ EXTRA_DIST += $(TESTSUITE_AT) ## testsuite data EXTRA_DIST += data/SPECS/attrtest.spec +EXTRA_DIST += data/SPECS/bcondtest.spec EXTRA_DIST += data/SPECS/buildrequires.spec EXTRA_DIST += data/SPECS/docmiss.spec EXTRA_DIST += data/SPECS/hello.spec diff --git a/tests/data/SPECS/bcondtest.spec b/tests/data/SPECS/bcondtest.spec new file mode 100644 index 0000000000..7172a31d29 --- /dev/null +++ b/tests/data/SPECS/bcondtest.spec @@ -0,0 +1,33 @@ +Name: bcondtest +Version: 1.0 +Release: 1 +Group: Testing +License: CC0 +BuildArch: noarch +Summary: Test package for the bcond macro + +%bcond normally_on 1 +%bcond normally_off 0 +%bcond both_features %[%{with normally_on} && %{with normally_off}] + +%if %{with normally_on} +Provides: has_bcond(normally_on) +%endif +%if %{with normally_off} +Provides: has_bcond(normally_off) +%endif +%if %{with both_features} +Provides: has_bcond(both_features) +%endif + +%description +%{summary} + +%install +mkdir -p %{buildroot}/opt +touch %{buildroot}/opt/file + +%files +/opt/file + +%changelog diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at index 730b79b3a4..b06742d15d 100644 --- a/tests/rpmbuild.at +++ b/tests/rpmbuild.at @@ -1791,3 +1791,76 @@ runroot rpmbuild -ba --quiet \ [], []) AT_CLEANUP + +AT_SETUP([bcond macro]) +AT_KEYWORDS([bcond build]) +RPMDB_INIT + +# basic bcond behavior with --eval +AT_CHECK([ +runroot rpm \ + --eval "%bcond normally_on 1" \ + --eval "%bcond normally_off 0" \ + --eval "%bcond both_features %[[%{with normally_on} && %{with normally_off}]]" \ + --eval "%{with normally_on}" \ + --eval "%{with normally_off}" \ + --eval "%{with both_features}" +], +[0], +[ + + +1 +0 +0 +], +[]) + +# bcond behavior, without CLI options +AT_CHECK([ +runroot rpmbuild -bb --quiet /data/SPECS/bcondtest.spec +runroot rpm -q --provides -p /build/RPMS/noarch/bcondtest-1.0-1.noarch.rpm | + grep has_bcond | sort +], +[0], +[has_bcond(normally_on) +], +[]) + +# bcond behavior, --with +AT_CHECK([ +runroot rpmbuild -bb --quiet --with normally_on --with normally_off \ + /data/SPECS/bcondtest.spec +runroot rpm -q --provides -p /build/RPMS/noarch/bcondtest-1.0-1.noarch.rpm | + grep has_bcond | sort +], +[0], +[has_bcond(both_features) +has_bcond(normally_off) +has_bcond(normally_on) +], +[]) + +# bcond behavior, --without +AT_CHECK([ +runroot rpmbuild -bb --quiet --without normally_on --without normally_off \ + /data/SPECS/bcondtest.spec +runroot rpm -q --provides -p /build/RPMS/noarch/bcondtest-1.0-1.noarch.rpm | + grep has_bcond | sort +], +[0], +[], +[]) + +# bcond behavior, CLI overriding a complex defailt +AT_CHECK([ +runroot rpmbuild -bb --quiet --with both_features /data/SPECS/bcondtest.spec +runroot rpm -q --provides -p /build/RPMS/noarch/bcondtest-1.0-1.noarch.rpm | + grep has_bcond | sort +], +[0], +[has_bcond(both_features) +has_bcond(normally_on) +], +[]) +AT_CLEANUP From 09c3977bb7be7291152c2214255c32efb3ab8fe3 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 29 Jan 2021 14:45:25 +0100 Subject: [PATCH 2/5] Remove documentation from comments; it's now in the actual docs --- macros.in | 52 +--------------------------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/macros.in b/macros.in index 1e2624842e..de8ea12d85 100644 --- a/macros.in +++ b/macros.in @@ -79,66 +79,16 @@ %undefined() %{expand:%%{?%{1}:0}%%{!?%{1}:1}} # Handle conditional builds. +# (see 'conditionalbuilds' in the manual) # # Shorthands for %{defined with_...}: %with() %{expand:%%{?with_%{1}:1}%%{!?with_%{1}:0}} %without() %{expand:%%{?with_%{1}:0}%%{!?with_%{1}:1}} -# When checking conditions: never use without_foo, _with_foo nor _without_foo, -# only with_foo. This way changing default set of bconds for given spec is just -# a matter of changing single line in it and syntax is more readable. - -# To define a build condition, use: -# %bcond -# If is true, %bcond defines the symbol `with_` UNLESS the -# `--without ` command line switch is given. -# If is false, %bcond defines the symbol `with_` ONLY if the -# `--with ` command line switch is given. -# -# For example, in the following spec file: -# - "extra_fonts" is on, but can be deactivated by `--without extra_fonts` -# - "static" is off, but can be activated by `--with static` -# - "static_fonts" is on by default if both "extra_fonts" and "static" are, -# but can be overridden by `--with static_fonts`/`--without static_fonts`. -# -# (at the beginning) -# %bcond extra_fonts 1 -# %bcond static 0 -# %bcond static_fonts %[%{with extra_fonts} && %{with static}] -# (and later) -# %if %{with extra_fonts} -# ... -# %else -# ... -# %endif -# %if ! %{with static} -# ... -# %endif -# %if %{with static} -# ... -# %endif -# %if %{with static_fonts} -# ... -# %endif -# %{?with_static: ... } -# %{!?with_static: ... } -# %{?with_extra_fonts: ... } -# %{!?with_extra_fonts: ... } -# %bcond() %{expand:%[ (%2) ? "%{expand:%%{!?_without_%{1}:%%global with_%{1} 1}}" : "%{expand:%%{?_with_%{1}:%%global with_%{1} 1}}" ]} - -# Another way to define a bcond is %bcond_with and %bcond_without. -# %bcond_with corresponds to `%bcond ... 0`: the feature is off by default -# and needs to be activated with --with ... command line switch. -# %bcond_without is for the dual case. -# -# %bcond_with foo defines symbol with_foo if --with foo was specified on -# command line. -# %bcond_without foo defines symbol with_foo if --without foo was *not* -# specified on command line. %bcond_with() %{expand:%%{?_with_%{1}:%%global with_%{1} 1}} %bcond_without() %{expand:%%{!?_without_%{1}:%%global with_%{1} 1}} From 9a4af2d5e3fec0a2e29ca10047348f8d05e90951 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 29 Jan 2021 14:50:24 +0100 Subject: [PATCH 3/5] Explain internal operation in the comments --- macros.in | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/macros.in b/macros.in index de8ea12d85..f2b8ed3b48 100644 --- a/macros.in +++ b/macros.in @@ -81,9 +81,10 @@ # Handle conditional builds. # (see 'conditionalbuilds' in the manual) # -# Shorthands for %{defined with_...}: -%with() %{expand:%%{?with_%{1}:1}%%{!?with_%{1}:0}} -%without() %{expand:%%{?with_%{1}:0}%%{!?with_%{1}:1}} +# Internally, the `--with foo` option defines the macro `_with_foo` and the +# `--without foo` option defines the macro `_without_foo`. +# Based on those and a default (used when neither is given), bcond macros +# define the macro `with_foo`, which should later be checked: %bcond() %{expand:%[ (%2) ? "%{expand:%%{!?_without_%{1}:%%global with_%{1} 1}}" @@ -92,6 +93,10 @@ %bcond_with() %{expand:%%{?_with_%{1}:%%global with_%{1} 1}} %bcond_without() %{expand:%%{!?_without_%{1}:%%global with_%{1} 1}} +# Shorthands for %{defined with_...}: +%with() %{expand:%%{?with_%{1}:1}%%{!?with_%{1}:0}} +%without() %{expand:%%{?with_%{1}:0}%%{!?with_%{1}:1}} + # #============================================================================== # ---- Required rpmrc macros. From a902996206d688fde1642dc71eb266c8dd0ea2f9 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 29 Jan 2021 14:45:59 +0100 Subject: [PATCH 4/5] Remove `_with_*` from the documentation This section uses the `_with_*` macro, which is dangerous when used in combination with `%bcond` or `%bcond_without` because it doesn't honor the "default". The section above already explains what users should do -- some variation of: %{?with_gnutls:--with static} \ %{!?with_openssl:--without openssl} ... which is more verbose, but works with %bcond` & `%bcond_without`. --- docs/manual/conditionalbuilds.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/docs/manual/conditionalbuilds.md b/docs/manual/conditionalbuilds.md index a2d9139673..bcf8bdeb16 100644 --- a/docs/manual/conditionalbuilds.md +++ b/docs/manual/conditionalbuilds.md @@ -83,16 +83,5 @@ macros which is nicer in other situations, e.g.: Always test for the `with`-condition, not the `without`-counterpart! -## Pass it to `%configure` - -To pass options to configure or other scripts that understand a `--with-foo` or -`--without-foo` parameter, you can use the `%{?_with_foo}` macro: - -``` -%configure \ - %{?_with_gnutls} \ - %{?_with_openssl} -``` - ## References * [macros](https://github.com/rpm-software-management/rpm/blob/master/macros.in) From 4498840b5b1513710eb095ecb93ab1e7adbd135f Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 3 Sep 2021 17:04:32 +0200 Subject: [PATCH 5/5] Define %bcond_with/%bcond_without in terms of %bcond --- macros.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/macros.in b/macros.in index f2b8ed3b48..27d8017170 100644 --- a/macros.in +++ b/macros.in @@ -90,8 +90,8 @@ ? "%{expand:%%{!?_without_%{1}:%%global with_%{1} 1}}" : "%{expand:%%{?_with_%{1}:%%global with_%{1} 1}}" ]} -%bcond_with() %{expand:%%{?_with_%{1}:%%global with_%{1} 1}} -%bcond_without() %{expand:%%{!?_without_%{1}:%%global with_%{1} 1}} +%bcond_with() %{expand:%%bcond %{1} 0} +%bcond_without() %{expand:%%bcond %{1} 1} # Shorthands for %{defined with_...}: %with() %{expand:%%{?with_%{1}:1}%%{!?with_%{1}:0}}