The nTec Build System

    Page Graphic

The build system we used in-house at Nanosoft Technologies.

Home

   

Introduction

I've received permission to distribute the nTec build system here, for free. This is a fairly powerful build-system, allowing you to set up automatic build-trees very quickly. Of course, since this release, nTec has folded, leaving me holding all the code anyway. There are more recent versions of this system available now, which need documentation before release. They are deployed in NBASE, if you feel adventurous.

After some investigation, I found out it relied on an in-house tool called mkhead, which is used to generate header-files. The problem is, this tool needs the NBASE library. While this library is now available, I was originally not in a position to distribute it.

The solution, of course, was to rewrite it so that it no longer did. This tool was later deployed as a replacement for the original mkhead at nTec, and is required to build the headers for NBASE. Python is required:

Getting Software

Download: mkhead.py.gz

If you're using Netscape, like me, you may find you have to hold down [shift] while clicking this link. Worse yet, Netscape seems to want to uncompress this file by itself, so if you get mkhead.py instead of mkhead.py.gz, then skip step 1 below.

Go through the following steps:

  1. Unzip the file (gzip -d mkhead.py.gz)
  2. Rename it to mkhead (mv mkhead.py mkhead)
  3. Make it executable (chmod +x mkhead)
  4. Install it somewhere on your path (mv mkhead /usr/local/bin/)
Download QuickMake

Go through the following steps:

  1. Change to a suitable directory, home is fine.
  2. Extract the file (tar -xvzf quickmake-3.2.0.tar.gz)
  3. The needed files are in the created directory. These files are a terse README and the actual quickmakefile. To learn how to use this, look down.

How to use mkhead

By itself, mkhead may be quite useful. Here is a simple example:

example.h
// Inner example file 1

#ifndef __EX_DEFINED_1
#define __EX_DEFINED_1
//@((sysh)){{
#include <stdio.h>
//@}}
//@((example1)){{
// Some example code goes here
void HelloWorld()
{
	printf("Hello World\n");
}
//@}}
#endif // __EX_DEFINED_1
main.h
// Main header file.
//@READ <example.h>

// Include System Headers
//@BLOCK ((sysh))

// Define Stuff from example.h
//@BLOCK ((example1))

If you can follow this, you notice that there are two exported blocks in example.h, sysh and example1. The main file is what is used to generate a headerfile with. It reads the external headerfile first, and then inserts the two blocks it read into itself. You run mkhead main.h to get:

// Main header file.

// Include System Headers
#include <stdio.h>

// Define Stuff from example.h
// Some example code goes here
void HelloWorld()
{
        printf("Hello World\n");
}

Obviously, you may redirect this anywhere you like. But this is not all that composes the build-system! QuickMake is the other side.

How to use QuickMake

QuickMake is a powerful build system, with a lot of options and flexibility. However, it is designed to be simple to use, and this simplicity leads to some requirements. Since QuickMake is entirely a build-system, a step-by-step guide is given.
Setting up your project tree.
QuickMake expects a certain directory structure. We will start from a project root directory. In this project root, you should create a directory called src.

You should not actually place any source files in this directory, although the system is set up to allow it. You should instead make subdirectories with names descriptive of the module being defined inside them. You should also create a directory under src called include, to place your application-specific header files in.

You also have the option of creating a doc directory under your project root to place any documentation in. We will assume that you have done this.

Adding makefiles to your tree.
This is probably the simplest step. You should copy a makefile (from QuickMake, in the distribution it is called quickmakefile-(version), where version is probably 3.2.0) into the project root directory as makefile.

This file is not a template, in fact, you should never edit it. It is a fully self-contained build-system.

