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) is a generic tool handling program maintenance that can be used as an alternative for make(1). 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.

Icmake, its support programs, and scripts do not offer an Integrated Development Environment (IDE). Icmake merely performs tasks for which scripts can be written, and only a minimal set of pre-defined scripts (icmstart and icmbuild) that repeatedly have shown to be extremely useful when developing and maintaining programs are included in the icmake distribution.

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

The program icmun(1) disassembles 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 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.

This manpage describes icmake's options in the next section. Following that section icmake's C-like scripting language and support programs are described in the following separate sections:


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


The following preprocessor directives are recognized:


Icmake supports the following five data and value types:

Variables can be defined at the global level as well as inside functions (not only at the top of compound statements but also between statements and in the initialization section of for-statements). When defined inside functions, the standard C scoping and visibility rules apply. Variables are strongly typed, and cannot have type void.

Variables may be initialized when they are defined. Initializations are expressions which may use predefined or user-defined functions, constant values, and values of variables. Functions or variables that are used for initialization must be visible at the initialization point.


The following predefined int constants are available:

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



All C operators (including the ternary operator) are available (except for pointer operators, as icmake does not support pointers). They operate like their C-programming language's counterparts. Comparison operators return 1 if the comparison is true, otherwise 0 is returned.


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


  • a older b: returns 1 if file a is older than file b. E.g., "libprog.a" older "source.o". The files a and b do not have to exist:
    if both don't exist 0 is returned;
    if a doesn't exist, 1 is returned;
    if b doesn't exist 0 is returned;
    if they are equally old 0 is returned.

  • []: the index operator retrieves a character from a string variable or constant: it returns a string as an rvalue. Thus, the following statement compiles OK:
         // assume str1 and str2 are strings
        str1 = str2[3];
    but the following statement won't compile:
        str2[3] = "a"; 
    If an invalid (out of bounds) index value is specified an empty string is returned.

  • The `backtick` operator (`string cmd`)
    A string placed between two backticks is executed by the popen(3) function. The standard output gererated by the command that is stored in the string argument is returned as a list. An empty list indicates that the command could not be executed.
    A command that could be executed but did not produce any output returns a list containing one empty element. The command's standard error stream output is not collected by the backtick operator. However, standard shell redirection may be used to collect the standard error stream's output. Example:
        printf(`"ls"`);     // prints the elements in 
                            // the current directory
    The predefined function eval(string cmd) behaves exactly like the backtick operator: they are synonyms. )


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


    Type-casts using the standard C cast-operator can be used to cast


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


    Icmake provides the following predefined functions, which can be used anywhere in icmake scripts. The functions are ordered by categories, and within categories they are ordered alphabetically by function name. Five categories are distinguished:

    Functions operating on ints:

    Functions operating on lists:

    Functions operating on strings:

    Functions manipulating filenames:

    System-related functions:


    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 the parameter Example (the implementations of the user-defined functions usage, modified, and compile are left as an exercise for the reader):
        void main(int argc, list argv)
            if (argc == 1)
                usage(element(0, argv));
            if (list toCompile = modified("*.cc"))
                for (int idx = listlen(toCompile); idx--; )
    After initializing all global variables in order of their definitions main is called by icmake's run-time support system. Icmake scripts end once main returns (or exit is called by the script).

    Additionally defined user functions

    Additional functions may be defined. Once defined, they 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.

    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 an empty list.

    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 the conditions of if and while statements and in the initialization section of for statements.

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


    The icm-dep program is a support program for icmake to determine source-file dependencies. It is called automatically when USE_ALL or PRECOMP is specified in the icmconf file that is processed by icmake.

    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 may immediately after icmake's --icm-dep option be specified. The following options are recognized:


    The icmun program expects one argument, the binary (bimfile) file produced by `icmake -c'. It disassembles the binary file an shows the assembler instructions and structure of the binary file. Note that in standard installations icmun is not located in one of the directories of the PATH environment variable, but is located in the /usr/lib/icmake directory.

    As an illustration, assume the following script is compiled by icmake (e.g., by calling icmake -c demo.im):

        void main()
            printf("hello world");
    the resulting demo.bim file can be processed by icmun (e.g., calling /usr/lib/icmake/icmun demo.bim. Icmun then writes the following to the standard output fle:

        icmun by Frank B. Brokken (f.b.brokken@rug.nl)
        icmun V9.03.00, copyright (c) GPL 1992-2020.
        Binary file statistics:
            strings           at offset 0x0025
            variables         at offset 0x0031
            filenames         at offset 0x0031
            first instruction at offset 0x001f
        String constants dump:
            "hello world"
        Disassembled code:
            [0014] 06 00 00   push string "hello world"
            [0017] 05 01 00   push int 0001
            [001a] 1b 1d      callrss 29 (printf)
            [001c] 1c 02      add sp, 2
            [001e] 23         ret
            [001f] 21 14 00   call [0014]
            [0022] 04         push int 0
            [0023] 24         pop reg
            [0024] 1d         exit


    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 additional examples of icmake script.


    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.

    The functions sizeof(list lst) and sizeoflist(list lst) are deprecated and should no longer be used. They are removed in a future version of icmake. Use listlen(list lst) instead.


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


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