Home Wiki > openSUSE:Specfile guidelines
Sign up | Login

openSUSE:Specfile guidelines

tagline: From openSUSE

RPM itself places very few limitations on what you can do in spec files, so they can quickly become difficult to read and maintain. These guidelines try to minimize the variations in specific areas so spec files are maintainable.

General Rules

All spec files must be comprehensible. If other packagers are unable to read the spec file, it will be impossible to perform a review and to collaborate on the package.

Specfile Template

When writing a package from scratch, you should base your spec file on the spec file template (see rpmdevtools). A basic setup for a package MYPACK can be generated by

osc-plugin-install devel:tools rpmdevtools

or (change URL according to your version of openSUSE)

sudo zypper -p obs://devel:tools/openSUSE_Leap_42.2 -v in osc rpmdevtools

Once you have done so:

# A folder already created for a project, like home:user.
# Create a new package.
osc mkpac MYPACK
# Download source tarball from upstream (the group that develops the code).
wget http://upstream.example.org/source/.../MYPACK-1.0.tar.gz
# Create a spec file template for MYPACK. rpmdev-newspec -t lib MYPACK # Record changes to the MYPACK package. osc vc # Edit spec file. vim MYPACK.spec

and then later:

# Test it builds correctly
osc build
# Checkin/commit to OBS server
osc ci

Please try to conform to this template as much as possible.

It is not the only way to write a spec file, but doing so makes it easier for QA to spot mistakes and quickly understand what you are trying to do.

Spec files for specific languages can often be created with specialized tools like cpanspec or gem2rpm-opensuse. See also

Specfile Encoding

Use ASCII characters unless necessary (if so, save as UTF-8).

Unless you need to use characters outside the ASCII repertoire, you will not need to be concerned about the encoding of the spec file. If you do need non-ASCII characters, save your spec files as UTF-8. If you are in doubt as to what characters are ASCII, please refer to an ASCII chart.

Specfile Licensing

For legal reasons, spec files must have a license header.

Use the following template:

# spec file for package $YOUR_PACKAGE
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.

# Please submit bugfixes or comments via http://bugs.opensuse.org/


Use macros instead of hard-coded directory names.

A list of macros and what they do is available at openSUSE:Packaging Conventions RPM Macros. Having macros in a Source: or Patch: line is a matter of style. Some people enjoy the ready readability of a source line without macros. Others prefer the ease of updating for new versions when macros are used. In all cases, remember to be consistent in your spec file and verify that the URLs you list are valid. If you need to determine the actual string when it contains macros, you can use rpm. For example, to determine the actual Source: value, you can run:

rpm -q --specfile foo.spec --qf "$(grep -i ^Source foo.spec)\n"

Caution: the above command works with %{name} and %{version}, but may fail with user defined macros.

Macros vs RPM variables

There are two styles of defining the Build Root and Optimization Flags in a spec file.

macro style variable style
Build Root  %{buildroot} $RPM_BUILD_ROOT
Opt. Flags  %{optflags} $RPM_OPT_FLAGS

Both are considered valid, as they will resolve to the same values in all scenarios. Pick a style and use it consistently throughout your packaging. Do not mix the two styles in openSUSE packages, as it is bad from a QA and usability point of view.

It is preferred to use the % macro style.

RPM macros are expanded before a section is run, and it is slower for variables to be read by sh during runtime. It is also more similar to other macros like %{_bindir} which have no variable equivalent.

Macros vs shell commands

For many commonly used shell commands, there is a macro equivalent For example:

Macro Shell Command
 %{__cat} cat
 %{__ln_s} ln -s
 %{__mkdir_p} mkdir -p

These macros provide a better portability, however, since there is only a single provider for this in OBS, the use of macros is deprecated in favor of the more readable shell commands. The spec file cleaner bot even converts macros to their shell command counter part automatically.


See openSUSE:RPM conditional builds.

For a list of version macros for different openSUSE releases, see openSUSE RPM distro version macros.

For example, to detect Leap 42.1:

%if 0%{?sle_version} == 120100 && 0%{?is_opensuse}
# perform Leap 42.1 specific actions here
# something else

For other distributions, see openSUSE:Build_Service_cross_distribution_howto.


Naming / versioning

See openSUSE:Package naming guidelines.

