While its advice has been softened somewhat through the addition of some disclaimer language, the thrust of the section on how to define spec variables is still communicated by its title:
%global Preferred Over %define Use %global instead of %define, unless you really need only locally defined submacros within other macro definitions (a very rare case). Rationale: The two macro defining statements behave the same when they are at the top level of rpm’s nesting level. But when they are used in nested macro expansions (like in %{!?foo: ... } constructs, %define theoretically only lasts until the end brace (local scope), while %global definitions have global scope. Note that %define and %global differ in more ways than just scope: the body of a %define’d macro is lazily expanded (i.e., when used), but the body of %global is expanded at definition time. It’s possible to use %%-escaping to force lazy expansion of %global.
%global
%define
Use %global instead of %define, unless you really need only locally defined submacros within other macro definitions (a very rare case).
Rationale: The two macro defining statements behave the same when they are at the top level of rpm’s nesting level.
But when they are used in nested macro expansions (like in %{!?foo: ... } constructs, %define theoretically only lasts until the end brace (local scope), while %global definitions have global scope.
%{!?foo: ... }
Note that %define and %global differ in more ways than just scope: the body of a %define’d macro is lazily expanded (i.e., when used), but the body of %global is expanded at definition time. It’s possible to use %%-escaping to force lazy expansion of %global.
This is, in the words of RPM core developer Panu Matilainen, "bad advice that spread far and wide". Accompanied by a fuller explanation of how scoping (now) works for %define variables:
That used to be the case in rpm < 4.14 (prior to rhel-8 if you like). The worst issue with it was that %define appeared to worked in those situations but then an unrelated spec change could break suddenly break it. It was bad, but the "always use global" cure is worse than the disease. Since 4.14 only parametric macros have locally scoped macros.
That used to be the case in rpm < 4.14 (prior to rhel-8 if you like). The worst issue with it was that %define appeared to worked in those situations but then an unrelated spec change could break suddenly break it. It was bad, but the "always use global" cure is worse than the disease.
Since 4.14 only parametric macros have locally scoped macros.
We are strongly encouraged to stop telling people that they should be using %global everywhere, or really anywhere, unless it's absolutely necessary. (Meaning, unless immediate expansion of the variable is required.) For most specfile needs, the lazy expansion provided by %define is preferred.
+1 to drop this rule
So the recommendation should be flipped, or what? From
use %global always unless you really need %define
to
use %define always unless you really need %global
?
Yes, pretty much.
Yes - that's how it really should've been all along. Even in the old days, %global was needed in one case where it no longer is (that %{!?foo:%define foo bar} type construct), it didn't need this big hammer recommendation.
%{!?foo:%define foo bar}
How does this sound, for a new section? If we want I can open a PR and we can iterate on the wording there. (The two commands would be defined using a description list in asciidoc format.)
RPM supports two commands that can be used in .spec files to define new %-variables. (Called 'macros' in RPM terminology, since every %-expansion is a macro expansion. But macros can also be used for simple variable replacement.)
.spec
%
%define:: Expanded at time of use (lazy expansion). A macro created with %define can use other macros in its definition, and all macros will be replaced with their current value at the time the %define macro is expanded. This makes it very easy to use macros in loops, or to change their definition in different parts of the spec file.
%global:: Expanded at time of creation (immediate expansion). A macro created with %global is expanded as soon as it is created, so that any %-macros used in the definition are substituted with their value at the time the %global statement is processed. Because a macro defined with %global no longer contains the %-macros used in its definition, only their expanded values, later modifications to those macros will not affect the expansion of the global macro.
Packagers SHOULD use %define to create macros in spec files. Spec files MAY use %global instead, if immediate expansion is needed (a rare occurrence).
[NOTE] ===== Previous versions of these guidelines advised using `%global` in preference to `%define`. Due to changes in RPM, the rationale behind that advice no longer holds, and this section has been updated to reflect current best practices. However, because the previous advice was in place for many years, you will encounter `%global` macros in existing spec files, as well as in examples provided by these guidelines, that have not been updated to the current recommendations. ====
I can't decide if it should still get into the whole topic of lazy expansion in global macros using %%.
%%
And now I'm thinking the [NOTE] should even be a [CAUTION].
[NOTE]
[CAUTION]
We discussed this at today's FPC meeting. We're generally in favor, so please send a pull request to implement it. Ideally we'd like to get @pmatilai's +1 on the exact wording in that PR.
I'll whip something up today (hopefully).
Hey @pmatilai, a question that came up while working on this:
Are there any differences in the handling of things like subshell calls, when using %define vs. %global?
There are a lot of %global uses in our packaging templates, so in addition to updating the guidelines I wanted to also update (at least some of) those. But then I ran into these macros from the TCL packaging guidelines:
%{!?tcl_version: %global tcl_version %(echo 'puts $tcl_version' | tclsh)} %{!?tcl_sitelib: %global tcl_sitelib %{_datadir}/tcl%{tcl_version}}
...And that got me wondering. If this macro definition:
%global tcl_version %(echo 'puts $tcl_version' | tclsh)
is replaced with this macro definition:
%define tcl_version %(echo 'puts $tcl_version' | tclsh)
...will every use of %{tcl_version} be re-executing that echo 'puts $tcl_version' | tclsh shell command?
%{tcl_version}
echo 'puts $tcl_version' | tclsh
If the answer is yes (though I doubt it is), we may want to continue recommending %global for macros that invoke subshells or do other complex processing.
First draft PR now opened as #1454.
Shell expansion isn't special in any way, so yes it's re-executed at each use of such macro. Sometimes it's what you need, sometimes not.
The real problem with the existing "use %global everywhere" is the "everywhere", and switching to "use %define elsewhere" just leads to different problems. One should use whichever is appropriate for a given situation. And to make that call, people will need to understand the difference.
Thanks, @pmatilai!, that's a big help! I'll have to make some adjustments to #1454.