Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Begin the long, long journey towards a reference manual #1385

Merged
merged 10 commits into from Oct 7, 2020
144 changes: 52 additions & 92 deletions doc/manual/conditionalbuilds.md
@@ -1,105 +1,65 @@
# Passing conditional parameters into a rpm build

Source code is often built with optional features enabled or disabled.
When source code is packaged using rpm, the various features can be
chosen, added to a spec file, and a package will be produced with
binaries compiled with that feature set. This mechanism works fine
for packages with small feature sets, but does not work so well
for large, complicated, packages like the Linux kernel and/or
the Pine mailer which have a large number of features, as a given
feature set may not "work" for everyone.

RPM now has a supported mechanism to pass information from the rpm
command line to enable/disable features during a build. Two options have
been added to pass feature names from the rpm command line:
```
--with <feature> Enable <feature>
--without <feature> Disable <feature>
```
The new options are implemented using popt to add aliases to the existing rpm
options --define to specify macros from the command line. The magic necessary
to add the new options is (from the file /usr/lib/rpm/rpmpopt*)
```
rpmb alias --with --define "_with_!#:+ --with-!#:+"
rpmb alias --without --define "_without_!#:+ --without-!#:+"
```
(Note: The obscure "!#:+" popt token above says "substitute the next command
line argument found here, and, additionally, mark the argument as used.")
# Conditional Builds

Rpmbuild supports conditional package builds with the command line switches
`--with` and `--without`.

Here is an example of how to enable gnutls and disable openssl support:

For example, when rpm is invoked as
```
rpm ... --with ldap ...
$ rpmbuild -ba newpackage.spec --with gnutls --without openssl
```
then the popt aliases will cause the options to be rewritten as

## Enable `--with`/`--without` parameters

To use this feature in a spec file, add this to the beginning of the file:

```
rpm ... --define "_with_ldap --with-ldap" ...
# add --with gnutls option, i.e. disable gnutls by default
%bcond_with gnutls
# add --without openssl option, i.e. enable openssl by default
%bcond_without openssl
```
which causes a "%_with_ldap" macro to be defined with value "--with-ldap"
during a build.

The macro defined on the rpm command line can be used to conditionalize
portions of the spec file for the package. For example, let's say you
are trying to build the pine package using "--with ldap" to enable the
LDAP support in the pine mailer (i.e. configuring with "--with-ldap").
So the spec file should be written

If you want to change whether or not an option is enabled by default, only
change `%bcond_with` to `%bcond_without` or vice versa. In such a case, the
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:

```
...
./configure \
%{?_with_ldap} \
...
%if %{with gnutls}
BuildRequires: gnutls-devel
%endif
%if %{with openssl}
BuildRequires: openssl-devel
%endif
```
so that, if "--with ldap" was used as a build option, then configure
will be invoked (after macro expansion) as

Alternatively, you can test the presence (or lack thereof) of `%with_foo`
macros which is nicer in other situations, e.g.:

```
./configure --with-ldap ...
%configure \
%{?with_static:--enable-static} \
%{!?with_static:--disable-static}
```
(Note: The obscure "%{?_with_ldap: ...}" rpm macro syntax above says "if the
macro "_with_ldap" exists, then expand "...", else ignore.")

The spec file should include a default value for the "_with_ldap" macro,
and should support "--without ldap" as well. Here's a more complete example
for pine:
```
# Default values are --without-ldap --with-ssl.
#
# Read: If neither macro exists, then add the default definition.
%{!?_with_ldap: %{!?_without_ldap: %define _without_ldap --without-ldap}}
%{!?_with_ssl: %{!?_without_ssl: %define _with_ssl --with-ssl}}
...

# You might want to make sure that one and only one of required and
# mutually exclusive options exists.
#
# Read: It's an error if both or neither required options exist.
%{?_with_ssl: %{?_without_ssl: %{error: both _with_ssl and _without_ssl}}}
%{!?_with_ssl: %{!?_without_ssl: %{error: neither _with_ssl nor _without_ssl}}}

# Add build dependencies for ssl and ldap features if enabled.
# Note: Tag tokens must start at beginning-of-line.
#
# Read: If feature is enabled, then add the build dependency.
%{?_with_ssl:BuildRequires: openssl-devel}
%{?_with_ldap:BuildRequires: openldap-devel}
...

# Configure with desired features.
#
# Read: Add any defined feature values to the configure invocation.
%configure \
%{?_with_ssl} \
%{?_without_ssl} \
%{?_with_ldap} \
%{?_without_ldap}
...

# Conditional tests for desired features.
#
# Read: true if _with_ssl is defined, false if not defined.
%if %{?_with_ssl:1}%{!?_with_ssl:0}
...
%endif
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}
```

See also the %bcond_with and %bcond_without helper macros and their
documentation in /usr/lib/rpm/macros.
## References
* [doc/manual/conditionalbuilds](https://github.com/rpm-software-management/rpm/blob/master/doc/manual/conditionalbuilds)
* [macros](https://github.com/rpm-software-management/rpm/blob/master/macros.in)