You should now place copies of this file in any directory which requires one (in this example, that is the src directory, the doc directory, the src/include directory, and any directories you have defined under src.

Adding non-root configuration files.
The next step is to set up the build system configuration files.

These files are named qmake.in, and you need one in every directory where you have a QuickMake makefile. The qmake.in in the project root directory is particularly complicated, so we treat that one specially. For now, concentrate on the other ones.

In the src directory, you need to create a qmake.in file like the following:

src/qmake.in
SRCDIR=(all the directories you added)
SUBDIR=include
This tells QuickMake that it is expecting to find source files in all the directories listed in SRCDIR, and that it has to build include as well, but that it expects to find no source files in this directory. This is an important distinction, although in an average project include will probably be the only SUBDIR listed under src.

In each of your source subdirectories (under src), you will need a qmake.in that looks like the following:

src/[dir]/qmake.in
SRC=(all the source files you have in this directory)
This lets QuickMake know that you have source files in this directory to be built. Note that you MUST define at least one source file, otherwise the build will not complete (in such a case, just temporarily remove the source directory from the listing in the qmake.in in src, and add it later when you have sources to compile).

In src/include, you will need a qmake.in that looks like the following:

src/include/qmake.in
HEADERFILE=top.h
FILE=(all the header files in this directory)
The HEADERFILE directive should only be used if you are using QuickMake in the building of a library, as it defines the toplevel header file (typically called top.h) used by mkhead in generating the main header file. You should of course write a top.h file in this directory if you are building a library with a header file.

If you are using QuickMake to build a program, you should omit this line, and thus should not create a top.h file.

The FILE directive is used to specify non-source files used by the project. This is very important when you are using QuickMake to package your project for release, although it makes little difference normally. Thus you should always doublecheck your FILE directives before you package, or your package may not function.

The last place you will need a non-root qmake.in is in doc. This is where you place all your documentation. The file there should look something like this:

doc/qmake.in
DOC=(all the doc files in the directory)
This merely instructs QuickMake that you have documentation files in this directory.
Adding the root configuration file.
The qmake.in in your project root directory must be added now. This file defines many aspects of your project.

Here we will use an example. This is the root qmake.in from a personal project of mine, the ZAZZ Widget Set, which would have eventually found its way onto this site, but I stopped developing it a while ago...

qmake.in
# toplevel makefile input

SUBDIR=doc
CC=gcc
CFLAGS=-pipe -O0 -mpentium -Wall -g
LFLAGS=-pipe -O0 -mpentium -g
INCLUDELOCAL=include
HEADER=zazz.h
MINORVER=0.1
MAJORVER=0
LIB=zazz
INSTALLLIB=/usr/lib
INSTALLH=/usr/include
TARBALL=zazz-0.0.1.tar.gz
FILE=zazz.spec
This definately deserves explanation.

The SUBDIR directive serves the same function it does in src, to identify directories that need to be built, but do not contain source files. Documentation, found in the doc directory, certainly does not contain sources, but it needs to be included in the final packaging.

The CC directive simply sets your C compiler. You actually should be able to omit this if you want, I used to use "color-gcc" as my compiler for a while, since it gave me nice colorful error messages. Be warned that QuickMake expects to be using some form of gcc, and may fail if you use a compiler that does not perfectly conform to gcc's calling conventions.

The CFLAGS and LFLAGS directives specify the C compiler flags and final linker flags, respectively, used when building the project. These are some pretty typical debugging flags (see the gcc docs for details).

The INCLUDELOCAL directive tells QuickMake where your application-specific include files are located, relative to src. This is almost always identical to what is listed here.

The HEADER directive tells QuickMake to build a main headerfile using mkhead. Note that this is really only for building libraries (which ZAZZ certainly is). If you are building an executable, leave this out.

The MINORVER and MAJORVER directives specify the major and minor versions of your project. While currently these are only truly important for library builds, you should include them in any project, since future versions of QuickMake may require them for other things.

The LIB directive tells QuickMake to build a shared library and static library file from the sources. This is very obviously only applicable to projects making library files, and you should omit this if you are making an executable file.
NOTE that the equivalent for executable files is LINKFINAL, which causes an executable file to be built from the sources. The syntax is otherwise identical.

The INSTALLLIB and INSTALLH directives set the directories to install libraries and main headerfiles into. Obviously this is only for libraries, and the equivalent for executable-file builds is INSTALLBIN, which specifies the install directory for an executable file.

The TARBALL directive specifies the name of a file to build when making a final distribution package. This should be specified whenever you want to build tarballs or rpms using QuickMake.

The final FILE directive tells QuickMake about an important non-source file, an RPM .spec file in this case. If you write such a .spec file for your project, you can use QuickMake's automatic RPM generator.

Writing code.
Really, this step is entirely up to you. Populate your project directory with source files, following the tree structure listed above, making sure to update all the qmake.in files that should point to new sources.
Using the new build-system.
The last step of using QuickMake is, of course, using the actual build system. To use the build system, go to the project root directory. From there, you may use the following:
make
Build the entire project, or rebuild any files that have changed. Quickmake maintains dependancy information automatically.
make install
Does all that make does, plus installs any install targets.
make uninstall
Removes any installed targets.
make clean
Cleans up the project directory.
make dist
Generates the tarball file if one is listed.
make rpm
Generates RPM's of the project, assuming you are set up to do so (you must have a spec file in the project root, and you must have RPM set up properly to do builds).






All material on these pages is Copyright (c) Jennifer E. Elaan. Vim