|
|
Eagle Mode -
Make System
Copyright © 2010-2011,2018,2020-2021 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, or "auto".
- 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 "auto", which means to detect
the number of available cpus cores.
- --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.
- --runtime-lib-search-dir dir
- A directory where to search for shared libraries at runtime ("rpath"). 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.
This is quite outdated and it never worked.
- clang
- Use the Clang C/C++ compiler.
This should work.
- gnu
- Use the GNU C/C++ compiler (gcc). This is the default and it has been
successfully tested with many gcc versions. Minimum should be something like
version 4.9. Cygwin and MinGW are also supported.
- int
- Use the Intel C/C++ compiler (icc) on Linux.
This is quite outdated and certainly not working anymore.
- mic
- Use the Microsoft C/C++ compiler on Windows.
Tested with Visual Studio 2019 - not all plugins working.
- sun
- Use the Sun C/C++ compiler on Linux.
This is quite outdated and certainly not working anymore.
- wat
- Use the Watcom or Open Watcom C/C++ compiler on Windows.
This is quite outdated and certainly not working anymore.
|