icmbuild - A generic, C++/C program maintenance facility
Icmbuild is a small C program calling
icmake(1) to do program maintenance as defined by the icmbuild
script that’s (commonly) found in /usr/lib/icmake.
Icmbuild’s actions are tailored through a
configuration file (icmconf) which must be present in the directory
where program maintenance is requested. This file is automatically installed
by icmstart(1). Refer to icmconf(7)’s man-page for
details about this file.
Icmbuild assumes that your sources exist in and below the
current working directory. The file icmconf in
icmake(1)’s distribution provides an example of an
icmconf file that can be used by icmbuild. In that example it
is assumed that C++ sources are maintained, but program maintenance
for, e.g., C sources can also easily be configured. If
icmbuild is called, but icmconf is not available it displays a
usage-summary after which icm() ends.
Icmbuild() handles the maintenance for all sources in each
of the subdirectories named in the file CLASSES, and also of all
sources in the current working directory. `Maintenance’ involves
compiling all as yet uncompiled source files, recompilation of modified
source files, optionally library maintenance and optionally the
pre-compilation of header files, which normally results in a marked
reduction of source compilation times.
When source files are compiled object modules are produced which
may be stored in a library, against which the object module of the
program’s main function is linked. It is also possible to
specify additional libraries against which the program must be linked.
If a library is constructed it is kept up to date by
icmbuild. When a source is successfully compiled its new object
module replaces the old one in the library. At that point the separate
object files are no longer required and are removed by icmbuild.
To use icmbuild do as follows:
- o
- Install icmbuild in your path (icmake’s installation
procedure should already have taken care of that);
- o
- Copy icmconf (and probably a file CLASSES) to your
project’s base directory (i.e., the directory where and below which
the project’s sources are found). Usually this has already been
taken care of by the (icmstart) script;
Next:
- o
- Modify the #defines in the file icmconf to taste;
- o
- Enter the names of subdirectories containing sources on separate lines in
the file CLASSES
- Note that the order of the classes mentioned in CLASSES is
relevant in that new class (subdirectory) names can always be added to the
end of the file CLASSES, but reordering the lines in the
CLASSES file should be avoided as that may easily result in
overwriting identically named object files from already existing
directories.
- If reordering is necessary, then first run the command icmbuild
clean to remove all files that were thus far created by
icmbuild. Recompilation is necessary as the names of the object
files contain class order-numbers for identification. These class-order
numbers prevent file-name collisions (e.g., two classes might use a file
data.cc) and because of the number-prefixes replacement of a file
x.o from class A by file x.o from class B is
prevented;
- o
- Start icmbuild.
The next section covers icmbuild’s modes of
operation.
Icmbuild recognizes three options of which only one can be
specified. See the following section for information about which option is
recognized by by which icmbuild command.
- o
- -h: display usage information (which is also automatically shown
when the current directory does not contain a file icmconf) and
terminate icmbuild;
- o
- -c: clear the screen (by calling clear) before starting the
compilation process;
- o
- -s: strip the compiled program or library at its installation
directory (see the various install modes below).
Icmbuild recognizes the following commands (possible
options are shown between square brackets). With the install commands
a path argument must be specified, which must be an existing
user-writable directory:
- o
- clean
clean up remnants of previous actions (the directory specified by the
TMP_DIR define in icmconf is removed). If precompiled
headers were created (i.e., PRECOMP in icmconf was
specified) then all files having extension .gch in the main
directory and in the directories listed in the CLASSES file are
also removed. If USE_ALL was specified then those files are also
removed;
- o
- cleangch
all .gch files that were precompiled are removed (whether existing in
the gch subdirectory of the TMP_DIR directory (specified in
icmconf), or in directories specified in the CLASSES file,
or in the project’s main directory). If icmconf does not
specify PRECOMP then nothing happens;
- o
- cleantmp
same as icmbuild clean, but the .gch files and files specified
by the USE_ALL define in icmconf are not removed;
- o
- [-s] install program path
install the constructed program in the specified path (to be used
after issuing icmbuild program, see below). Path can be
absolute or relative and may optionally specify the name of the installed
program. Example:
icmbuild install program ~/bin/prog
This installs the constructed binary program in the user’s bin
directory with the name prog;
- o
- [-s] install static path
install the constructed static library in the specified path (to be used
after issuing icmbuild library, see below). Path can be
absolute or relative and may optionally specify the name of the installed
library. Example:
icmbuild install static /usr/lib/
This installs the constructed static library (assume its name is
libspecial.a) in /usr/lib as /usr/lib/libspecial.a.
- o
- [-s] install shared path when using this installation command,
icmconf must contain #define SHARED (cf. icmconf(7)).
It installs the constructed shared library in the specified path (to be
used after issuing icmbuild library). Path can be absolute
or relative, and must specify an existing directory. Example:
icmbuild install shared /usr/lib/
This installs the constructed binary shared library (e.g.
libspecial.so) in /usr/lib as /usr/lib/libspecial.so.
In addition, the soft-links
libspecial.so -> libspecial.so.X
libspecial.so.X -> libspecial.so.X.Y.Y.Z
are defined in /usr/lib, where X.Y.Z are the major, minor and
subminor versions defined in the file VERSION.
- o
- [-c] library
do library maintenance (builds a static and optionally (if icmconf
defines SHARED) a shared (dynamic) library);
- o
- [-c] program
do program maintenance (builds a program from the sources in the current
working directory and from the sources in the directories specified in the
file CLASSES);
- o
- If no commands are specified (but optionally only -c) then the
DEFCOM specification in the icmconf is inspected. Recognized
specifications are:
#define DEFCOM "program"
which is quivalent to the command icmbuild [-c] program;
if DEFCOM is specified as
#define DEFCOM "library"
then this is quivalent to the command icmbuild [-c] library.
- If an explicit command is passed to icmbuild then DEFCOM
specifications are ignored.
Class dependencies are handled by icmake’s support
program icm-dep. It can be called from icmake by passing it
the option -d. All options and arguments following -d are
forwared to icm-dep.
The program icm-dep is automatically called by
icmbuild to handle class dependencies. Consider two classes
Options and Process. If Process uses Options and
if precompiled header files are used, then in addition to
Option’s header file, Process’s header must also
be precompiled if Option’s header file changes. Likewise, if
Option’s data organization is altered and Option
defines inline members used by Process or Process defines an
Option data member then, in addition to Option’s
sources sources Process’s sources must also be compiled. For
the latter case icmconf provides the USE_ALL specification: if
a `USE_ALL’ file exists in a directory, then all sources of
that directory are recompiled.
The program icm_dep determines the program’s class
dependencies, and recompiles class header files of all classes depending on
classes whose header files must be recompiled. Furthermore, if a
`USE_ALL’ file exists in a directory then all sources of
classes depending on that directory’s class are also recompiled.
Icm-dep’s options are described in
icmake(1)’s man-page.
To start its work, icm_dep needs one command-line argument:
go. Any other argument results in icm_dep performing a `dry
run’: it performs all its duties (and verbose messages are displayed
as if go had been specified), but no files (precompiled headers or
USE_ALL files) are touched or removed. If neither options nor
arguments are specified icm_dep writes its usage summary to the
standard output.
By default icmbuild calls icmake -d -V go:
icm_dep is called to perform its duties and to show its actions on
the standard output stream. By specifying a #define ICM_DEP parameter
in the icmconf file this default can be overruled (cf.
icmconf(7)).
The mentioned paths are sugestive only and may be installation
dependent:
- o
- /usr/share/icmake/icmconf Unabbreviated example of an
icmbuild configuration file;
- o
- /usr/share/icmake/CLASSES Example of an icmbuild
CLASSES file.
Here is an example of the configuration file icmconf for a
concrete program, using facilities of the bobcat library:
#define CLS
#define LIBRARY "modules"
#define MAIN "main.cc"
#define SOURCES "*.cc"
#define OBJ_EXT ".o"
#define SHAREDREQ ""
#define TMP_DIR "tmp"
#define USE_ALL "a"
#define USE_ECHO ON
#define CXX "g++"
#define CXXFLAGS " --std=c++2a -Wall -O2 -pthread" " -fdiagnostics-color=never "
#define IH ".ih"
#define PRECOMP "-x c++-header"
#define REFRESH
#define LDFLAGS ""
#define ADD_LIBRARIES "bobcat"
#define ADD_LIBRARY_PATHS ""
#define DEFCOM "program"
icmake(1), icmconf(7), icmstart(1),
icmstart.rc(7)
This is free software, distributed under the terms of the GNU
General Public License (GPL).
Frank B. Brokken (f.b.brokken@rug.nl).