Contents

Make a skeleton spec file

We are going to create a package for verit. You don’t have to understand what verit does. The point is to show the steps needed to create an RPM package for a C project that uses autoconf and automake.

First, change to the directory where you want the RPM spec file to be created.

cd ~/rpmbuild/SPECS

One of the packages we had you install in setup is rpmdevtools, which contains several useful utilities for working with RPM packages. One of those tools is rpmdev-newspec, which creates a skeleton spec file for you. It has a number of templates which it uses to create the spec files; look in /etc/rpmdevtools to see the available templates. We will use the minimal template.

rpmdev-newspec verit

Now there is a file named verit.spec in your current directory. Let’s see what is inside.

Name:           verit
Version:
Release:        1%{?dist}
Summary:

License:
URL:
Source0:

BuildRequires:
Requires:

%description


%prep
%autosetup


%build
%configure
%make_build


%install
rm -rf $RPM_BUILD_ROOT
%make_install


%files
%license add-license-file-here
%doc add-docs-here



%changelog
* Mon Sep 13 2021 Jerry James
-

Determine the version

Let’s start filling in the spec file. First, what version are we packaging? At the time of this writing, the latest released version is 2021.06, so add that to the Version: line. While most software, including verit, now carries version numbers of the form number.number[.number], that style is not universal. If you are making a package for an upstream that has an unusual version numbering style, see the versioning guidelines for help on determining what to put in the Version: field.

Use autochangelog

Autochangelog is a recent addition to Fedora. It lets you avoid dealing directly with the Release: field and the %changelog section. Change the Release: field to read %autorelease. At the end of the spec file, replace the lines after %changelog with %autochangelog.

Write a summary

Next we need a summary. What does this package do? The home page says:

An open, trustable and efficient SMT-solver

Let’s reduce that to just “SMT solver” (Fedora already has a handful of these). Notice that there is no period in the summary. It is not a complete sentence, but rather a short descriptive phrase.

Determine the license

If you haven’t yet downloaded the tarball for the version you are packaging, do so now. Unpack the sources, and run licensecheck on the source files, as described here. In the case of verit 2021.06, the output looks like this:

