skip to main content

LCFG Build Tools : Converting from the old system

Depending on the complexity of a component there might be very little to alter or there might be lots of changes required to move from the old LCFG build tools to the new system. The intention is that in the majority of cases the work required will be minimal.

Throughout these examples the presumption is that you have the following packages installed and the versions are the same or newer:

perl-LCFG-Build-Tools-0.0.38-1/noarch
perl-LCFG-Build-PkgSpec-0.0.23-1/noarch
perl-LCFG-Build-VCS-0.0.21-1/noarch

You can download these as RPMs from the LCFG website (listed in the "Development Packages" section). You can also install them as standard Perl packages by fetching them from CPAN.

Conversion is easy!

Here is the really good news, if your component looks like that described in the "Anatomy of a Component Package" page then there really is very little to do. It boils down to:

$ cd lcfg-foo
$ lcfg-cfg2meta
$ cvs add lcfg.yml
[edit specfile with your favourite editor, see below]
[edit ChangeLog with your favourite editor]
$ cvs commit -m "Converted to new build tools"
$ lcfg-reltool microversion
$ lcfg-reltool devrpm

That is it! You've got yourself an RPM generated with the new build tools system. Good examples of this are the file and auth components.

specfile changes required

It is not apparent from this simple example but the package will now be built using a tool called CMake. In this simple case all the necessary files to run CMake are generated just before the source is packed into the gzipped tar file. To actually use CMake to build the RPM you need to make some small modifications to the specfile.

Firstly, you should really add a build-requirement on the cmake package. In the future we intend to build packages inside a chroot using a tool such as mock. The chroot will not have CMake installed by default so you must specify that it is required. You want a line like:

BuildRequires:  cmake >= 2.6.0, /etc/rpm/macros.cmake, lsb

Secondly, you need to modify the %build section to look like:

%build
%cmake -DPERL_INSTALLDIRS:STRING=vendor
make

Here we are relying on a macro to hide all the magic incantantations necessary to drive CMake properly. That is why there is a build requirement on the file /etc/rpm/macros.cmake, it is not essential but it makes things a lot simpler.

Thirdly, you need to alter the %install section to pass the DESTDIR option rather than PREFIX. It should now look something like:

%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT

%{_fixperms} $RPM_BUILD_ROOT/*

Finally, if you want the component changelog to be added to the specfile you now need to add a %changelog section. The new build tools will not just blindly append it to the end of the specfile for you. You need this:

%changelog
@LCFG_CHANGELOG@

A complete example which shows the various changes which are required is the specfile for the LCFG client component.

What are the gotchas?

It is too good to be true, right? There's always a catch isn't there? As with everything, "it depends".

You need to check through all your files for macros (i.e. @FOO@) and ensure they are all supported by the new build tools. A full list of macros along with descriptions and values is available. If you've been fairly conservative with your macro usage then you'll be fine, if you have had some extra variables defined in your config.mk you can either hardwire the values throughout your files or breakout the CMake, see below for more details.

You also need to check your specfile, this is the place where problems are most likely to strike. Primarily this is because the list of macros available for filling-out the template has been restricted to aid platform-independence. To help with this process, when the specfile template is completed the tools print out a list of any unknown macros to STDERR. Part of the output will be something like:

LCFG: Successfully exported the source tree.
Unknown macro FOO
Unknown macro BAR
Unknown macro BAZ
LCFG: Successfully translated template files.
LCFG: Successfully generated source tar file.
LCFG: Successfully generated metadata files for RPM

You can check the macros being used by a particular component with the "checkmacros" command. For example with the "boot" component:

$ lcfg-reltool checkmacros --dir ~/dice/lcfg-boot/
Use of compile-time-only macro, EGREP, at: 
        boot.cin:131
        boot.cin:146
        boot.cin:152
        boot.cin:186
        boot.cin:192
        boot.cin:224
        boot.cin:330
        boot.cin:349
Use of compile-time-only macro, LCFGOS, at: 
        boot.cin:33
        boot.cin:34
        boot.cin:264
        boot.cin:265
Use of compile-time-only macro, MSG, at: 
        waitonboot.cin:6
        boot.cin:11
        boot.def.cin:7
Use of compile-time-only macro, SED, at: 
        boot.cin:159
        boot.cin:202
        boot.cin:285
Use of compile-time-only macro, SHELL, at: 
        waitonboot.cin:1
        boot.cin:1
Use of compile-time-only macro, SORT, at: 
        boot.cin:157
        boot.cin:197

Note that none of the warnings can be truly considered an error. Even a message about an unknown macro is fine if you add the specification for that variable to a local CMakeLists.txt file for that component. In general it has to be left up to the software author to interpret the true importance of a particular warning.

The warnings are listed in order of importance:

  1. Use of unknown macro
  2. Use of deprecated macro
  3. Use of linux-only macro
  4. Use of macosx-only macro
  5. Use of compile-time-only macro

In each instance you will get a list of filenames and the line numbers of where the macros are used. The special case in which all of these warnings (except that for "deprecated macro") should be considered a fatal error is with the RPM specfile. By design, locally defined macros and those which are platform specific or compile-time only cannot be used in the specfile.

You might also need to replace the "Copyright" field name with "License", the field name was changed some time ago but the old build tools silently rewrote the specfile.

How does it all work?

When you use lcfg-reltool to execute commands such as pack, devpack, srpm, rpm and devrpm just prior to packing the source code into a gzipped tarfile a couple of CMake files are generated and added to the source directory. If you unpack the generated tar file you will find that there are extra files named CMakeLists.txt and lcfg.cmake. The first file is what drives CMake and, yes, it really does have to be named like that... The second file contains all the LCFG variables and macros you might need to build your package. Some of it is standard and some of it is generated differently for each package. You can view examples of the two files for the file component: CMakeLists.txt and lcfg.cmake.

More Complex Examples

Often a component comes with other scripts and Perl libraries which need installing. Or maybe they have some extra templates and configuration files which need to be put into special locations. At this point you need to venture into the world of CMake. To make it easier a set of CMake macros have been provided to make this as easy as possible. The LCFG release tool is designed to only generate a CMakeLists.txt file if one does not already exist, it will, however, always generate the lcfg.cmake file. Examples below show how to take advantage of this behaviour.

Adding a Perl module (or three)

Taking lcfg-sysinfo as an example of a component which ships a Perl module. We need to create a CMakeLists.txt file which looks like:

cmake_minimum_required(VERSION 2.6)

project (lcfg-sysinfo)

include(lcfg.cmake)

lcfg_add_component(${LCFG_NAME})

lcfg_add_perl_tree(lib)

Everything except the last line is standard and what would be generated in the simple case. Here the lcfg_add_perl_tree macro has been used, this will search for any files matching "*.pm" inside the specified directory and install them into the correct location. It will strip any perl docs (pod), install them into /usr/lib/lcfg/doc/pod/ and also generate manual pages which get put into section 3.

In many cases a component with Perl modules has them stored in the top-level directory rather than in lib (or something similar). There are two ways to work with this situation. The best option is to create a lib directory (or perllibs, or whatever you want it named) and move the Perl module tree into there. The second option is to manually add each Perl module using the lcfg_add_perl_module macro. An example would be to do something like:

lcfg_add_perl_module(LCFG/Foo.pm LCFG::Foo)
lcfg_add_perl_module(LCFG/Foo/Bar.pm LCFG::Foo::Bar)

Note that in this case you need to specify the relative path to the module and the Perl name of the module.

Adding scripts

The other common scenario is that a component needs to ship scripts which are to be installed into /usr/bin or /usr/sbin. Again there are some CMake macros to help. The lcfg-authorize component is a simple example.

cmake_minimum_required(VERSION 2.6)

project (lcfg-authorize)

include(lcfg.cmake)

lcfg_add_component(${LCFG_NAME})

lcfg_add_perl_tree(lib)

lcfg_add_bin(bin/lcfgcap podstrip)

The work is done here with the lcfg_add_bin macro. There is a similar macro named lcfg_add_sbin for installing into /usr/sbin. If you give a second argument of "podstrip" any perl documentation will be extracted from the script and installed into /usr/lib/lcfg/doc/pod/. Manual pages will also be generated and put into section 1 for lcfg_add_bin and section 8 for lcfg_add_sbin.

Checking for Uncommitted Files

Previously there was a checkcommitted target which could be added to the uptodate target in a Makefile to ensure all files are committed into the revision-control system before making a new release. To achieve the same thing you will need to set an extra option in the new LCFG build tools metadata file. In the vcs section you need to add the checkcommitted key and set it to true. It should look something like this:

vcs:
  checkcommitted: 1
  genchangelog: 1
  logname: Changes
  type: CVS

Generating the change log from the VCS log

Previously there was a cvschangelog target which could be added to the changelog target in a Makefile to generate the project change log file from the version-control system log. To achieve the same thing you will need to set an extra option in the new LCFG build tools metadata file. In the vcs section you need to add the genchangelog key and set it to true. It should look something like the example above.