#1454 Update advice on creating specfile macros
Opened by ferdnyc. Modified
ferdnyc/packaging-committee rpm-macro-guidelines  into  master

Download 1454.patch

The guideline to use %global in preference to %define was
described by an RPM developer as "bad advice that spread far and
wide". This change completely reverses that advice, instructing
packagers to use %define by default and %global only when
needed.

This PR currently contains just the guidelines-text change. I'm hoping to also update many of the specfile templates and other bits of code that use %global (there are currently over 400 matches for %global in the packaging guidelines source), but that's in part pending an answer to my question over in #1449. I wanted to get this opened ASAP so everyone could decide how they feel about the wording, though.

Fixes #1449

i out a word, that should say "MAY be updated..."

1 new commit added

  • Add missing word

I am not a huge fan of introducing the term "variables" into this. They are macros, not variables.

Just making sure I understand this correctly,

  • %globals are expanded once at definition time,
  • %defines are expanded on every use?

Assuming this is correct, this advice might be too strong:

Packagers SHOULD use %define to create macros in spec files.
Legacy uses of %global MAY be updated to use %define.
Spec files MAY contain uses of %global
if immediate expansion is needed (a rare occurrence).

There will be instances where the time of evaluation will make a difference (for example, macros could be pulled in as BuildRequires, but not in Requires, leading them to be undefined at runtime), or macros that shell out and query the environment - and I don't think these are really that rare.

And assuming that I understand this correctly, it might be better to say something like

  • use %define when it doesn't matter when the macros is expanded (or how often), i.e. usually for simple text replacements
  • use %global when it does matter when / how often expansion happens , if the expansion involves some sort of "expensive computation", or if the expansion relies on things that are only available inside the build environment

TL;DR: I don't think we can just flip the "use %global instead of %define" rule around and don't expect things to break in funny ways.

@decathorpe

Just making sure I understand this correctly,

  • %globals are expanded once at definition time,
  • %defines are expanded on every use?

Broadly, yes, but I'm not sure how things like shell invocations play into that — just because %define macros are lazily expanded, doesn't necessarily mean that a %() subshell invocation will be re-executed at each use. (Doesn't mean that it won't, either, which is why I put that question to @pmatilai in #1449 -- but he hasn't responded yet, so I'll open an issue in the RPM upstream repo to clear that point up.)

The RPM macro docs do mention that %global is in part "useful to avoid re-expansion of expensive macros", but doesn't elaborate on what exactly that means at all.

But beyond that, situations like this:

for example, macros could be pulled in as BuildRequires, but not in Requires, leading them to be undefined at runtime),

...are where %define is most preferable to %global, because a %define macro will resolve even if some of its component macros are defined after it... with %global, the moment the statement is processed you've lost your chance to define/redefine any of the macros used in that statement.

With %define, macros are expanded at time of use, yes... but those uses still occur at build-time. No %define'd macros should survive to runtime unless they're explicitly escaped via %% invocations.

IOW, if I use a %define macro in a %preun script, the "time of use" is when that %preun code is processed into a script by rpmbuild as it's processing the specfile. What gets written into the RPM metadata is a static script with all of the macros expanded. There's no runtime dependency on the macros.

Ditto if I use a macro in a Version: or Provides: or etc. line in the specfile... the value that's stored is the expansion of that macro, regardless whether it's a %global macro or a %define macro. The only difference is that the %define macro is expanded when the Version: or Provides: line is processed, whereas the %global macro was expanded way back when it was created.

Question posted to the RPM repo's Q&A area: https://github.com/rpm-software-management/rpm/discussions/3727

Apologies for being slow to respond to this stuff.

I'd recommend dropping the SHOULD/MAY language entirely because recommending one over the other doesn't make sense. It's like a recommendation between a spoon and a shovel: they do kinda similar things, but sometimes you need one and sometimes the other, and there's no universal recommendation you could make.

I think we should just help packagers make informed choices. Explaining the actual difference like here is good, practical examples of when to use each should help more.
For a practical rule of thumb, something like "Use %global for unchanging global values, otherwise use %define."

@pmatilai

I'd recommend dropping the SHOULD/MAY language entirely because recommending one over the other doesn't make sense.

Well, they're guidelines, not RPM documentation — being prescriptive is sort of the entire point. I agree that including an explanation of the two is useful, but the guidelines are there specifically to provide rules for packagers to follow.

The rule can be (and will probably have to be) some form of, "packagers SHOULD use whatever makes the most sense for a given case" (heck, that could even be a MUST rule), but there's still gonna be a rule.

(And speaking of RPM documentation, I think this stuff could be covered in more detail in the actual RPM documentation — which, as I mentioned, doesn't really ever come out and say that shell invocations and other operations will be re-executed on every expansion of a %define macro — but that's a conversation for the PR against https://github.com/rpm-software-management/rpm/blob/master/docs/manual/macros.md that I expect I'll be talked into submitting :wink: )

For a practical rule of thumb, something like "Use %global for unchanging global values, otherwise use %define."

See, that's a pretty big departure from where this all started, because most of our macros ARE unchanging global values. Now, it's likely that's more out of necessity than anything else, since we scared people off of %define for so long that %global is all they know. As a result, they often tend to treat all macros as if they can only be unchanging global values.

(Which sort of explains, but doesn't, the unnecessary nonsense %global ... %{expand: ... } that started all this. The only explanation I can give for that is that we've so brainwashed our packagers into %global being the only way to define a macro, they no longer remember — or never knew — what it means relative to %define.)

So I definitely agree that helping packagers better understand the difference is useful.

I also agree that practical examples demonstrating situations that would favor either %global or %define (like the ones I used in my Q&A post, as a starting point) would also be useful... but in the back of my mind it feels wrong if we end up having better examples than the real docs, so that's probably (also) another topic for that macros.md PR. :grinning:

We talked about this again, in the meeting this week, and one idea that came up was to try to move the real part of the documentation to upstream/rpm and then the Fedora docs could just say something like "use define/global appropriately as needed, see this link to the upstream rpm docs on how they work"

Metadata