A program maintenance utility



icmake - A program maintenance (make) utility using a C-like grammar


icmake [options] source[.im] [dest[.bim]] [-- [args]]

icmun bimfile


Icmake(1) was designed as a generic tool that can be used as an alternative to make(1), handling program maintenance. It's a generic tool in that icmake-scripts, written in a language closely resembling the C programming language, can perform tasks that are traditionally the domain of scripting languages.

Icmake allows programmers to use a programming language (closely resembling the well-known C-programming language) to define the actions that are required for (complex) program maintenance. For this, icmake offers various special operators as well as a set of support functions that have shown their usefulness in program maintenance.

Although icmake-scripts can be written from scratch, often the required activities are highly comparable. This observation resulted in the construction of two icmake-scripts, which are now part of the standard icmake distribution: icmstart(1), initializing a directory for program development and icmbuild(1), handling the actual program maintenance. Both come predefined as scripts tailored to initializing and maintaining C++ programs (or, after minimal adaptation, C programs), but can easily be adapted to other programming languages. Both icmstart and icmbuild can be run without explicitly calling icmake.

This man-page covers icmake (the program), its support programs and the syntax and facilities offered by icmake's scripting language. Refer to the icmstart(1)) man-page for information about how a directory can be initialized (created) in which (by default) a C++ or C program can be developed and refer to the icmbuild(1) man-page for information about how icmbuild can be used to handle program maintenance.

It should be stressed that icmake and its support programs and scripts do not offer an Integrated Development Environment (IDE). It merely performs tasks for which scripts can be written, and it offers just a minimal set of pre-defined scripts (icmstart and icmbuild) that repeatedly have shown to be extremely useful when developing and maintaining programs.

In its standard operation mode, icmake calls the following programs:

The program icmun(1) can be used to disassemble compiled byte-code (.bim) files. Icmun is mainly used for illustration, education, and debugging. As it is not required for icmake's daily use it is not installed in a standard PATH directory but (since icmake's version 9.02.00) in icmake's lib directory, which commonly is /usr/lib/icmake.

Traditional make-utilities recompile sources once header files are modified. When developing C++ programs this is often a bad idea, as adding a new member to a class does not normally require you to recompile all of the class's source files. To handle class dependencies icmbuld(1) may inspect class dependencies, (re)compiling sources of dependent classes whenever necessary. By default, class-dependencies are not interpreted, but this can easily be changed by activating the PRECOMP and/or USE_ALL defines which are found in the file icmconf. Refer to the icmconf(7) man-page for further details.

Precompiled header files can also easily be used. Precompiled header files dramatically reduce the time that is required for compiling the source files of classes. Refer to the icmconf(7) man-page (in particular the description of the PRECOMP define) for further details.

Icmake's C-like scripting language is described below, in the following sections of this man-page:


Where available, single letter options are listed between parentheses beyond their associated long-option variants.

The -- option is special:

Icmake supports several options, and only one of these can be specified when icmake is invocated.


bimfile: binary icmake script file.

ICM-DEP invocation and options

To start its work, the dependencies-analyzer icm_dep needs one command-line argument: go. Any other argument results in icm_dep performing a `dry run': it then 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.

Options of icm-dep can be specified immediately following icmake's --icm-dep option. The following options are recognized by icm-dep:


The following preprocessor directives are available:


Icmake supports these data types:

Variables can be defined at the global level as well as at any local level inside functions. When defined inside functions, the standard C scoping and visibility rules apply. E.g., local variables can only be used in their own or in more deeply nested blocks, their visibility is masked in more deeply nested blocks by defining an identically named variable inside those more deeply nested blocks. Variables are strongly typed, and cannot have type void.

Variables may be initialized when they are defined. Initializations are expressions, that can use pre- or user-defined functions, constant values, and values of variables that are visible at the point of definition.


The following constants are predefined by icmake. All constants are int values:

symbol value intended for

O_ALL 8 makelist
O_DIR 2 makelist
O_FILE 1 makelist
O_SUBDIR 4 makelist

OFF 0 echo
ON 1 echo

P_CHECK 0 system calls
P_NOCHECK 1 system calls

S_IEXEC 32 stat
S_IFCHR 1 stat
S_IFDIR 2 stat
S_IFREG 4 stat
S_IREAD 8 stat
S_IWRITE 16 stat

The following constants are architecture dependent:

symbol 1 when defined on the platform, otherwise 0

unix Unix, usually with GNU's gcc compiler
UNIX may alternatively be available
linux x86 running Linux (usually with gcc)
LINUX may alternatively be available
M_SYSV, M_UNIX x86 running SCO/Unix
_POSIX _SOURCE Unix with Posix compliant compiler
__hpux HP-UX, with the native HP compiler


int-typed operand(s):

All C operators are available (except for pointer operators, as icmake does not support pointers). They operate like their C-programming language counterparts.

string-typed operand(s):

For string type variables and/or constants the following operators are available (a and b represent string variables or constants):

list-typed operand(s):

For list type variables and/or values the following operators are available:


Type-casts may be performed using the standard C cast-operator to cast:


Icmake offers the following subset of C's statements. They can be used as in the C programming language.


Icmake offers the following predefined functions, which can be used anywhere in icmake scripts. The following overview is ordered alphabetically by function name.


void main

Icmake scripts must be provided with a user-defined function main. The function main has three optional parameters, which may be omitted from the last one (envp) to the first (argc), like in C. Its full prototype is (note: void return type):

    void main(int argc, list argv, list envp)
In main(), Example:

    void main(int argc, list argv)
        list toCompile;
        int idx;

        if (argc == 1)
            usage(element(0, argv));

        if (toCompile = altered("*.cc"))
            for (idx = length(toCompile); idx--; )
                compile(element(idx, toCompile));

            if (getenv("dryrun")[0] == "0")
                linking(element(2, argv));

Having initialized all global variables in order of their definitions main is called by icmake's run-time support system to perform additional tasks.

Additionally defined user functions

Additional functions may be defined. Once defined, these functions can be called. Forward referencing of either variables or functions is not supported, but recursively calling functions is. As function declarations are not supported indirect recursion is not supported either.

User-defined functions must have the following elements:

Function bodies may contain (optionally initialized) variable definitions. Variable definitions start with a type name, followed by one or more comma separated (optionally initialized) variable identifiers. If a variable is not explicitly initialized it is initialized by default. By default an int variable is initialized to 0, a string is initialized to an empty string ("") and a list is initialized to a list of zero elements.

In addition to variable definitions, bodies may contain zero or more statements (cf. section FLOW CONTROL). Note that variables may be defined (and optionally initialized) anywhere inside functions, and also in if, for and while statements.

The behavior of icmake-scripts using non-void functions that do not return values is not defined.


The mentioned paths are sugestive only and may vary over different icmake-installations:


The distribution (usually in /usr/share/doc/icmake) contains a directory examples containing various examples of icmake script. Note in particular the examples/icmbuild subdirectory containing a general script for C++ and C program maintenance.


icmbuild(1), icmconf(7), icmstart(1), icmstart.rc(7), make(1)


Standard comment starting on lines containing preprocessor directives may not extend over multiple lines.

Path names containing blanks are not supported.


This is free software, distributed under the terms of the GNU General Public License (GPL).


Frank B. Brokken (f.b.brokken@rug.nl).