NAME

aconfig - syntax


DESCRIPTION

Aconfig reads directives from a system file (supplied as a command line argument). It then creates:

init
The directory init contains header files defining ATMOS messages and ATMOS configuration variables (messages.h, config.h and config.s) and a C source file defining the processes to be created by the kernel at startup (init.c).

makefiles
Aconfig creates one makefile for each module, containing the rules needed to build the object code for that module. A top-level makefile is also generated which runs 'make' on all of the per-module makefiles, and then links together the individual object files into the final image (using syslink).

syslink.input
Aconfig creates a file syslink.input which is used as input to syslink.

For details of command line usage, see the aconfig manpage.

Note that the case of directives is ignored (i.e. ``Module'' is the same as ``module'').


BASIC DIRECTIVES

Path

Adds a path to the list of directories to be searched for module directories:

        Path /path/to/modules

Note that the current directory is always searched first, and the ATMOSROOT directory last.

Hardware

The Hardware directive causes the contents of a specified file to be read and interpreted as configuration commands:

        Hardware piglet

This causes the file source/hardware/piglet.hw to be located and obeyed. This file contains board-specific hardware information, including the target architecture. The corresponding aconfig symbol is also set.

Package

The Package directive causes the contents of a specified file to be read and interpreted as configuration commands:

        Package core

This causes the file source/software/core.pkg to be located and obeyed. The Package directive can be used to group any number of modules and processes into a single unit, which may be included in the image using a single directive.

Config

The Config directives may be used to give values to defined symbols (for example hardware addresses) or to control compilation options:

        Config.h  IOBASE (0x03800000)
        Config.s  YESV2 1
        Config.hs UART (0x03100000)

The Config.h directive writes a line to the config.h file. The rest of the line is written to the config.h file preceded by #define. Config.s is identical, except that the output is written to the config.s file.

The Config.hs directive writes the line to both files.

Set and Unset

The Set directive controls internal operation of the aconfig program through the If directive.

Used with one argument, set creates an internal variable and initialises it to the boolean value TRUE.

        Set IPAMode
        Set Switchmode

Note that these values do not appear in the config.h/s output files.

If the variable name is followed by an equals sign, the variable is initialised with the string value of the rest of the line. This value can then be substituted into subsequent directives using the notation ${variable}. For example the sequence:

        Set objs = a.o b.o
        Set objs = ${objs} c.o
        Make.cat abc.o ${objs} ../llibc/llibc.o

has the same final effect as

        Make.cat abc.o a.o b.o c.o ../../llibc.o

The Unset directive parallels the Set directive above. It either creates a new variable, or modifies the value of a current variable. In either case the value is initialised to the boolean value FALSE.

        Unset Debug
        Unset IPAMode

Note that the case of aconfig variables is ignored. Thus the following are equivalent:

        Set debug
        set DEbuG

If, Else and Endif

The If directive conditionally executes further directives based on the logical value of one or more Set symbols. If a symbol has not been set, its logical value is FALSE. If the expression evaluates to TRUE, lines up to the matching Else or Endif directive are executed. Otherwise lines up to the matching Else or Endif directive are ignored. An Else directive may be followed by a further If directive to continue testing at the same level.

Symbols may be combined using the operators || (logical or), && (logical and) and ! (logical negation).

        If IPAMode
                Config PORT_COUNT 2
        Else If Switchmode || !nic
                Config PORT_COUNT 4
        Else
                Config PORT_COUNT 0
        Endif

Note that this example would be better implemented in hardware files. The usual application for If statements is to control Make lines (see below).

Logical expressions may be used in place of symbol values. Strings can be tested for equality and inequality, while signed integers can be compared with each other.

Example:

        set a = 1
        set b = 2
        if "${a}" == "a"
                do stuff
        endif
        if ${b} > ${a}
                do stuff
        endif

Foreach

Example:

        foreach i foo bar baz
                Make.cc ${i}
                foreach j x y z
                        Make.cc ${i}${j}
                done
        done

