2017-03-15 2 views
0

Je voudrais appeler une macro RPM en prenant un argument d'une autre macro. En m4, cela serait fait trivialement comme celui-ci (juste un exemple, pas ce que je veux vraiment faire):RPM: invoquer une macro avec des arguments d'une autre macro avec des arguments

define(`path', `/mnt/$1/lib') 
define(`mkd', `mkdir path($1)/stuff') 
mkd(`usr') 
=> mkdir /mnt/usr/lib/stuff 

Ou dans CPP syntaxe:

#define path(x) /mnt/x/lib 
#define mkd(x) mkdir path(x)/stuff 
mkd(usr) 
=> mkdir /mnt/usr/lib/stuff 

L'évidence équivalent en RPM (cassé) serait:

# THIS IS BROKEN 
%define path() /mnt/%1/lib 
%define mkd() mkdir %{path %1}/stuff 
%mkd usr 

Mais cette ne le fait pas travail, RPM imprime "erreur: trop de niveaux de récursion dans l'expansion macro. Il est probablement dû à une déclaration de macro récursive. "

Je l'ai fait « travailler » avec le code suivant:.

%define path() /mnt/%1/lib 
%define mkd() mkdir %{expand:%%{path %1}}/stuff 
%mkd usr 

Cependant, je ne peux pas croire que ce code maladroit serait la méthode recommandée pour ce faire une autre approche qui semble fonctionner utilise des arguments d'option:

%define path(d:) /mnt/%{-d*}/lib 
%define mkd(p:) mkdir %{path -d%{-p*}}/stuff 
%mkd -p usr 

Mais cela ne fonctionne que parce que je caractères d'options différentes, si j'utilise « -d » pour les deux macros, il échoue comme le exampl e ci-dessus. Je n'aime pas non plus beaucoup cette solution, car l'utilisation d'options semble ici non intuitive.

Quelle serait la méthode préférée pour obtenir l'effet désiré?

Répondre

1

J'ai trouvé une solution plus élégante. Je ne comprends pas pourquoi cela fonctionne, et je ne sais pas s'il est généralement applicable:

%define path() /mnt/%1/lib 
%global mkd() mkdir %{path %%1}/stuff 
%mkd usr 
=> mkdir /mnt/usr/lib/stuff 

Il ne fonctionne que si mkd est de définir avec %global. path peut être défini avec %define ou %global. Nommer également le caractère pourcentage cité.

+1

Il fonctionne parce que% global n'est pas évalué quand il est analysé (comme% define) mais dans le temps où il est appelé. A chaque fois que vous écrivez%, vous devez généralement utiliser% global. – msuchy

+0

@msuchy C'est l'inverse. Les macros '% define' sont évaluées lorsqu'elles sont utilisées,'% global' lorsqu'elles sont définies. C'est pourquoi cela fonctionne: la définition de 'mkd' est figée avec le' path' déjà développé, donc aucune récursion ne se produit quand l'argument est substitué. – matejcik

1

La gestion RPM des macros récursives est interrompue. Autant que j'ai pu le savoir, il n'y a pas de manière "recommandée"; Cela ne fonctionne tout simplement pas et les solutions de contournement que vous avez énumérées sont aussi proches que possible. Dans les jeux de macros RPM que j'ai vus (y compris dans RPM lui-même), ceci est généralement résolu par des arguments conditionnels: utilisez l'option -p si elle est fournie, %1 sinon.

%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} 

Vous pouvez également utiliser des définitions de « non-fonction » - c'est un peu ce qui se passe dans le cas %define/%global.

%define _path /mnt/%1/lib 
# note no parentheses at end of `_path` 
%define path() %_path 
%define mkd() mkdir %{_path}/stuff 

De cette façon, la %_path macro est inline dans les path() et mkd() définitions et aucune récursivité se passe.

Cela ne fonctionnerait pas si vous vouliez utiliser %2 pour le chemin, mais parce que c'est un autre nom, vous pouvez l'utiliser l'ancienne ......... o_O

%define maketwo() mkdir %1; mkdir %{path %2}/stuff