can an RPM spec file “include” other files?

2019-04-21 08:46发布

问题:

Is there a kind of "include" directive in RPM spec? I couldn't find an answer by googling.

Motivation: I have a RPM spec template which the build process modifies with the version, revision and other build-specific data. This is done by sed currently. I think it would be cleaner if the spec would #include a build-specific definitions file, which would be generated by the build process, so I don't need to search and replace in the spec.

If there is no include, is there an idiomatic way to do this (quite common, I believe) task?

回答1:

RPM does not support includes.

I have solved similar problems with either m4 macro processor or by just concatenating parts of spec (when the "include" was at the beginning).

If you only need to pass a few variables at build time, and not include several lines from another file, you can run

rpmbuild --define 'myvar SOMEVALUE' -bb myspec.spec

and you can use %myvar in the spec.



回答2:

Sufficiently recent versions of rpmbuild certainly do support %include:

%include common.inc

Unfortunately, they aren't very smart about it -- there is no known set of directories, in which it will look for the requested files, for example. But it is there and variables are expanded, for example:

%include %{_topdir}/Common/common.inc


回答3:

I faced this same issue recently. I wanted to define multiple sub-packages that were similar, but each varied just slightly (they were language-specific RPMs). I didn't want to repeat the same boiler-plate stuff for each sub-package.

Here's a generic version of what I did:

%define foo_spec() %{expand:%(cat '%{myloc}/main-foo.spec')}
%{foo_spec bar}
%{foo_spec baz}
%{foo_spec qux}

The use of %{expand} ensures that %(cat) is only executed a single time, when the macro is defined. The content of the main-foo.spec file is then three times, and each time %1 in the main-foo.spec file expands to each of bar, baz and qux, in turn, allowing me to treat it as a template. You could easily expand this to more than one parameter, if you have the need (I did not).



回答4:

For the underlying issue, there maybe two additional solutions that are present in all rpm versions that I am aware of.

  1. Subpackages
  2. macro and rpmrc files.

Subpackages

Another alternative (and perhaps the "RPM way") is to use sub-packages. Maximum RPM also has information and examples of subpackages.

I think the question is trying to structure something like,

  • two spec files; say rpm_debug.spec and rpm_production.spec
  • both use %include common.spec

debug and production could also be client and server, etc. For the examples of redefining a variable, each subpackage can have it's own list of variables.

Limitations

The main advantage of subpackages is that only one build takes place; This may also be a disadvantage. The debug and production example may highlight this. That can be worked around using strip to create variants or compiling twice with different output; perhaps using VPATH with Gnu Make). Having to compile large packages and then only have simple variations, like with/without developer info, like headers, static libraries, etc. can make you appreciate this approach.

Macros and Rpmrc

Subpackages don't solve the problem of structural defines that you wish for an entire rootfs hierarchy, or larger collection of RPMs. We have rpmbuild --showrc for this. You can have a large amount of variables and macros defined by altering rpmrc and macros when you run rpm and rpmbuild. From the man page,

   rpmrc Configuration
       /usr/lib/rpm/rpmrc
       /usr/lib/rpm/redhat/rpmrc
       /etc/rpmrc
       ~/.rpmrc

   Macro Configuration
       /usr/lib/rpm/macros
       /usr/lib/rpm/redhat/macros
       /etc/rpm/macros
       ~/.rpmmacros

I think these two features can solve all the problems that %include can. However, %include is a familiar concept and was probably added to make rpm more full-featured and developer friendly.



回答5:

You can include the *.inc files from the SOURCES directory (%_sourcedir):

Source1: common.inc

%include %{SOURCE1}

In this way they will go automatically into SRPMS.



回答6:

Which version are you talking about? I currently have %include filename.txt in my spec file and it seems to work just like the C #include directive.

> rpmbuild --version
RPM version 4.8.1


回答7:

I've used scripts (name your favorite) to take a template and create the spec file from that. Also, the %files tag can import a file that is created by another process, e.g. Python's bdist-rpm.