Eagle Mode -
Make System

Copyright © 2010-2011 Oliver Hamann. Homepage: http://eaglemode.sourceforge.net/

# Contents

1 Introduction
2 Maker scripts
2.1 General requirements for a maker script
2.2 Example
2.3 GetDependencies function
2.4 IsEssential function
2.5 GetFileHandlingRules function
2.6 GetExtraBuildOptions function
2.7 Build function
3 unicc
3.1 Examples
3.2 Calling Conventions
3.3 Compilers

# 1 Introduction

Eagle Mode is compiled, linked and installed with an own make system written in Perl. It is a replacement for classic makefiles, and it features auto-dependencies, multiple (sub-)projects, easy extension, optional continuation on non-fatal errors, easy portability, and special file handling rules. The latter allows to define patterns for marking project files for installation, clean-up, execution-attribute-setting, backup, and private use. The make system is well-tested and has also been used for some other projects than Eagle Mode.

The make system consists of three layers:

- The upper-most layer is the make.pl program in the top-directory of the project. It it called by the user and has options for doing all the necessary things. Type "perl make.pl --help" to read the help text. Unfortunately, make.pl still lacks a certain configuration interface. This means that you would have to edit it directly if you want to use the make system for another project than Eagle Mode.

- The middle layer consists of so-called "maker scripts" in the subdirectory `makers`. There is one maker script for each "project" (i.e. sub-project of Eagle Mode). They can be seen as the makefiles.

- The bottom layer is made of unicc, which is a unified high-level interface to C/C++ compilers. It has a command line similar to compilers, but it features auto-dependencies and compilation to object files and linkage with one call. This means, unicc can do what simple classic makefiles often do.

The following chapters are describing the maker scripts and unicc in detail.

# 2 Maker scripts

## 2.1 General requirements for a maker script

As already said, the maker scripts can be seen as makefiles for the (sub-)projects. Each maker script must follow these rules:

- The script file must lie in the directory `$EM_DIR/makers` (replace $EM_DIR by the source directory of Eagle Mode).

- The script file name must end with ".maker.pm", otherwise it will not be found by make.pl.

- The script must be written in the Perl programming language.

- The script must define a package with the same name as the file name without ending. We call it the (sub-)project name.

- Within that package, the script must define a set of functions as described blow.

- At execution, the current directory is always set to the top-level directory, there where make.pl is. All paths are relative to that point.

PITFALL WARNING: If you copy and edit a maker script, please do not forget to set the package name to the same name as the file name (without .maker.pm), otherwise you will get very strange error messages.

## 2.2 Example

Here comes a simple sample maker script for a dynamic library project named "example" which depends on emCore. It uses unicc for compilation and linkage. Its path would have to be `$EM_DIR/makers/examples.maker.pm`.

>     package example;

>     use strict;
>     use warnings;

>     sub GetDependencies
>     {
>             return ('emCore');
>     }

>     sub IsEssential
>     {
>             return 0;
>     }

>     sub GetFileHandlingRules
>     {
>             return ();
>     }

>     sub GetExtraBuildOptions
>     {
>             return ();
>     }

>     sub Build
>     {
>             shift;
>             my %options=@_;

>             system(
>                     @{$options{'unicc_call'}},
>                     "--math",
>                     "--rtti",
>                     "--exceptions",
>                     "--bin-dir"       , "bin",
>                     "--lib-dir"       , "lib",
>                     "--obj-dir"       , "obj",
>                     "--inc-search-dir", "include",
>                     "--link"          , "emCore",
>                     "--type"          , "dynlib",
>                     "--name"          , "example",
>                     "src/example/example.cpp"
>             )==0 or return 0;

>             return 1;
>     }

## 2.3 GetDependencies function

This function returns an array of project names. Those projects are always built before.

In addition to the dependencies defined by this function, every project implicitly depends on a special project which is named "defaults".

## 2.4 IsEssential function

Returns 0 or 1:

0 means that the project is not so essential and that the user may want to ignore a failure with building the project.

1 means that the project is so essential, that the overall building shall always be stopped on a failure with building the project.

## 2.5 GetFileHandlingRules function

Returns an array of file handling rules. These rules are used to decide whether a file should be deleted by the clean command, whether it should be copied by the install command, and whether it should have execution permission then.

For most files, the rules from the defaults project are already correct. But other projects can give some additional rules for their individual files.

Each rule is a string of the form:

> <op><flag>[<op><flag>[<op><flag>...]]:<pattern>

With:

> <op> is either a + for setting the flag, or a - for removing the flag.

> <flag> is the name of the flag. Possible names are:

> `clean` | - | The file has to be deleted by the clean command.
> `install` | - | The file has to be installed by the install command.
> `exec` | - | The file is an executable.
> `private` | - | The file must not be released in addition to files which have the clean flag set (developer's private stuff).
> `nobackup` | - | The file must not be backed up in addition to files which have the clean flag set (developer's private stuff).

> <pattern> is a pattern for matching the file path. It's a Perl regular expression.

The flag operations of a rule are applied to all files whose file paths match the pattern. Hereby the path is relative to the current directory (the top-level directory), and the path elements are separated by slashes, even on Windows.

If there are contrary rules, the later one counts. The project dependencies are respected.

Be careful when writing the regular expressions. One error could mean that the clean command deletes some or all of the source files. Please study all existing rules before making new ones. Make backups before testing.

## 2.6 GetExtraBuildOptions function

The make.pl program defines some user options for the build command. Each project may define additional options though this function. It returns an array of references where each reference refers an array of three strings: The name of the option, the default value, and a description.

## 2.7 Build function

This function performs compilation, linkage and maybe other things for building the project. Output files which are up to date should not be re-generated (this is usually solved by using unicc). The beginning of the function body should look like:

> `shift;`
> `my %options=@_;`

Thereby the hashes variable %options contains all the options. Hash index is the option name, hash value is the option value. Following options are defined by default:

> `compiler`
>   Name of compiler and linker to be used.

> `cpus`
>   Number of CPUs to be used.

> `debug`
>   Whether to produce debug information. Must be "yes" or "no".

> `unicc`
>   Relative path to the unicc directory.

> `unicc_call`
>   Reference to an array which contains the first arguments for calling unicc.pl. It's like:

>       [ 'perl', catfile($options{'unicc'},'unicc.pl'),
>         '--compiler', $options{'compiler'},
>         '--cpus', $options{'cpus'},
>         $options{'debug'} eq 'yes' ? ('--debug') : () ]

> `utils`
>   Relative path to the utils directory.

> `projects`
>   This should not be used by the maker scripts.

> `continue`
>   This should not be used by the maker scripts.

In addition, there are all the extra options defined through GetExtraBuildOptions from all the projects.

The Build function has to return 1 on success. On failure, it may either return 0 or call the die function.

# 3 unicc

unicc is a unified high-level interface to C/C++ compilers. It takes a couple of source files, compiles them to object files, and links these in order to create an executable, a static library or a dynamic library. Each operation is performed only if the output file is not existing, or if it is not newer than the input files. Therefore, include file dependencies are checked recursively, but only if found via an explicit given include path (option --inc-search-dir). This normally means that standard include files are not checked.

unicc is written in Perl, and it can be found in: `$EM_DIR/makers/unicc`

## 3.1 Examples

Here is a simple example for building a program using the GNU compiler:

> `$EM_DIR/makers/unicc/unicc.pl --compiler gnu hello.c --name hello`

And here comes a more complex example:

> `$EM_DIR/makers/unicc/unicc.pl --compiler wat src/hello.c src/world.c \
> --obj-dir obj --lib-search-dir lib --inc-search-dir include \
> --bin-dir bin --debug --type wexe --name helloworld`

## 3.2 Calling Conventions

This chapter describes the arguments and options for calling unicc.pl. They can be given in any order.

> src-file
>   Path name of a source file including the file name ending which must be ".c", ".cpp", ".cc" or ".cxx". On Windows, ".rc" files are also supported. This argument can be given multiple times.

> `--compiler` name
>   Name of the compiler. See the Compilers chapter more below for all possible names. The default is `gnu`.

> `--cpus` count
>   Number of CPUs to be used. More precisely, it is the maximum number of source files to be compiled in parallel. The default is 1.

> `--type` type
>   Set the type of the output file. Possible types are:

>   `cexe` | - | console executable (this is the default)
>   `wexe` | - | windowed executable (different against cexe on Windows only)
>   `lib` | - | static library
>   `dynlib` | - | dynamic library

> `--name` name
>   Set the name of the output file without ending, and, if it's a library, without the UNIX "lib" in front (Default: "unnamed").

> `--obj-dir` dir
>   Target directory for object files and other temporary files (default: ".").

> `--bin-dir` dir
>   Target directory for the executable (default: "."). Ignored if type is not cexe or wexe.

> `--lib-dir` dir
>   Target directory for the library, if type is lib or dynlib (default: "."). In addition, this option acts like --lib-search-dir.

> `--lib-search-dir` dir
>   A directory where to search for libraries to be linked. This option can be given multiple times.

> `--inc-search-dir` dir
>   A directory where to search for include files. This option can be given multiple times.

> `--link` name
>   Name of a library to be linked. The name must be without file name ending and without the UNIX "lib" in front (e.g. say "X11" instead of "libX11.a"). This argument can be given multiple times. The order may be important (high-level first).

> `--math`
>   Link with the standard math library.

> `--rtti`
>   Enable Run Time Type Information.

> `--exceptions`
>   Enable C++ exceptions.

> `--debug`
>   Create debug information in the output.

> `--def` name[`=`value]
>   Define a preprocessor variable. This option can be given multiple times.

## 3.3 Compilers

Here is a list of all possible values for the compiler option:

> `bor`
>   Use the Borland C/C++ compiler on Windows. Please do not use this for compiling Eagle Mode! It has been tested with Borland C++ 5.6.4 (C++BuilderX) and CodeGear C++ 5.9 (C++Builder 2007), but Eagle Mode always crashes right away or it even fails to compile (seems difficult to solve).

> `gnu`
>   Use the GNU C/C++ compiler (gcc). This has been successfully tested with many gcc versions. Minimum should be something like version 3.3. Cygwin and MinGW are also supported.

> `int`
>   Use the Intel C/C++ compiler (icc) on Linux.
>   Successfully tested with:
>   * icc 9.1 on Linux, 64-bit

> `mic`
>   Use the Microsoft C/C++ compiler on Windows.
>   Successfully tested with:
>   * cl 13.10 (Visual Studio .NET 2003)
>   * cl 14.00 AMD64 (Platform SDK for Server 2003 R2)

> `sun`
>   Use the Sun C/C++ compiler on Linux.
>   Successfully tested with:
>   * Sun Studio 12 RC 1 on Linux, 64-bit

> `wat`
>   Use the Watcom or Open Watcom C/C++ compiler on Windows.
>   Successfully tested with:
>   * Watcom 11.0b
>   * Open Watcom 1.7a