Error

The Error directive terminates the aconfig processing, printing the rest of the line as an error message and terminating aconfig.

        Error No architecture specified

This is useful with the Else clause of an If directive to detect improper configurations.

Warning

As above, but generates a warning. Aconfig does not terminate.

Module

The Module directive specifies the name, and possibly the location, of a module to be included in the image.

        Module timer
        Module stack from /usr/local/atmos/stack

The module name refers to a file, in this case timer.module, which is either in the file timer/timer.module along the path, or within the directory supplied as the second (optional) argument.

This directive causes the file to be opened and the directives in it processed. Certain directives may appear only within a module file (see Module).

Colour

The colour directive creates a 'colour' module - this is identical to a normal module except that aconfig expects to find the module file in the directory colours/nameofcolour.module, and the makefile is created in the colours subdirectory of the build directory.

Instance

A module's code may be included more than once in an image isomg the Instance directive.

The Instance directive creates a copy of a module's code in the final image:

        Instance <name> of <module>

The Module directive is equivalent to an Instance directive with the instance name the same as the module name:

Example:

        Module ptime

creates an implicit instance of the module called ptime. Explicit instance directives are only needed for multiple copies of the same module.

Process

The Process directive enters a process into the process table read by the kernel at startup.

        Process name is <instance>/<executable> [args]
        Process timer is timer/timer

The instance/executable parameter refers to an executable named executable in the instance instance. See Object.

NoInit

The NoInit directive suppresses the automatic inclusion of the init module in the image.

        NoInit

This is used when configuring boot ROMs.

Syslink

The Syslink directive overrides the default Syslink line generated in the top-level make file.

        Syslink -oimage -Mmapfile syslink.input

The line should reference syslink.input to pick up the automatically-generated input file. This directive may be used to set ROM mode, and alter the text base, when building boot ROMs.

Link

Link provides a flexible alternative to Syslink, as it allows an arbitrary number of lines (however, the total string must be less than 2K in size), and does not assume that Syslink is the first command to be executed.

        Link
        {
                line 1 of command(s) to build final image
                line 2 of comamnd(s) to build final image
                ...
        }

If you want to add manual dependencies to the makefile for the image produced, then add them as follows:

        Link : <dependency1> <dependency2> ...
        {
                line 1 of command(s) to build final image
                line 2 of comamnd(s) to build final image
                ...
        }

Import

The import directive can be used to make available only the headers, message definitions and aconfig variables set of a module or package:

        Import module timer
        Import package stack


MODULE FILES

Export

Use an export directive to export a header, shared library or unshared library from a module so that other modules can use it.

The Export Header directive exports a header file:

        Export Header kernel.h
        Export Header /homedir/common/extra.h

Note that all exported headers are automatically made available to all modules - a module does not need to explicitly request header files.

Exporting a header from a module adds that module to the global include path, which is used in makerules when dependency checking is done at build time rather than by aconfig. See the autodepend manpage.

The Export SLibrary directive arranges for syslink (the syslink manpage) to link the named library (usually created with catobj) into the shared area of the image. In addition, the named library is added to the list of targets to be built for this module.

        Export Slibrary slibc.o

The Export Ulibrary directive adds the named library to the list of targets to be built for this module.

        Export Ulibrary llibc.o

Typically, unshared libraries are pulled into a build with a make.cat or make.cat++ line such as the following:

        make.cat++ ilmi.o main.o port.o ../portlib/portlib.o

Object

The Object directive specifies an object to be placed in the unshared image area. Following the Object directive is a list of potential processes within that object, as a sequence of Executable statements (see Executable):

        Object name.o
        {
            Executable <name> [options]
        }

Note that a process is not actually created until an actual Process directive uses it (see Process).

Executable

The options to the Executable directive are:

process - to identify a process entry point.

prologue - to identify a process prolog.

qhandler - to identify a dynamic queue handler.

