icmake - A program maintenance (make) utility using a
C-like grammar
icmake option(s) [source [dest]] [args]
Icmake(1) is a generic tool for program maintenance which
can be used as an alternative for, e.g., 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.
This man-page consists of the following sections:
- o
- ICMAKE V. 13.00.00 covers the changes since icmake version
12.03.00;
- o
- OPTIONS covers icmake’s options;
- o
- EXECUTING ICMAKE SCRIPTS covers how to call icmake
scripts;
- o
- ICM-DEP describes the icm-dep support program;
- o
- ICM-MULTICOMP describes the icm-multicomp support
program;
- o
- ICM-SPCH describes the icm-spch support program;
- o
- ICM-UN describes the icm-un support program;
- o
- FILES provides an overvieuw of the locations of icmake and
its support programs (as used by the Debian Linux distribution);
- o
- EXAMPLES contains references to locations containing some
examples;
- o
- SEE ALSO contains references to man-pages of icmake support
programs and man-pages of programs related to icmake. In
particular
- o
- icmstart(1), describes how to initialize a directory for
(C++ or C) program development;
- o
- icmbuild(1), covers how to use icmake for the maintenance of
such programs.
- o
- icmscript(7) covers the syntax and facilities of
icmake’s scripting language, allowing you to write your own
icmake scripts.
Icmake allows programmers to use a scripting 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.
Icmake should not be confused with an Integrated
Development Environment (IDE). Icmake merely performs tasks for which
scripts can be written, and a minimal set of pre-defined scripts
(icmstart and icmbuild) that have proven their usefulness when
developing and maintaining programs are included in icmake’s
distribution.
When using icmbuild(1) for program maintenance the
following icmake support programs are used:
- o
- icm-comp byte-code compiling an icmake script;
- o
- icm-dep handling class-dependencies;
- o
- icm-exec executing a byte-code compiled icmake script;
- o
- icm-multicomp (optionally) using multi-threaded source file
compilation;
- o
- icm-pp pre-processing an icmake script;
- o
- icm-spch (optionally) constructing a project-wide Single
Pre-Compiled Hbeader file (SPCH).
In addition to the above programs the icmake project
provides
- o
- the icmodmap program can be used when developing C++
programs using modules (cf. the icmodmap(1) man-page);
- o
- icm-un disassembling compiled icmake byte-code files
(`bim-files’). icm-un is primarily used for
illustration, education, and debugging and is called by icmake when
specifying its option --unassemble or -u (see also section
ICMUN).
Some make-utilities by default recompile sources once header files
are modified. When developing C++ programs this is often not
required, as adding new member functions to classes does not require the
recompilatopm of all source files of those classes. Class dependencies are
optionally inspected by icmbuld(1) (they are inspected when the
USE_ALL, SPCH, and/or (now deprecated) PRECOMP #define
directives in the icmconf file are activated (cf. the
icmconf(7) man-page for details).
In icmake version 13.00.00 the following modifications were
implemented w.r.t. its version 12.03.00:
- o
- option --all (-a) was added to the icm-spch program
performing in sequence the actions of its --list, --precompile, and
--soft-link options. Several existing options were altered. See the
ICM-SPH section for details.
- o
- the (internal) headers inspected by icmake --spch (or -S)
are not modified anymore.
- o
- to remove the (now obsoleted) #ifndef SPCH_ specifications from
files listed in existing spch files written by previous versions of
icm-spch the program noifndef.cc, available in the
icmake source distribution in its support/ sub-directory can
be used to remove existing #ifnef SPCH_ sections from a
project’s .ih files;
- o
- icmake --source compiles the icmake script to a
temporary .bim file;
- o
- the support program icmun was renamed to icm-un (called by
icmake when specifying the --unassemble (-u) option,
so in practice the name change is automatically handled).
- o
- The icmconf(7) script can use -o in its #define SPCH
specification. All (space character delimited) words following -o
are passed to icm-spch as separate `-o word’
options;
- o
- When developing C++ programs the environment variable
ICMAKE_CXXFLAGS is no longer used. Instead the environment variable
ICMAKE_CPPSTD is used. Use this latter environment variable to
define one point of maintenance specifying the version of the C++
standard used when compiling sources;
- o
- When using Debian (or a comparable distributions) the script
’rebuild’ can be used to rebuild icmake’s binaries
after installing ’libbobcat-dev’, resulting in a reduction
of their sizes of about 40%.
- o
- The icmake program itself was redesigned.
Where available, single letter options are listed between
parentheses beyond their associated long-option variants. Icmake
defines action options and non-action options. The first
action option that is encountered is used.
When using icmbuild(1) for program maintenance
icmake is called automatically, and the user doesn’t have to
specify any icmake options.
- o
- --about (-a)
Ends icmake after showing some information about icmake;
- o
- --compile (-c) [options] source [bim-file]
The icmake script is first pre-processed (see option
--preprocess below) whereafter the pre-processed file is compiled
by icm-comp producing a bim-file. If the bim-file
name is not specified then source’s base-name, receiving
extension .bim, is used.
If source is a previously pre-processed file then option -P
can be specified to suppress its pre-processing. E.g.,
icmake -c -P source dest.bim
If the bim-file exists and is younger than source then source
is not compiled;
- o
- --dependencies (-d) [options] action
The icm-dep program is called determining the dependencies among
classes. All options and arguments following this option are forwarded to
icm-dep. Refer to the ICM-DEP section of this man-page for
information about icm-dep;
- o
- --execute (-e) [option] bim-file [arguments]
Executes the bim-file, Before specifying bim-file option
--no-version-check (see below, or the equivalent short option
-n) can be specified to allow mismatches between
icmake’s main version and the icmake version that was
used to compile the bim-file.
Command-line arguments specified beyond bim-file are forwarded as
arguments to the bim-file’s main function (cf. the
icmscript(7) man-page for details about writing
icmake-scripts);
- o
- --force (-f) [options] source [bim-file]
Acts like option --compile, but compilation is always performed, even
if the bim-file is up-to-date;
- o
- --help (-h)
Ends icmake after providing usage info. Usage info is also provided
when icmake is started without arguments;
- o
- --multicomp (-m) [options] jobs
’compiler-spec’
The optional options are the options passed to the
icm-multicomp program (cf. section ICM-MULTICOMP below).
See also the icomonf(7) man-page’s #define MULTICOMP
directive: when specified threaded compilation is automatically used;
- o
- --no-process (-N)
Implies option --verbose (see below). This option is recognized by
options --dependencies, --execute, --source and -t (either
as two separate options or by `gluing’ both options together, like
-Ne). When specified, the support program is not run, but the
command(s) that would have been used are shown to the standard
output;
- o
- --no-version-check (-n)
This option is available with the action options --execute,
--source, --unassemble, and -t. When specified the main
versions stored in the specified icm-bim file and icmake itself may
differ. This option should normally not be required, but was primarily
added for development purposes;
- o
- --preprocess (-p) [options] source [pim-file]
The file specified as first argument is pre-processed, producing a
`.pim’ file. If a second filename argument is provided then
that file becomes the .pim file. If not specified, then the first
filename, using the extension .pim, is used.
With this option pre-processor symbol-defining options can be used: symbols
whose values can be used in source. E.g., when issuing the command
icmake -p -d one --define two source dest.pim
icmake pre-processes source, defines the pre-processor symbols
one and two (each having value 1), and produces the pim-file
dest.pim. Note that instead of using long options --define
short options -d can also be used;
- o
- --spch (-S) ...
A SPCH is built. All options and arguments following --spch are
forwarded to the icm-spch support program. (cf. section
ICM-SPCH below).
See also the icomonf(7) man-page’s #define SPCH
directive: when specified a SPCH is automatically constructed;
- o
- --source (-s) [options] source [arguments]
Icmake uses --compile to compile the icmake source file
specified as first argument (constructing a temporary bim-file) and then
uses --execute to execute the bim-file, forwarding any subsequent
arguments as arguments to the bim-file’s main
function.
Following the --source option options available for
icmake’s --compile command can be specified.
Following those options options of icmake’s --execute
options can be specified. Those latter options must be preceded by
--execute or -e. E.g., when issuing the command
icmake -s -d one -en source
then icmake first compiles source after defining the
pre-processor symbol one, and then executes the bim-file, passing
--no-version-check to icm-exec;
- o
- -t tmpspec [options] source [arguments]
This option is intended for icmake-scripts although it can also be
used in a command-line icmake call. The -t option can be
used in quite a few different ways which is covered in the next section
(EXECUTING ICMAKE SCRIPTS).
- o
- --tmpdir=directory (-T)
By default temporary files are created in the /tmp sub-directory, or
in the user’s home (${HOME}) directory if /tmp/
cannot be used. To specify another directory to write temporary files in
icmake’s option --tmpdir (or -T) can be
specified, followed by the name of an (existing) directory to use for
temporary files.
E.g., when compiling an icmake file main.im, the output of
icmake’s pre-processor is written to a temporary file which
is removed after compilation. To write the temporary file to
~/.icmake icmake can be called as
icmake -T ~/.icmake -c main.im
- o
- --unassemble (-u)
The file specified as first argument is an icmake bim-file, which is
unassembled (cf. section ICM-UN below for more information about
unassembling icmake bim-files);
- o
- --verbose (-V)
Icmake child processes and their arguments are written to the
standard output stream before they are called. This option may precede
`action’ options (-c, -d, -e, -s and -u), either as
two separate options or by `gluing’ both options together, like
-Ve.
- o
- --version (-v)
Ends icmake after displaying its version.
The -t option is available primarily for being used in
executable icmake scripts. The first line of executable icmake
scripts consists of the following components:
- o
- a shebang (#!) specification followed by
icmake’s location;
- o
- the -t option followed by its argument (see below);
and optionally:
- o
- compilation and execution options (specified as described at the
--source option);
- o
- a non-option component (e.g., :) which will be replaced by the
location of the executable icmake script;
- o
- remaining components on the first line are forwarded as-is to the
icmake script’s main function;
E.g., the following simple icm executable script
`args’ could be defined in ~/bin:
#!/usr/bin/icmake -t. -d one : two --dir three
void main(int argc, list argv)
{
#ifdef one
printf << "one is defined\n";
#endif
printf << argc << " arguments: " << argv << ’\n’;
}
When it’s called as ~/bin/args four five then the arguments
four and five are added to the two --dir three arguments
already specified by the script itself. Called this way the script outputs.
Its 1st argument is the name of a temporary .bim file which is
different at each new call:
one is defined
/tmp/F04dgh two --dir three four five
The argument of the -t option is used to specify the
location of the files used by icmake’s -t option
(/dir can also be specified as multiple directories, like
/dir/sub1/sub2):
- o
- if it’s a single dot (-t.) the compiled (temporary) bim-file
is written in icmake’s directory used for temporary files
(e.g., /tmp or $HOME);
- o
- if it’s ~/dir or /dir then icmake writes
temporary files in the specified directory, replacing ~ by the
user’s $HOME directory;
- o
- if it’s ~/dir/name or /dir/name then
[~]/dir/name specifies the path of the compiled .bim file,
writing all other temporary files in the same directory as the .bim
file. The .bim file is kept after execution (allowing it to be
executed repeatedly using ’icmake -e’). The
icmake-script is not compiled if the .bim file is younger
than the script.
Icm-dep is a support program called by icmake
--dependencies (or its short alternative -d) to determine
source- and precompiled-header file dependencies.
When using icmbuild(1) and an icmconf file contains
the #define SPCH directive icmake -d is not
used; instead, directories inspected when using a SPCH are automatically
inspected (and updated when necessary) by icmake -S.
Icmake -d’s synopsis is
icmake -d [options] argument
Specifications following -d are forwared to icm-dep. The following
options can be specified after -d:
- o
- --classes=filename (-c)
By default, icm-dep inspects dependencies of the directories
mentioned in the file CLASSES. If the icmconf(7) file
specifies PARSER_DIR and/or SCANNER_DIR then those
directories are also considered. Use this option to specify the file
containing the names of directories to be inspected by
icm-dep.
- o
- --gch
If an icmconf file specifies the (deprecated) #define PRECOMP
directive then icmake -d checks whether precompiled headers
must be refreshed. If an icmconf file does not contain a
#define PRECOMP diretive, but precompiled headers should
nonetheless be inspected, then option --gch can be specified;
- o
- --help (-h)
A summary of icm-dep’s usage is written to the standard output
and icmake terminates, returning 0 to the operating system;
- o
- --icmconf=filename (-i)
By default icmake -d inspects the content of icmconf
files, This option is used if instead of icmconf another file
should be inspected;
- o
- --mainih=mainheader (-m)
In the icmconf file the #define IH directive is used to
specify the suffix of class header files that should be precompiled,
assuming that their filenames are equal to the names of the directories
which are listed in the CLASSES file. But CLASSES does not
specify the name of the program’s top-level directory. This option
is used to specify the name of the top-level header file to precompile. By
default main.ih is used;
- o
- --no-gch
If an icmconf file contains a (deprecated) #define PRECOMP
directive but icmake -d should not check whether precompiled
headers must be refreshed then specify option --no-gch;
- o
- --no-use-all
If this option is specified then the #define USE_ALL
"filename" directive in the icmconf file (cf.
icmconf(7)) is ignored;
- o
- --use-all=filename
If this option is specified then all files in directories containing the
file filename and source files in directories (recursively)
depending on the files in those directories are recompiled;
- o
- --verbose (-V)
This option can be specified multiple times. The number of times it is
specified determines the verbosity of icmake -d’s
output. If not specified then icmake -d silently performs
its duties. If specified once (which is the default specification), then
icmake -d writes to the standard output the actions it
performs; if specified twice it also reports non-default options and
automatically included directories; if specified three times it also
reports class dependencies; if specified more often it reports what files
it encountered and what decision it would make when go would be
specified;
- o
- --version (-v)
Icmake -d writes icm-dep’s version number to the
standard output and terminates, returning 0 to the operating system.
Following the non-terminating options argument go must be
specified to allow icmake -d to perform its actions.
Specifying another argument results in a `dry run’: it analyzes
dependencies, but won’t remove or touch files.
Icmake -d can be used for software projects which
are developed as described in the C++ Annotations, section Header file
organization in chapter Classes. For those projects classes are
developed in their own directories, which are direct sub-directories of the
project’s main program directory. Their class interfaces are provided
in class-header files bearing the names of the class-directories, and all
headers that are required by the class’s sources are declared in a
separate internal header files, commonly having extensions
.ih.
Icmake supports multi-threaded source-file compilation,
often significantly reducing the compilation time of the source files of
projects. When using icmbuild(1) multi-threaded compilation is
automatically used when icmconf files contain the #define
MULTICOMP directive (cf. icmconf(7)). It can also be called
independently from icmconf using icmake’s
--multicomp (or -m) option.
Icmake -m’s synopsis is
icmake -m [options] arguments
Icmake -m accepts the following options:
- o
- --help (-h)
Icmake -m writes a summary of its usage to the standard output
and terminates, returning 0 to the operating system;
- o
- --nr (-n)
When compiling source files and option --nr is specified then the
thread number compiling a source file is written to the standard output
stream.
- o
- --quiet (-q)
When this options is not specified then the path names of the compiled
object and source files are written to the standard output stream. When it
is specified once only the source files’ directories and filenames
are written to the standard output stream, and when it is specified more
than once no information about the compiled files is written to the
standard output stream.
- o
- --threads=nThreads (-t)
By default the computer’s number of cores determines the number of
threads being used when compiling the source files. A different number of
threads can be requested using this option, e.g., --threads 5.
- o
- --version (-v)
Icmake -m reports its version number to the standard output
and terminates, returning 0 to the operating system.
Icmake -m needs one command-line argument and an
optional second argument:
- o
- the first argument is the name of the file specifying which files must be
compiled. Use icmbuild(1) to write this file. It can also be
constructed otherwise:
The specified file must contain groups of file specifications where each
group starts with a line like : support tmp/o 5 where the 2nd
element (here: support) specifies the (sub-)directory of the source
files (use . to refer to the project’s top-level directory);
the 3rd element (here: tmp/o) specifies the destination directory
of the compiled files (which is created if not existing); and the 4th
element (here: t) specifies the prefix to add in front of the
compiled object files.
Following this line the remaining lines of a group specify the names of the
source files (located in specified (sub-)directory) to compile.
Once the compilation ends (either because all files were successfully
ccompiled, or because a compilation failed) the specification file is
removed;
- o
- the second argument is optional. By default the following specification is
used (all on one line)
g++ -c -o $2 ${ICMAKE_CPPSTD} --Wall -Werror $1
Here $1 is replaced by the location of the source file to compile and
$2 is replaced by the location of the compiled object file. If the
environment variable ICMAKE_CPPSTD is defined (specifying the
C++ standard to use, e.g., ICMAKE_CPPSTD=--std=c++26) then
its value replaces ${ICMAKE_CPPSTD} in the specification.
If the default compiler specification cannot be used the command to compile
source files can be provided as icmake -m’s second
command-line argument, which should be quoted, like
’g++ -c -o $2 ’${ICMAKE_CPPSTD}’ --Wall -Werror $1’
or the second command-line argument can be f:file, where file
is the name of a file whose first line contains the specification of the
command compiling source files (which must specify $1 and $2
and optionally $ICMAKE_CPPSTD).
The PATH environment variable is used to locate the compiler; the
compiler’s absolute path can also be specified.
Single Pre-Compiled Headers (SPCH) are available using
icmake --spch (or -S).
Icmake -S’s synopsis is
icmake -S [options] arguments
Icmake -S accepts the following options:
- o
- --all=file (-a)
Call in sequence icm -S’s options --list,
--precompile, and --soft-links (see below), where file
is written by option --list and used as option argument for
--precompile and --soft-links;
- o
- --classes=filename (-c)
The file filename is the name of a file containing a list of
directories inspected by the --list option (by default CLASSES).
The project’s top directory is automatically inspected unless the
option --no-topdir is specified;
- o
- --help (-h)
Icmake -S writes a summary of its usage to the standard output
and terminates, returning 0 to the operating system;
- o
- --internal=.ext (-i)
.ext is the extension used for the internal headers (including the
dot). By default .ih is used;
- o
- --list (-l)
Ignored when option --all is specified.
Write the names of the files to process when constructing an SPCH to the
file specified as icmake -S’s first command line
argument. The specified filename may not have an extension or directory
specifications (e.g., spch);
- o
- --no-topdir (-n)
Ignore the internal header found in the project’s top directory. This
option is used when, e.g., merely constructing a library instead of a
program;
- o
- --precompile=file (-p)
Precompile file (the name of the file specified at the option
--list) to the SPCH file specified as icmake
-S’s first command-line argument. If that argument ends in
/ then the SPCH ’argument’file.gch is written.
By default the SPCH is constructed by the following command (all on one
line):
g++ -c -o $2 ${ICMAKE_CPPSTD} -Wall -Werror -O2 -x c++-header $1
Here, $1 is replaced by ’file’, and $2 is replaced by the name
of the SPCH, while $ICMAKE_CPPSTD refers to the value of the
ICMAKE_CPPSTD environment variable (specifying the C++
standard to use, e.g., ICMAKE_CPPSTD=--std=c++26).
Alternatively, the command constructing the SPCH can be provided as second
command-line argument, which should be quoted like
’g++ -c -o $2 ’${ICMAKE_CPPSTD}’ -Wall -Werror -O2 -x c++-header $1’
or the second command-line argument can be f:file, where file
is the name of a file whose first line specifies the command constructing
the SPCH (which must specify $1 and $2 and optionally
$ICMAKE_CPPSTD).
The PATH environment variable is used to locate the compiler; the
compiler’s absolute path can also be used.
- o
- --soft-links=file (-s)
Ignored when option --all is specified.
This option uses the same arguments as used with the --precompile
option. This option creates .gch soft-links from the header files
listed in file to the generated SPCH-file;
- o
- --unused=regex (-u)
In practice this option is probably not required, but files matching (POSIX
extended) regex are not inspected by icmake -S. When
used specifications like (...)|(...) can be used to specify
multiple regexes. Alternatively f:file can be used as option
argument to specify a file whose non-empty lines contain regexes;
- o
- --version (-v)
Icmake -S writes its version number to the standard output and
terminates, returning 0 to the operating system;
- o
- --warn (-w)
interactively warn when existing header files are about to be modified,
accepting or refusing the modifications. Once refused icm-spch
ends.
Icmake -S needs one, and optionally two arguments,
which were described at the --list, --precompile, and
soft-links option descriptions.
Pre-compiled headers have been available for quite some time, and
usually result in a significant reduction of the compilation time. Using
single precompiled headers results in a large reduction of required
disk-space compared to using precompiled headers for separate
directories.
When using SPCHs almost identical precompiled headers for separate
directories are avoided: only one precompiled header is constructed which is
then used by all components of a project. As identical sections are avoided
the sizes (and construction times) of SPCHs are much smaller, usually
requiring only 5 to 10 % of the space (and construction time) ccompared to
using separately constructed pre-compiled headers.
SPCHs can easily be used in combination with icmbuild(1).
Often a specification in a project’s icmconf file like
#define SPCH "" is all it takes (cf.
icmconf(7)).
The support program icm-un is called by icmake
-u, expecting one argument, a bim-file. It disassembles the binary
file an shows the assembler instructions and the structure of the
bim-file.
As an illustration, assume the following script is compiled by
icmake -c demo.im):
void main()
{
printf << "hello world\n";
}
the resulting demo.bim file is disasembled by icmake -u
demo.bim writing the following to the standard output fle:
icm-un by Frank B. Brokken (f.b.brokken@rug.nl)
icm-un V12.04.00
Copyright (c) GPL 1992-2024. NO WARRANTY.
Binary file statistics:
strings at offset 0x0025
variables at offset 0x0033
filename at offset 0x0033
code at offset 0x0014
first opcode at offset 0x0021
String constants dump:
[0025 (0000)] ""
[0026 (0001)] "hello world."
Disassembled code:
[0014] 06 01 00 push string "hello world."
[0017] 05 01 00 push int 0001
[001a] 1b 1d callrss 1d (printf)
[001c] 1c 02 add sp, 02
[001e] 04 push int 0
[001f] 24 pop reg
[0020] 23 ret
[0021] 21 14 00 call [0014]
[0024] 1d exit
Offsets are shown using the hexadecimal number system and are
absolute byte offsets in the bim-file. The string constants dump also shows,
between parentheses, the offsets of the individual strings relative to the
beginning of the strings section. The output also shows the opcodes of the
instructions of the compiled .im source files. If opcodes use
arguments then these argument values are shown following their opcodes. Each
opcode line ends by showing the opcode’s mnemonic plus (if
applicable) the nature of its argument.
The mentioned paths are the ones that are used in the source
distribution and are used by the Debian Linux distribution. However, they
are sugestive only and may have been configured differently:
Binary programs:
- o
- /usr/bin/icmake: the main icmake program;
- o
- /usr/bin/icmbuild: the wrapper program around the icmbuild
script handling standard program maintenance;
- o
- /usr/bin/icmodmap: the module mapper which initialized the
maintenance of C++ programs using modules;
- o
- /usr/bin/icmstart: an icmake-script that is can be used to
create the startup-files of new projects;
Support programs:
- o
- /usr/libexec/icmake/icm-comp: the compiler called by
icmake;
- o
- /usr/libexec/icmake/icm-dep: the support program handling
class-dependencies;
- o
- /usr/libexec/icmake/icm-exec: the byte-code interpreter;
- o
- /usr/libexec/icmake/icm-multicomp: the multi-thread source file
compiler;
- o
- /usr/libexec/icmake/icm-pp: the preprocessor called by
icmake;
- o
- /usr/libexec/icmake/icm-spch: the program preparing SPCHs;
- o
- /usr/libexec/icmake/icm-un: the icmake unassembler.
The distribution (usually in /usr/share/doc/icmake)
contains a directory examples containing additional examples of
icmake script. The icmstart script is an icmake script
as is /usr/libexec/icmake/icmbuild, which is called by the
/usr/bin/icmbuild program. See also the EXAMPLE section in the
icmscript(7) man-page.
chmod(1), icmbuild(1), icmconf(7),
icmodmap(1), icmscript(7), icmstart(1),
icmstart.rc(7), make(1)
This is free software, distributed under the terms of the GNU
General Public License (GPL).
Frank B. Brokken (f.b.brokken@rug.nl).