./AUTHORS: UNKNOWN
./LICENSE: BSD (3 clause)
./Makefile.am: *No copyright* UNKNOWN
./Makefile.in:  [generated file]
./README.md: *No copyright* UNKNOWN
./aclocal.m4: FSF Unlimited License (with Retention) [generated file]
./configure: FSF Unlimited License [generated file]
./configure.ac: *No copyright* UNKNOWN
./example/prepro.smt2: *No copyright* UNKNOWN
./example/xor_unsound.smt2: *No copyright* UNKNOWN
./m4/m4_ax_check_compile_flag.m4: FSF All Permissive License
./m4/m4_ax_prog_bison.m4: GNU General Public License v2.0 or later
./scripts/compile: GNU General Public License v2.0 or later [generated file]
./scripts/depcomp: GNU General Public License v2.0 or later [generated file]
./scripts/install-sh: MIT License [generated file]
./scripts/missing: GNU General Public License v2.0 or later [generated file]
./scripts/tap-driver.sh: GNU General Public License v2.0 or later [generated file]
./scripts/test-driver: GNU General Public License v2.0 or later [generated file]
./src/Makefile.am: *No copyright* UNKNOWN
./src/Makefile.in:  [generated file]
./src/complete.c: *No copyright* UNKNOWN
./src/complete.h: *No copyright* UNKNOWN
./src/config.h.in: *No copyright* UNKNOWN
./src/hint.c: *No copyright* UNKNOWN
./src/hint.h: *No copyright* UNKNOWN
./src/main.c: *No copyright* UNKNOWN
./src/response.c: *No copyright* UNKNOWN
./src/response.h: *No copyright* UNKNOWN
./src/undo.c: *No copyright* UNKNOWN
./src/undo.h: *No copyright* UNKNOWN
./src/veriT-config.h: *No copyright* UNKNOWN
./src/veriT-state.c: *No copyright* UNKNOWN
./src/veriT-state.h: *No copyright* UNKNOWN
./src/veriT.c: *No copyright* UNKNOWN
./src/veriT.h: *No copyright* UNKNOWN
./test/Makefile.am: *No copyright* UNKNOWN
./test/Makefile.in:  [generated file]
./test/main.c: *No copyright* UNKNOWN
./test/picotest.h: BSD (3 clause)
./example/define-fun/cnst.smt2: *No copyright* UNKNOWN
./example/define-fun/eq.smt2: *No copyright* UNKNOWN
./example/proof/la_test.smt2: *No copyright* UNKNOWN
./example/proof/la_test_2.smt2: *No copyright* UNKNOWN
./example/proof/la_test_2p.smt2: *No copyright* UNKNOWN
./example/proof/la_test_3.smt2: *No copyright* UNKNOWN
./example/proof/la_test_4.smt2: *No copyright* UNKNOWN
./example/proof/la_test_p.smt2: *No copyright* UNKNOWN
./example/proof/qnt-simplify_1.smt2: *No copyright* UNKNOWN
./example/proof/quant-clausify_1.smt2: *No copyright* UNKNOWN
./example/proof/quant-clausify_2.smt2: *No copyright* UNKNOWN
./example/proof/step-simp_1.smt2: *No copyright* UNKNOWN
./example/proof/step-simp_2.smt2: *No copyright* UNKNOWN
./example/proof/step-simp_3.smt2: *No copyright* UNKNOWN
./src/SAT/veriT-SAT.c: *No copyright* UNKNOWN
./src/SAT/veriT-SAT.h: *No copyright* UNKNOWN
./src/arith/LA-hw.c: *No copyright* UNKNOWN
./src/arith/LA-hw.h: *No copyright* UNKNOWN
./src/arith/LA-mp.c: *No copyright* UNKNOWN
./src/arith/LA-mp.h: *No copyright* UNKNOWN
./src/arith/LA-pre.c: *No copyright* UNKNOWN
./src/arith/LA-pre.h: *No copyright* UNKNOWN
./src/arith/LA.c: *No copyright* UNKNOWN
./src/arith/LA.h: *No copyright* UNKNOWN
./src/arith/eq-store.c: *No copyright* UNKNOWN
./src/arith/eq-store.h: *No copyright* UNKNOWN
./src/arith/gcd-cache.def: *No copyright* UNKNOWN
./src/arith/numbers-hw.c: *No copyright* UNKNOWN
./src/arith/numbers-hw.h: *No copyright* UNKNOWN
./src/arith/numbers-mp.c: *No copyright* UNKNOWN
./src/arith/numbers-mp.h: *No copyright* UNKNOWN
./src/arith/simplex-hw.c: *No copyright* UNKNOWN
./src/arith/simplex-hw.h: *No copyright* UNKNOWN
./src/arith/simplex-mp.c: *No copyright* UNKNOWN
./src/arith/simplex-mp.h: *No copyright* UNKNOWN
./src/arith/simplex.c: *No copyright* UNKNOWN
./src/arith/simplex.h: *No copyright* UNKNOWN
./src/arith/totality.c: *No copyright* UNKNOWN
./src/arith/totality.h: *No copyright* UNKNOWN
./src/bool/bool.c: *No copyright* UNKNOWN
./src/bool/bool.h: *No copyright* UNKNOWN
./src/bool/clause.c: *No copyright* UNKNOWN
./src/bool/cnf.c: *No copyright* UNKNOWN
./src/bool/cnf.c.tpl: *No copyright* UNKNOWN
./src/bool/cnf.h: *No copyright* UNKNOWN
./src/bool/literal.c: *No copyright* UNKNOWN
./src/bool/literal.h: *No copyright* UNKNOWN
./src/congruence/congruence.c: *No copyright* UNKNOWN
./src/congruence/congruence.h: *No copyright* UNKNOWN
./src/instantiation/ccfv-bckt.c: *No copyright* UNKNOWN
./src/instantiation/ccfv-bckt.h: *No copyright* UNKNOWN
./src/instantiation/ccfv-constr.c: *No copyright* UNKNOWN
./src/instantiation/ccfv-constr.h: *No copyright* UNKNOWN
./src/instantiation/ccfv-mod.c: *No copyright* UNKNOWN
./src/instantiation/ccfv-mod.h: *No copyright* UNKNOWN
./src/instantiation/ccfv.c: *No copyright* UNKNOWN
./src/instantiation/ccfv.h: *No copyright* UNKNOWN
./src/instantiation/discrimination-tree.c: *No copyright* UNKNOWN
./src/instantiation/discrimination-tree.h: *No copyright* UNKNOWN
./src/instantiation/free-vars.c: *No copyright* UNKNOWN
./src/instantiation/free-vars.h: *No copyright* UNKNOWN
./src/instantiation/inst-create.c: *No copyright* UNKNOWN
./src/instantiation/inst-create.h: *No copyright* UNKNOWN
./src/instantiation/inst-del.c: *No copyright* UNKNOWN
./src/instantiation/inst-del.h: *No copyright* UNKNOWN
./src/instantiation/inst-enum.c: *No copyright* UNKNOWN
./src/instantiation/inst-enum.h: *No copyright* UNKNOWN
./src/instantiation/inst-index.c: *No copyright* UNKNOWN
./src/instantiation/inst-index.h: *No copyright* UNKNOWN
./src/instantiation/inst-man.c: *No copyright* UNKNOWN
./src/instantiation/inst-man.h: *No copyright* UNKNOWN
./src/instantiation/inst-pre.c: *No copyright* UNKNOWN
./src/instantiation/inst-pre.h: *No copyright* UNKNOWN
./src/instantiation/inst-strategy.h: *No copyright* UNKNOWN
./src/instantiation/inst-symbs.c: *No copyright* UNKNOWN
./src/instantiation/inst-symbs.h: *No copyright* UNKNOWN
./src/instantiation/inst-trigger-selection.c: *No copyright* UNKNOWN
./src/instantiation/inst-trigger-selection.h: *No copyright* UNKNOWN
./src/instantiation/inst-trigger.c: *No copyright* UNKNOWN
./src/instantiation/inst-trigger.h: *No copyright* UNKNOWN
./src/instantiation/syntactic-unify.c: *No copyright* UNKNOWN
./src/instantiation/syntactic-unify.h: *No copyright* UNKNOWN
./src/instantiation/ujobs.c: *No copyright* UNKNOWN
./src/instantiation/ujobs.h: *No copyright* UNKNOWN
./src/instantiation/unify.c: *No copyright* UNKNOWN
./src/instantiation/unify.h: *No copyright* UNKNOWN
./src/pre/HOL.c: *No copyright* UNKNOWN
./src/pre/HOL.h: *No copyright* UNKNOWN
./src/pre/bclauses.c: *No copyright* UNKNOWN
./src/pre/bclauses.h: *No copyright* UNKNOWN
./src/pre/bfun-elim.c: *No copyright* UNKNOWN
./src/pre/bfun-elim.h: *No copyright* UNKNOWN
./src/pre/binder-rename.c: *No copyright* UNKNOWN
./src/pre/binder-rename.h: *No copyright* UNKNOWN
./src/pre/connectives.c: *No copyright* UNKNOWN
./src/pre/connectives.h: *No copyright* UNKNOWN
./src/pre/distinct-elim.c: *No copyright* UNKNOWN
./src/pre/distinct-elim.h: *No copyright* UNKNOWN
./src/pre/fix-trigger.c: *No copyright* UNKNOWN
./src/pre/fix-trigger.h: *No copyright* UNKNOWN
./src/pre/ite-elim.c: *No copyright* UNKNOWN
./src/pre/ite-elim.h: *No copyright* UNKNOWN
./src/pre/let-elim.c: *No copyright* UNKNOWN
./src/pre/let-elim.h: *No copyright* UNKNOWN
./src/pre/nary-elim.c: *No copyright* UNKNOWN
./src/pre/nary-elim.h: *No copyright* UNKNOWN
./src/pre/pm.c: *No copyright* UNKNOWN
./src/pre/pm.h: *No copyright* UNKNOWN
./src/pre/pre.c: *No copyright* UNKNOWN
./src/pre/pre.h: *No copyright* UNKNOWN
./src/pre/qnt-tidy.c: *No copyright* UNKNOWN
./src/pre/qnt-tidy.h: *No copyright* UNKNOWN
./src/pre/qnt-trigger.c: *No copyright* UNKNOWN
/src/pre/qnt-trigger.h: *No copyright* UNKNOWN
./src/pre/qsimp-by-unification.c: *No copyright* UNKNOWN
./src/pre/qsimp-by-unification.h: *No copyright* UNKNOWN
./src/pre/rare-symb.c: *No copyright* UNKNOWN
./src/pre/rare-symb.h: *No copyright* UNKNOWN
./src/pre/simp-formula-sat.c: *No copyright* UNKNOWN
./src/pre/simp-formula-sat.h: *No copyright* UNKNOWN
./src/pre/simp-node-proof.c: *No copyright* UNKNOWN
./src/pre/simp-node-proof.h: *No copyright* UNKNOWN
./src/pre/simp-sym.c: *No copyright* UNKNOWN
./src/pre/simp-sym.h: *No copyright* UNKNOWN
./src/pre/simp-unit.c: *No copyright* UNKNOWN
./src/pre/simp-unit.h: *No copyright* UNKNOWN
./src/pre/simplify-AC.c: *No copyright* UNKNOWN
./src/pre/simplify-AC.h: *No copyright* UNKNOWN
./src/pre/simplify.c: *No copyright* UNKNOWN
./src/pre/simplify.h: *No copyright* UNKNOWN
./src/pre/skolem.c: *No copyright* UNKNOWN
./src/pre/skolem.h: *No copyright* UNKNOWN
./src/proof/proof-checking.c: *No copyright* UNKNOWN
./src/proof/proof-checking.h: *No copyright* UNKNOWN
./src/proof/proof-id.c: *No copyright* UNKNOWN
./src/proof/proof-id.h: *No copyright* UNKNOWN
./src/proof/proof-lemma-hash.c: *No copyright* UNKNOWN
./src/proof/proof-lemma-hash.h: *No copyright* UNKNOWN
./src/proof/proof-output.c: *No copyright* UNKNOWN
./src/proof/proof-output.h: *No copyright* UNKNOWN
./src/proof/proof-print.c: *No copyright* UNKNOWN
./src/proof/proof-print.h: *No copyright* UNKNOWN
./src/proof/proof-rules-tautologies.c: *No copyright* UNKNOWN
./src/proof/proof-rules-tautologies.h: *No copyright* UNKNOWN
./src/proof/proof-rules.c: *No copyright* UNKNOWN
./src/proof/proof-rules.h: *No copyright* UNKNOWN
./src/proof/proof-sat-solver.c: *No copyright* UNKNOWN
./src/proof/proof-sat-solver.h: *No copyright* UNKNOWN
./src/proof/proof-step-hash.c: *No copyright* UNKNOWN
./src/proof/proof-step-hash.h: *No copyright* UNKNOWN
./src/proof/proof-step-table.c: *No copyright* UNKNOWN
./src/proof/proof-step-table.h: *No copyright* UNKNOWN
./src/proof/proof-step.c: *No copyright* UNKNOWN
./src/proof/proof-step.h: *No copyright* UNKNOWN
./src/proof/proof-subproof.c: *No copyright* UNKNOWN
./src/proof/proof-subproof.h: *No copyright* UNKNOWN
./src/proof/proof-type.c: *No copyright* UNKNOWN
./src/proof/proof-type.h: *No copyright* UNKNOWN
./src/proof/proof-unsat-core.c: *No copyright* UNKNOWN
./src/proof/proof-unsat-core.h: *No copyright* UNKNOWN
./src/proof/proof.c: *No copyright* UNKNOWN
./src/proof/proof.h: *No copyright* UNKNOWN
./src/symbolic/DAG-arith.c: *No copyright* UNKNOWN
./src/symbolic/DAG-arith.h: *No copyright* UNKNOWN
./src/symbolic/DAG-flag.c: *No copyright* UNKNOWN
./src/symbolic/DAG-flag.h: *No copyright* UNKNOWN
./src/symbolic/DAG-print.c: *No copyright* UNKNOWN
./src/symbolic/DAG-print.h: *No copyright* UNKNOWN
./src/symbolic/DAG-prop.c: *No copyright* UNKNOWN
./src/symbolic/DAG-prop.h: *No copyright* UNKNOWN
./src/symbolic/DAG-ptr.h: *No copyright* UNKNOWN
./src/symbolic/DAG-smtlib.c: *No copyright* UNKNOWN
./src/symbolic/DAG-sort-pm.c: *No copyright* UNKNOWN
./src/symbolic/DAG-sort-pm.h: *No copyright* UNKNOWN
./src/symbolic/DAG-sort.c: *No copyright* UNKNOWN
./src/symbolic/DAG-sort.h: *No copyright* UNKNOWN
./src/symbolic/DAG-stat.c: *No copyright* UNKNOWN
./src/symbolic/DAG-stat.h: *No copyright* UNKNOWN
./src/symbolic/DAG-subst.c: *No copyright* UNKNOWN
./src/symbolic/DAG-subst.h: *No copyright* UNKNOWN
./src/symbolic/DAG-symb-DAG.c: *No copyright* UNKNOWN
./src/symbolic/DAG-symb-DAG.h: *No copyright* UNKNOWN
./src/symbolic/DAG-symb.c: *No copyright* UNKNOWN
./src/symbolic/DAG-symb.h: *No copyright* UNKNOWN
./src/symbolic/DAG-tmp.c: *No copyright* UNKNOWN
./src/symbolic/DAG-tmp.h: *No copyright* UNKNOWN
./src/symbolic/DAG.c: *No copyright* UNKNOWN
./src/symbolic/DAG.h: *No copyright* UNKNOWN
./src/symbolic/context-handling.c: *No copyright* UNKNOWN
./src/symbolic/context-handling.h: *No copyright* UNKNOWN
./src/symbolic/context-recursion-proof.c: *No copyright* UNKNOWN
./src/symbolic/context-recursion-proof.h: *No copyright* UNKNOWN
./src/symbolic/context-recursion.c: *No copyright* UNKNOWN
./src/symbolic/context-recursion.h: *No copyright* UNKNOWN
./src/symbolic/dbg-trigger.c: *No copyright* UNKNOWN
./src/symbolic/dbg-trigger.h: *No copyright* UNKNOWN
./src/symbolic/polarities.c: *No copyright* UNKNOWN
./src/symbolic/polarities.h: *No copyright* UNKNOWN
./src/symbolic/qnt-utils.c: *No copyright* UNKNOWN
./src/symbolic/qnt-utils.h: *No copyright* UNKNOWN
./src/symbolic/recursion.c: *No copyright* UNKNOWN
./src/symbolic/recursion.h: *No copyright* UNKNOWN
./src/symbolic/veriT-DAG.h: *No copyright* UNKNOWN
./src/symbolic/veriT-status.h: *No copyright* UNKNOWN
./src/utils/assoc.h: *No copyright* UNKNOWN
./src/utils/bitset.c: *No copyright* UNKNOWN
./src/utils/bitset.h: *No copyright* UNKNOWN
./src/utils/dll-DAG.h: *No copyright* UNKNOWN
./src/utils/dll.c: *No copyright* UNKNOWN
./src/utils/dll.h: *No copyright* UNKNOWN
./src/utils/general.c: *No copyright* UNKNOWN
./src/utils/general.h: *No copyright* UNKNOWN
./src/utils/h-util.c: *No copyright* UNKNOWN
./src/utils/h-util.h: *No copyright* UNKNOWN
./src/utils/h.h: *No copyright* UNKNOWN
./src/utils/ha.c.tpl: *No copyright* UNKNOWN
./src/utils/hash.c: *No copyright* UNKNOWN
./src/utils/hash.h: *No copyright* UNKNOWN
./src/utils/hashmap.c: *No copyright* UNKNOWN
./src/utils/hashmap.h: *No copyright* UNKNOWN
./src/utils/hk.h: *No copyright* UNKNOWN
./src/utils/list.c: *No copyright* UNKNOWN
./src/utils/list.h: *No copyright* UNKNOWN
./src/utils/nonce.c: *No copyright* UNKNOWN
./src/utils/nonce.h: *No copyright* UNKNOWN
./src/utils/options.c: *No copyright* UNKNOWN
./src/utils/options.h: *No copyright* UNKNOWN
./src/utils/stack.h: *No copyright* UNKNOWN
./src/utils/statistics.c: *No copyright* UNKNOWN
./src/utils/statistics.h: *No copyright* UNKNOWN
./src/utils/sys.c: *No copyright* UNKNOWN
./src/utils/sys.h: *No copyright* UNKNOWN
./src/utils/table.c: *No copyright* UNKNOWN
./src/utils/table.h: *No copyright* UNKNOWN
./src/utils/types.h: *No copyright* UNKNOWN
./src/utils/veriT-qsort.c: BSD (3 clause)
./src/utils/veriT-qsort.h: *No copyright* UNKNOWN
./src/utils/veriT-signal.c: *No copyright* UNKNOWN
./src/utils/veriT-signal.h: *No copyright* UNKNOWN
./src/veriT-SAT/main.c: *No copyright* UNKNOWN
./test/suits/discrimination-tree.h: *No copyright* UNKNOWN
./test/suits/syntactic-unify.h: *No copyright* UNKNOWN
./src/parsers/dimacs/dimacs.c: *No copyright* UNKNOWN
./src/parsers/dimacs/dimacs.h: *No copyright* UNKNOWN
./src/parsers/smtlib2/parser_macro.h: *No copyright* UNKNOWN
./src/parsers/smtlib2/smtfun.c: *No copyright* UNKNOWN
./src/parsers/smtlib2/smtfun.h: *No copyright* UNKNOWN
./src/parsers/smtlib2/smtlex.c: *No copyright* UNKNOWN
./src/parsers/smtlib2/smtlib2.h: *No copyright* UNKNOWN
./src/parsers/smtlib2/smtsyn.c: GNU General Public License v3.0 or later
./src/parsers/smtlib2/smtsyn.h: GNU General Public License v3.0 or later
./src/parsers/smtlib2/smttypes.h: *No copyright* UNKNOWN

