URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [tools/] [src/] [libcdl/] [doc/] [language.sgml] - Rev 561
Go to most recent revision | Compare with Previous | Blame | View Log
<!-- {{{ Banner -->
<!-- =============================================================== -->
<!-- -->
<!-- language.sgml -->
<!-- -->
<!-- The CDL language. -->
<!-- -->
<!-- =============================================================== -->
<!-- ####COPYRIGHTBEGIN#### -->
<!-- -->
<!-- =============================================================== -->
<!-- Copyright (C) 2000, 2001, 2002 Red Hat, Inc. -->
<!-- -->
<!-- This material may be distributed only subject to the terms -->
<!-- and conditions set forth in the Open Publication License, v1.0 -->
<!-- or later (the latest version is presently available at -->
<!-- http://www.opencontent.org/openpub/) -->
<!-- Distribution of the work or derivative of the work in any -->
<!-- standard (paper) book form is prohibited unless prior -->
<!-- permission obtained from the copyright holder -->
<!-- =============================================================== -->
<!-- -->
<!-- ####COPYRIGHTEND#### -->
<!-- =============================================================== -->
<!-- #####DESCRIPTIONBEGIN#### -->
<!-- -->
<!-- Author(s): bartv -->
<!-- Contact(s): bartv -->
<!-- Date: 2000/02/06 -->
<!-- Version: 0.01 -->
<!-- -->
<!-- ####DESCRIPTIONEND#### -->
<!-- =============================================================== -->
<!-- }}} -->
<chapter id="language">
<title>The CDL Language</title>
<!-- {{{ Introit -->
<para>
The &CDL; language is a key part of the &eCos; component framework.
All packages must come with at least one &CDL; script, to describe
that package to the framework. The information in that script includes
details of all the configuration options and how to build the package.
Implementing a new component or turning some existing code into an
&eCos; component always involves writing corresponding &CDL;. This
chapter provides a description of the &CDL; language. Detailed
information on specific parts of the language can be found in <xref
linkend="reference">.
</para>
<!-- }}} -->
<!-- {{{ Language overview -->
<sect1 id="language.overview">
<title>Language Overview</title>
<para>
A very simple &CDL; script would look like this:
</para>
<programlisting width=72>
cdl_package CYGPKG_ERROR {
display "Common error code support"
compile strerror.cxx
include_dir cyg/error
description "
This package contains the common list of error and
status codes. It is held centrally to allow
packages to interchange error codes and status
codes in a common way, rather than each package
having its own conventions for error/status
reporting. The error codes are modelled on the
POSIX style naming e.g. EINVAL etc. This package
also provides the standard strerror() function to
convert error codes to textual representation."
}
</programlisting>
<para>
This describes a single package, the error code package, which does
not have any sub-components or configuration options. The package has
an internal name, <varname>CYGPKG_ERROR</varname>, which can be
referenced in other &CDL; scripts using e.g.
<literal>requires CYGPKG_ERROR</literal>. There will also be a
<literal>#define</literal> for this symbol in a configuration header
file. In addition to the package name, this script provides a number
of properties for the package as a whole. The &display; property
provides a short description. The &description; property involves a
rather longer one, for when users need a bit more information. The
&compile; and &include-dir; properties list the consequences of this
package at build-time. The package appears to lack any on-line
documentation.
</para>
<para>
Packages could be even simpler than this. If the package only provides
an interface and there are no files to be compiled then there is no
need for a &compile; property. Alternatively if there are no exported
header files, or if the exported header files should go to the
top-level of the <filename
class="directory">install/include</filename> directory, then there is
no need for an &include-dir; property. Strictly speaking the
&description; and &display; properties are optional as well, although
application developers would not appreciate the resulting lack of
information about what the package is supposed to do.
</para>
<para>
However many packages tend to be a bit more complicated than the error
package, containing various sub-components and configuration options.
These are also defined in the &CDL; scripts and in much the same way
as the package. For example, the following excerpt comes from the
infrastructure package:
</para>
<programlisting width=72>
cdl_component CYGDBG_INFRA_DEBUG_TRACE_ASSERT_BUFFER {
display "Buffered tracing"
default_value 1
active_if CYGDBG_USE_TRACING
description "
An output module which buffers output from tracing and
assertion events. The stored messages are output when an
assert fires, or CYG_TRACE_PRINT() (defined in
<cyg/infra/cyg_trac.h>) is called. Of course, there will
only be stored messages if tracing per se (CYGDBG_USE_TRACING)
is enabled above."
cdl_option CYGDBG_INFRA_DEBUG_TRACE_BUFFER_SIZE {
display "Trace buffer size"
flavor data
default_value 32
legal_values 5 to 65535
description "
The size of the trace buffer. This counts the number of
trace records stored. When the buffer fills it either
wraps, stops recording, or generates output."
}
…
}
</programlisting>
<para>
Like a &cdl-package;, a &cdl-component; has a name and a body. The
body contains various properties for that component, and may also
contain sub-components or options. Similarly a &cdl-option; has a
name and a body of properties. This example lists a number of
new properties: &default-value;, &active-if;, &flavor; and
&legal-values;. The meaning of most of these should be fairly obvious.
The next sections describe the various &CDL; commands and properties.
</para>
<para>
There is one additional and very important point: &CDL; is not a
completely new language; instead it is implemented as an extension of
the existing &Tcl; scripting language. The syntax of a &CDL; script is
&Tcl; syntax, which is described below. In addition some of the more
advanced facilities of &CDL; involve embedded fragments of &Tcl; code,
for example there is a &define-proc; property which specifies some
code that needs to be executed when the component framework generates
the configuration header files.
</para>
</sect1>
<!-- }}} -->
<!-- {{{ CDL commands -->
<sect1 id="language.commands">
<title>CDL Commands</title>
<para>
There are four &CDL;-related commands which can occur at the top-level
of a &CDL; script: &cdl-package;, &cdl-component;, &cdl-option; and
&cdl-interface;. These correspond to the basic building blocks of the
language (CDL interfaces are described in <xref
linkend="language.interface">). All of these take the same basic form:
</para>
<programlisting width=72>
cdl_package <name> {
…
}
cdl_component <name> {
…
}
cdl_option <name> {
…
}
cdl_interface <name> {
…
}
</programlisting>
<para>
The command is followed by a name and by a body of properties, the
latter enclosed in braces. Packages and components can contain other
entities, so the &cdl-package; and &cdl-component; can also have
nested commands in their bodies. All names must be unique within a
given configuration. If say the C library package and a TCP/IP stack
both defined an option with the same name then it would not be
possible to load both of them into a single configuration. There is a
<link linkend="language.naming">naming convention</link> which should
make accidental name clashes very unlikely.
</para>
<para>
It is possible for two packages to use the same name if there are no
reasonable circumstances under which both packages could be loaded at
the same time. One example would be architectural HAL packages: a
given &eCos; configuration can be used on only one processor, so the
architectural HAL packages <varname>CYGPKG_HAL_ARM</varname> and
<varname>CYGPKG_HAL_I386</varname> can re-use option names; in fact
in some cases they are expected to.
</para>
<para>
Each package has one top-level &CDL; script, which is specified in the
packages <link
linkend="language.database"><database>ecos.db</database> database
entry</link>. Typically the name of this top-level script is related to
the package, so the kernel package uses
<filename>kernel.cdl</filename>, but this is just a convention. The
first command in the top-level script should be &cdl-package;, and the
name used should be the same as in the <database>ecos.db</database>
database. There should be only one &cdl-package; command per package.
</para>
<para>
The various &CDL; entities live in a hierarchy. For example the kernel
package contains a scheduling component, a synchronization primitives
component, and a number of others. The synchronization component
contains various options such as whether or not mutex priority
inheritance is enabled. There is no upper bound on how far components
can be nested, but it is rarely necessary to go more than three or
four levels deeper than the package level. Since the naming convention
incorporates bits of the hierarchy, this has the added advantage of
keeping the names down to a more manageable size.
</para>
<para>
The hierarchy serves two purposes. It allows options to be controlled
en masse, so disabling a component automatically disables all the
options below it in the hierarchy. It also permits a much simpler
representation of the configuration in the graphical configuration
tool, facilitating navigation and modification.
</para>
<para>
By default a package is placed at the top-level of the hierarchy, but
it is possible to override this using a &parent; property. For example
an architectural HAL package such as <varname>CYGPKG_HAL_SH</varname>
typically re-parents itself below <varname>CYGPKG_HAL</varname>, and a
platform HAL package would then re-parent itself below the
architectural HAL. This makes it a little bit easier for users to
navigate around the hierarchy. Components, options and interfaces can
also be re-parented, but this is less common.
</para>
<para>
All components, options and interfaces that are defined directly in
the top-level script will be placed below the package in the hierarchy.
Alternatively they can be nested in the body of the &cdl-package;
command. The following two script fragments are equivalent:
</para>
<programlisting width=72>
cdl_package CYGPKG_LIBC {
…
}
cdl_component CYGPKG_LIBC_STRING {
…
}
cdl_option CYGPKG_LIBC_CTYPE_INLINES {
…
}
</programlisting>
<para>
and:
</para>
<programlisting width=72>
cdl_package CYGPKG_LIBC {
…
cdl_component CYGPKG_LIBC_STRING {
…
}
cdl_option CYGPKG_LIBC_CTYPE_INLINES {
…
}
}
</programlisting>
<para>
If a script defines options both inside and outside the body of the
&cdl-package; then the ones inside will be processed first. Language
purists may argue that it would have been better if all contained
options and components had to go into the body, but in practice it is
often convenient to be able to skip this level of nesting and the
resulting behavior is still well-defined.
</para>
<para>
Components can also contain options and other &CDL; entities, in fact
that is what distinguishes them from options. These can be defined in
the body of the &cdl-component; command:
</para>
<programlisting width=72>
cdl_component CYGPKG_LIBC_STDIO {
cdl_component CYGPKG_LIBC_STDIO_FLOATING_POINT {
…
}
cdl_option CYGSEM_LIBC_STDIO_THREAD_SAFE_STREAMS {
…
}
}
</programlisting>
<para>
Nesting options inside the bodies of components like this is fine for
simple packages with only a limited number of configuration options,
but it becomes unsatisfactory as the number of options increases.
Instead it is possible to split the &CDL; data into multiple &CDL;
scripts, on a per-component basis. The &script; property should be
used for this. For example, in the case of the C library all
stdio-related configuration options could be put into
<filename>stdio.cdl</filename>, and the top-level CDL script
<filename>libc.cdl</filename> would contain the following:
</para>
<programlisting width=72>
cdl_package CYGPKG_LIBC {
…
cdl_component CYGPKG_LIBC_STDIO {
…
script stdio.cdl
}
}
</programlisting>
<para>
The <varname>CYGPKG_LIBC_STDIO_FLOATING_POINT</varname> component and
the <varname>CYGSEM_LIBC_STDIO_THREAD_SAFE_STREAMS</varname> option
can then be placed at the top-level of <filename>stdio.cdl</filename>.
It is possible to have some options nested in the body of a
&cdl-component; command and other options in a separate file accessed
by the &script; property. In such a case the nested options would be
processed first, and then the other script would be read in. A script
specified by a &script; property should only define new options,
components or interfaces: it should not contain any additional
properties for the current component.
</para>
<para>
It is possible for a component's &CDL; script to have a sub-component
which also has a &script; property, and so on. In practice excessive
nesting like this is rarely useful. It is also possible to ignore the
&CDL; language support for constructing hierarchies automatically and
use the &parent; property explicitly for every single option and
component. Again this is not generally useful.
</para>
<note>
<para>
At the time of writing interfaces cannot act as containers. This may
change in a future version of the component framework. If the change
is made then interfaces would support the &script; property, just like
components.
</para>
</note>
</sect1>
<!-- }}} -->
<!-- {{{ CDL properties -->
<!-- {{{ Introit -->
<sect1 id="language.properties">
<title>CDL Properties</title>
<para>
Each package, component, option, and interface has a body of
properties, which provide the component framework with information
about how to handle each option. For example there is a property for a
descriptive text message which can be displayed to a user who is
trying to figure out just what effect manipulating the option would
have on the target application. There is another property for the
default value, for example whether a particular option should be
enabled or disabled by default.
</para>
<para>
All of the properties are optional, it is legal to define a
configuration option which has an empty body. However some properties
are more optional than others: users will not appreciate having to
manipulate an option if they are not given any sort of description or
documentation. Other properties are intended only for very specific
purposes, for example &make-object; and &include-files;, and are used
only rarely.
</para>
<para>
Because different properties serve very different purposes, their
syntax is not as uniform as the top-level commands. Some properties
take no arguments at all. Other properties take a single argument such
as a description string, or a list of arguments such as a &compile;
property which specifies the file or files that should be compiled if
a given option is active and enabled. The &define-proc; property takes
as argument a snippet of &Tcl; code. The &active-if;, &calculated;,
&default-value;, &legal-values; and &requires; properties take various
expressions. Additional properties may be defined in future which take
new kinds of arguments.
</para>
<para>
All property parsing code supports options for every property,
although at present the majority of properties do not yet take any
options. Any initial arguments that begin with a hyphen character
<literal>-</literal> will be interpreted as an option, for example:
</para>
<programlisting width=72>
cdl_package CYGPKG_HAL_ARM {
…
make -priority 1 {
…
}
}
</programlisting>
<para>
If the option involves additional data, as for the
<literal>-priority</literal> example above, then this can be written
as either <literal>-priority=1</literal> or as
<literal>-priority 1</literal>. On occasion the option parsing
code can get in the way, for example:
</para>
<programlisting width=72>
cdl_option CYGNUM_LIBC_TIME_DST_DEFAULT_STATE {
…
legal_values -1 to 1
default_value -1
}
</programlisting>
<para>
Neither the &legal-values; nor the &default-value; property will
accept <literal>-1</literal> as a valid option, so this will result in
syntax errors when the &CDL; script is read in by the component
framework. To avoid problems, the option parsing code will recognize
the string <literal>--</literal> and will not attempt to interpret any
subsequent arguments. Hence this option should be written as:
</para>
<programlisting width=72>
cdl_option CYGNUM_LIBC_TIME_DST_DEFAULT_STATE {
…
legal_values -- -1 to 1
default_value -- -1
}
</programlisting>
<para>
The property parsing code involves a recursive invocation of the Tcl
interpreter that is used to parse the top-level commands. This means
that some characters in the body of an option will be treated
specially. The <literal>#</literal> character can be used for
comments. The backslash character <literal>\</literal>, the
dollar character <literal>$</literal>, square brackets
<literal>[</literal> and <literal>]</literal>, braces
<literal>{</literal> and <literal>}</literal>, and the quote character
<literal>"</literal> may all receive special treatment. Most of the
time this is not a problem because these characters are not useful for
most properties. On occasion having a &Tcl; interpreter around
performing the parser can be very powerful. For more details of
how the presence of a &Tcl; interpreter can affect &CDL; scripts,
see <xref linkend="language.tcl">.
</para>
<para>
Many of the properties can be used in any of &cdl-package;,
&cdl-component;, &cdl-option; or &cdl-interface;. Other properties are
more specific. The &script; property is only relevant to components.
The &define-header;, &hardware;, &include-dir;, &include-files;, and
&library; properties apply to a package as a whole, so can only occur
in the body of a &cdl-package; command. The &calculated;,
&default-value;, &legal-values; and &flavor; properties are not
relevant to packages, as will be explained later. The &calculated; and
&default-value; properties are also not relevant to interfaces.
</para>
<para>
This section lists the various properties, grouped by purpose. Each
property also has a full reference page in <xref linkend="reference">.
Properties related to values and expressions are described in more
detail in <xref linkend="language.values">. Properties related to
header file generation and to the build process are described in
<xref linkend="build">.
</para>
<!-- }}} -->
<!-- {{{ User-visible -->
<sect2 id="language.properties.user">
<title>Information-providing Properties</title>
<para>
Users can only be expected to manipulate configuration options
sensibly if they are given sufficient information about these options.
There are three properties which serve to explain an option in plain
text: the <link linkend="ref.display">&display;</link> property gives
a textual alias for an option, which is usually more comprehensible
than something like <literal>CYGPKG_LIBC_TIME_ZONES`</literal>; the
<link linkend="ref.description">&description;</link> property gives a
longer description, typically a paragraph or so; the <link
linkend="ref.doc">&doc;</link> property specifies the location of
additional on-line documentation related to a configuration option. In
the context of a graphical tool the &display; string will be the
primary way for users to identify configuration options; the
&description; paragraph will be visible whenever the option is
selected; the on-line documentation will only be accessed when the
user explicitly requests it.
</para>
<programlisting width=72>
cdl_package CYGPKG_UITRON {
display "uITRON compatibility layer"
doc ref/ecos-ref.a.html
description "
eCos supports a uITRON Compatibility Layer, providing
full Level S (Standard) compliance with Version 3.02 of
the uITRON Standard, plus many Level E (Extended) features.
uITRON is the premier Japanese embedded RTOS standard."
…
}
</programlisting>
<para>
All three properties take a single argument. For &display; and
&description; this argument is just a string. For &doc; it should be a
pointer to a suitable HTML file, optionally including an anchor within
that page. If the <link linkend="package.hierarchy">directory layout
conventions</link> are observed then the component framework will look
for the HTML file in the package's <filename
class="directory">doc</filename> sub-directory, otherwise the &doc;
filename will be treated as relative to the package's top-level directory.
</para>
</sect2>
<!-- }}} -->
<!-- {{{ Hierarchy -->
<sect2 id="language.properties.hierarchy">
<title>The Configuration Hierarchy</title>
<para>
There are two properties related to the hierarchical organization of
components and options: <link linkend="ref.parent">&parent;</link> and
<link linkend="ref.script">&script;</link>.
</para>
<para>
The &parent; property can be used to move a &CDL; entity somewhere
else in the hierarchy. The most common use is for packages, to avoid
having all the packages appear at the top-level of the configuration
hierarchy. For example an architectural HAL package such as
<varname>CYGPKG_HAL_SH</varname> is placed below the common HAL
package <varname>CYGPKG_HAL</varname> using a &parent; property.
</para>
<programlisting width=72>
cdl_package CYGPKG_HAL_SH {
display "SH architecture"
parent CYGPKG_HAL
…
}
</programlisting>
<para>
The &parent; property can also be used in the body of a
&cdl-component;, &cdl-option; or &cdl-interface;, but this is less
common. However care has to be taken since excessive re-parenting can
be confusing. Care also has to be taken when reparenting below some
other package that may not actually be loaded in a given
configuration, since the resulting behavior is undefined.
</para>
<para>
As a special case, if the parent is the empty string then the
&CDL; entity is placed at the root of the hierarchy. This is useful
for global preferences, default compiler flags, and other settings
that may affect every package.
</para>
<para>
The &script; property can only be used in the body of a
&cdl-component; command. The property takes a single filename as
argument, and this should be another &CDL; script containing
additional options, sub-components and interfaces that should go below
the current component in the hierarchy. If the <link
linkend="package.hierarchy">directory layout conventions</link> are
observed then the component framework will look for the specified file
relative to the <filename class="directory">cdl</filename>
subdirectory of the package, otherwise the filename will be treated as
relative to the package's top-level directory.
</para>
<programlisting width=72>
cdl_component CYGPKG_LIBC_STDIO {
display "Standard input/output functions"
flavor bool
requires CYGPKG_IO
requires CYGPKG_IO_SERIAL_HALDIAG
default_value 1
description "
This enables support for standard I/O functions from <stdio.h>."
script stdio.cdl
}
</programlisting>
</sect2>
<!-- }}} -->
<!-- {{{ Value -->
<sect2 id="language.properties.value">
<title>Value-related Properties</title>
<para>
There are seven properties which are related to option values and
state: <link linkend="ref.flavor">&flavor;</link>,
<link linkend="ref.calculated">&calculated;</link>,
<link linkend="ref.default-value">&default-value;</link>,
<link linkend="ref.legal-values">&legal-values;</link>,
<link linkend="ref.active-if">&active-if;</link>,
<link linkend="ref.implements">&implements;</link>, and
<link linkend="ref.requires">&requires;</link>. More detailed
information can be found in <xref linkend="language.values">.
</para>
<para>
In the context of configurability, the concept of an option's value is
somewhat non-trivial. First an option may or may not be loaded: it is
possible to build a configuration which has the math library but not
the kernel; however the math library's &CDL; scripts still reference
kernel options, for example
<varname>CYGSEM_LIBM_THREAD_SAFE_COMPAT_MODE</varname> has a
&requires; constraint on
<varname>CYGVAR_KERNEL_THREADS_DATA</varname>. Even if an option is
loaded it may or may not be active, depending on what is happening
higher up in the hierarchy: if the C library's
<varname>CYGPKG_LIBC_STDIO</varname> component is disabled then some
other options such as <varname>CYGNUM_LIBC_STDIO_BUFSIZE</varname>
become irrelevant. In addition each option has both a boolean
enabled/disabled flag and a data part. For many options only the
boolean flag is of interest, while for others only the data part is of
interest. The &flavor; property can be used to control this:
</para>
<variablelist>
<varlistentry>
<term><literal>flavor none</literal></term>
<listitem>
<para>
This flavor indicates that neither the boolean nor the data parts are
user-modifiable: the option is always enabled and the data is always
set to <literal>1</literal>. The most common use for this is to have a
component that just acts as a placeholder in the hierarchy, allowing
various options to be grouped below it.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>flavor bool</literal></term>
<listitem>
<para>
Only the boolean part of the option is user-modifiable. The data part
is fixed at <literal>1</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>flavor data</literal></term>
<listitem>
<para>
Only the data part of the option is user-modifiable. The boolean part
is fixed at enabled.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>flavor booldata</literal></term>
<listitem>
<para>
Both the boolean and the data part of the option are user-modifiable.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
For more details of &CDL; flavors and how a flavor affects expression
evaluation, and other consequences, see <xref
linkend="language.values">. The &flavor; property cannot be used for a
package because packages always have the <literal>booldata</literal>
flavor. Options and components have the <literal>bool</literal> flavor
by default, since most configuration choices are simple yes-or-no
choices. Interfaces have the <literal>data</literal> flavor by default.
</para>
<para>
The &calculated; property can be used for options which should not be
user-modifiable, but which instead are fixed by the target hardware or
determined from the current values of other options. In general
&calculated; options should be avoided, since they can be confusing to
users who need to figure out whether or not a particular option can
actually be changed. There are a number of valid uses for &calculated;
options, and quite a few invalid ones as well. The <link
linkend="ref.calculated">reference packages</link> should be consulted
for further details. The property takes an <link
linkend="language.expression">ordinary &CDL; expression</link> as
argument, for example:
</para>
<programlisting width=72>
# A constant on some target hardware, perhaps user-modifiable on other
# targets.
cdl_option CYGNUM_HAL_RTC_PERIOD {
display "Real-time clock period"
flavor data
calculated 12500
}
</programlisting>
<para>
The &calculated; property cannot be used for packages or interfaces.
The value of a package always corresponds to the version of that
package which is loaded, and this is under user control. Interfaces
are implicitly calculated, based on the number of active and enabled
implementors.
</para>
<para>
The &default-value; property is similar to &calculated;, but only
specifies a default value which users can modify. Again this property
is not relevant to packages or interfaces. A typical example would be:
</para>
<programlisting width=72>
cdl_option CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT {
display "Include GDB multi-threading debug support"
requires CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
default_value CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
…
}
</programlisting>
<para>
The &legal-values; property imposes a constraint on the possible
values of the data part of an option. Hence it is only applicable to
options with the <literal>data</literal> or
<literal>booldata</literal> flavors. It cannot be used for a package
since the only valid value for a package is its version number. The
arguments to the &legal-values; property should constitute a <link
linkend="language.list-expression">&CDL; list expression</link>.
</para>
<programlisting width=72>
cdl_option CYGNUM_LIBC_TIME_STD_DEFAULT_OFFSET {
display "Default Standard Time offset"
flavor data
legal_values -- -90000 to 90000
default_value -- 0
…
}
</programlisting>
<para>
The &active-if; property does not relate directly to an option's
value, but rather to its active state. Usually this is controlled via
the configuration hierarchy: if the
<varname>CYGPKG_LIBC_STDIO</varname> component is disabled then all
options below it are inactive and do not have any consequences.
In some cases the hierarchy does not provide sufficient control, for
example an option should only be active if two disjoint sets of
conditions are satisfied: the hierarchy could be used for one of these
conditions, and an additional &active-if; property could be used for
the other one. The arguments to &active-if; should constitute a
<link linkend="language.goal-expression">&CDL; goal expression</link>.
</para>
<programlisting width=72>
# Do not provide extra semaphore debugging if there are no semaphores
cdl_option CYGDBG_KERNEL_INSTRUMENT_BINSEM {
active_if CYGPKG_KERNEL_SYNCH
…
}
</programlisting>
<para>
The &implements; property is related to the concept of <link
linkend="language.interface">&CDL; interfaces</link>. If an option is
active and enabled and it implements a particular interface then it
contributes <literal>1</literal> to that interface's value.
</para>
<programlisting width=72>
cdl_package CYGPKG_NET_EDB7XXX_ETH_DRIVERS {
display "Cirrus Logic ethernet driver"
implements CYGHWR_NET_DRIVERS
implements CYGHWR_NET_DRIVER_ETH0
…
}
</programlisting>
<para>
The &requires; property is used to impose constraints on the user's
choices. For example it is unreasonable to expect the C library to
provide thread-safe implementations of certain functions if the
underlying kernel support has been disabled, or even if the kernel is
not being used at all.
</para>
<programlisting width=72>
cdl_option CYGSEM_LIBC_PER_THREAD_ERRNO {
display "Per-thread errno"
doc ref/ecos-ref.15.html
requires CYGVAR_KERNEL_THREADS_DATA
default_value 1
…
}
</programlisting>
<para>
The arguments to the &requires; property should be a <link
linkend="language.goal-expression">&CDL; goal expression</link>.
</para>
</sect2>
<!-- }}} -->
<!-- {{{ Header file generation -->
<sect2 id="language.properties.define">
<title>Generating the Configuration Header Files</title>
<para>
When creating or updating a build tree the component framework will
also generate configuration header files, one per package. By default
it will generate a <literal>#define</literal> for each option,
component or interface that is active and enabled. For options with
the <literal>data</literal> or <literal>booldata</literal> flavors the
<literal>#define</literal> will use the option's data part, otherwise
it will use the constant <literal>1</literal>. Typical output would
include:
</para>
<programlisting width=72>
#define CYGFUN_LIBC_TIME_POSIX 1
#define CYGNUM_LIBC_TIME_DST_DEFAULT_STATE -1
</programlisting>
<para>
There are six properties which can be used to control the header file
generation process:
<link linkend="ref.define-header">&define-header;</link>,
<link linkend="ref.no-define">&no-define;</link>,
<link linkend="ref.define-format">&define-format;</link>,
<link linkend="ref.define">&define;</link>,
<link linkend="ref.if-define">&if-define;</link>, and
<link linkend="ref.define-proc">&define-proc;</link>.
</para>
<para>
By default the component framework will generate a configuration
header file for each package based on the package's name: everything
up to and including the first underscore is discarded, the rest of the
name is lower-cased, and a <literal>.h</literal> suffix is appended.
For example the configuration header file for the kernel package
<varname>CYGPKG_KERNEL</varname> is <filename
class="headerfile">pkgconf/kernel.h</filename>. The &define-header;
property can be used to specify an alternative filename. This applies
to all the components and options within a package, so it can only be
used in the body of a &cdl-package; command. For example the following
specifies that the configuration header file for the SPARClite HAL
package is <filename
class="headerfile">pkgconf/hal_sparclite.h</filename>.
</para>
<programlisting width=72>
cdl_package CYGPKG_HAL_SPARCLITE {
display "SPARClite architecture"
parent CYGPKG_HAL
hardware
define_header hal_sparclite.h
…
}
</programlisting>
<note>
<para>
At present the main use for the &define-header; property is related
to hardware packages, see the <link linkend="ref.hardware">reference
pages</link> for more details.
</para>
</note>
<para>
The &no-define; property is used to suppress the generation of the
default <literal>#define</literal>. This can be useful if an option's
consequences are all related to the build process or to constraints,
and the option is never actually checked in any source code. It can
also be useful in conjunction with the &define;, &if-define; or
&define-proc; properties. The &no-define; property does not take any
arguments.
</para>
<programlisting width=72>
cdl_component CYG_HAL_STARTUP {
display "Startup type"
flavor data
legal_values { "RAM" "ROM" }
default_value {"RAM"}
no_define
define -file system.h CYG_HAL_STARTUP
…
}
</programlisting>
<para>
This example also illustrates the &define; property, which can be used
to generate a <literal>#define</literal> in addition to the default
one. It takes a single argument, the name of the symbol to be defined.
It also takes options to control the configuration header file in
which the symbol should be defined and the format to be used.
</para>
<para>
The &define-format; property can be used to control how the value part
of the default <literal>#define</literal> gets formatted. For example
a format string of <literal>"0x%04x"</literal> could be used to
generate a four-digit hexadecimal number.
</para>
<para>
The &if-define; property is intended for use primarily to control
assertions, tracing, and similar functionality. It supports a specific
implementation model for these, allowing control at the grain of
packages or even individual source files. The <link
linkend="ref.if-define">reference pages</link> provide additional
information.
</para>
<para>
The &define-proc; property provides an escape mechanism for those
cases where something special has to happen at configuration header
file generation time. It takes a single argument, a fragment of &Tcl;
code, which gets executed when the header file is generated. This code
can output arbitrary data to the header file, or perform any other
actions that might be appropriate.
</para>
</sect2>
<!-- }}} -->
<!-- {{{ Builds -->
<sect2 id="language.properties.build">
<title>Controlling what gets Built</title>
<para>
There are six properties which affect the build process:
<link linkend="ref.compile">&compile;</link>,
<link linkend="ref.make">&make;</link>,
<link linkend="ref.make-object">&make-object;</link>,
<link linkend="ref.library">&library;</link>,
<link linkend="ref.include-dir">&include-dir;</link>, and
<link linkend="ref.include-files">&include-files;</link>.
The last three apply to a package as a whole, and can only occur in
the body of a &cdl-package; command.
</para>
<para>
Most of the source files that go into a package should simply be
compiled with the appropriate compiler, selected by the target
architecture, and with the appropriate flags, with an additional set
defined by the target hardware and possible modifications on a
per-package basis. The resulting object files will go into the library
<filename>libtarget.a</filename>, which can then be linked against
application code. The &compile; property is used to list these source
files:
</para>
<programlisting width=72>
cdl_package CYGPKG_ERROR {
display "Common error code support"
compile strerror.cxx
include_dir cyg/error
…
}
</programlisting>
<para>
The arguments to the &compile; property should be one or more source
files. Typically most of the sources will be needed for the package as
a whole, and hence they will be listed in one or more &compile;
properties in the body of the &cdl-package;. Some sources may be
specific to particular configuration options, in other words there is
no point in compiling them unless that option is enabled, in which
case the sources should be listed in a &compile; property in the
corresponding &cdl-option;, &cdl-component; or &cdl-interface; body.
</para>
<para>
Some packages may have more complicated build requirements, for
example they may involve a special target such as a linker script
which should not end up in the usual library, or they may involve
special build steps for generating an object file. The &make; and
&make-object; properties provide support for such requirements, for
example:
</para>
<programlisting>
cdl_package CYGPKG_HAL_MN10300_AM33 {
display "MN10300 AM33 variant"
…
make {
<PREFIX>/lib/target.ld: <PACKAGE>/src/mn10300_am33.ld
$(CC) -E -P -Wp,-MD,target.tmp -DEXTRAS=1 -xc $(INCLUDE_PATH) \
$(CFLAGS) -o $@ $<
@echo $@ ": \\" > $(notdir $@).deps
@tail +2 target.tmp >> $(notdir $@).deps
@echo >> $(notdir $@).deps
@rm target.tmp
}
}
</programlisting>
<para>
For full details of custom build steps and the build process
generally, see <xref linkend="build">.
</para>
<para>
By default all object files go into the library
<filename>libtarget.a</filename>. It is possible to override this at
the package level using the &library; property, but this should be
avoided since it complicates application development: instead of just
linking with a single library for all &eCos;-related packages, it
suddenly becomes necessary to link with several libraries.
</para>
<para>
The &include-dir; and &include-files; properties relate to a package's
exported header files. By default a package's header files will be
exported to the <filename class="directory">install/include</filename>
directory. This is the desired behavior for some packages like the C
library, since headers like <filename
class="headerfile">stdio.h</filename> should exist at that level.
However if all header files were to end up in that directory then
there would be a significant risk of a name clash. Instead it is
better for packages to specify some sub-directory for their exported
header files, for example:
</para>
<programlisting width=72>
cdl_package CYGPKG_INFRA {
display "Infrastructure"
include_dir cyg/infra
…
}
</programlisting>
<para>
The various header files exported by the infrastructure, for example
<filename class="headerfile">cyg_ass.h</filename> and <filename
class="headerfile">cyg_trac.h</filename> will now end up in the
<filename class="directory">install/include/cyg/infra</filename>
sub-directory, where a name clash is very unlikely.
</para>
<para>
For packages which follow the <link
linkend="package.hierarchy">directory layout conventions</link> the
component framework will assume that the package's
<filename class="directory">include</filename> sub-directory contains
all exported header files. If this is not the case, for example
because the package is sufficiently simple that the layout convention
is inappropriate, then the exported header files can be listed
explicitly in an &include-files; property.
</para>
</sect2>
<!-- }}} -->
<!-- {{{ Miscellaneous -->
<sect2 id="language.properties.miscellaneous">
<title>Miscellaneous Properties</title>
<para>
The <link linkend="ref.hardware">&hardware;</link> property is
only relevant to packages. Some packages such as device drivers and
HAL packages are hardware-specific, and generally it makes no sense to
add such packages to a configuration unless the corresponding hardware
is present on your target system. Typically hardware package selection
happens automatically when you select your target. The &hardware;
property should be used to identify a hardware-specific package, and
does not take any arguments.
</para>
<programlisting width=72>
cdl_package CYGPKG_HAL_MIPS {
display "MIPS architecture"
parent CYGPKG_HAL
hardware
include_dir cyg/hal
define_header hal_mips.h
…
}
</programlisting>
<para>
At present the &hardware; property is largely ignored by the component
framework. This may change in future releases.
</para>
</sect2>
<!-- }}} -->
</sect1>
<!-- }}} -->
<!-- {{{ Naming conventions -->
<sect1 id="language.naming">
<title>Option Naming Convention</title>
<para>
All the options in a given configuration live in the same namespace.
Furthermore it is not possible for two separate options to have the
same name, because this would make any references to those options in
&CDL; expressions ambiguous. A naming convention exists to avoid
problems. It is recommended that component writers observe some or all
of this convention to reduce the probability of name clashes with
other packages.
</para>
<para>
There is an important restriction on option names. Typically the
component framework will output a <literal>#define</literal> for every
active and enabled option, using the name as the symbol being defined.
This requires that all names are valid C preprocessor symbols, a
limitation that is enforced even for options which have the
&no-define; property. Preprocessor symbols can be any sequence of
lower case letters <literal>a</literal>-<literal>z</literal>, upper
case letters, <literal>A</literal>-<literal>Z</literal>, the
underscore character <literal>_</literal>, and the digits
<literal>0</literal>-<literal>9</literal>. The first character must be
a non-digit. Using an underscore as the first character is
discouraged, because that may clash with reserved language
identifiers. In addition there is a convention that preprocessor
symbols only use upper case letters, and some component writers may
wish to follow this convention.
</para>
<para>
A typical option name could be something like
<varname>CYGSEM_KERNEL_SCHED_BITMAP</varname>. This name consists of
several different parts:
</para>
<orderedlist>
<listitem>
<para>
The first few characters, in this case the three letters
<literal>CYG</literal>, are used to identify the organization that
produced the package. For historical reasons packages produced by Red
Hat tend to use the prefix <literal>CYG</literal> rather than
<literal>RHAT</literal>. Component writers should use their own
prefix: even when cutting and pasting from an existing &CDL; script
the prefix should be changed to something appropriate to their
organization.
</para>
<para>
It can be argued that a short prefix, often limited to upper case
letters, is not sufficiently long to eliminate the possibility of
name clashes. A longer prefix could be used, for example one based on
internet domain names. However the C preprocessor has no concept of
namespaces or <literal>import</literal> directives, so it would always
be necessary to use the full option name in component source code
which gets tedious - option names tend to be long enough as it is.
There is a small increased risk of name clashes, but this risk is felt
to be acceptable.
</para>
</listitem>
<listitem>
<para>
The next three characters indicate the nature of the option, for
example whether it affects the interface or just the implementation. A
list of common tags is given below.
</para>
</listitem>
<listitem>
<para>
The <literal>KERNEL_SCHED</literal> part indicates the location of the
option within the overall hierarchy. In this case the option is part of
the scheduling component of the kernel package. Having the hierarchy
details as part of the option name can help in understanding
configurable code and further reduces the probability of a name clash.
</para>
</listitem>
<listitem>
<para>
The final part, <literal>BITMAP</literal>, identifies the option
itself.
</para>
</listitem>
</orderedlist>
<para>
The three-character tag is intended to provide some additional
information about the nature of the option. There are a number of
pre-defined tags. However for many options there is a choice:
options related to the platform should normally use
<literal>HWR</literal>, but numerical options should normally use
<literal>NUM</literal>; a platform-related numerical option such as
the size of an interrupt stack could therefore use either tag.
There are no absolute rules, and it is left to component writers to
interpret the following guidelines:
</para>
<variablelist>
<varlistentry>
<term><literal>xxxARC_</literal></term>
<listitem><para>
The <literal>ARC</literal> tag is intended for options related
to the processor architecture. Typically such options will only occur
in architectural or variant HAL packages.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxHWR_</literal></term>
<listitem><para>
The <literal>HWR</literal> tag is intended for options related to
the specific target board. Typically such options will only occur in
platform HAL packages.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxPKG_</literal></term>
<listitem><para>
This tag is intended for packages or components, in other words
options which extend the configuration hierarchy. Arguably a
<literal>COM</literal> tag would be more appropriate for
components, but this could be confusing because of the considerable
number of computing terms that begin with com.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxGLO_</literal></term>
<listitem><para>
This is intended for global configuration options, especially
preferences.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxDBG_</literal></term>
<listitem><para>
The <literal>DBG</literal> tag indicates that the option is in
some way related to debugging, for example it may enable assertions in
some part of the system.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxTST_</literal></term>
<listitem><para>
This tag is for testing-related options. Typically these do not
affect actual application code, instead they control the interaction
between target-side test cases and a host-side testing infrastructure.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxFUN_</literal></term>
<listitem><para>
This is for configuration options which affect the interface of a
package. There are a number of related tag which are also
interface-related. <literal>xxxFUN_</literal> is intended primarily
for options that control whether or not one or more functions are
provided by the package, but can also be used if none of the other
interface-related tags is applicable.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxVAR_</literal></term>
<listitem><para>
This is analogous to <literal>FUN</literal> but controls the presence
or absence of one or more variables or objects.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxCLS_</literal></term>
<listitem><para>
The <literal>CLS</literal> tag is intended only for packages that
provide an object-oriented interface, and controls the presence or
absence of an entire class.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxMFN_</literal></term>
<listitem><para>
This is also for object-orientated interfaces, and indicates the
presence or absence of a member function rather than an entire class.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxSEM_</literal></term>
<listitem><para>
A <literal>SEM</literal> option does not affect the interface (or if
does affect the interface, this is incidental). Instead it is used for
options which have a fundamental effect on the semantic behavior of a
package. For example the choice of kernel schedulers is semantic in
nature: it does not affect the interface, in particular the function
<function>cyg_thread_create</function> exists irrespective of which
scheduler has been selected. However it does have a major impact on
the system's behavior.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxIMP_</literal></term>
<listitem><para>
<literal>IMP</literal> is for implementation options. These do not
affect either the interface or the semantic behavior (with the
possible exception of timing-related changes). A typical
implementation option controls whether or not a particular function or
set of functions should get inlined.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxNUM_</literal></term>
<listitem><para>
This tag is for numerical options, for example the number of
scheduling priority levels.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxDAT_</literal></term>
<listitem><para>
This is for data items that are not numerical in nature, for example a
device name.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxBLD_</literal></term>
<listitem><para>
The <literal>BLD</literal> tag indicates an option that affects
the build process, for example compiler flag settings.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxINT_</literal></term>
<listitem><para>
This should normally be used for &CDL; interfaces, which is a language
construct that is largely independent from the interface exported by a
package via its header files. For more details of &CDL; interfaces
see <xref linkend="language.interface">.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxPRI_</literal></term>
<listitem><para>
This tag is not normally used for configuration options. Instead
it is used by &CDL; scripts to pass additional private information to
the source code via the configuration header files, typically inside a
&define-proc; property.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>xxxSRC_</literal></term>
<listitem><para>
This tag is not normally used for configuration options. Instead
it can be used by package source code to interact with such options,
especially in the context of the &if-define; property.
</para></listitem>
</varlistentry>
</variablelist>
<para>
There is one special case of a potential name clash that is worth
mentioning here. When the component framework generates a
configuration header file for a given package, by default it will use
a name derived from the package name (the &define-header; property can
be used to override this). The file name is constructed from the
package name by removing everything up to and including the first
underscore, converting the remainder of the name to lower case, and
appending a <literal>.h</literal> suffix. For example the kernel
package <varname>CYGPKG_KERNEL</varname> will involve a header file
<filename class="headerfile">pkgconf/kernel.h</filename>. If a
configuration contained some other package
<varname>XYZPKG_KERNEL</varname> then this would attempt to use the
same configuration header file, with unfortunate effects. Case
sensitivity could introduce problems as well, so a package
<varname>xyzpkg_kernel</varname> would involve the same problem. Even
if the header file names preserved the case of the package name, not
all file systems are case sensitive. There is no simple solution to
this problem. Changing the names of the generated configuration header
files would involve a major incompatible change to the interface, to
solve a problem which is essentially hypothetical in nature.
</para>
</sect1>
<!-- }}} -->
<!-- {{{ Introduction to Tcl -->
<sect1 id="language.tcl">
<title>An Introduction to Tcl</title>
<para>
All &CDL; scripts are implemented as &Tcl; scripts, and are read in by
running the data through a standard &Tcl; interpreter, extended with a
small number of additional commands such as
<literal>cdl_option</literal> and <literal>cdl_component</literal>.
Often it is not necessary to know the full details of &Tcl; syntax.
Instead it is possible to copy an existing script, perform some copy
and paste operations, and make appropriate changes to names and to
various properties. However there are also cases where an
understanding of &Tcl; syntax is very desirable, for example:
</para>
<programlisting width=72>
cdl_option CYGDAT_UITRON_MEMPOOLFIXED_EXTERNS {
display "Externs for initialization"
flavor data
default_value {"static char fpool1[ 2000 ], \\\n\
fpool2[ 2000 ], \\\n\
fpool3[ 2000 ];"}
…
}
</programlisting>
<para>
This causes the &cdl-option; command to be executed, which in turn
evaluates its body in a recursive invocation of the &Tcl; interpreter.
When the &default-value; property is encountered the braces around the
value part are processed by the interpreter, stopping it from doing
further processing of the braced contents (except for backslash
processing at the end of a line, that is special). In particular it
prevents command substitution for
<literal>[ 2000 ]</literal>. A single argument will be
passed to the &default-value; command which expects a &CDL;
expression, so the expression parsing code is passed the following:
</para>
<screen width=72>
"static char fpool1[ 2000 ], \\\n fpool2[ 2000 ], \\\n fpool3[ 2000 ];"
</screen>
<para>
The &CDL; expression parsing code will treat this as a simple string
constant, as opposed to a more complicated expression involving other
options and various operators. The string parsing code will perform
the usual backslash substitutions so the actual default value will be:
</para>
<screen width=72>
static char fpool1[ 2000 ], \
fpool2[ 2000 ], \
fpool3[ 2000 ];
</screen>
<para>
If the user does not modify the option's value then the following
will be generated in the appropriate configuration header file:
</para>
<programlisting width=72>
#define CYGDAT_UITRON_MEMPOOLFIXED_EXTERNS static char fpool1[ 2000 ], \
fpool2[ 2000 ], \
fpool3[ 2000 ];
</programlisting>
<para>
Getting this desired result usually requires an understanding of both
&Tcl; syntax and &CDL; expression syntax. Sometimes it is possible to
substitute a certain amount of trial and error instead, but this may
prove frustrating. It is also worth pointing out that many &CDL;
scripts do not involve this level of complexity. On the other hand,
some of the more advanced features of the &CDL; language involve
fragments of &Tcl; code, for example the &define-proc; property. To
use these component writers will need to know about the full &Tcl;
language as well as the syntax.
</para>
<para>
Although the current example may seem to suggest that &Tcl; is rather
complicated, it is actually a very simple yet powerful scripting
language: the syntax is defined by just eleven rules. On occasion this
simplicity means that Tcl's behavior is subtly different from other
languages, which can confuse newcomers.
</para>
<para>
When the Tcl interpreter is passed some data such as
<literal>puts Hello</literal>, it splits this data into a command
and its arguments. The command will be terminated by a newline or by a
semicolon, unless one of the quoting mechanisms is used. The command
and each of its arguments are separated by white space. So in the
following example:
</para>
<screen width=72>
puts Hello
set x 42
</screen>
<para>
This will result in two separate commands being executed. The first
command is <literal>puts</literal> and is passed a single argument,
<literal>Hello</literal>. The second command is <literal>set</literal>
and is passed two arguments, <literal>x</literal> and
<literal>42</literal>. The intervening newline character serves to
terminate the first command, and a semi-colon separator could be used
instead:
</para>
<screen width=72>
puts Hello;set x 42
</screen>
<para>
Any white space surrounding the semicolon is just ignored because it
does not serve to separate arguments.
</para>
<para>
Now consider the following:
</para>
<screen width=72>
set x Hello world
</screen>
<para>
This is not valid &Tcl;. It is an attempt to invoke the
<literal>set</literal> command with three arguments:
<literal>x</literal>, <literal>Hello</literal>, and
<literal>world</literal>. The <literal>set</literal> only takes two
arguments, a variable name and a value, so it is necessary to combine
the data into a single argument by quoting:
</para>
<screen width=72>
set x "Hello world"
</screen>
<para>
When the &Tcl; interpreter encounters the first quote character it
treats all subsequent data up to but not including the closing quote
as part of the current argument. The quote marks are removed by the
interpreter, so the second argument passed to the
<literal>set</literal> command is just <literal>Hello world</literal>
without the quote characters. This can be significant in the context
of &CDL; scripts. For example:
</para>
<programlisting width=72>
cdl_option CYG_HAL_STARTUP {
…
default_value "RAM"
}
</programlisting>
<para>
The &Tcl; interpreter strips off the quote marks so the &CDL;
expression parsing code sees <literal>RAM</literal> instead of
<literal>"RAM"</literal>. It will treat this as a reference to
some unknown option <varname>RAM</varname> rather than as a string
constant, and the expression evaluation code will use a value of
<literal>0</literal> when it encounters an option that is not
currently loaded. Therefore the option
<varname>CYG_HAL_STARTUP</varname> ends up with a default value of
<literal>0</literal>. Either braces or backslashes should be used to
avoid this, for example
<literal>default_value { "RAM" }</literal>.
</para>
<note>
<para>
There are long-term plans to implement some sort of &CDL; validation
utility <application class="software">cdllint</application> which
could catch common errors like this one.
</para>
</note>
<para>
A quoted argument continues until the closing quote character is
encountered, which means that it can span multiple lines. Newline or
semicolon characters do not terminate the current command in such
cases. &description; properties usually make use of this:
</para>
<programlisting width=72>
cdl_package CYGPKG_ERROR {
description "
This package contains the common list of error and
status codes. It is held centrally to allow
packages to interchange error codes and status
codes in a common way, rather than each package
having its own conventions for error/status
reporting. The error codes are modelled on the
POSIX style naming e.g. EINVAL etc. This package
also provides the standard strerror() function to
convert error codes to textual representation."
…
}
</programlisting>
<para>
The &Tcl; interpreter supports much the same forms of backslash
substitution as other common programming languages. Some backslash
sequences such as <literal>\n</literal> will be replaced by the
appropriate character. The sequence <literal>\\</literal> will be
replaced by a single backslash. A backslash at the very end of a line
will cause that backslash, the newline character, and any white space
at the start of the next line to be replaced by a single space. Hence
the following two Tcl commands are equivalent:
</para>
<programlisting width=72>
puts "Hello\nworld\n"
puts \
"Hello
world
"
</programlisting>
<para>
If a &description; string needs to contain quote marks or other
special characters then backslash escapes can be used. In addition to
quote and backslash characters, the Tcl interpreter treats square
brackets, the <literal>$</literal> character, and braces specially.
Square brackets are used for command substitution, for example:
</para>
<screen width=72>
puts "The answer is [expr 6 * 9]"
</screen>
<para>
When the Tcl interpreter encounters the square brackets it will treat
the contents as another command that should be executed first, and the
result of executing that is used when continuing to process the
script. In this case the Tcl interpreter will execute the command
<literal>expr 6 * 9</literal>, yielding a result of 42
<footnote>
<para>
It is possible that some versions of the Tcl interpreter will instead
produce a result of 54 when asked to multiply six by nine. Appropriate
<ulink url="http://www.douglasadams.com/creations/hhgg.html">reference
documentation</ulink> should be consulted for more information on why
42 is in fact the correct answer.
</para>
</footnote>
and then the
Tcl interpreter will execute <literal>puts "The answer is 42"</literal>.
It should be noted that the interpreter performs only one level
of substitution: if the result of performing command substitution
performs further special characters such as square brackets then these
will not be treated specially.
</para>
<para>
Command substitution will not prove useful for many &CDL; scripts,
except for e.g. a &define-proc; property which involves a fragment of
&Tcl; code. Potentially there are some interesting uses, for example
to internationalize &display; strings. However care does have to be
taken to avoid unexpected command substitution, for example if an
option description involves square brackets then typically these would
require backslash-escapes.
</para>
<para>
The <literal>$</literal> character is used in Tcl scripts to perform
variable substitution:
</para>
<programlisting width=72>
set x [expr 6 * 9]
puts "The answer is $x"
</programlisting>
<para>
Variable substitution, like command substitution, is unlikely to
prove useful for many &CDL; scripts except in the context of
&Tcl; fragments. If it is necessary to have a <literal>$</literal>
character then a backslash escape may have to be used.
</para>
<para>
Braces are used to collect a sequence of characters into a single
argument, just like quotes. The difference is that variable, command
and backslash substitution do not occur inside braces (with the
sole exception of backslash substitution at the end of a line).
Therefore given a line in a &CDL; script such as:
</para>
<programlisting width=72>
default_value {"RAM"}
</programlisting>
<para>
The braces are stripped off by the &Tcl; interpreter, leaving
<literal>"RAM"</literal> which will be handled as a string constant by
the expression parsing code. The same effect could be achieved using
one of the following:
</para>
<programlisting width=72>
default_value \"RAM\"
default_value "\"RAM\""
</programlisting>
<para>
Generally the use of braces is less confusing. At this stage it is
worth noting that the basic format of &CDL; data makes use of
braces:
</para>
<programlisting width=72>
cdl_option <name> {
…
};
</programlisting>
<para>
The &cdl-option; command is passed two arguments, a name and a body,
where the body consists of everything inside the braces but not the
braces themselves. This body can then be executed in a recursive
invocation of the &Tcl; interpreter. If a &CDL; script contains
mismatched braces then the interpreter is likely to get rather
confused and the resulting diagnostics may be difficult to understand.
</para>
<para>
Comments in Tcl scripts are introduced by a hash character
<literal>#</literal>. However, a hash character only introduces a
comment if it occurs where a command is expected. Consider the
following:
</para>
<programlisting width=72>
# This is a comment
puts "Hello" # world
</programlisting>
<para>
The first line is a valid comment, since the hash character occurs
right at the start where a command name is expected. The second line
does not contain a comment. Instead it is an attempt to invoke the
<literal>puts</literal> command with three arguments:
<literal>Hello</literal>, <literal>#</literal> and
<literal>world</literal>. These are not valid arguments for the
<literal>puts</literal> command so an error will be raised.
If the second line was rewritten as:
</para>
<programlisting width=72>
puts "Hello"; # world
</programlisting>
<para>
then this is a valid Tcl script. The semicolon identifies the end of
the current command, so the hash character occurs at a point where the
next command would start and hence it is interpreted as the start of a
comment.
</para>
<para>
This handling of comments can lead to subtle behavior. Consider the
following:
</para>
<programlisting width=72>
cdl_option WHATEVER {
# This is a comment }
default_value 0
…
}
</programlisting>
<para>
Consider the way the Tcl interpreter processes this. The command name
and the first argument do not pose any special difficulties. The
opening brace is interpreted as the start of the next argument, which
continues until a closing brace is encountered. In this case the
closing brace occurs on the second line, so the second argument passed
to <literal>cdl_option</literal> is
<literal>\n # This is a comment
</literal>. This second argument is processed in a recursive
invocation of the Tcl interpreter and does not contain any commands,
just a comment. Top-level script processing then resumes, and the next
command that is encountered is <literal>default_value</literal>. Since
the parser is not currently processing a configuration option this is
an error. Later on the Tcl interpreter would encounter a closing brace
by itself, which is also an error.
</para>
<para>
For component writers who need more information about &Tcl;,
especially about the language rather than the syntax, various
resources are available. A reasonable starting point is the
<ulink url="http://www.tcl.tk/scripting/">Scriptics developer
web site</ulink>.
</para>
</sect1>
<!-- }}} -->
<!-- {{{ Values and Expressions -->
<sect1 id="language.values">
<title>Values and Expressions</title>
<!-- {{{ Introit -->
<para>
It is fairly reasonable to expect that enabling or disabling a
configuration option such as
<varname>CYGVAR_KERNEL_THREADS_DATA</varname> in some way affects its
<emphasis>value</emphasis>. This will have an effect on any
expressions that reference this option such as
<literal>requires CYGVAR_KERNEL_THREADS_DATA</literal>. It will
also affect the consequences of that option: how it affects the build
process and what happens to any constraints that
<varname>CYGVAR_KERNEL_THREADS_DATA</varname> may impose (as opposed
to constraints on this option imposed by others).
</para>
<para>
In a language like C the handling of variables is relatively
straightforward. If a variable <varname>x</varname> gets referenced in
an expression such as <literal>if (x != 0)</literal>,
and that variable is not defined anywhere, then the code will fail to
build, typically with an unresolved error at link-time. Also in C
a variable <varname>x</varname> does not live in any hierarchy, so its
value for the purposes of expression evaluation is not affected by
anything else. C variables also have a clear type such as
<literal>int</literal> or <literal>long double</literal>.
</para>
<para>
In &CDL; things are not so straightforward.
</para>
<!-- }}} -->
<!-- {{{ Option Values -->
<sect2 id="language.values.value">
<!-- {{{ Introit -->
<title>Option Values</title>
<para>
There are four factors which go into an option's value:
</para>
<orderedlist>
<listitem>
<para>
An option may or may not be loaded.
</para>
</listitem>
<listitem>
<para>
If the option is loaded, it may or may not be active.
</para>
</listitem>
<listitem>
<para>
Even if the option is active, it may or may not be enabled.
</para>
</listitem>
<listitem>
<para>
If the option is loaded, active and enabled then it will have some
associated data which constitutes its value.
</para>
</listitem>
</orderedlist>
<!-- }}} -->
<!-- {{{ Loaded -->
<sect3 id="language.values.value.loaded">
<title>Is the Option Loaded?</title>
<para>
At any one time a configuration will contain only a subset of all
possible packages. In fact it is impossible to combine certain
packages in a single configuration. For example architectural HAL
packages should contain a set of options defining endianness, the
sizes of basic data types and so on (many of which will of course be
constant for any given architecture). Any attempt to load two
architectural HAL packages into a configuration will fail because of
the resulting name clash. Since &CDL; expressions can reference
options in other packages, and often need to do so, it is essential to
define the resulting behavior.
</para>
<para>
One complication is that the component framework does not know about
every single option in every single package. Obviously it cannot know
about packages from arbitrary third parties which have not been
installed. Even for packages which have been installed, the current
repository database does not hold details of every option, only of the
packages themselves. If a &CDL; expression contains a reference to
some option <varname>CYGSEM_KERNEL_SCHED_TIMESLICE</varname> then the
component framework will only know about this option if the kernel
package is actually loaded into the current configuration. If the
package is not loaded then theoretically the framework might guess
that the option is somehow related to the kernel by examining the
option name but this would not be robust: the option could easily be
part of some other package that violates the naming convention.
</para>
<para>
Assume that the user is building a minimal configuration which does
not contain the kernel package, but does have other packages which
contain the following constraints:
</para>
<programlisting width=72>
requires CYGPKG_KERNEL
requires CYGPKG_KERNEL_THREADS_DATA
requires !CYGSEM_KERNEL_SCHED_TIMESLICE
</programlisting>
<para>
Clearly the first constraint is not satisfied because the kernel is
not loaded. The second constraint is also not satisfied. The third
constraint is trivially satisfied: if there is no kernel then the
kernel's timeslicing support cannot possibly be enabled.
</para>
<para>
Any options which are not in the current configuration are handled as
follows:
</para>
<orderedlist>
<listitem>
<para>
Any references to that option will evaluate to <literal>0</literal>,
so <literal>requires !CYGSEM_KERNEL_SCHED_TIMESLICE</literal> will
be satisfied but
<literal>requires CYGSEM_KERNEL_THREADS_DATA</literal> will not
be satisfied.
</para>
</listitem>
<listitem>
<para>
An option that is not loaded has no consequences on the build process.
It cannot directly result in any <literal>#define's</literal> in a
configuration header file, nor in any files being compiled. This is
only reasonable: if the option is not loaded then the component
framework has no way of knowing about any &compile; or similar
properties. An option that is not loaded can have indirect
consequences by being referenced in &CDL; expressions.
</para>
</listitem>
<listitem>
<para>
An option that is not loaded cannot impose any constraints on the rest
of the configuration. Again this is the only reasonable behavior: if
the option is not loaded then any associated &requires; or
&legal-values; properties will not be known.
</para>
</listitem>
</orderedlist>
</sect3>
<!-- }}} -->
<!-- {{{ Active -->
<sect3 id="language.values.value.active">
<title>Is the Option Active</title>
<para>
The next issue to consider is whether or not a particular option is
active. Configuration options are organized in a hierarchy of
components and sub-components. For example the C library package
contains a component <varname>CYGPKG_LIBC_STDIO</varname> containing
all the options related to standard I/O. If a user disables the
component as a whole then all the options below it become inactive: it
makes no sense to disable all stdio functionality and then manipulate
the buffer sizes.
</para>
<para>
Inactive is not quite the same as disabled, although the effects are
similar. The value of an inactive option is preserved. If the user
modifies a buffer size option, then disables the whole stdio
component, the buffer size value remains in case the stdio component
is re-enabled later on. Some tools such as the graphical configuration
tool will treat inactive options specially, for example such options
may be grayed out.
</para>
<para>
The active or inactive state of an option may affect other packages.
For example a package may use the <function>sprintf</function>
function and require support for floating point conversions, a
constraint that is not satisfied if the relevant option is inactive.
It is necessary to define exactly what it means for an option to be
inactive:
</para>
<orderedlist>
<listitem>
<para>
An option is inactive if its parent is either inactive or disabled.
For example if <varname>CYGPKG_LIBC_STDIO</varname> is disabled then
all the options and sub-components become inactive; since
<varname>CYGPKG_LIBC_STDIO_FLOATING_POINT</varname> is now inactive,
<varname>CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT</varname> is inactive
as well.
</para>
</listitem>
<listitem>
<para>
Options may also be inactive as a result of an &active-if; property.
This is useful if a particular option is only relevant if two or more
disjoint sets of conditions need to be satisfied, since the
hierarchical structure can only cope with at most one such set.
</para>
</listitem>
<listitem>
<para>
If an option is inactive then any references to that option in &CDL;
expressions will evaluate to <literal>0</literal>. Hence a constraint
of the form
<literal>requires CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT</literal>
is not satisfied if the entire stdio component is disabled.
</para>
</listitem>
<listitem>
<para>
An option that is inactive has no consequences on the build process.
No <literal>#define</literal> will be generated. Any &compile; or
similar properties will be ignored.
</para>
</listitem>
<listitem>
<para>
An option that is inactive cannot impose any constraints on the rest
of the configuration. For example
<varname>CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT</varname> has a
dependency <literal>requires CYGPKG_LIBM</literal>, but if all of
the stdio functionality is disabled then this constraint is ignored
(although of course there may be other packages which have a
dependency on <varname>CYGPKG_LIBM</varname>.
</para>
</listitem>
</orderedlist>
</sect3>
<!-- }}} -->
<!-- {{{ Enabled/data -->
<sect3 id="language.values.value.enabled">
<title>Is the Option Enabled? What is the Data?</title>
<para>
The majority of configuration options are boolean in nature, so the
user can either enable or disable some functionality. Some options are
different. For example <varname>CYGNUM_LIBC_STDIO_BUFSIZE</varname> is
a number, and <varname>CYGDAT_LIBC_STDIO_DEFAULT_CONSOLE</varname> is
a string corresponding to a device name. A few options like
<varname>CYGDAT_UITRON_TASK_EXTERNS</varname> can get very
complicated. &CDL; has to cope with this variety, and define the exact
behavior of the system in terms of constraints and build-time
consequences.
</para>
<para>
In &CDL; the value of an option consists of two parts. There is a
boolean part, controlling whether or not the option is enabled. There
is also a data part, providing additional information. For most
options one of these parts is fixed, as controlled by the option's
&flavor; property:
</para>
<informaltable frame="all" colsep=1 rowsep=1 pgwide=0 tocentry=0>
<tgroup cols=3 colsep=1 rowsep=1 align=left>
<thead>
<row>
<entry>Flavor</entry>
<entry>Enabled</entry>
<entry>Data</entry>
</row
</thead>
<tbody>
<row>
<entry><literal>none</literal></entry>
<entry>Always enabled</entry>
<entry><literal>1</literal>, not modifiable</entry>
</row>
<row>
<entry><literal>bool</literal></entry>
<entry>User-modifiable</entry>
<entry><literal>1</literal>, not modifiable</entry>
</row>
<row>
<entry><literal>data</literal></entry>
<entry>Always enabled</entry>
<entry>User-modifiable</entry>
</row>
<row>
<entry><literal>booldata</literal></entry>
<entry>User-modifiable</entry>
<entry>User-modifiable</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
The effects of the boolean and data parts are as follows:
</para>
<orderedlist>
<listitem>
<para>
If an option is disabled, in other words if the boolean part is false,
then any references to that option in &CDL; expressions will evaluate
to <literal>0</literal>. This is the same behavior as for inactive
options. The data part is not relevant. The <literal>none</literal>
and <literal>data</literal> flavors specify that the option is always
enabled, in which case this rule is not applicable.
</para>
</listitem>
<listitem>
<para>
If an option is enabled then any references to that option in &CDL;
expressions will evaluate to the option's data part. For two of the
flavors, <literal>none</literal> and <literal>bool</literal>, this
data part is fixed to the constant <literal>1</literal> which
generally has the expected result.
</para>
</listitem>
<listitem>
<para>
If a component or package is disabled then all sub-components and
options immediately below it in the hierarchy are inactive. By a
process of recursion this will affect all the nodes in the subtree.
</para>
</listitem>
<listitem>
<para>
If an option is disabled then it can impose no constraints on the rest
of the configuration, in particular &requires; and &legal-values;
properties will be ignored. If an option is enabled then its
constraints should be satisfied, or the component framework will
report various conflicts. Note that the &legal-values; constraint only
applies to the data part of the option's value, so it is only useful
with the <literal>data</literal> and <literal>booldata</literal>
flavors. Options with the <literal>none</literal> and
<literal>data</literal> flavors are always enabled so their
constraints always have to be satisfied (assuming the option is
active).
</para>
</listitem>
<listitem>
<para>
If an option is disabled then it has no direct consequences at
build-time: no <literal>#define</literal> will be generated, no files
will get compiled, and so on. If an option is active and enabled then
all the consequences take effect. The option name and data part are
used to generate the <literal>#define</literal> in the appropriate
configuration header file, subject to various properties such as
&no-define;, but the data part has no other effects on the build
system.
</para>
</listitem>
</orderedlist>
<para>
By default all options and components have the <literal>bool</literal>
flavor: most options are boolean in nature, so making this the default
allows for slightly more compact &CDL; scripts. Packages have the
<literal>booldata</literal> flavor, where the data part always
corresponds to the version of the package that is loaded into the
configuration: changing this value corresponds to unloading the old
version and loading in a different one.
</para>
<note>
<title>&CDL; Flavors</title>
<para>
The concept of &CDL; flavors tends to result in various discussions
about why it is unnecessarily complicated, and would it not have been
easier to do … However there are very good reasons why CDL
works the way it does.
</para>
<para>
The first common suggestion is that there is no need to have separate
flavors <literal>bool</literal>, <literal>data</literal>, and so on. A
boolean option could just be handled as a data option with legal
values <literal>0</literal> and <literal>1</literal>. The counter
arguments are as follows:
</para>
<orderedlist>
<listitem>
<para>
It would actually make &CDL; scripts more verbose. By default all
options and components have the <literal>bool</literal> flavor, since
most options are boolean in nature. Without a <literal>bool</literal>
flavor it would be necessary to indicate explicitly what the legal
values are somehow, e.g. with a &legal-values; property.
</para>
</listitem>
<listitem>
<para>
The boolean part of an option's value has a very different effect from
the data part. If an option is disabled then it has no consequences at
build time, and can impose no constraints. A <literal>data</literal>
option always has consequences and can impose constraints. To get the
desired effect it would be necessary to add &CDL; data indicating that
a value of <literal>0</literal> should be treated specially. Arguably
this could be made built-in default behavior, although that would
complicate options where <literal>0</literal> is a perfectly legal
number, for example
<varname>CYGNUM_LIBC_TIME_STD_DEFAULT_OFFSET</varname>.
</para>
</listitem>
<listitem>
<para>
There would no replacement for a <literal>booldata</literal> option
for which <literal>0</literal> is a valid value. Again some additional
&CDL; syntax would be needed to express such a concept.
</para>
</listitem>
</orderedlist>
<para>
Although initially it may seem confusing that an option's value has
both a boolean and a data part, it is an accurate reflection of how
configuration options actually work. The various alternatives would
all make it harder to write &CDL; scripts.
</para>
<para>
The next common suggestion is that the data part of a value should be
typed in much the same way as C or C++ data types. For example it
should be possible to describe
<varname>CYGNUM_LIBC_STDIO_BUFSIZE</varname> as an integer value,
rather than imposing &legal-values; constraints. Again there are very
good reasons why this approach was not taken:
</para>
<orderedlist>
<listitem>
<para>
The possible legal values for an integer are rarely correct for a
&CDL; option. A constraint such as
<literal>1 to 0x7fffffff</literal> is a bit more accurate,
although if this option indicates a buffer size it is still not
particularly good — very few targets will have enough
memory for such a buffer. Forcing &CDL; writers to list the
&legal-values; constraints explicitly should make them think a bit
more about what values are actually sensible. For example
<varname>CYGNUM_LIBC_TIME_DST_DEFAULT_OFFSET</varname> has legal
values in the range <literal>-90000 to 90000</literal>,
which helps the user to set a sensible value.
</para>
</listitem>
<listitem>
<para>
Not all options correspond to simple data types such as integers.
<varname>CYGDAT_LIBC_STDIO_DEFAULT_CONSOLE</varname> is a C string,
and would have to be expressed using something like
<literal>char []</literal>. This introduces plenty of
opportunities for confusion, especially since square brackets may get
processed by the &Tcl; interpreter for command substitution.
</para>
</listitem>
<listitem>
<para>
Some configuration options can get very complicated indeed, for
example the default value of
<varname>CYGDAT_UITRON_TASK_INITIALIZERS</varname> is:
</para>
<programlisting width=72>
CYG_UIT_TASK( "t1", 1, task1, &stack1, CYGNUM_UITRON_STACK_SIZE ), \
CYG_UIT_TASK( "t2", 2, task2, &stack2, CYGNUM_UITRON_STACK_SIZE ), \
CYG_UIT_TASK( "t3", 3, task3, &stack3, CYGNUM_UITRON_STACK_SIZE ), \
CYG_UIT_TASK( "t4", 4, task4, &stack4, CYGNUM_UITRON_STACK_SIZE )
</programlisting>
<para>
This would require &CDL; knowing about C macros, structures, arrays,
static initializers, and so on. Adding such detailed knowledge about
the C language to the component framework is inappropriate.
</para>
</listitem>
<listitem>
<para>
&CDL; needs to be usable with languages other than C. At present this
includes C++, in future it may include languages such as Java. Each
language adds new data types and related complications, for example
C++ classes and inheritance. Making &CDL; support a union of all data
types in all possible languages is not sensible.
</para>
</listitem>
</orderedlist>
<para>
The &CDL; approach of treating all data as a sequence of characters,
possibly constrained by a &legal-values; property or other means, has
the great advantage of simplicity. It also fits in with the &Tcl;
language that underlies &CDL;.
</para>
</note>
</sect3>
<!-- }}} -->
<!-- {{{ Examples -->
<sect3 id="language.values.value.examples">
<title>Some Examples</title>
<para>
The following excerpt from the C library's &CDL; scripts can be used
to illustrate how values and flavors work in practice:
</para>
<programlisting width=72>
cdl_component CYGPKG_LIBC_RAND {
flavor none
compile stdlib/rand.cxx
cdl_option CYGSEM_LIBC_PER_THREAD_RAND {
requires CYGVAR_KERNEL_THREADS_DATA
default_value 0
}
cdl_option CYGNUM_LIBC_RAND_SEED {
flavor data
legal_values 0 to 0x7fffffff
default_value 1
}
cdl_option CYGNUM_LIBC_RAND_TRACE_LEVEL {
flavor data
legal_values 0 to 1
default_value 0
}
}
</programlisting>
<para>
If the application does not require any C library functionality then
it is possible to have a configuration where the C library is not
loaded. This can be achieved by starting with the minimal template, or
by starting with another template such as the default one and then
explicitly unloading the C library package. If this package is not
loaded then any references to the <varname>CYGPKG_LIBC_RAND</varname>
component or any of its options will have a value of
<literal>0</literal> for the purposes of expression evaluation. No
<literal>#define's</literal> will be generated for the component or
any of its options, and the file <filename>stdlib/rand.cxx</filename>
will not get compiled. There is nothing special about the C library
here, exactly the same would apply for say a device driver that does
not correspond to any of the devices on the target hardware.
</para>
<para>
Assuming the C library is loaded, the next thing to consider is
whether or not the component and its options are active. The component
is layered immediately below the C library package itself, so if the
package is loaded then it is safe to assume that the package is also
enabled. Therefore the parent of <varname>CYGPKG_LIBC_RAND</varname>
is active and enabled, and in the absence of any &active-if;
properties <varname>CYGPKG_LIBC_RAND</varname> will be active as well.
</para>
<para>
The component <varname>CYGPKG_LIBC_RAND</varname> has the flavor
<literal>none</literal>. This means the component cannot be disabled.
Therefore all the options in this component have an active and enabled
parent, and in the absence of any &active-if; properties they are all
active as well.
</para>
<para>
The component's flavor <literal>none</literal> serves to group
together all of the configuration options related to random number
generation. This is particularly useful in the context of the
graphical configuration tool, but it also helps when it comes to
naming the options: all of the options begin with
<literal>CYGxxx_LIBC_RAND</literal>, giving a clear hint about both
the package and the component within that package. The flavor means
that the component is always enabled and has the value
<literal>1</literal> for the purposes of expression evaluation. There
will always be a single <literal>#define</literal> of the form:
</para>
<programlisting width=72>
#define CYGPKG_LIBC_RAND 1
</programlisting>
<para>
In addition the file <filename>stdlib/rand.cxx</filename> will always
get built. If the component had the default <literal>bool</literal>
flavor then users would be able to disable the whole component,
and one less file would need to be built. However random number
generation is relatively simple, so the impact on eCos build times are
small. Furthermore by default the code has no dependencies on other
parts of the system, so compiling the code has no unexpected side
effects. Even if it was possible to disable the component, the
sensible default for most applications would still leave it enabled.
The net result is that the flavor <literal>none</literal> is probably
the most sensible one for this component. For other components the
default <literal>bool</literal> flavor or one of the other flavors
might be more appropriate.
</para>
<para>
Next consider option <varname>CYGSEM_LIBC_PER_THREAD_RAND</varname>
which can be used to get a per-thread random number seed, possibly
useful if the application needs a consistent sequence of random
numbers. In the absence of a &flavor; property this option will be
boolean, and the &default-value; property means that it is disabled by
default — reasonable since few applications need this
particular functionality, and it does impose a constraint on the rest
of the system. If the option is left disabled then no
<literal>#define</literal> will be generated, and if there were any
&compile; or similar properties these would not take effect. If the
option is enabled then a <literal>#define</literal> will be generated,
using the option's data part which is fixed at <literal>1</literal>:
</para>
<programlisting width=72>
#define CYGSEM_LIBC_PER_THREAD_RAND 1
</programlisting>
<para>
The <varname>CYGSEM_LIBC_PER_THREAD_RAND</varname> option has a
&requires; constraint on
<varname>CYGVAR_KERNEL_THREADS_DATA</varname>. If the C library option
is enabled then the constraint should be satisfied, or else the
configuration contains a conflict. If the configuration does not
include the kernel package then
<varname>CYGVAR_KERNEL_THREADS_DATA</varname> will evaluate to
<literal>0</literal> and the constraint is not satisfied. Similarly if
the option is inactive or disabled the constraint will not be
satisfied.
</para>
<para>
<varname>CYGNUM_LIBC_RAND_SEED</varname> and
<varname>CYGNUM_LIBC_RAND_TRACE_LEVEL</varname> both have the
<literal>data</literal> flavor, so they are always enabled and the
component framework will generate appropriate
<literal>#define's</literal>:
</para>
<programlisting width=72>
#define CYGNUM_LIBC_RAND_SEED 1
#define CYGNUM_LIBC_RAND_SEED_1
#define CYGNUM_LIBC_RAND_TRACE_LEVEL 0
#define CYGNUM_LIBC_RAND_TRACE_LEVEL_0
</programlisting>
<para>
Neither option has a &compile; or similar property, but any such
properties would take effect. Any references to these options in &CDL;
expressions would evaluate to the data part, so a hypothetical
constraint of the form
<literal>{ requires CYGNUM_LIBC_RAND_SEED > 42 }</literal>
would not be satisfied with the default values. Both options use a
simple constant for the &default-value; expression. It would be
possible to use a more complicated expression, for example the default
for <varname>CYGNUM_LIBC_RAND_TRACE_LEVEL</varname> could be
determined from some global debugging option or from a debugging
option that applies to the C library as a whole. Both options also
have a &legal-values; constraint, which must be satisfied since the
options are active and enabled.
</para>
<note>
<para>
The value <literal>0</literal> is legal for both
<varname>CYGNUM_LIBC_RAND_SEED</varname> and
<varname>CYGNUM_LIBC_RAND_TRACE_LEVEL</varname>, so in a &CDL;
expression there is no easy way of distinguishing between the options
being absent or having that particular value. This will be addressed
by future enhancements to the expression syntax.
</para>
</note>
</sect3>
<!-- }}} -->
</sect2>
<!-- }}} -->
<!-- {{{ Expressions -->
<sect2 id="language.expression">
<title>Ordinary Expressions</title>
<para>
Expressions in &CDL; follow a conventional syntax, for example:
</para>
<programlisting width=72>
default_value CYGGLO_CODESIZE > CYGGLO_SPEED
default_value { (CYG_HAL_STARTUP == "RAM" &&
!CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS &&
!CYGINT_HAL_USE_ROM_MONITOR_UNSUPPORTED &&
!CYGSEM_HAL_POWERPC_COPY_VECTORS) ? 1 : 0 }
default_value { "\"/dev/ser0\"" }
</programlisting>
<para>
However there is a complication in that the various arguments to a
&default-value; property will first get processed by a &Tcl;
interpreter, so special characters like quotes and square brackets may
get processed. Such problems can be avoided by enclosing non-trivial
expressions in braces, as in the second example above. The way
expression parsing actually works is as follows:
</para>
<orderedlist>
<listitem>
<para>
The &Tcl; interpreter splits the line or lines into a command and its
arguments. In the first &default-value; expression above the command
is <literal>default_value</literal> and there are three arguments,
<literal>CYGGLO_CODESIZE</literal>, <literal>></literal> and
<literal>CYGGLO_SPEED</literal>. In the second and third examples
there is just one argument, courtesy of the braces.
</para>
</listitem>
<listitem>
<para>
Next option processing takes place, so any initial arguments that
begin with a hyphen will be interpreted as options. This can cause
problems if the expression involves a negative number, so the
special argument <literal>--</literal> can be used to prevent option
processing on the subsequent arguments.
</para>
</listitem>
<listitem>
<para>
All of the arguments are now concatenated, with a single space in
between each one. Hence the following two expressions are equivalent,
even though they will have been processed differently up to this point.
</para>
<programlisting>
default_value CYGGLO_CODESIZE > CYGGLO_SPEED
default_value {CYGGLO_CODESIZE > CYGGLO_SPEED}
</programlisting>
</listitem>
<listitem>
<para>
The expression parsing code now has a single string to process.
</para>
</listitem>
</orderedlist>
<para>
&CDL; expressions consist of four types of element: references to
configuration options, constant strings, integers, and floating point
numbers. These are combined using a conventional set of operators: the
unary operators <literal>-</literal>, <literal>~</literal> and
<literal>!</literal>; the arithmetic operators <literal>+</literal>,
<literal>-</literal>, <literal>*</literal>, <literal>/</literal> and
<literal>%</literal>; the shift operators <literal><<</literal>
and <literal>>></literal>; the comparison operators
<literal>==</literal>, <literal>!=</literal>, <literal><</literal>,
<literal><=</literal>, <literal>></literal> and
<literal>>=</literal>; the bitwise operators
<literal>&</literal>, <literal>^</literal> and
<literal>|</literal>; the logical operators <literal>&&</literal> and
<literal>||</literal>; the string concatenation operator
<literal>.</literal>; and the ternary conditional operator
<literal>A ? B : C</literal>. There is also support for
some less widely available operators for logical equivalence and
implication, and for a set of function-style operations. Bracketed
sub-expressions are supported, and the operators have the usual
precedence:
</para>
<informaltable frame="all" pgwide=0 colsep=1 rowsep=1>
<tgroup cols=3 align="left" colsep=1 rowsep=1>
<colspec colnum=1 align="center">
<colspec colnum=2 align="center">
<colspec colnum=3 align="center">
<thead>
<row>
<entry>Priority</entry>
<entry>Operators</entry>
<entry>Category</entry>
</row>
</thead>
<tbody>
<row>
<entry>16</entry>
<entry>references, constants</entry>
<entry>basic elements</entry>
</row>
<row>
<entry>15</entry>
<entry><literal>f(a, b, c)</literal></entry>
<entry>function calls</entry>
</row>
<row>
<entry>14</entry>
<entry><literal>~</literal></entry>
<entry>bitwise not</entry>
</row>
<row>
<entry>14</entry>
<entry><literal>!</literal></entry>
<entry>logical not</entry>
</row>
<row>
<entry>14</entry>
<entry><literal>-</literal></entry>
<entry>arithmetic negation</entry>
</row>
<row>
<entry>13</entry>
<entry><literal>* / %</literal></entry>
<entry>multiplicative arithmetic</entry>
</row>
<row>
<entry>12</entry>
<entry><literal>+ - .</literal></entry>
<entry>additive arithmetic and string concatenation</entry>
</row>
<row>
<entry>11</entry>
<entry><literal><< >></literal></entry>
<entry>bitwise shifts</entry>
</row>
<row>
<entry>10</entry>
<entry><literal><= < > >=</literal></entry>
<entry>inequality</entry>
</row>
<row>
<entry>9</entry>
<entry><literal>== !=</literal></entry>
<entry>comparison</entry>
</row>
<row>
<entry>8</entry>
<entry><literal>&</literal></entry>
<entry>bitwise and</entry>
</row>
<row>
<entry>7</entry>
<entry><literal>^</literal></entry>
<entry>bitwise xor</entry>
</row>
<row>
<entry>6</entry>
<entry><literal>|</literal></entry>
<entry>bitwise or</entry>
</row>
<row>
<entry>5</entry>
<entry><literal>&&</literal></entry>
<entry>logical and</entry>
</row>
<row>
<entry>4</entry>
<entry><literal>||</literal></entry>
<entry>logical or</entry>
</row>
<row>
<entry>3</entry>
<entry><literal>xor, eqv</literal></entry>
<entry>logical equivalance</entry>
</row>
<row>
<entry>2</entry>
<entry><literal>implies</literal></entry>
<entry>logical implication</entry>
</row>
<row>
<entry>1</entry>
<entry><literal>? :</literal></entry>
<entry>conditional</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
Function calls have the usual format of a name, an opening bracket,
one or more arguments separated by commas, and a closing bracket. For
example:
</para>
<programlisting width=72>
requires { !is_substr(CYGBLD_GLOBAL_CFLAGS, " -fno-rtti") }
</programlisting>
<para>
Functions will differ in the number of arguments and may impose
restrictions on some or all of their arguments. For example it may be
necessary for the first argument to be a reference to a configuration
option. The available functions are described in <xref
linkend="language.functions">.
</para>
<para>
The logical <literal>xor</literal> operator evaluates to true if
either the left hand side or the right hand side but not both evaluate
to true The logical <literal>eqv</literal> operator evaluates to true
if both the left and right hand sides evaluate to true, or if both
evaluate to false. The <literal>implies</literal> operator evaluates
to true either if the left hand side is false or if the right hand
side is true, in other words <literal>A implies B</literal>
has the same meaning as <literal>!A || B</literal>. An
example use would be:
</para>
<programlisting width=72>
requires { is_active(CYGNUM_LIBC_MAIN_DEFAULT_STACK_SIZE) implies
(CYGNUM_LIBC_MAIN_DEFAULT_STACK_SIZE >= (16 * 1024)) }
</programlisting>
<para>
This constraint would be satisfied if either the support for a main
stack size is disabled, or if that stack is at least 16K. However if
such a stack were in use but was too small, a conflict would be raised.
</para>
<para>
A valid &CDL; identifier in an expression, for example
<varname>CYGGLO_SPEED</varname>, will be interpreted as a reference to
a configuration option by that name. The option does not have to be
loaded into the current configuration. When the component framework
evaluates the expression it will substitute in a suitable value that
depends on whether or not the option is loaded, active, and enabled.
The exact rules are described in <xref
linkend="language.values.value">.
</para>
<para>
A constant string is any sequence of characters enclosed in quotes.
Care has to be taken that these quotes are not stripped off by the
&Tcl; interpreter before the &CDL; expression parser sees them.
Consider the following:
</para>
<programlisting width=72>
default_value "RAM"
</programlisting>
<para>
The quote marks will be stripped before the &CDL; expression parser
sees the data, so the expression will be interpreted as a reference to
a configuration option <varname>RAM</varname>. There is unlikely to be
such an option, so the actual default value will be
<literal>0</literal>. Careful use of braces or other &Tcl; quoting
mechanisms can be used to avoid such problems.
</para>
<para>
String constants consist of the data inside the quotes. If the data
itself needs to contain quote characters then appropriate quoting is
again necessary, for example:
</para>
<programlisting width=72>
default_value { "\"/dev/ser0\"" }
</programlisting>
<para>
An integer constant consists of a sequence of digits, optionally
preceeded with the unary <literal>+</literal> or <literal>-</literal>
operators. As usual the sequence <literal>0x</literal> or
<literal>0X</literal> can be used for hexadecimal data, and a leading
<literal>0</literal> indicates octal data. Internally the component
framework uses 64-bit arithmetic for integer data. If a constant is
too large then double precision arithmetic will be used instead.
Traditional syntax is also used for double precision numbers, for
example <literal>3.141592</literal> or <literal>-3E6</literal>.
</para>
<para>
Of course this is not completely accurate: &CDL; is not a typed
language, all data is treated as if it were a string. For example the
following two lines are equivalent:
</para>
<programlisting width=72>
requires CYGNUM_UITRON_SEMAS > 10
requires { CYGNUM_UITRON_SEMAS > "10" }
</programlisting>
<para>
When an expression gets evaluated the operators will attempt
appropriate conversions. The <literal>></literal> comparison
operator can be used on either integer or double precision numbers, so
it will begin by attempting a string to integer conversion of both
operands. If that fails it will attempt string to double conversions.
If that fails as well then the component framework will report a
conflict, an evaluation exception. If the conversions from string to
integer are successful then the result will be either the string
<literal>0</literal> or the string <literal>1</literal>, both of which
can be converted to integers or doubles as required.
</para>
<para>
It is worth noting that the expression
<literal>CYGNUM_UITRON_SEMAS >10</literal> is not ambiguous.
&CDL; identifiers can never begin with a digit, so it is not possible
for <literal>10</literal> to be misinterpreted as a reference to an
identifier instead of as a string.
</para>
<para>
Of course the implementation is slightly different again. The &CDL;
language definition is such that all data is treated as if it were a
string, with conversions to integer, double or boolean as and when
required. The implementation is allowed to avoid conversions until
they are necessary. For example, given
<literal>CYGNUM_UITRON_SEMAS > 10</literal> the
expression parsing code will perform an immediate conversion from
string to integer, storing the integer representation, and there is no
need for a conversion by the comparison operator when the expression
gets evaluated. Given
<literal>{ CYGNUM_UITRON_SEMAS > "10" }</literal>
the parsing code will store the string representation and a conversion
happens the first time the expression is evaluated. All of this is an
implementation detail, and does not affect the semantics of the
language.
</para>
<para>
Different operators have different requirements, for example the
bitwise or operator only makes sense if both operands have an integer
representation. For operators which can work with either integer or
double precision numbers, integer arithmetic will be preferred.
</para>
<para>
The following operators only accept integer operands:
unary <literal>~</literal> (bitwise not), the shift operators
<literal><<</literal> and <literal>>></literal>, and the
bitwise operators <literal>&</literal>, <literal>|</literal> and
<literal>^</literal>.
</para>
<para>
The following operators will attempt integer arithmetic first, then
double precision arithmetic: unary <literal>-</literal>,
the arithmetic operators <literal>+</literal>, <literal>-</literal>,
<literal>*</literal>, <literal>/</literal>, and <literal>%</literal>;
and the comparision operators <literal><</literal>,
<literal><=</literal>, <literal>></literal> and
<literal>>=</literal>.
</para>
<para>
The equality <literal>==</literal> and inequality
<literal>!=</literal> operators will first attempt integer conversion
and comparison. If that fails then double precision will be attempted
(although arguably using these operators on double precision data is
not sensible). As a last resort string comparison will be used.
</para>
<para>
The operators <literal>!</literal>, <literal>&&</literal> and
<literal>||</literal> all work with boolean data. Any string that can
be converted to the integer <literal>0</literal> or the double
<literal>0.0</literal> is treated as false, as is the empty string or
the constant string <literal>false</literal>. Anything else is
interpreted as true. The result is either <literal>0</literal> or
<literal>1</literal>.
</para>
<para>
The conditional operator <literal>? :</literal> will interpret
its first operand as a boolean. It does not perform any processing on
the second or third operands.
</para>
<para>
In practice it is rarely necessary to worry about any of these
details. In nearly every case &CDL; expressions just work as expected,
and there is no need to understand the full details.
</para>
<note>
<para>
The current expression syntax does not meet all the needs of component
writers. Some future enhancements will definitely be made, others are
more controversial. The list includes the following:
</para>
<orderedlist>
<listitem>
<para>
An option's value is determined by several different factors: whether
or not it is loaded, whether or not it is active, whether or not it is
enabled, and the data part. Currently there is no way of querying
these individually. This is very significant in the context of options
with the <literal>bool</literal> or <literal>booldata</literal>
flavors, because there is no way of distinguishing between the option
being absent/inactive/disabled or it being enabled with a data field
of <literal>0</literal>. There should be unary operators that allow
any of the factors to be checked.
</para>
</listitem>
<listitem>
<para>
Only the <literal>==</literal> and <literal>!=</literal> operators can
be used for string data. More string-related facilities are needed.
</para>
</listitem>
<listitem>
<para>
An implies operator would be useful for many goal expression, where
<literal>A implies B</literal> is equivalent to
<literal>!A ||B</literal>.
</para>
</listitem>
<listitem>
<para>
Similarly there is inadequate support for lists. On occasion it would
be useful to write expressions involving say the list of implementors
of a given CDL interface, for example a sensible default value could
be the first implementor. Associated with this is a need for an
indirection operator.
</para>
</listitem>
<listitem>
<para>
Arguably extending the basic &CDL; expression syntax with lots of new
operators is unnecessary, instead expressions should just support
&Tcl; command substitution and then component writers could escape
into &Tcl; scripts for complicated operations. This has some major
disadvantages. First, the inference engine would no longer have any
sensible way of interpreting an expression to resolve a conflict.
Second, the component framework's value propagation code keeps track
of which options get referenced in which expressions and avoids
unnecessary re-evaluation of expressions; if expressions can involve
arbitrary &Tcl; code then there is no simple way to eliminate
unnecessary recalculations, with a potentially major impact on
performance.
</para>
</listitem>
</orderedlist>
</note>
<note>
<para>
The current implementation of the component framework uses 64 bit
arithmetic on all host platforms. Although this is adequate for
current target architectures, it may cause problems in future. At some
stage it is likely that an arbitrary precision integer arithmetic
package will be used instead.
</para>
</note>
</sect2>
<!-- }}} -->
<!-- {{{ Functions -->
<sect2 id="language.functions">
<title>Functions</title>
<para>
CDL expressions can contain calls to a set of built-in functions
using the usual syntax, for example;
</para>
<programlisting width=72>
requires { !is_substr(CYGBLD_GLOBAL_CFLAGS, "-fno-rtti") }
</programlisting>
<para>
The available function calls are as follows:
</para>
<variablelist>
<!-- {{{ get_data() -->
<varlistentry>
<term><literal>get_data(option)</literal></term>
<listitem>
<para>
This function can be used to obtain just the data part of a loaded
configuration option, ignoring other factors such as whether or not
the option is active and enabled. It takes a single argument which
should be the name of a configuration option. If the specified option
is not loaded in the current configuration then the function returns
0, otherwise it returns the data part. Typically this function will
only be used in conjunction with <function>is_active</function> and
<function>is_enabled</function> for fine-grained control over the
various factors that make up an option's value.
</para>
</listitem>
</varlistentry>
<!-- }}} -->
<!-- {{{ is_active() -->
<varlistentry>
<term><literal>is_active(option)</literal></term>
<listitem>
<para>
This function can be used to determine whether or not a particular
configuration option is active. It takes a single argument which
should be the name of an option, and returns a boolean. If the
specified option is not loaded then the function will return false.
Otherwise it will consider the state of the option's parents and
evaluate any &active-if; properties, and return the option's current
active state. A typical use might be:
</para>
<programlisting width=72>
requires { is_active(CYGNUM_LIBC_MAIN_DEFAULT_STACK_SIZE) implies
(CYGNUM_LIBC_MAIN_DEFAULT_STACK_SIZE >= (16 * 1024)) }
</programlisting>
<para>
In other words either the specified configuration option must be
inactive, for example because the current application does not use
any related C library or POSIX functionality, or the stack size must
be at least 16K.
</para>
<para>
The configuration system's inference engine can attempt to satisfy
constraints involving <function>is_active</function> in various
different ways, for example by enabling or disabling parent
components, or by examining &active-if; properties and manipulating
terms in the associated expressions.
</para>
</listitem>
</varlistentry>
<!-- }}} -->
<!-- {{{ is_enabled() -->
<varlistentry>
<term><literal>is_enabled(option)</literal></term>
<listitem>
<para>
This function can be used to determine whether or not a particular
configuration option is enabled. It takes a single argument which
should be the name of an option, and returns a boolean. If the
specified option is not loaded then the function will return false.
Otherwise it will return the current boolean part of the option's
value. The option's active or inactive state is ignored. Typically
this function will be used in conjunction with
<function>is_active</function> and possibly
<function>get_data</function> to provide fine-grained control over the
various factors that make up an option's value.
</para>
</listitem>
</varlistentry>
<!-- }}} -->
<!-- {{{ is_loaded() -->
<varlistentry>
<term><literal>is_loaded(option)</literal></term>
<listitem>
<para>
This function can be used to determine whether or not a particular
configuration option is loaded. It takes a single argument which
should be the name of an option, and returns a boolean. If the
argument is a package then the <function>is_loaded</function> function
provides little or no extra information, for example the following two
constraints are usually equivalent:
</para>
<programlisting width=72>
requires { CYGPKG_KERNEL }
requires { is_loaded(CYGPKG_KERNEL) }
</programlisting>
<para>
However if the specified package is loaded but re-parented below a
disabled component, or inactive as a result of an &active-if;
property, then the first constraint would not be satisfied but the
second constraint would. In other words the
<function>is_loaded</function> makes it possible to consider in
isolation one of the factors that are considered when CDL expressions
are evaluated.
</para>
<para>
The configuration system's inference engine will not automatically
load or unload packages to satisfy <function>is_loaded</function>
constraints.
</para>
</listitem>
</varlistentry>
<!-- }}} -->
<!-- {{{ is_substr() -->
<varlistentry>
<term><literal>is_substr(haystack, needle)</literal></term>
<listitem>
<para>
This can be used to check whether or not a particular string is
present in another string. It is used mainly for manipulating compiler
flags. The function takes two arguments, both of which can be
arbitrary expressions, and returns a boolean.
</para>
<para>
<function>is_substr</function> has some understanding of word
boundaries. If the second argument starts with a space character then
that will match either a real space or the start of the string.
Similarly if the second argument ends with a space character then that
will match a real space or the end of the string. For example, all of
the following conditions are satisfied:
</para>
<programlisting width=72>
is_substr("abracadabra", "abra")
is_substr("abracadabra", " abra")
is_substr("hocus pocus", " pocus")
is_substr("abracadabra", "abra ")
</programlisting>
<para>
The first is an exact match. The second is a match because the leading
space matches the start of the string. The third is an exact match,
with the leading space matching an actual space. The fourth is a match
because the trailing space matches the end of the string. However, the
following condition is not satisfied.
</para>
<programlisting width=72>
is_substr("abracadabra", " abra ")
</programlisting>
<para>
This fails to match at the start of the string because the trailing
space is not matched by either a real space or the end of the string.
Similarly it fails to match at the end of the string.
</para>
<para>
If a constraint involving <function>is_substr</function> is not
satisfied and the first argument is a reference to a configuration
option, the inference engine will attempt to modify that option's
value. This can be achieved either by appending the second argument to
the current value, or by removing all occurrences of that argument
from the current value.
</para>
<programlisting width=72>
requires { !is_substr(CYGBLD_GLOBAL_CFLAGS, " -fno-rtti ") }
requires { is_substr(CYGBLD_GLOBAL_CFLAGS, " -frtti ") }
</programlisting>
<para>
When data is removed the leading and trailing spaces will be left. For
example, given an initial value of
<<varname>CYGBLD_GLOBAL_CFLAGS</varname> of
<literal>-g -fno-rtti -O2</literal> the result will be
<literal>-g -O2</literal> rather than <literal>-g-O2</literal>.
</para>
<para>
If exact matches are needed, the function
<function>is_xsubstr</function> can be used instead.
</para>
</listitem>
</varlistentry>
<!-- }}} -->
<!-- {{{ is_xsubstr() -->
<varlistentry>
<term><literal>is_xsubstr(haystack, needle)</literal></term>
<listitem>
<para>
This function checks whether or not the pattern string is an exact
substring of the string being searched. It is similar to
<function>is_substr</function> but uses exact matching only. In other
words, leading or trailing spaces have to match exactly and will not
match the beginning or end of the string being searched. The function
takes two arguments, both of which can be arbitrary expressions, and
returns a boolean. The difference between
<function>is_substr</function> and <function>is_xsubstr</function> is
illustrated by the following examples:
</para>
<programlisting width=72>
cdl_option MAGIC {
flavor data
default_value { "abracadabra" }
}
…
requires { is_substr(MAGIC, " abra") }
requires { is_xsubstr(MAGIC, " abra") }
</programlisting>
<para>
The first goal will be satisfied because the leading space in the
pattern matches the beginning of the string. The second goal will not
be satisfied initialy because there is no exact match, so the
inference engine is likely to update the value of
<varname>MAGIC</varname> to <literal>abracadabra abra</literal> which
does give an exact match.
</para>
</listitem>
</varlistentry>
<!-- }}} -->
<!-- {{{ version_cmp() -->
<varlistentry>
<term><literal>version_cmp(A, B)</literal></term>
<listitem>
<para>
This function is used primarily to check that a sufficiently recent
<link linkend="package.versions">version</link> of some other package
is being used. It takes two arguments, both of which can be arbitrary
expressions. In practice usually one of the arguments will be a
reference to a package and the other will be a constant version
string. The return value is -1 if the first argument is a more recent
version then the second, 0 if the two arguments correspond to
identical versions, and 1 if the first argument is an older version.
For example the following constraint can be used to indicate that the
current package depends on kernel functionality that only became
available in version 1.3:
</para>
<programlisting width=72>
requires { version_cmp(CYGPKG_KERNEL, "v1.3") <= 0 }
</programlisting>
</listitem>
</varlistentry>
<!-- }}} -->
</variablelist>
<note>
<para>
At this time it is not possible to define new functions inside a CDL
script. Instead functions can only be added at the C++ level, usually
by extending libcdl itself. This is partly because there is more to
CDL functions than simple evaluation: associated with most functions
is support for the inference engine, so that if a constraint involving
a function is not currently satisfied the system may be able to find a
solution automatically.
</para>
</note>
</sect2>
<!-- }}} -->
<!-- {{{ Goal expressions -->
<sect2 id="language.goal-expression">
<title>Goal Expressions</title>
<para>
The arguments to certain properties, notably &requires; and
&active-if;, constitute a goal expression. As with an ordinary
expression, all of the arguments get combined and then the expression
parser takes over. The same care has to be taken with constant strings
and anything else that may get processed by the Tcl interpreter, so
often a goal expression is enclosed entirely in braces and the
expression parsing code sees just a single argument.
</para>
<para>
A goal expression is basically just a sequence of ordinary
expressions, for example:
</para>
<programlisting width=72>
requires { CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
!CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
!CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT }
</programlisting>
<para>
This consists of three separate expressions, all of which should
evaluate to a non-zero result. The same expression could be written
as:
</para>
<programlisting width=72>
requires { CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS &&
!CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT &&
!CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT }
</programlisting>
<para>
Alternatively the following would have much the same effect:
</para>
<programlisting width=72>
requires CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
requires !CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
requires !CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
</programlisting>
<para>
Selecting between these alternatives is largely a stylistic choice.
The first is slightly more concise than the others. The second is more
likely to appeal to mathematical purists. The third is more amenable
to cutting and pasting.
</para>
<para>
The result of evaluating a goal expression is a boolean. If any part
of the goal expression evaluates to the integer <literal>0</literal>
or an equivalent string then the result is false, otherwise it is
true.
</para>
<para>
The term “goal expression” relates to the component
framework's inference engine: it is a description of a goal that
should be satisfied for a conflict-free configuration. If a &requires;
constraint is not satisfied then the inference engine will examine the
goal expression: if there is some way of changing the configuration
that does not introduce new conflicts and that will cause the goal
expression to evaluate to true, the conflict can be resolved.
</para>
<para>
The inference engine works with one conflict and hence one goal
expression at a time. This means that there can be slightly different
behavior if a constraint is specified using a single &requires;
property or several different ones. Given the above example, suppose
that none of the three conditions are satisfied. If a single goal
expression is used then the inference engine might be able to satisfy
only two of the three parts, but since the conflict as a whole cannot
be resolved no part of the solution will be applied. Instead the user
will have to resolve the entire conflict. If three separate goal
expressions are used then the inference engine might well find
solutions to two of them, leaving less work for the user. On the other
hand, if a single goal expression is used then the inference engine
has a bit more information to work with, and it might well find a
solution to the entire conflict where it would be unable to find
separate solutions for the three parts. Things can get very
complicated, and in general component writers should not worry about
the subtleties of the inference engine and how to manipulate its
behavior.
</para>
<para>
It is possible to write ambiguous goal expressions, for example:
</para>
<programlisting width=72>
requires CYGNUM_LIBC_RAND_SEED -CYGNUM_LIBC_RAND_TRACE_LEVEL > 5
</programlisting>
<para>
This could be parsed in two ways:
</para>
<programlisting width=72>
requires ((CYGNUM_LIBC_RAND_SEED - CYGNUM_LIBC_RAND_TRACE_LEVEL) > 5)
requires CYGNUM_LIBC_RAND_SEED && ((-CYGNUM_LIBC_RAND_TRACE_LEVEL) > 5)
</programlisting>
<para>
The goal expression parsing code will always use the largest ordinary
expression for each goal, so the first interpretation will be used.
In such cases it is a good idea to use brackets and avoid possible
confusion.
</para>
</sect2>
<!-- }}} -->
<!-- {{{ List expressions -->
<sect2 id="language.list-expression">
<title>List Expressions</title>
<para>
The arguments to the &legal-values; property constitute a goal
expression. As with an ordinary and goal expressions, all of the
arguments get combined and then the expression parser takes over. The
same care has to be taken with constant strings and anything else that
may get processed by the Tcl interpreter, so often a list expression
is enclosed entirely in braces and the expression parsing code sees
just a single argument.
</para>
<para>
Most list expressions take one of two forms:
</para>
<programlisting width=72>
legal_values <expr1> <expr2> <expr3> ...
legal_values <expr1> to <expr2>
</programlisting>
<para>
<literal>expr1</literal>, <literal>expr2</literal> and so on are
ordinary expressions. Often these will be constants or references to
calculated options in the architectural HAL package, but it is
possible to use arbitrary expressions when necessary. The first syntax
indicates a list of possible values, which need not be numerical. The
second syntax indicates a numerical range: both sides of the
<literal>to</literal> must evaluate to a numerical value; if either
side involves a floating point number then any floating point number
in that range is legal; otherwise only integer values are legal;
ranges are inclusive, so <literal>4</literal> is a valid value given a
list expression <literal>1 to </literal>; if one or both
sides of the <literal>to</literal> does not evaluate to a numerical
value then this will result in a run-time conflict. The following
examples illustrate these possibilities:
</para>
<programlisting width=72>
legal_values { "red" "green" "blue" }
legal_values 1 2 4 8 16
legal_values 1 to CYGARC_MAXINT
legal_values 1.0 to 2.0
</programlisting>
<para>
It is possible to combine the two syntaxes, for example:
</para>
<programlisting width=72>
legal_values 1 2 4 to CYGARC_MAXINT -1024 -20.0 to -10
</programlisting>
<para>
This indicates three legal values <literal>1</literal>,
<literal>2</literal> and <literal>-1024</literal>, one
integer range <literal>4 to CYGARC_MAXINT</literal>, and one
floating point range <literal>-20.0 to -10.0</literal>. In
practice such list expressions are rarely useful.
</para>
<para>
The identifier <varname>to</varname> is not reserved, so it is
possible to have a configuration option with that name (although it
violates every naming convention). Using that option in a list
expression may however give unexpected results.
</para>
<para>
The graphical configuration tool uses the &legal-values; list
expression to determine how best to let users manipulate the option's
value. Different widgets will be appropriate for different lists, so
<literal>{ "red" "green" "blue" }</literal> might
involve a pull-down option menu, and
<literal>1 to 16</literal> could involve a spinner. The
exact way in which &legal-values; lists get mapped on to GUI widgets
is not defined and is subject to change at any time.
</para>
<para>
As with goal expressions, list expressions can be ambiguous. Consider
the following hypothetical example:
</para>
<programlisting width=72>
legal_values CYGNUM_LIBC_RAND_SEED -CYGNUM_LIBC_RAND_TRACE_LEVEL
</programlisting>
<para>
This could be parsed in two ways:
</para>
<programlisting width=72>
legal_values (CYGNUM_LIBC_RAND_SEED - CYGNUM_LIBC_RAND_TRACE_LEVEL)
legal_values (CYGNUM_LIBC_RAND_SEED) (-CYGNUM_LIBC_RAND_TRACE_LEVEL)
</programlisting>
<para>
Both are legal. The list expression parsing code will always use the
largest ordinary expression for each element, so the first
interpretation will be used. In cases like this it is a good idea to
use brackets and avoid possible confusion.
</para>
</sect2>
<!-- }}} -->
</sect1>
<!-- }}} -->
<!-- {{{ Interfaces -->
<!-- FIXME: Maybe the use of interfaces in generic drivers should be
used - if only because interfaces are not really a good solution for
what we need there (the generic driver cannot contain the
cdl_interface and be active_if on it, since it'll result in other
packages not being able to implement the interface.) -->
<sect1 id="language.interface">
<title>Interfaces</title>
<para>
For many configurability requirements, options provide sufficient
expressive power. However there are times when a higher level of
abstraction is appropriate. As an example, suppose that some package
relies on the presence of code that implements the standard kernel
scheduling interface. However the requirement is no more stringent
than this, so the constraint can be satisfied by the mlqueue
scheduler, the bitmap scheduler, or any additional schedulers that may
get implemented in future. A first attempt at expressing the
dependency might be:
</para>
<programlisting width=72>
requires CYGSEM_KERNEL_SCHED_MLQUEUE || CYGSEM_KERNEL_SCHED_BITMAP
</programlisting>
<para>
This constraint will work with the current release, but it is limited.
Suppose there is a new release of the kernel which adds another
scheduler such as a deadline scheduler, or suppose that there is a new
third party package which adds such a scheduler. The package
containing the limited constraint would now have to be updated and
another release made, with possible knock-on effects.
</para>
<para>
&CDL; interfaces provide an abstraction mechanism: constraints can be
expressed in terms of an abstract concept, for example
“scheduler”, rather than specific implementations such as
<varname>CYGSEM_KERNEL_SCHED_MLQUEUE</varname> and
<varname>CYGSEM_KERNEL_SCHED_BITMAP</varname>. Basically an interface
is a calculated configuration option:
</para>
<programlisting width=72>
cdl_interface CYGINT_KERNEL_SCHEDULER {
display "Number of schedulers in this configuration"
…
}
</programlisting>
<para>
The individual schedulers can then implement this interface:
</para>
<programlisting width=72>
cdl_option CYGSEM_KERNEL_SCHED_MLQUEUE {
display "Multi-level queue scheduler"
default_value 1
implements CYGINT_KERNEL_SCHEDULER
…
}
cdl_option CYGSEM_KERNEL_SCHED_BITMAP {
display "Bitmap scheduler"
default_value 0
implements CYGINT_KERNEL_SCHEDULER
…
}
</programlisting>
<para>
Future schedulers can also implement this interface. The value of an
interface, for the purposes of expression evaluation, is the number of
active and enabled options which implement this interface. Packages
which rely on the presence of a scheduler can impose constraints such
as:
</para>
<programlisting width=72>
requires CYGINT_KERNEL_SCHEDULER
</programlisting>
<para>
If none of the schedulers are enabled, or if the kernel package is not
loaded, then <varname>CYGINT_KERNEL_SCHEDULER</varname> will evaluate
to <literal>0</literal>. If at least one scheduler is active and
enabled then the constraint will be satisfied.
</para>
<para>
Because interfaces have a calculated value determined by the
implementors, the &default-value; and &calculated; properties are not
applicable and should not appear in the body of a &cdl-interface;
command. Interfaces have the <literal>data</literal> flavor by
default, but the <literal>bool</literal> and
<literal>booldata</literal> flavors may be specified instead. A
<literal>bool</literal> interface is disabled if there are no active
and enabled implementors, otherwise it is enabled. A
<literal>booldata</literal> interface is disabled if there are no
active and enabled implementors, otherwise it is enabled and has a
value corresponding to the number of these implementors. Other
properties such as &requires; and &compile; can be used as normal.
</para>
<para>
Some component writers will not want to use interfaces in this way.
The reasoning is that their code will only have been tested with the
existing schedulers, so the &requires; constraint needs to be
expressed in terms of those schedulers; it is possible that the
component will still work with a new scheduler, but there are no
guarantees. Other component writers may take a more optimistic view
and assume that their code will work with any scheduler until proven
otherwise. It is up to individual component writers to decide which
approach is most appropriate in any given case.
</para>
<para>
One common use for interfaces is to describe the hardware
functionality provided by a given target. For example the &CDL;
scripts for a TCP/IP package might want to know whether or not the
target hardware has an ethernet interface. Generally it is not
necessary for the TCP/IP stack to know exactly which ethernet hardware
is present, since there should be a device driver which implements the
appropriate functionality. In &CDL; terms the device drivers should
implement an interface <varname>CYGHWR_NET_DRIVERS</varname>, and the
&CDL; scripts for the TCP/IP stack can use this in appropriate
expressions.
</para>
<note>
<para>
Using the term <emphasis>interface</emphasis> for this concept is
sometimes confusing, since the term has various other meanings as
well. In practice, it is often correct. If there is a configuration
option that implements a given &CDL; interface, then usually this
option will enable some code that provides a particular interface at
the C or C++ level. For example an ethernet device driver implements
the &CDL; interface <varname>CYGHWR_NET_DRIVERS</varname>, and also
implements a set of C functions that can be used by the TCP/IP stack.
Similarly <varname>CYGSEM_KERNEL_SCHED_MLQUEUE</varname> implements
the &CDL; interface <varname>CYGINT_KERNEL_SCHEDULER</varname> and
also provides the appropriate scheduling functions.
</para>
</note>
</sect1>
<!-- }}} -->
<!-- {{{ Package database -->
<sect1 id="language.database">
<title>Updating the <database>ecos.db</database> database</title>
<para>
The current implementation of the component framework requires that
all packages be present in a single component repository and listed in
that repository's <database>ecos.db</database> database. This is not
generally a problem for application developers who can consider the
component repository a read-only resource, except when adding or
removing packages via the administration tool. However it means that
component writers need to do their development work inside a
component repository as well, and update the database with details of
their new package or packages. Future enhancements to the component
framework may allow new components to be developed outside a
repository.
</para>
<para>
Like most files related to the component framework, the
<database>ecos.db</database> database is actually a &Tcl; script.
Typical package entries would look like this:
</para>
<programlisting width=72>
package CYGPKG_LIBC {
alias { "C library" libc clib clibrary }
directory language/c/libc
script libc.cdl
description "
This package enables compatibility with the ISO C standard - ISO/IEC
9899:1990. This allows the user application to use well known standard
C library functions, and in eCos starts a thread to invoke the user
function main()"
}
package CYGPKG_IO_PCI {
alias { "PCI configuration library" io_pci }
directory io/pci
script io_pci.cdl
hardware
description "
This package contains the PCI configuration library."
}
</programlisting>
<para>
The <literal>package</literal> command takes two arguments, a name and
a body. The name must be the same as in the &cdl-package; command in
the package's top-level &CDL; script. The body can contain the
following five commands: <literal>alias</literal>,
<literal>directory</literal>, <literal>script</literal>,
<literal>hardware</literal> and <literal>description</literal>.
</para>
<variablelist>
<varlistentry>
<term><literal>alias</literal></term>
<listitem>
<para>
Each package should have one or more aliases. The first alias is
typically used when listing the known packages, because a string like
<literal>C library</literal> is a bit easier to read and
understand than <varname>CYGPKG_LIBC</varname>. The other aliases are
not used for output, but are accepted on input. For example the
<application class="software">ecosconfig</application> command-line
tool will accept <literal>add libc</literal> as an option, as well
as <literal>add CYGPKG_LIBC</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>directory</literal></term>
<listitem>
<para>
This is used to specify the location of the package relative to the
root of the component repository. It should be noted that in the
current component framework this location cannot be changed in
subsequent releases of the package: if for some reason it is desirable
to install a new release elsewhere in the repository, all the old
versions must first be uninstalled; the database cannot hold two
separate locations for one package.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>script</literal></term>
<listitem>
<para>
The <literal>script</literal> command specifies the location of the
package's top-level &CDL; script, in other words the one containing the
&cdl-package; definition. If the package follows the <link
linkend="package.hierarchy">directory layout conventions</link> then
this script will be in the <filename class="directory">cdl</filename>
sub-directory, otherwise it will be relative to the package's top-level
directory. Again once a release has been made this file should not
change in later releases. In practice the top-level script is generally
named after the package itself, so changing its name is unlikely to be
useful.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>hardware</literal></term>
<listitem>
<para>
Packages which are tied to specific hardware, for example device
drivers and HAL packages, should indicate this in both the
&cdl-package; command of the &CDL; script and in the database entry.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>description</literal></term>
<listitem>
<para>
This should give a brief description of the package. Typically the
text for the &description; property in the &cdl-package; command will
be re-used.
</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>
Most of the information in the <database>ecos.db</database> file could
be obtained by a relatively simple utility. This would be passed a
single argument identifying a package's top-level &CDL; script. The
directory path relative to the component repository root could be
determined from the filename. The name, <literal>description</literal>
and <literal>hardware</literal> fields could be obtained from the
script's &cdl-package; command. The &display; property would supply
the first alias, additional aliases could be obtained by extending the
syntax of that property or by other means. Something along these lines
may be provided by a future release of the component framework.
</para>
</note>
<para>
Currently the <database>ecos.db</database> database also holds
information about the various targets. When porting to a new target it
will be necessary to add information about the target to the database,
as well as the details of the new platform HAL package and any related
packages.
</para>
</sect1>
<!-- }}} -->
</chapter>
Go to most recent revision | Compare with Previous | Blame | View Log