epilogue - to identify a process epilog.

stack - to specify stack size (in words).

priority - to specify process priority.

These options may occur in any order. The default process entry-point is main. Executable statements may only occur within an Object statement.

Make

You use Make directives to tell aconfig to output rules to the makefile for your module for making your objects from your source files. Aconfig automatically determines dependencies and outputs suitable dependency rules to the makefile.

For example, if you have a module which has a C source file src1.c and an assembler source file src2.s and you intend to link these together into a single library called mylib.o then you might put the following into your module file:

        Make.cc  src1
        Make.as  src2
        Make.cat mylib.o src1.o src2.o

Sometimes it is useful to be able to pass additional options to the command that makes your object. For example, if you wanted to pass the option -Wall to the compiler, you might say:

        Make.cc  src1 -Wall

The commands that aconfig will write to your makefile are defined in makerule definition lines (see Makerule).

Message

The Message directive defines an ATMOS message. Each message is given a name, a number, a C structure definition, from which a number of macros are generated in the init/messages.h file.

Example:

        Message CONN
        {
            ATMOS_MQID q;
            WORD vci;
        }

This generates: a pair of message numbers, one for the request (MSG_N_CONN) and one for the reply (MSG_R_CONN); a data structure typedef (MSG_T_CONN); and a macro (MSG_D_CONN) which casts a received message into the typedef.

The definition of message structures should assume only those explicit types defined by atypes.h. Other variables should be defined by pointers to explicitly-named struct constructs. This avoids circular dependencies in creating modules.

If a message id is not set (see Messageid) a default message number will be assigned sequentially by aconfig.

Messageid

The Messageid directive sets the base for any messages that may be defined:

        Messageid 0x002000

This may be used to ensure that all messages have fixed message numbers.

Modulesource

Use this command where the source files for a module are in a different location to the module file itself. For example, if you want your module file to live in /path/to/module and to export some header files from /different/path/to/headers then your module file would look like this:

        modulesource /different/path/to/headers
        export header myheader.h
        export header sys/myheader.h


ADVANCED DIRECTIVES

Architecture

The Architecture directive is an internal directive to the aconfig program. It is used to select the set of rules used by the Make commands. One architecture is supported:

        Architecture arm

This directive is mandatory, and must appear in the hardware file. This directive causes architecture-specific files of the form arch.arch (for example arm.arch) to be executed from the hardware directory. This file should contain a list of Makerule directives.

Makerule

The Makerule directive specifies a rule for use by the Make directive (see Make).

The directive specifies the rule suffix, a template for the source file, and whether or not the resulting file forms part of the final image. This is followed by a sequence of rule lines enclosed in braces:

        MakeRule cc c
        {
                $0.o: $S
                arm-gcc -c -O2 -nostdinc $1 -o $0.o -I. $I $S
        }

This example defines the Make.cc directive.

Normally aconfig will generate dependency rules for the target by scanning it for #include directives. To suppress this behaviour (e.g. for object files) add the option N:

        MakeRule cat X N
        {
                $0: $1
                catobj -o $0 $1
        }

(Here 'X' is simply a dummy extension that will never be found in the build directory by aconfig).

autodepend

It is sometimes more convenient to have the dependencies autogenerated at the same time that the target object file is generated. For example, the gcc ``-DM'' option causes cpp to automatically write dependencies to a local file named after the target object file.

The autodepend command tells aconfig that a particular makerule supports this. For example:

        autodepend cc

Any makerules that are copied from this rule (via copyrule) will inherit this setting.

A deliberate side effect of this is that aconfig will not attempt to work out the include path needed for this file. Instead it will construct a make command which uses the global include path.

Makerule Rewriting

Within the Makerule lines, the following re-writing is performed (using the cc example):

$0
the first token on the resulting Make.cc line

$1
the rest of the Make.cc line

$N
the accumulated list of imported module source paths

$O
the output object directory