Metadata Tags

  • AutoReqProv: should not be used unless you want to turn off automatic dependency processing.
  • Source: an HTTP link should be specified where possible (openSUSE:Package source verification).
  • Group: only package groups listed in the package group guidelines should be used.
  • BuildRoot: should always be used, even if newer versions of RPM override it anyway. The preferred path is %{_tmppath}/%{name}-%{version}-build.
  • Summary: should be a short description of what the package is (summary guidelines).

Do not use the following tags:

  • Copyright: deprecated, use License instead (licensing guidelines).
  • Packager: rebuilding the RPM package elsewhere forces this value onto the new packager, leading to subsequent confusion about who to contact. The identities of the packagers should be specified with changelog entries instead.
  • Vendor: same reason as for Packager. If you want to override the default set by the openSUSE Build Service, use a prjconf-level %define.

Description Section(%description)

See openSUSE:Package description guidelines.


See openSUSE:Package dependencies.


All patches in openSUSE spec files SHOULD have a comment within the patch file (or above its respective "PatchN:" tag) about its status. For details see openSUSE:Packaging Patches guidelines.

Preparation Section (%prep)

Quiet %setup

The -q option should be passed to the %setup macro.

This will reduce the size of the build logfile significantly, especially with source archives that extract a lot of files.

Build Section (%build)

Compiler flags

Compilers used to build packages should honor the applicable compiler flags set in the system rpm configuration.

In practice, this means %{optflags} (variable: $RPM_OPT_FLAGS, see above) for C, C++, and Fortran compilers. Honoring means that the contents of that variable is used as the basis of the flags actually used by the compiler during the package build. Adding to and overriding or filtering parts of these flags is permitted if there is a good reason to do so; the rationale for doing so should be reviewed and documented in the specfile especially in the override and filter cases.

Parallel make

Whenever possible, invocations of make should be done in parallel.

This should be done using:

make %{?_smp_mflags}

This is also available as the %make_build macro, but it is not available for openSUSE 13.2, Leap 42.2 and SLE 12 SP2 (rpm < 4.12).

This generally speeds up builds, especially on SMP machines. It is much preferable to make %{?jobs:-j%jobs}, as the former allows alternate make flags to be used, such as make -lN, and not hardcoding -jN. Do make sure, however, that the package builds cleanly this way; some make files do not support parallel building, or have broken dependencies.

If a package does not support parallel building, please explicitly write -j1.

This facilitate grepping for such packages among a group of specfiles. There may be other reasons to use -j1, for example due to otherwise excessive memory usage. (Such a case occurs for example when building Boost for MINGW.) The common workers on build.opensuse.org have only 2 GB RAM assigned as of September 2013. In any case, consider adding a comment saying what led to the use of -j1, whether it is due to broken dependencies, or memory requirements, etc.

Install Section (%install)

Running make install must not attempt to chown any files.

Since rpmbuild is run as an unprivileged user, the %install section must not run chown directly or indirectly, for example, `install -o root...`). File ownership shall be set in the later %files section instead.

Use %make_install instead of %makeinstall (without an underscore).

%make_install is a macro equivalent to make install DESTDIR="%{?buildroot}". Should you be creating a package for older RPM versions (rpm < 4.10, e.g. SLE 11), use the expanded version instead of the macro.

There is also a second macro with a confusingly similar name, %makeinstall (note: no underscore). Avoid using this.

In attempt to work with broken software, this macro expands to a very long line which sets all variables to %buildroot plus their final paths, but does not set DESTDIR itself, which causes certain broken software to actually fail.

An example of this is xapian-core-1.2.17, where:

# configure.ac contains:
# include/Makefile.mk contains:
inc_HEADERS = include/xapian.h

With this, %makeinstall's expansion, "make install ... includedir=/buildroot/usr/include" has no effect since the awkward Makefile requires incdir to be set instead of includedir. Because %makeinstall does not set DESTDIR, xapian-core will try to install xapian.h to the default location, /usr/include, rather than /buildroot/usr/include. A double failure, so to say.

SUSE's rpm redefines %makeinstall to be the same as %make_install, but as it is conceivable that your specfile may be used on other distro targets, it is best to avoid %makeinstall, and only ever use %make_install or its expanded form.

Removing the buildroot

Do not attempt to clean or remove the buildroot folder manually.