The toplevel LICENSE file contains a BSD license. The various autotools scripts can be ignored, as no part of them will appear in the final binary package. But what’s up with smtsyn.c and smtsyn.h? They seem to be GPLv3+ files. If we look into them, we find that these are files generated by bison. The license text at the top of those files lets us know that we can incorporate them into a project with a different license without changing that license. Therefore, we select BSD as the license for the project.

Now we have to translate that into the name used by Fedora packages in the License: field. The Fedora project maintains a list of licenses. The “Short Name” column is what goes into the License: field of an RPM spec file. For the verit package, BSD is the correct value.

The URL field

Next, put the project URL into the URL: field of the spec file. This should be some sort of home page for the project. In the verit case, the value of the field is https://www.verit-solver.org/. If the project is on github, the project URL may be the main repository page for the project, which will be a URL of the form https://github.com/owner/project. In that case, check whether either of the pages https://owner.github.io/project or https://owner.github.io/ exist and contain useful content. Use one of them as the URL if so.

The Source field

The Source fields in the spec file identify those files that must be present in the build root in order to build the software. See the Source URL guidelines for help determining the appropriate URL for this field.

The name of the package should be replaced with %{name} in this URL, and the version number should be replaced with %{version}. The intent is to avoid changing the URL field every time a new version is released.