$R
the complete path to the release directory

$S
the complete path to the current source file

$I
A list of include directives for the current source file. If the makerule used has been marked as autodepend then this will be the global include path only.

$D
A list of defines and undefines, one for each Define or Undefine statement

$$
A literal $

Note that the -n option to aconfig causes the release directory to be bypassed (with a warning).

The second argument to the Makerule directive is used to locate the source file, which is opened and parsed to generate the list of dependencies for that file.

Editrule

You can change a makerule (usually based on conditional execution) using editrule. The arguments are the name of the rule (e.g. cc) followed by a sed expression (sed is a line-based editor with powerful regular expression based search and replace facilities).

Example:

        Editrule cc s/-O2 /-O3 /

Copyrule

You can copy an existing rule. For example, to copy the 'cc' rule to create a new rule for files ending in the extension 'y':

        Copyrule cc myrule y

You can then say things like:

        Make.myrule myfile
        Editrule myrule s/gcc/ygcc/

Appendrule

Use the Appendrule directive to add a line to an existing makerule. Example:

        Appendrule ar ranlib $0

AlterRules

Use the AlterRules directive to change all makerules used by a particular module.

Example:

        AlterRules in kernel s/-O2 /-O3 /

To limit the change to a specific makerule within the module, append the makerule to the name of the module, separated by '/':

        AlterRules in kernel/cc s/-O2 /-O3 /

Reserved Word Configuration

You can alter some of the reserved words that aconfig writes to the files it generates.

mtod
This changes the name of the message manipulation macro, usually mtod, found in messages.h. Example:
        reserved mtod = my_mtod

Module Configuration Directives