openSUSE marks it as bad coding style to have rm -rf %{buildroot} (or rm -rf $RPM_BUILD_ROOT) at the beginning of an %install section like this:

rm -Rf "%buildroot"
mkdir -p "%buildroot/%_prefix/..." 


rm -Rf "%buildroot"
make install


%{buildroot} is normally within /var/tmp and you just opened a trivial race condition to a local attacker on your machine to take over your account (or even root if you build as root). It is better not to `rm -rf %{buildroot}` in %install at all (and rely on %clean to do it).

Somewhat better would be the following, (do not do this, it is done automatically for you):

rm -Rf "%buildroot";
mkdir "%buildroot";
mkdir -p "%buildroot/%_prefix/..."


rm -Rf "%buildroot";
mkdir "%buildroot";
make install
In this case the mkdir %buildroot would fail and the build would abort if an attacker tries to replace the buildroot by his own symlink.

Clean Section (%clean)

The %clean section should not be included -- it is no longer necessary.

The %clean section, if specified, will be run after the binary and source RPMs have been generated. In the Open Build Service, this section is not necessary because chroots and VM environments that are used to build the package are generally torn down anyway. Building packages in environments not started from scratch is usually not supported for openSUSE packages (cf. boo#176528#c4)

Starting with rpm-4.7/openSUSE_11.3, rpm defaults to "%clean: rm -Rf %{buildroot}" if the %clean section is completely absent from the spec file.

If a package contains a %clean section, it should be safe to remove. Check with another maintainer first if you are not sure.


Great care should be taken when using scriptlets. Some common scriptlets are documented in openSUSE:Packaging scriptlet snippets.

Scriptlet requirements

Your package has to require everything you use in scriptlets.

The notation for %pre*/%post* scriptlets is as follows:

Requires(pre): ...
Requires(post): ...

Scriplets are only allowed to write in certain directories.

Build scripts of packages shall only alter (create, modify, delete) files under %buildroot, %_builddir and valid temporary locations like /tmp, /var/tmp (or %_tmppath as set by the rpmbuild process) according to the following table:

/tmp, /var/tmp, %_tmppath  %_builddir  %buildroot
%prep yes yes no
%build yes yes no
%install yes yes yes
%check yes yes no
%clean yes yes yes

Further clarification: This must hold true irrespective of the builder's uid.

Files Section (%files)

openSUSE follows the Filesystem Hierarchy Standard (FHS) with regards to filesystem layout, which defines where files should be placed on the system. Any deviation from the FHS should be justified in a comment in the spec file.


Your package should own all files that are installed as part of the %install process.

Packages must not own files already owned by other packages (or, if they legitimately do, the package needs a Conflict: tag). The rule of thumb here is that the first package to be installed should own the files that other packages may rely upon. If you feel that you have a good reason to own a file or that another package owns, then please present that at package review time.

Directory ownership is a little more complex than file ownership. Although the rule of thumb is the same: own all the directories you create but none of the directories of packages you depend on, there are several instances where it is desirable for multiple packages to own a directory. Examples of this include:

Forward compatibility with future versions of a package

The package you depend on to provide a directory may choose to own a different directory in a later version and your package will run unmodified with that later version.

One common example of this is a Perl module. Assume perl-A-B depends on perl-A and installs files into /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi/A/B. The base Perl package guarantees that it will own /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi for as long as it remains compatible with version 5.8.8, but a future upgrade of the perl-A package may install into (and thus own) /usr/lib/perl5/vendor_perl/5.9.0/i386-linux-thread-multi/A. So the perl-A-B package needs to own /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi/A as well as /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi/A/B in order to maintain proper ownership.

Common directory for unrelated packages

Multiple packages may have files in a common directory, but are not necessarily dependent on one of the packages. Take the following example:

  • Package foo-animal-emu puts files into /usr/share/Foo/Animal/Emu
  • Package foo-animal-llama puts files into /usr/share/Foo/Animal/Llama

Neither package depends on the other one. Neither package depends on any other package which owns the /usr/share/Foo/Animal directory. In this case, each package must own the /usr/share/Foo/Animal directory.

This is to prevent unowned directories from being installed on a system.

An openSUSE package must not contain any duplicate files in the %files listing.

Files packaged more than once (in two or more subpackages) and files containing the same content are both considered to be duplicate files.

It is recommended to run %fdupes %buildroot (requires adding BuildRequires: fdupes) to smartly eliminate duplicate content by replacing those files with hardlinks to one another.


Permissions on files must be set properly. Executables should be set with executable permissions, for example. Every %files section must include a %defattr(...) line. Here is a good default:


Unless you have a very good reason to deviate from that, you should use %defattr(-,root,root) for all %files sections in your package. You can use %defattr(-,root,root,0755) to fix permission issues with directories. E.g. when an umask was too tight while unpacking.

SUID bits

SUID bits set by default require explicit approval by the SUSE Security Team.

See the openSUSE package security guidelines for more information.

Documentation files

Any relevant documentation included in the source distribution should be included in the package.

Irrelevant documentation include build instructions, the omnipresent INSTALL file containing generic build instructions, for example, and documentation for non-Linux systems, e.g. README.MSDOS. Also pay attention about which subpackage you include documentation in, for example API documentation belongs in the -devel subpackage, not the main one. Or if there is a lot of documentation, consider putting it into a subpackage of its own. In this case, it is recommended to use *-doc as the subpackage name, and Documentation as the value of the Group tag.

Any file marked as %doc must not affect the runtime of the application.

That is, if it is in %doc, the program must run properly if it is not present.

Configuration files

Configuration files must be marked as such in packages. As a rule of thumb, use %config(noreplace) instead of plain %config unless your best, educated guess is that doing so will break things. In other words, think hard before overwriting local changes in configuration files on package upgrades. An example case when not to use noreplace is when a package's configuration file changes so that the new package revision would not work with the config file from the previous package revision. Whenever plain %config is used, add a brief comment to the specfile explaining why.

Do not use %config or %config(noreplace) under /usr. /usr is deemed to not contain configuration files in openSUSE.

Development files

If the software being packaged contains files intended solely for development, those files should be put in a -devel subpackage. The following are examples of file types which should be in -devel:

  • Header files (e.g. .h files)
  • Unversioned shared libraries (e.g. libfoo.so). Versioned shared libraries, e.g. libfoo.so.3, libfoo.so.3.0.0 should not be in -devel.
  • pkgconfig files. A reasonable exception is when the main package itself is a development tool, e.g. gcc or gdb.

Packages containing pkgconfig (.pc) files must utilize BuildRequires: pkg-config so that the proper runtime dependency Requires: pkg-config is added.

Locale files

openSUSE includes an rpm macro called %find_lang. This macro will locate all of the locale files that belong to your package (by name), and put this list in a file. You can then use that file to include all of the locales. %find_lang should be run in the %install section of your spec file, after all of the files have been installed into the buildroot. Using %find_lang helps keep the spec file simple, and helps avoid several other packaging mistakes.

  • Packages that use %_datadir/* to grab all the locale files in one line also grab ownership of the locale directories, which is not permitted.
  • Most packages that have locales have lots of locales. Using %find_lang is much easier in the spec file than having to do:
  • As new locale files appear in later package revisions, %find_lang will automatically include them when it is run, preventing you from having to update the spec any more than is necessary.
  • To include the locale files found by %find_lang you have add the -f %{name}.lang option to the %files section. So the section header should look like %files -f %{name}.lang.

Non-ASCII filenames

Filenames that contain non-ASCII characters must be encoded as UTF-8.

Since there is no way to note which encoding the filename is in, using the same encoding for all filenames is the best way to ensure users can read the filenames properly. If upstream ships filenames that are not encoded in UTF-8, you can use a utility like convmv (from the convmv package) to convert the filename in your %install section.


The GNU build system (autotools) offers a "libexecdir" variable/option, which specifies a location "for installing executable programs to be run by other programs rather than by users". Packages often create a subdirectory in libexecdir, for which they may also use the predefined convenient variable ${pkglibexecdir} in Automake files; one might find "pkglibexec_PROGRAMS = myhelper" in Makefile.am.

However, older versions of the Filesystem Hierarchy Standard (before 3.0) do not include any provision for libexecdir, and the rpm package in (open)SUSE has been changed to expand %_libexecdir to /usr/lib instead of /usr/libexec.

Changelog section (%changelog)

openSUSE uses a separate changelog file instead of placing it in the spec file.

See HOWTO write good changes for more information.