Reputation: 383
I would like to invoke an RPM macro taking an argument from another macro. In m4
, this would be done trivially like this (just an example, not what I really want to do):
define(`path', `/mnt/$1/lib')
define(`mkd', `mkdir path($1)/stuff')
mkd(`usr')
=> mkdir /mnt/usr/lib/stuff
Or in CPP
syntax:
#define path(x) /mnt/x/lib
#define mkd(x) mkdir path(x)/stuff
mkd(usr)
=> mkdir /mnt/usr/lib/stuff
The obvious equivalent in RPM (broken!) would be:
# THIS IS BROKEN
%define path() /mnt/%1/lib
%define mkd() mkdir %{path %1}/stuff
%mkd usr
But this does not work, RPM prints "error: Too many levels of recursion in macro expansion. It is likely caused by recursive macro declaration."
I have made it "work" with the following code:
%define path() /mnt/%1/lib
%define mkd() mkdir %{expand:%%{path %1}}/stuff
%mkd usr
However I can't believe that this clumsy code would be the recommended way for doing this. Another approach that appears to work is using option arguments:
%define path(d:) /mnt/%{-d*}/lib
%define mkd(p:) mkdir %{path -d%{-p*}}/stuff
%mkd -p usr
But this works only because I used different option characters; if I use '-d
' for both macros, it fails like the example above. I don't like this solution much either, because using options seems non-intuitive here.
What would be the preferred way to achieve the desired effect?
Upvotes: 0
Views: 1280
Reputation: 383
It seems that the problem reported in this question is solved in recent versions of rpm, between 4.11 and 4.14.
~> rpm --version
RPM version 4.14.1
~> rpm --eval '
%define path() /mnt/%1/lib
%define mkd() mkdir %{path %1}/stuff
%define foo bar
%mkd %foo'
=> mkdir /mnt/bar/lib/stuff
With rpm 4.11, this fails with "too many levels of recursion", and the workaround of the previous answer (%global mkd() mkdir %{path %%1}/stuff
) is necessary.
Upvotes: 0
Reputation: 2072
RPM handling of recursive macros is broken. As far as I was able to find out, there is no "recommended" way; this simply doesn't work and the workarounds you listed are as close as you're going to get.
Within RPM macro sets I've seen (including some within RPM itself), this is usually solved through conditional arguments: use -p
option if supplied, %1
otherwise.
%define path(p:) /mnt/%{-p:%{-p*}}%{!-p:%1}/lib
%define mkd(d:) mkdir %{path -p %1}/stuff
echo "making path at %{path hello}"
%{mkd hello}
You can also use "non-function" definitions -- this is sort of what is going on in the %define
/%global
case.
%define _path /mnt/%1/lib
# note no parentheses at end of `_path`
%define path() %_path
%define mkd() mkdir %{_path}/stuff
This way, the %_path
macro is inlined into the path()
and mkd()
definitions and no recursion is happening.
This would not work if you wanted to use %2
for the path, but because that is a different name, you can use it the old way ......... o_O
%define maketwo() mkdir %1; mkdir %{path %2}/stuff
Upvotes: 1
Reputation: 383
I found a more elegant solution. I don't understand why it works, and I'm not sure if it's generally applicable:
%define path() /mnt/%1/lib
%global mkd() mkdir %{path %%1}/stuff
%mkd usr
=> mkdir /mnt/usr/lib/stuff
It works only if mkd
is define with %global
. path
can be define either with %define
or %global
. Also node the quoted percent character.
Upvotes: 1