For the verit package, we will use this as the Source0 URL:

https://verit.loria.fr/download/%{version}/%{name}-%{version}-rmx.tar.gz

BuildRequires

Each BuildRequires tag in a spec file identifies some package that must be installed prior to building the target package. Let’s examine the verit package.

At the top level of the source directory, we see a file named configure.ac. This is an autoconf input file, and will often contain references to other packages needed to build this one. Under # Check programs, we see that the configure script checks for lex, awk, bison, and sed. Both awk (gawk) and sed are installed in the build root by default, but lex (flex) and bison are not, so add BuildRequires for both.

Under # Checks for libraries we see that the configure script wants to find the gmp library. There is a gmp-devel package, but be aware of the need to use pkgconfig requires in some cases. This does not appear to be one of those cases, so add BuildRequires: gmp-devel to the spec file.

Looking into the src subdirectory, we see that this project contains files with a .c suffix; i.e., they are C source files. We need a C compiler to build, then, so add BuildRequires: gcc to the spec file. Finally, as is common with autotools projects, a Makefile will be generated, so add BuildRequires: make to the spec file. It should now look like this:

Name:           verit
Version:        2021.06
Release:        %autorelease
Summary:        SMT solver

License:        BSD
URL:            https://www.verit-solver.org/
Source0:        https://verit.loria.fr/download/%{version}/%{name}-%{version}-rmx.tar.gz

