Tuesday, February 28, 2012

How to Create an RPM Package

In this blog, I'm going to teach you how to create an RPM package.
  1. Create a simple hello.cpp
  2. #include <iostream>
    using namespace std;
    int main() {
        cout << "Hello World" << endl;
        return 0;
  3. Create a Makefile
  4. CC = g++ 
    CCFLAGS = -g -Wall
    SRC = hello.cpp
    TARGET = hello
    .PHONY: clean install
    all: hello
    install: $(TARGET)
        if [ -d ${DESTDIR} ]; then rm -rf ${DESTDIR}; fi
        mkdir -p ${DESTDIR}
        cp $(TARGET) ${DESTDIR} 
        $(CC) $(CCFLAGS) -o $(TARGET) $(SRC)
        rm -rf $(TARGET)
  5. Put hello.cpp and the Makefile in a directory structure like this
  6. /home/foobar/hello/Makefile
  7. Create a tarball of hello project
  8. cd /home/foobar
    tar czvf hello-0.1.tar.gz hello/
  9. Create an rpmbuild directory
  10. mkdir -p /home/foobar/rpmbuild
  11. Create BUILD  BUILDROOT  RPMS  SOURCES  SPECS  SRPMS directories inside the /home/foobar/rpmbuild directory
  12. BUILD --> the source files are unpacked and compiled here
    BUILDROOT --> files are installed here
    RPMS --> binary RPMs are created here
    SOURCES --> source tarballs
    SPECS --> spec files
    SRPMS --> source RPMs

  13. Create a spec file in the /hom/foobar/rpmbuild/SPECS/hello.spec
  14. Summary             : Hello World program
    Name                : hello
    Version             : 0.1 
    Release             : 1%{?dist}
    License             : GPLv3+
    Source              : %{name}-%{version}.tar.gz
    A simple Hello World program
    %setup -q -n %{name}
    make install DESTDIR="%{buildroot}%{_bindir}"
    %prep --> this stage calls %setup to unpack hello-0.1.tar.gz to /home/foobar/rpmbuild/BUILD/hello. %{name} is a macro variable that substitutes to hello

    %build --> this stage calls "make" in the /home/foobar/rpmbuild/BUILD/hello to create a hello executable

    %install --> this stage calls "make install" to install the files into /home/foobar/rpmbuild/BUILDROOT/usr/bin. %{buildroot} is a macro variable that substitutes to /home/foobar/rpmbuild/BUILDROOT. Make sure the Makefile supports DESTDIR argument

    %files --> lists all the files to be installed. %{_bindir} is a macro variablesubstitutes to /usr/bin. In this example, only hello executable needs to be installed into /usr/bin

  15. Build the source and binary RPMs
  16. rpmbuild -ba /home/foobar/SPECS/hello.spec
    -ba option means build all (prep, build, install)
    The binary RPM will be created in /home/foobar/rpmbuild/RPMS
    The source RPM will be created in /home/foobar/rpmbuild/SRPMS

  17. Install the newly created binary RPM
  18. sudo rpm -ivh hello-0.1-1.fc16.i686.rpm
  19. Test if hello program was successfully installed
  20. hello
    You should see "Hello World" output

  21. Remove the hello package
  22. sudo rpm -e hello

1 comment:

  1. Step # 8 doesn't work for me.

    I try this:

    $ rpmbuild -ba ./home/ec2-user/foobar/rpmbuild/SPECS/hello.spec

    I get this:

    Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.r47lfF
    + umask 022
    + cd /home/ec2-user//BUILD
    + cd /home/ec2-user/BUILD
    + rm -rf hello
    + /usr/bin/gzip -dc /home/ec2-user/SOURCES/hello-0.1.tar.gz
    + /usr/bin/tar -xf -
    + STATUS=0
    + '[' 0 -ne 0 ']'
    + cd hello
    + /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
    + exit 0
    Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.pHBGef
    + umask 022
    + cd /home/ec2-user//BUILD
    + cd hello
    + make
    makefile:11: *** missing separator. Stop.
    error: Bad exit status from /var/tmp/rpm-tmp.pHBGef (%build)

    RPM build errors:
    Bad exit status from /var/tmp/rpm-tmp.pHBGef (%build)

    What should I do?