You can define module-specific configuration directives (similar to config.h and config.s. This is useful primarily for cases where you want to change a configuration value but want to avoid having to rebuild the entire build tree.

Example:

Put the following in your module file to let aconfig know that your module is prepared to allow module-specific configuration:

        allow moduleconfig

Next, #include the module-specific configuration file into your source:

        #include <config/mymodule.h>

Finally, put your configuration directive in the system file:

        config mymodule.hs MYVARIABLE 3

Note that the module-specific configuration files automatically #include config.h or config.s.

Warning Suppression

You can suppress warnings on a module-by module basis using the module-specific command nowarn:

    nowarn <option>

Where <option> is one or more of:

  relative  - warnings about relative includes
  parsable  - warnings about unparsable include lines
  export    - warnings about unexport headers
  duplicate - warnings about duplicated exports

Including files

Files may be included directly using the include directive, which includes the given file (relative to ATMOSROOT).

When including a file using the include command, arguments may be passed ``in'' to the included file. Within the included file, these arguments are accessed as variables _1, _2, _3 and so-on. The special variable _0 gives the full path to the current file. Arguments are nestable such that if an include file includes a second file, its own arguments are saved and restored.

The keyword local declares a list of variables that should be made local to this included file. Changes to these variables will not be visible outside this file, although they will be visible in files included from this one.

Example

  % include a file with no arguments
  % from atmos/source/software/myfile
  include software/myfile
  % include a file with some arguments
  include software/myfile foo bar
  % make use of passed in arguments:
  config.h SOMEDEFINE ${_0}
  module ${_1}
  % declare a variable as local
  local baz

Module versions

You can set the version of a module with the moduleversion directive:

  % set the version of the current module to 1.23
  moduleversion 1.23

Versions consist of a major version and a minor version. Changes to the major version number imply a change in the module's public interface, while changes in the minor number imply a bugfix.

The version can be tested using a requires directive in a module file. For example:

  % we require PPP version 2.01 or later:
  requires pp 2.01

Setting the module version also sets an automatic variable, _module_version. For example:

  allow moduleconfig
  config mymodule.h PPP_VERSION ${_pp_version}

Makefile Directives

Text can be added to the makefiles that are generated by aconfig using the make-directive command. In a module file context this will add to the makefile for that module, otherwise it adds text for the top-level makefile.

Example:

  make-directive
  {
     include /path/to/my_rules.make
  }

Global Makefile Directives

A make directive can be added to the makefile for all modules using the global-make-directive command.

Example: global-make-directive { include /path/to/rules_for_all_modules.make }


PERL EXTENSION

Aconfig has a perl interpreter built in, which can be used to add new aconfig commands. Aconfig automatically adds the directory ATMOSROOT/software/build/perl/lib to perl's INC path, while the aconfig command perl can be used to execute arbitrary perl statements. Example:

  % load perl module defining aconfig/perl API
  perl use aconfig;
  % execute arbitrary perl statements
  perl print "The time now is " . time() . "\n";

The aconfig API exported to perl is defined in the aconfig-perl manpage.


=head1 COMMAND EXPANSION

Command substitution allows the output of a command to replace a piece of text in the input.

Example:

        set who = `whoami`

This sets the variable who to the standard output of the whoami command (with trailing newlines deleted).

Note that the native command interpreter is used for executing the command - i.e. /bin/sh on Solaris and Linux, and cmd.exe under Windows. This can have implications when using quotes in your command, since a single quote is not recognised as a quoting character by cmd.exe.


PREDEFINED VARIABLES

A number of variables are automatically defined by aconfig. Access these via variable expansion - e.g. ${aconfig_syntax_version}.

aconfig_syntax_version
The version of the syntax supported by a particular aconfig binary can be tested using the automatic variable aconfig_syntax_version.

aconfig_module
The name of the current module.

aconfig_module_src
The source directory of the current module.

atmosroot
The current ATMOSROOT value (e.g. c:/atmos/source).

aconfig_supports_perl
This variable is set if the system supports perl extension.


EXAMPLES

Minimal Top-Level System file

        Hardware piglet
        Set Debugging
        Package core

Example Module File

        MessageId 0x00010800
        Message TELL
        {
            char cmd[96];
        }
        If multicons
            Export Header multicons.h
            Config.hs MULTICONS
            Make.cc multicons
            Make.cat atomsconsole.o multicons.o ../llibc/nlibc.o
        Endif
        Object atmosconsole.o
        {
            Executable console process process
        }
        Process console is console/console

Creating a Process

Given a module called atm_driver, the following directives within atm_driver's module file (atm_driver/atm_driver.module) will create two separate (potential) executables:

        Object atm.o
        {
            Executable atm process atm_process priority 1
            Executable msnl process msnl_process qhandler msnl_qhandle
        }

This arranges that potentially, the code from atm.o can be used to create the following executables:

atm
An executable called 'atm' with an entry point of atm_process and a priority of 1.

msnl
An executable called 'msnl' with an entry point of msnl_process and an active queue handler function msnl_qhandle.

To actually arrange for a process to be created you would use the following directive:

        Process myprocess is atm_driver/atm

This creates a process called myprocess which uses the code from atm_driver/atm.o and has an entry point of atm_process (from the Executable directive).

Multiple Processes

If you wanted to have two processes running this code, then you could add the following:

        Instance atm_driver2 of atm_driver
        Process myprocess2 is atm_driver2/atm

Note that you will have two copies of the unshared code from atm.o in your image.

Calculating Factorials!

This uses shell expansion and include files with local variables to calculate factorials (extremely inefficiently!). The result is placed in the aconfig variable result.

Create a file factorial, in atmos/source/factorial:

  local num
  set num = ${_1}
  if ${num} == 1
      set result = 1
  else
      set newnum = `expr ${num} - 1`
      include factorial ${newnum}
      set result = `expr ${result} '*' ${num}`
  endif

Invoke it from your system file:

  include factorial 6
  warning 6! = ${result}


SEE ALSO

The ATMOS Book, DO-007001-TC

the aconfig manpage, the syslink manpage, the catobj manpage, the aconfig-perl manpage


VERSION

This document describes aconfig syntax version 21.