BuildRequires:  bison
BuildRequires:  flex
BuildRequires:  gcc
BuildRequires:  gmp-devel
BuildRequires:  make

%description

%prep
%autosetup


%build
%configure
%make_build


%install
rm -rf $RPM_BUILD_ROOT
%make_install


%files
%license add-license-file-here
%doc add-docs-here



%changelog
%autochangelog

Description

The %description section is typically filled in with text from a README file. Failing that, do your best to write a paragraph describing what this package does. You want a person who has never heard of the software before to be able to get some idea of the purpose of the package from reading the description. As noted in the packaging guidelines, keep lines to 80 characters or less. Longer lines can be displayed in strange ways in the various graphical software managers. I usually limit description lines to 72 characters to be on the safe side.

Prep

The %prep section is where we do anything that must be done prior to building the software. Typically, the first step is to unpack a tarball or zip file. The %autosetup macro is often sufficient. It knows how to unpack a variety of files and compression types. This macro assumes that, after unpacking, it will find the source files in a directory named %{name}-%{version}. If that is not the case, we need to tell it so. In the verit case, the name of the directory is verit2-2021.06-rmx. That trailing “-rmx” does not match what %autosetup expects. Change the %autosetup invocation to read:

%autosetup -n %{name}-%{version}-rmx

Build

