NAME¶
icmake - A program maintenance (
make) utility using a
C-like
grammar
SYNOPSIS¶
icmake [options]
source[.im] [dest[.bim]] [-- [args]]
icmun bimfile
DESCRIPTION¶
Icmake(1) can be used as an alternative to
make(1). In its
standard operation more, it calls the following programs:
- o
- icm-pp to preprocess the icmake file
- o
- icm-comp to byte-code compile the icmake s
- o
- icm-exec to interpret the byte-code file
Icmake allows the programmer to use a program language (closely
resembling the well-known
C-programming language) to define the actions
involved in (complex) program maintenance. For this,
icmake offers
various special operators as well as a set of support functions that have
proven to be useful in program maintenance.
The program
icmun(1) may be used to disassemble the compiled byte-code
file.
Traditional make-utilities recompile sources once header files are modified. In
the context of
C++ program development this is often a bad idea, as
adding a new member to a class does not normally require you to recompile the
class’s sources. To handle class dependencies in a more sensible way,
icmake(1)’s
CLASSES file may define dependencies among
classes. By default, class-dependencies are not interpreted. See the
icmconf(7) man-page for details.
ADDITONS SINCE VERSION 7.00¶
- o
- Integral constants may be specified using hexadecimal notation (e.g.,
0x12ab);
- o
- The IM environment variable may contain multiple directories,
separated from each other by colons ( :).
- o
- #define-directives may refer to other macro definitions using the
${identifier} format.
- o
- #ifdef, #ifndef, #else and #endif directives
can be nested.
- o
- The `backtick’ operator is defined, executing a program in a shell
and collecting its standard output in a list (see below).
- o
- The index operator ([]) is defined as an alternative to the
pre-defined function element(), and can be used on lists and
strings.
- o
- The function string getenv(string envvar) is predefined. If
existing scripts already define a getenv() function of their own,
it it suggested to remove this function and use the new getenv()
function instead. Alternatively, rename the script-defined function
getenv() and calls of this function to, e.g.
my_getenv().
- o
- The function int strstr(string haystack, string needle) is renamed
to int strfind(string haystack, string needle).
- NOTE: this modification in version 7.00 could very well affect
your earlier (6.xx) icmake scripts. Changing `strstr’ into
`strfind’ should bring your older scripts up-to-date again.
OPTIONS¶
Icmake:
source:
icmake script source file (default extension:
.im).
dest: binary
icmake script file (default:
`source’.bim).
--:
icmake/
icmake-script arguments separator
args: arguments following
-- are entered into the
icmake
scipt
main() function’s
argv-list (see below at section
USER DEFINED FUNCTIONS).
- o
- -a
information about icmake
- o
- -b
blunt execution of the destinationfile
- o
- -c
the destination file is only compiled
- o
- -i file
file: name of source. Icmake argument processing stops.
- o
- -o file
all icmake output is written to file (Not implemented on unix
platforms)
- o
- -p
only the preprocessor is activated
- o
- -q
quiet mode: copyright banner not displayed
- o
- -t file
file is used as a temporary bim-file, to be removed on exit.
Icmake argument processing stops.
Icmun:
bimfile: binary
icmake script file.
PREPROCESSOR DIRECTIVES¶
The following preprocessor directives are available:
- o
- comment:
standard C comment (all between /* and */) as well as
comment-to-end-of-line (all line contents following //) are
ignored.
- o
- Shell startup: The first line of the icmake-script may start with
#!path, where path defines the absolute location of the
icmake program. By making the script executable, it can be called
without explicitly calling icmake.
- E.g., if the first line of an (executable) icmakefile ’icm’
(without extension) contains
#!/usr/bin/icmake -qi
then icm may be given as a command, thus executing
/usr/bin/icmake -qi icm ...
Alternatively,
#! /usr/bin/icmake -qt /tmp/icm
may be used, resulting in the execution of
#! /usr/bin/icmake -qt /tmp/icm icm ...
In this case the binary makefile is not kept, but a temporary file
/tmp/icm.PID is used and removed on exit. The PID extension being
the process-id of the icmake program executing icm.
- o
- #include "filename"
The file filename is included at the location of the directive
- o
- #include <filename>
The file filename is included at the location of the #include
directive; filename is searched in the directories pointed to by
the IM environment variable.
- o
- #define identifier definition
The text identifier will be replaced by definition. The
definition may contain references to already defined identifiers, using
the ${identifier} format. If the ${identifier} hasn’t
been defined (yet), the text ${identifier} is literally kept. At
each #define at most 100 text-replacements are performed,
preventing infinite recursion.
- o
- #ifdef identifier
If the identifier macro was defined the next block of code (until a
matching #else or #endif directive was detected) is
byte-compiled. Otherwise, the block of code is ignored.
- o
- #ifndef identifier
If the identifier macro was not defined the next block of code
(until a matching #else or #endif directive was detected) is
byte-compiled. Otherwise, the block of code is ignored.
- o
- #else
Terminates a #ifdef and #ifndef directive, reversing the
acceptance decision about the following code.
- o
- #endif
Terminates the preprocessor block starting at the matching #ifdef,
#ifndef or #else directive.
- o
- #undef identifier
Remove identifier from the set of defined symbols. This will not
affect the specification of any previously defined symbols in which
identifier was used.
DATA TYPES¶
The following data types are available:
- o
- int
Integral values, ranging from -0x8000 until 0x7fff. int
constants may be specified as decimal numbers, hexadecimal numbers or as
ASCII character constants (e.g., ’x’).
- o
- string
Text variables. Text constants are delimited by double quotes. Multiple text
constants may be concatenated, but a text constant may not extend over
multiple lines. To indicate an end-of-line in a text constant use the
\n escape sequence. The escape sequences \a \b \f \n \r and
\t are available. Otherwise, \x is interpreted as a literal
x. So, use \\ to indicate \ within a text
constant.
- o
- list
A data structure containing a series of individually accessible
string values. When a list contains elements, its first element is
indicated by index 0.
- o
- void
Used with function definitions to indicate that the function does not return
a value.
Variables may be defined both at the global level as well as locally to
functions. Variables are strongly typed. A variable cannot have the type
void.
Variables may be initialized when they are defined. The initialization can use
return values of functions, but cannot use variables. Consider initializations
as being constructed from constant values.
PREDEFINED SYMBOLS¶
The following symbols are predefined by
icmake. All are constant
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 symbols are available depending on the architecture:
|
|
symbol |
1 when defined on the platform, otherwise 0 |
|
|
MSDOS |
MS-DOS platform (with MSC 7.00 compiler) |
unix |
Unix, usually with GNU’s gcc compiler |
linux |
x86 running Linux (usually with gcc) |
M_SYSV, M_UNIX |
x86 running SCO/Unix (usually with) Microsoft C |
_POSIX |
_SOURCE Unix with Posix complient compiler |
__hpux |
HP-UX, with the native HP compiler |
|
|
|
|
OPERATORS¶
All
C operators, except for the ternary operator, are supported,
operating like their
C counterparts on
int variables and/or
values.
Additionally, for
string type variables and/or values the following
operators are available:
- o
- a + b: returns a new string value containing the
concatenation of string values a and b. Note that
string constants may be concatetated without using the +
operator, e.g.,
"hello " "world"
"hello " + "world"
- o
- a += b: a must be a string variable, to which the
string variable or value b is appended.
- o
- string comparisons: operators == != <= >= < > != and
== may be applied to string values or variables, returning 1
if the comparison succeeds, otherwise 0. Comparison is case sensitively,
and follows the ASCII character set.
- o
- !a: the boolean ! operator returns 1 if the string a
is empty, otherwise 0 is returned.
- o
- a younger b, a newer b: returns 1 if file a is more recent
than file b. E.g., "source.cc" newer
"source.o". If b doesn’t exist, 1 is returned;
if a doesn’t exist 0 is returned; if neither a nor
b exists, 0 is returned; if they are of the same age, 0 is
returned. Explicit tests for the existence of a file can be performed
using the exists() predefined function (see below, section
PREDEFINED FUNCTIONS).
- o
- a older b: turns 1 if file a is older than file b.
E.g., "libprog.a" older "source.o". If a
doesn’t exist, 1 is returned; if b doesn’t exist 0 is
returned; if neither a nor b exists, 0 is returned; if they
are of the same age, 0 is returned.
- o
- []: the index operator is defined as an alternative to the built-in
function element. It can only be applied (as holds true for
element() as well) as so-called rvalue. Therefore,
constructions like:
// assume str1 and str2 are strings
str1 = str2[3]
will be accepted, but the following construction will not be accepted:
str2[3] = str; // won’t compile
For
list type variables and/or values the following operators are
available:
- o
- a + b: returns a new list value containing the concatenation
of list values a and b. This is not a set
operation: if an element appears both in a and in b, they
will appear twice in the resulting list.
- o
- a - b: returns a new list value containing the elements in
a that are not present in b. This is a set
operation.
- o
- a += b: elements in b are added to the elements in a,
which must be a list variable. This is not a set
operation.
- o
- a -= b: elements in b are removed from the elements in
a, which must be a list variable. This is a set
operation.
- o
- list equality comparisons: operators != and == may be
applied to list values or variables. Operator == returns 1
if both lists have element-by-element identical elements, 0 otherwise.
Operator != reverses the result of ==.
- o
- !a: the boolean ! operator returns 1 if the list a is
empty, otherwise 0 is returned.
- o
- []: the index operator is defined as an alternative to the built-in
function element. It can only be applied (as holds true for
element() as well) as so-called rvalue. Therefore,
constructions like:
// assume lst is a list, str is a string
str = lst[3]
will be accepted, but the following construction will not be accepted:
lst[3] = str; // won’t compile
Typecasts may be performed using the standard
C cast-operator to cast:
- o
- Strings to ints and vice versa ((int)"123",
(string)55)
- o
- Strings may be cast to lists (list lst = (list)"hello")
FLOW CONTROL¶
Icmake offers the following subset of
C’s statement types.
They can be used as in the
C programming language.
- o
- expression ;
The plain expression statement;
- o
- The compound statement
Different from C icmake does not support variable definitions
inside a compound statement. All variables used locally by a function must
be defined as either function parameters or as variables that are defined
immediately at the beginning of a function’s body.
- o
- if (condition) statement
- o
- if (condition) statement else statement
- o
- for (init; condition; increment) statement
The variable(s) used in the initialization section must already have been
defined. The init, condition and increment sections
may be left empty. The empty condition section is interpreted as `always
true’.
- o
- while (condition) statement
The do ... while() statement is not implemented for
icmake.
- o
- return (for void functions) and return expression for
other functions.
- o
- break
To leave for and while statements, overruling the
statement’s condition. C’s continue is not
available.
- o
- exit(expression)
To terminate the icmake-script. The expression must evaluate
to an int value, which becomes the script’s exit value.
PREDEFINED FUNCTIONS¶
Icmake offers the following predefined functions, which can be used
immediately by
icmake scripts. The function overview is ordered
alphabetically by function name, but where appropriate short summary labels
are provided:
Helper functions of
exec() (see also below at
exec()):
- o
- void arghead(string h)
Defines the `argument head’, to be used with exec(). By
default, the `argument head’ is an empty string.
- o
- void argtail (string t)
Defines the `argument tail’, to be used with exec(). By
default, the `argument tail’ is an empty string.
String-to-ascii converters:
- o
- int ascii(string s)
Returns the first character of s as an int; e.g.,
ascii("A") returns 65;
- o
- string ascii(int i)
Returns i as a string, e.g., ascii(65) returns the string
"A";
System calls:
- o
- The `backtick` operator (`)
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 automatically
collected. Standard shell redirection could be used to collect the
standard error stream’s output as well. Example:
string s = "ls";
printf(`s`); // prints the elements in the current
// directory
Filename modifiers:
- o
- string change_base(string file, string newbase)
Changes the basename of file, returns the changed name. E.g,
change_base("/path/demo.im", "out") returns
"/path/out.im";
- o
- string change_ext(string file, string newext)
Changes the extension of file, returns the changed name. E.g,
change_ext("source.cc", "o") returns
"source.o";
- o
- string change_path(string file, string newpath)
Changes the path specification of file, returns the changed name.
E.g, change_path("tmp/binary", "/usr/bin")
returns "/usr/bin/binary". Note that the
/-separator is inserted if required.
System calls:
- o
- string chdir(string newdir)
Changes the script’s working directory, returns the previous dir as
an absolute path.
Use chdir(".") to get current working directory,
chdir("") may be used to obtain the startup working
directory (this functionality was broken in releases before than 7.00, but
is now operational). The function terminates the icmake-script if
the specified newdir does not exist.
- o
- string chdir(int checking, string newdir)
Same functionality as the previous function, but by specifying
checking as P_NOCHECK the function won’t terminate
the script. Rather, it will return the script’s current working
directory.
Helper functions of
exec() (see also below at
exec()):
- o
- cmdhead(string h)
Defines a `command head’, to be used with exec(). By default,
the `command head’ is an empty string.
- o
- cmdtail(string t)
Defines a `command tail’, to be used with exec(). By default,
the `command tail’ is an empty string.
Icmake execution modifier:
- o
- echo(int opt)
Controls echoing of called programs (and their arguments), specify
OFF if echoing is not requested. By default ON is active.
Functions returning elements of aggregates:
- o
- string element(int index, list lst)
Returns string index (0-based) from lst. An empty string is
returned if an unavailable index value is provided. See also the []
operator in the section OPERATORS.
- o
- string element(int index, string str)
Returns character index (0-based) from str. An empty string is
returned if an unavailable index value is provided. See also the []
operator in the section OPERATORS.
System calls:
- o
- exec(string cmd, ...)
Executes command with arguments. Each argument will be prefixed by
arghead()’s argument and postfixed by
argtail()’s argument. Note that no blanks are inserted
between arghead()’s contents, the argument proper, and
argtail()’s argument. All thus modified arguments are
concatenated, this time separated by single blanks, and then
cmdhead()’s contents are inserted between the command and
the first argument (on either side delimited by single blanks) and
cmdtail()’s contents are appended to the arguments (again,
separated by a single blank). PATH is searched to locate
cmd. 0 is returned.
- o
- exec(int checkcmd, string cmd, ...)
Same functionality as the previous function, but by specifying
checking as P_NOCHECK the function won’t terminate
the script. Rather, it will return the called command’s exit
status, or 0x7f00 if the command wasn’t found.
- o
- execute(string cmd, string cmdhd, string arghd, ..., string
argtl, string cmdtl)
Same as exec(), but command head/tail and argument head/tail must be
specified. The actually executed command starts with cmd, followed
by cmdhd. Next is a series of arguments follows, each enclosed by
arghd and argtl. The command terminates with cmdtl. 0
is returned
- o
- execute(int checking, string cmd, string cmdhd, string arghd,
..., string argtl, string cmdtl)
Same functionality as the previous function, but by specifying
checking as P_NOCHECK the function won’t terminate
the script. Rather, it will return the called command’s exit
status, or 0x7f00 if the command wasn’t found. )
System interface:
- o
- int exists(string file)
Returns a non-zero value if file exists, otherwise 0 is returned.
Input interface:
- o
- list fgets(string file, int offset)
The next line found at offet offset is read from file. It
returns a list retlist containing two elements:
element(0, retlist) is the string that was read (including the
\n, if found)
element(1, retlist) is the next offset to read.
- An empty return list signifies EOF. Since an empty list’s
`first’ eement is an empty string, which is converted to the value
0, a file may be read and processed as follows:
list line;
while (1)
{
line = fgets("filename", (int)line[1]);
if (!line)
break;
process(line[0]);
}
Output interface:
- o
- int fprintf(string filename, ...)
Appends all (comma separated) arguments to the file filename. Returns
the number of printed arguments.
Filename modifier:
- o
- string get_base(string file)
Returns the base name of file. The base name is the file without its
path prefix and without its extension. The extension is all information
starting at the final dot in the filename. If no final dot is found, the
file name is the base name. Eg., the base name of a.b equals
a, the base name of a.b.c equals a.b, the base name
of a/b/c equals c.
System interface:
- o
- list getenv(string envvar)
Returns the value of environment variable envvar in a list containing
two elements:
the first element indicates whether the environment variable was defined
(value "1") or not (value "0");
the second element indicates the value of the environment variable.
- Enivironment variables are of the form variable=value, and if
defined the list’s second element contains value. If the
value is empty, the variable is defined, but has no text associated with
it.
Filename modifier:
- o
- string get_ext(string file)
Returns the extension of file, except for the separating dot. The
extension is all information starting at the final dot in the filename. If
no final dot is found, the extension is an empty string.
Input interface:
- o
- string getch()
Returns the next pressed key as a string (no `Enter’ required for
ms-dos and unix (incl. linux) systems).
Filename modifier:
- o
- string get_path(string file)
Returns the path-prefix of file. The path prefix is all information
up to (and including) the final directory separator (which is, depending
on the operating system, a forward- or backslash).
- If no path is found, an empty strring is returned.
System interface:
- o
- int getpid()
Returns the process-id (UNIX) or PSP-paragraph (DOS) of the icmake byte code
interpreter icm-exec.
Input interface:
- o
- string gets()
Returns the next line read from the keyboard as a string. The line
entered on the keyboard must be terminated by an `Enter’ key, which
is not stored in the returned string.
Functions creating lists of files:
- o
- list makelist(string mask)
Returns a list of all files matching mask. E.g.,
makelist("*.c") returns a list containing all files
ending in .c.
- o
- list makelist(type, string mask)
Same as the previous function, but the type of the directory elements may be
specified as its first argument:
symbol |
meaning |
O_ALL |
obtain all directory entries |
O_DIR |
obtain all directories, including . and .. |
O_FILE |
obtain a list of files |
O_SUBDIR |
obtain all subdirectories |
|
|
Note that the pattern * will not match hidden entries under Unix-type
operating systems. Use .* for that.
- o
- list makelist(string mask, newer, string comparefile)
Returns list of all files matching mask which are newer than a provided
comparefile. Operator younger may be used instead of newer.
Note that newer and younger are operators, not strings.
- o
- list makelist([int = O_FILE,] string mask, newer, string
comparefile)
Same as the previous function, but type may be specified as in
list makelist(type, string mask).
- o
- makelist(string mask, older, string comparefile)
See above; returns a list of files that are older than the comparefile.
- o
- makelist(type, string mask, older, string comparefile)
Same as the previous function, but type may be specified as in
list makelist(type, string mask).
Output interface:
- o
- int printf(...)
Shows all (comma separated) arguments to screen (i.e., the standard output
stream). Returns the number of printed arguments.
System interface:
- o
- int putenv(string envvar)
Adds envvar to the current (icmake) environment Use the
format: "VAR=value". Returns 0.
List information:
- o
- int sizeof(list l)
Returns the number of elements in list
System information:
- o
- list stat(string entry)
Returns stat(2) information of directory entry entry as a
list. The returned list has two elements: element 0 is the attribute
value, element 1 contains the size of the file.
- Attributes are returned as bit-flags, composed from the following
predefined constants:
S_IFCHR S_IFDIR S_IFREG
S_IREAD S_IWRITE S_IEXEC
See the stat(2) manual page for the meanings of these constants.
- o
- list stat(checking, string entry)
Same as the previous function, but by specifying checking as
P_NOCHECK the function won’t terminate the script. Rather,
it will rturn stat(2)’s return value.
String support:
- o
- int strlen(string s)
Returns the number of characters in s (not counting the final
0).
- o
- int strfind(string haystack, string needle)
returns index in haystack where needle is found, or -1 if
needle is not contained in haystack.
This function was called strstr() in versions before 7.00.
- o
- string strlwr(string s)
Returns a lower-case duplicate of s.
- o
- list strtok(string str, string separators)
Returns a list containing all substrings of str separated by one or
more (consecutive) characters in separators. E.g.,
strtok("hello icmake’s+world", " +")
returns the list containing the three strings "hello",
"icmake’s", and "world".
- o
- string strupr(string s)
Returns an upper-case duplicate of s.
- o
- string substr(string text, int offset, int count)
Returns a substring of text, starting at offset, consisting of
count characters. If offset exceeds (or equals) the
string’s size or if count <= 0, then an empty string is
returned. If offset is less than 0 then 0 is used.
System calls:
- o
- int system(string command)
Executes command. The return value indicates the executed
command’s exit value. The string command may contain
redirection and/or piping characters.
- o
- int system(int checking, string command)
Same functionality as the previous function, but by specifying
checking as P_NOCHECK the function won’t terminate
the script. Rather, it will return the called command’s exit
status, or 0x7f00 if the command wasn’t found. )
USER DEFINED FUNCTIONS¶
Icmake scripts may define functions, and a function
main()
must be defined. Functions must have the following elements:
- o
- The function’s return type. One of the available types must be used
explicitly, e.g., void. There is no default type.
- o
- The function’s name, e.g., compile.
- o
- A parameter list, defining zero or more comma-separated parameters. The
parameters themselves consist of a type name followed by the
parameter’s identifier. E.g., (string outfile, string
source).
- o
- A body surrounded by a pair of curly braces ({ and
}).
- 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. An int
variable is initialized to 0, a string is initialized to empty text
( "") and a list is initialized to a list of zero
elements.
- Following variable definitions, bodies may contain zero or more statements
(see below at section FLOW CONTROL for the various flow-control
statements). Note that all local variables must be defined at the very
beginning of function bodies.
User defined functions must be defined before they can be used, although they
may be called recursively. Therefore, indirect recursion is not supported by
icmake.
The user-defined function
main() has three optional arguments, which may
be omitted from the last one (
envp) to the first (
argc), as in
C. Its full prototype is (note:
void return type):
void main(int argc, list argv, list envp)
In
main(),
- o
- argc represents the number of elements in argv;
- o
- argv contains the arguments, with element 0 the compiled
icmake script (the ` .bim’ file);
- o
- envp containts the `environment’ variables. The function
sizeof() (see below) may be used to determine its elements.
Elements in envp have the form variable=value.
Alternatively, the function getenv() (see below) can be used to
retrieve a specific environment variable immediately. Example:
void main(int argc, list argv)
{
list toCompile;
int idx;
if (argc == 1)
usage(element(0, argv));
if (toCompile = altered("*.cc"))
{
for (idx = sizeof(toCompile); idx--; )
compile(element(idx, toCompile));
if (getenv("dryrun")[0] == "0")
linking(element(2, argv));
}
exit (0);
}
FILES¶
The mentioned paths are sugestive only and may be installation dependent:
- o
- /usr/bin/icmake: the main icmake program;
- o
- /usr/bin/icmun: the icmake unassembler;
- o
- /usr/lib/icm-pp: the preprocessor called by icmake;
- o
- /usr/lib/icm-comp: the compiler called by icmake;
- o
- /usr/lib/icm-exec: the byte-code interpreter called by
icmake;
EXAMPLES¶
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.
SEE ALSO¶
icmbuild(1),
icmconf(7),
icmstart(1),
icmstart.rc(7),
make(1)
BUGS¶
None reported
COPYRIGHT¶
This is free software, distributed under the terms of the GNU General Public
License (GPL).
AUTHOR¶
Frank B. Brokken (
f.b.brokken@rug.nl).