The %build section contains instructions on how to build the softare. The %configure and %make_build macros placed there by rpmdev-newspec are intended for use with software that supplies an autoconf-generated configure script. That’s perfect for us, so leave it as is.

Install

The %install section installs the software into a directory identified by the macro %buildroot. RPM uses the files placed there to build the final binary package.

Our %install section starts with the line rm -rf $RPM_BUILD_ROOT. That line was inserted by rpmdev-newspec, which aims to be compatible with all Linux distributions that use RPM. Fedora, however, does not want that line in spec files; see Tags and Section in the packaging guidelines. Remove it now.

Now we just have %make_install in the %install section. That macro runs make install with some flags that are commonly used to get the installed files to go into %buildroot. Like %configure and %make_build, it is intended for projects that use autoconf, so leave it alone and we’ll see if it does the job.

Files

The %files section lists all of the files that go into the binary RPM. We don’t have to guess; we’ll do a test build and install to help us figure this out. However, there are two things we can do right now. Since we see a file named LICENSE in the source directory, change the %license line to refer to it. Also, there is a README.md file, so change the %doc line to refer to it. The spec file should now look something like this:

Name:           verit
Version:        2021.06
Release:        %autorelease
Summary:        SMT solver

License:        BSD
URL:            https://www.verit-solver.org/
Source0:        https://verit.loria.fr/download/%{version}/%{name}-%{version}-rmx.tar.gz

BuildRequires:  bison
BuildRequires:  flex
BuildRequires:  gcc
BuildRequires:  gmp-devel
BuildRequires:  make

%description
veriT is an SMT (Satisfiability Modulo Theories) solver.  It is
open-source, proof-producing, and complete for quantifier-free formulas
with uninterpreted functions and linear arithmetic on real numbers and
integers.  It also offers good support for quantifiers.

This release is a remix of veriT adapted for usage inside proof
assistants.  Some features, especially non-linear arithmetic support,
were removed.

The front-end uses the SMTLIB-2 language (documented at
http://www.smtlib.org), but not all features are supported.

%prep
%autosetup -n %{name}-%{version}-rmx

%build
%configure
%make_build

%install
%make_install

%files
%license LICENSE
%doc README.md

%changelog
%autochangelog

First test build

Make sure that your spec file is in ~/rpmbuild/SPECS, and that verit-2021.06-rmx.tar.gz is in ~/rpmbuild/SOURCES. While in the ~/rpmbuild/SPECS directory, run rpmbuild -bs verit.spec. That command generates a source rpm in ~/rpmbuild/SRPMS.

Next, we will attempt to build the package with mock. Refer to building with mock for details. Briefly, run this command:

mock -r fedora-rawhide-x86_64 --rebuild ~/rpmbuild/SRPMS/verit-2021.06-1.fc35.src.rpm

You may have to replace fc35 in that filename. Make it match the name of file file in your ~/rpmbuild/SRPMS directory.

The test build runs all the way to the end, giving us the list of installed files that we need for the %files section:

RPM build errors:
error: Installed (but unpackaged) file(s) found:
   /usr/bin/veriT
   /usr/bin/veriT-SAT
   /usr/lib/debug/usr/bin/veriT-2021.06-1.fc36.x86_64.debug
   /usr/lib/debug/usr/bin/veriT-SAT-2021.06-1.fc36.x86_64.debug
    Installed (but unpackaged) file(s) found:
   /usr/bin/veriT
   /usr/bin/veriT-SAT
   /usr/lib/debug/usr/bin/veriT-2021.06-1.fc36.x86_64.debug
   /usr/lib/debug/usr/bin/veriT-SAT-2021.06-1.fc36.x86_64.debug

We can ignore the debug files as they will be handled automatically once we get everything else right. Add this to %files:

%{_bindir}/veriT
%{_bindir}/veriT-SAT

We’re done!

Build flags

Just kidding! Let’s look at that build log again. In particular, look at the build flags used for C source files. After the Fedora flags, you’ll see some flags inserted by veriT upstream:

-O3 -fomit-frame-pointer -finline-limit=1000000 -flto

We don’t necessarily want all of upstream’s flags. In particular, Fedora chooses its own optimization flag (currently -O2), so we do not want the -O3. The choice of omitting the frame pointer or not is also made by Fedora, so we should also remove -fomit-frame-ponter. The inline-limit flag should be fine. Fedora uses its own LTO flags, so we do not want -flto either.

If we run ./configure --help we can see that there is a --disable-lto flag to get rid of -flto, so add that. The configure script does not give us an option for eliminating -O3 or -fomit-frame-pointer however, so add this to %prep:

# Do not override Fedora flags.
sed -i '/-O3/d;/-fomit-frame-pointer/d' configure

Build again. The build is successful.

Trim BuildRequires

If we look through the build log, we may notice that flex and bison are never invoked. Indeed, a look in the source tree shows that the input files to those two programs, smtlex.l and smtsyn.y, are not included in the source tarball. All we get are the C files generated by those tools. Even though the configure script looks for them, we don’t really need them. Remove those BuildRequires.

At this point, the spec file should look something like this:

Name:           verit
Version:        2021.06
Release:        %autorelease
Summary:        SMT solver

License:        BSD
URL:            https://www.verit-solver.org/
Source0:        https://verit.loria.fr/download/%{version}/%{name}-%{version}-rmx.tar.gz

BuildRequires:  gcc
BuildRequires:  gmp-devel
BuildRequires:  make

%description
veriT is an SMT (Satisfiability Modulo Theories) solver.  It is
open-source, proof-producing, and complete for quantifier-free formulas
with uninterpreted functions and linear arithmetic on real numbers and
integers.  It also offers good support for quantifiers.

This release is a remix of veriT adapted for usage inside proof
assistants.  Some features, especially non-linear arithmetic support,
were removed.

The front-end uses the SMTLIB-2 language (documented at
http://www.smtlib.org), but not all features are supported.

%prep
%autosetup -n %{name}-%{version}-rmx

# Do not override Fedora flags
sed -i '/-O3/d;/-fomit-frame-pointer/d' configure

%build
# Fedora provides its own LTO flags
%configure --disable-lto
%make_build

%install
%make_install

%files
%license LICENSE
%doc README.md
%{_bindir}/veriT
%{_bindir}/veriT-SAT

%changelog
%autochangelog

Requires and Provides

Now that we have a reasonable looking package, lets make sure that the final Requires and Provides look right.

$ rpm -q --requires -p /var/lib/mock/fedora-rawhide-x86_64/result/verit-2021.06-1.fc36.x86_64.rpm
libc.so.6()(64bit)
libc.so.6(GLIBC_2.14)(64bit)
libc.so.6(GLIBC_2.2.5)(64bit)
libc.so.6(GLIBC_2.3)(64bit)
libc.so.6(GLIBC_2.3.4)(64bit)
libc.so.6(GLIBC_2.34)(64bit)
libc.so.6(GLIBC_2.4)(64bit)
libc.so.6(GLIBC_2.7)(64bit)
libgmp.so.10()(64bit)
libm.so.6()(64bit)
libm.so.6(GLIBC_2.29)(64bit)
rpmlib(CompressedFileNames) <= 3.0.4-1
rpmlib(FileDigests) <= 4.6.0-1
rpmlib(PayloadFilesHavePrefix) <= 4.0-1
rpmlib(PayloadIsZstd) <= 5.4.18-1
rtld(GNU_HASH)

I see a dependency on gmp, which is good.

$ rpm -q --provides -p /var/lib/mock/fedora-rawhide-x86_64/result/verit-2021.06-1.fc36.x86_64.rpm
verit = 2021.06-1.fc36
verit(x86-64) = 2021.06-1.fc36

That looks good, too. Let’s take a peek at the contents of the binary RPM while we are at it.

$ rpm -qlp /var/lib/mock/fedora-rawhide-x86_64/result/verit-2021.06-1.fc36.x86_64.rpm
6_64.rpm
/usr/bin/veriT
/usr/bin/veriT-SAT
/usr/lib/.build-id
/usr/lib/.build-id/32
/usr/lib/.build-id/32/cb2314d821f7a026cf760b7e2441f50dd3f8b7
/usr/lib/.build-id/cc
/usr/lib/.build-id/cc/8e40a29387b82292c07b70fd23aa7420766183
/usr/share/doc/verit
/usr/share/doc/verit/README.md
/usr/share/licenses/verit
/usr/share/licenses/verit/LICENSE

That looks fine.

Run tests

Upstream has provided us with some tests. We should run them to make sure we haven’t somehow broken the whole thing. With autotools projects, make check often does what we want. Let’s try it. Add this to the spec file:

%check
%make_build check

Run that again and the tests all pass. Great!

Run rpmlint

We finally have a viable spec file! Let’s run an automated tool over it that can detect many common packaging problems.

mock -r fedora-rawhide-x86_64 --install /var/lib/mock/fedora-rawhide-x86_64/result/*.{noarch,x86_64}.rpm rpmlint python3-enchant

Afterwards, we enter a mock shell:

mock --enable-network -r fedora-rawhide-x86_64 --shell

The --enable-network argument allows rpmlint to access the network in order to do some checks, such as URL validity. In the shell, run this command:

# rpmlint -i verit
================================================ rpmlint session starts ================================================
rpmlint: 2.1.0
configuration:
    /usr/lib/python3.10/site-packages/rpmlint/configdefaults.toml
    /etc/xdg/rpmlint/fedora.toml
    /etc/xdg/rpmlint/licenses.toml
    /etc/xdg/rpmlint/scoring.toml
    /etc/xdg/rpmlint/users-groups.toml
    /etc/xdg/rpmlint/warn-on-functions.toml
checks: 31, packages: 1

verit.x86_64: W: no-manual-page-for-binary veriT
verit.x86_64: W: no-manual-page-for-binary veriT-SAT
================= 1 packages and 0 specfiles checked; 0 errors, 2 warnings, 0 badness; has taken 0.1 s =================

There are indeed no man pages for these tools. Do the tools themselves provide any help? Try running veriT --help. Sure enough, we get a list of command line options. In that case, maybe we can construct useful man pages.

Generate a man page

The help2man package contains a useful tool that converts --help output to a man page. Run this command:

mock -r fedora-rawhide-x86_64 --install help2man

Then get a mock shell again:

mock -r fedora-rawhide-x86_64 --shell

Let’s see if we can find an invocation of help2man that generates a reasonable man page.

# su - mockbuild
$ cd build/BUILD/verit-2021.06-rmx
$ help2man ./veriT
help2man: can't get `--help' info from ./veriT
Try `--no-discard-stderr' if option outputs to stderr

We saw help output, so maybe help2man is right about it sending output to stderr. Let’s see:

$ help2man --no-discard-stderr ./veriT

That certainly looks like man page output. Let’s save it to a file so we can more easily work with it:

$ help2man --no-discard-stderr -o veriT.1 ./veriT
$ nroff -man veriT.1

That doesn’t look completely terrible. Let’s start going over it. Right away, we notice a problem on the first line of output:

THIS(1)                          User Commands                         THIS(1)

The command name is not “This”. The word “This” does not show up at the top of the veriT --help output. What is going on? Well, help2man also runs veriT --version to get the version number. Let’s see what that produces:

$ ./veriT --version
This is veriT, version 2021.06-rmx

Ah, that’s where “This” is coming from! Since help2man doesn’t know how to parse that, let’s pass the version number in directly.

$ help2man --no-discard-stderr -o veriT.1 --version-string=2021.06-rmx ./veriT

That looks a lot better. But the NAME section could use some work:

NAME
       veriT - manual page for veriT 2021.06-rmx

That’s not very useful. Let’s try passing in some useful text for the name section.

help2man --no-discard-stderr -o veriT.1 --version-string=2021.06-rmx -n 'SMT solver' ./veriT

That looks much better. But what’s this section at the end?

SEE ALSO
       The full documentation for veriT is maintained as a Texinfo manual.  If
       the  info  and  veriT programs are properly installed at your site, the
       command

              info veriT

       should give you access to the complete manual.

That is boilerplate text for GNU projects, which do indeed maintain Texinfo manuals. Non-GNU projects typically do not, and this one is no exception. Fortunately, help2man has the -N flag to turn that off. The final invocation looks like this:

help2man --no-discard-stderr -o veriT.1 --version-string=2021.06-rmx -n 'SMT solver' -N ./veriT

The ‘Version’ line under DESCRIPTION is not useful, since man already displays the version number in another way. However, we cannot tell help2man to not include it, because it is simply part of the output of veriT --help. We may want to remove that line with a sed command. After reordering the help2man options in a way that makes sense to me, substituting %{version} for the bare version number in that command line, and splitting the long line, I inserted this into the spec file, at the end of the %build section:

# Build man page
help2man -N --no-discard-stderr --version-string=%{version}-rmx \
  -n 'SMT solver' -o veriT.1 ./veriT
sed -i '/Version: veriT/d' veriT.1

We need to install the man page in the %install section. Add this:

# Install man page
install -D -m 0644 veriT.1 %{buildroot}%{_mandir}/man1/veriT.1

We also need to add %{_mandir}/man1/veriT.1* to %files. Why the asterisk at the end? Because RPM compresses man pages, so a suffix will be added to the file. Currently, gzip is used, so the suffix is “.gz”, but I don’t want to gamble that that will be the case forever. Some day we may have xz-compressed man pages. With the asterisk I don’t have to worry about it.

Now let’s build a man for the other binary, veriT-SAT. Let’s see what its help output looks like.

$ ./veriT-SAT --help
s SATISFIABLE
v 

Wait, what? Maybe I don’t understand what this binary does. Let’s look in the source directory, in src/veriT-SAT/main.c. Sure enough, there is no help text anywhere. Looking at the code in main() shows that it expects exactly one argument, a filename. The code parses the file as a SAT problem, solves it, and prints the result. We now have the choice of manually constructing a man page that says that, or omitting a man page for this binary. In the latter case, the final spec file looks like this:

Name:           verit
Version:        2021.06
Release:        %autorelease
Summary:        SMT solver

License:        BSD
URL:            https://www.verit-solver.org/
Source0:        https://verit.loria.fr/download/%{version}/%{name}-%{version}-rmx.tar.gz

BuildRequires:  gcc
BuildRequires:  gmp-devel
BuildRequires:  help2man
BuildRequires:  make

%description
veriT is an SMT (Satisfiability Modulo Theories) solver.  It is
open-source, proof-producing, and complete for quantifier-free formulas
with uninterpreted functions and linear arithmetic on real numbers and
integers.  It also offers good support for quantifiers.

This release is a remix of veriT adapted for usage inside proof
assistants.  Some features, especially non-linear arithmetic support,
were removed.

The front-end uses the SMTLIB-2 language (documented at
http://www.smtlib.org), but not all features are supported.

%prep
%autosetup -n %{name}-%{version}-rmx

# Do not override Fedora flags
sed -i '/-O3/d;/-fomit-frame-pointer/d' configure

%build
# Fedora provides its own LTO flags
%configure --disable-lto
%make_build

# Build man page
help2man -N --no-discard-stderr --version-string=%{version}-rmx \
  -n 'SMT solver' -o veriT.1 ./veriT
sed -i '/Version: veriT/d' veriT.1

%install
%make_install

# Install man page
install -D -m 0644 veriT.1 %{buildroot}%{_mandir}/man1/veriT.1

%check
%make_build check

%files
%license LICENSE
%doc README.md
%{_bindir}/veriT
%{_bindir}/veriT-SAT
%{_mandir}/man1/veriT.1*

%changelog
%autochangelog

Conclusion

I hope you learned something from this case study. Please send suggestions for improvements to Jerry James. If you want to submit the verit package to Fedora, please feel free. Just make sure nobody else beat you to it.