mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-26 08:41:47 -07:00
Convert design.mps.config to restructuredtext.
Copied from Perforce Change: 181186 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
dda63ee29d
commit
90299cee8f
1 changed files with 485 additions and 0 deletions
485
mps/manual/source/design/config.rst
Normal file
485
mps/manual/source/design/config.rst
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
.. sources:
|
||||
|
||||
`<https://info.ravenbrook.com/project/mps/master/design/config/>`_
|
||||
|
||||
.. mps:prefix:: design.mps.config
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
:mps:tag:`intro` This document describes how the MPS configuration is
|
||||
parameterized so that it can target different architectures, operating
|
||||
systems, build environments, varieties, and products.
|
||||
|
||||
:mps:tag:`bg` For background see [build system mail, configuration
|
||||
mail, :mps:ref:`meeting.general.something`]
|
||||
|
||||
|
||||
History
|
||||
-------
|
||||
|
||||
:mps:tag:`hist.0` Initial draft created by Richard Brooksby on
|
||||
1997-02-19 based on discussions of configuration at
|
||||
:mps:ref:`meeting.general.1997-02-05`.
|
||||
|
||||
:mps:tag:`hist.1` Various improvements and clarifications to the draft
|
||||
discussed between Richard and Nick Barnes at
|
||||
:mps:ref:`meeting.general.1997-02-19`.
|
||||
|
||||
:mps:tag:`hist.2` Converted from MMInfo database design document.
|
||||
Richard Brooksby, 2002-06-07.
|
||||
|
||||
:mps:tag:`hist.3` Updated for variety-reform branch, to remove untrue
|
||||
things, though the document could do with a rewrite. Richard Brooksby,
|
||||
2012-09-03.
|
||||
|
||||
:mps:tag:`hist.4` Converted to reStructuredText. Gareth Rees,
|
||||
2013-03-19.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
:mps:tag:`req.arch` Allow architecture specific configurations of the
|
||||
MPS.
|
||||
|
||||
:mps:tag:`req.os` Allow operating system specific configurations of
|
||||
the MPS.
|
||||
|
||||
:mps:tag:`req.builder` Allow build environment (compiler, etc.)
|
||||
specific configurations of the MPS.
|
||||
|
||||
:mps:tag:`req.prod` Allow product specific configurations of the MPS.
|
||||
[This requirement was retired on 2012-09-03. Client-specific
|
||||
customisation of the MPS will be handled by configuration management,
|
||||
while the MPS source remains generic, to reduce costs and increase
|
||||
reliability.]
|
||||
|
||||
:mps:tag:`req.var` Allow configurations with different amounts of
|
||||
instrumentation (assertions, metering, etc.).
|
||||
|
||||
:mps:tag:`req.impact` The configuration system should have a minimal
|
||||
effect on maintainability of the implementation.
|
||||
|
||||
:mps:tag:`req.port` The system should be easy to port across operating
|
||||
systems.
|
||||
|
||||
:mps:tag:`req.maint` Maintenance of the configuration and build system
|
||||
should not consume much developer time.
|
||||
|
||||
|
||||
Definitions
|
||||
-----------
|
||||
|
||||
:mps:tag:`def.platform` A platform is a combination of an architecture
|
||||
(:mps:ref:`.def.arch`), an operating system (:mps:ref:`.def.os`), and
|
||||
a builder (:mps:ref:`.def.builder`). The set of supported platforms is
|
||||
platform.*.
|
||||
|
||||
:mps:tag:`def.arch` An architecture is processor type with associated
|
||||
calling conventions and other binary interface stuff.
|
||||
|
||||
:mps:tag:`def.os` An operating system is the interface to external
|
||||
resources.
|
||||
|
||||
:mps:tag:`def.builder` A builder is the tools (C compiler, etc.) used
|
||||
to make the target (:mps:ref:`.def.target`).
|
||||
|
||||
:mps:tag:`def.var` A variety is a combination of annotations such as
|
||||
assertions, metering, etc.
|
||||
|
||||
:mps:tag:`def.prod` A product is the intended product into which the
|
||||
MPS will fit, e.g. ScriptWorks, Dylan, etc.
|
||||
|
||||
:mps:tag:`def.target` The target is the result of the build.
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
- No automatically generated code. Use only C compiler and linker.
|
||||
- Simple build function (:mps:ref:`design.mps.buildsys`).
|
||||
- Avoid conditional code spaghetti in implementations.
|
||||
- Dependency on a particular configuration should be minimized and
|
||||
localized when developing code.
|
||||
|
||||
|
||||
The build system
|
||||
----------------
|
||||
|
||||
Abstract Build Function
|
||||
.......................
|
||||
|
||||
:mps:tag:`build.fun` The MPS implementation assumes only a simple
|
||||
"build function" which takes a set of sources, possibly in several
|
||||
languages, compiles them with a set of predefined preprocessor
|
||||
symbols, and links the result with a set of libraries to form the
|
||||
target::
|
||||
|
||||
target := build(<defs>, <srcs>, <libs>)
|
||||
|
||||
:mps:tag:`build.sep` Separate compilation and linkage can be seen as a
|
||||
memoization of this function, and is not strictly necessary for the
|
||||
build.
|
||||
|
||||
:mps:tag:`build.cc` A consequence of this approach is that it should
|
||||
always be possible to build a complete target with a single UNIX
|
||||
command line calling the compiler driver (usually ``cc`` or ``gcc``),
|
||||
for example::
|
||||
|
||||
cc -o main -DCONFIG_VAR_DF foo.c bar.c baz.s -lz
|
||||
|
||||
:mps:tag:`build.defs` The "defs" are the set of preprocessor macros
|
||||
which are to be predefined when compiling the module sources, of the
|
||||
form::
|
||||
|
||||
CONFIG_VAR_<variety-code>
|
||||
|
||||
A variety-code is a code that appears after ``variety.`` in the tag of
|
||||
the relevant variety document (see :mps:ref:`design.mps.variety`),
|
||||
converted to upper case. Currently (2012-09-03) the valid variety
|
||||
codes are ``RASH``, ``HOT``, ``COOL``, ``DIAG``, and ``TI``.
|
||||
|
||||
If no ``CONFIG_VAR_`` is present, ``HOT`` is assumed in ``config.h``.
|
||||
|
||||
:mps:tag:`build.srcs` The "srcs" are the set of sources that must be
|
||||
compiled in order to build the target. The set of sources may vary
|
||||
depending on the configuration. For example, different sets of sources
|
||||
may be required to build on different architectures. [This is a
|
||||
dependency between the makefile (or whatever) and the module
|
||||
configuration in ``config.h``.]
|
||||
|
||||
:mps:tag:`build.libs` The "libs" are the set of libraries to which the
|
||||
compiled sources must be linked in order to build the target. For
|
||||
example, when building a test program, it might include the ANSI C
|
||||
library and an operating system interface library.
|
||||
|
||||
|
||||
File Structure
|
||||
..............
|
||||
|
||||
:mps:tag:`file.dir` Each product consists of a single directory
|
||||
(corresponding to a HOPE compound) containing all the sources for the
|
||||
whole family of targets.
|
||||
|
||||
:mps:tag:`file.base` The names of sources must be unique in the first
|
||||
eight characters in order to conform to FAT filesystem naming
|
||||
restrictions.
|
||||
|
||||
:mps:tag:`.file.ext` The extension may be up to three characters and
|
||||
directly indicates the source language.
|
||||
|
||||
[Where is the set of valid extensions and languages defined?]
|
||||
|
||||
|
||||
Modules and Naming
|
||||
..................
|
||||
|
||||
:mps:tag:`mod.unique` Each module has an identifier which is unique
|
||||
within the MPS.
|
||||
|
||||
:mps:tag:`mod.impls` Each module has one or more implementations which
|
||||
may be in any language supported by the relevant build environment.
|
||||
|
||||
:mps:tag:`mod.primary` The primary implementation of a module is
|
||||
written in target-independent ANSI C in a source file with the same
|
||||
name as the module (plus the ``an`` suffix if there are secondary
|
||||
implementations: see :mps:ref:`.mod.secondary`).
|
||||
|
||||
:mps:tag:`.mod.secondary` The names of other implementations should
|
||||
begin with the same prefix (the module identifier, or a shortened
|
||||
version of it) and be suffixed with on or more target parameter codes
|
||||
(defined below). In particular, the names of assembly language sources
|
||||
must include the target parameter code for the relevant architecture.
|
||||
|
||||
|
||||
Build System Rationale
|
||||
......................
|
||||
|
||||
:mps:tag:`build.rat` This simple design makes it possible to build the
|
||||
MPS using many different tools. Microsoft Visual C++, Metrowerks
|
||||
Codewarrior, and other graphical development tools do not support much
|
||||
in the way of generated sources, staged building, or other such stuff.
|
||||
The Visual C and Metrowerks "project" files correspond closely to a
|
||||
closure of the build function (:mps:ref:`.build.fun`). The simplicity
|
||||
of the build function has also made it easy to set up builds using
|
||||
NMAKE (DOS), MPW (Macintosh), and to get the MPS up and running on
|
||||
other platforms such as FreeBSD and Linux in very little time. The
|
||||
cost of maintaining the build systems on these various platforms is
|
||||
also reduced to a minimum, allowing the MM Group to concentrate on
|
||||
primary development. The source code is kept simple and
|
||||
straightforward. When looking at MPS sources you can tell exactly what
|
||||
is going to be generated with very little context. The sources are not
|
||||
munged beyond the standard ANSI C preprocessor.
|
||||
|
||||
:mps:tag:`build.port` The portability requirement
|
||||
(:mps:ref:`.req.port`) implies that the build system must use only
|
||||
standard tools that will be available on all conceivable target
|
||||
platforms. Experience of development environments on the Macintosh
|
||||
(Metrowerks Codewarrior) and Windows NT (Visual C++) indicates that we
|
||||
cannot assume much sophistication in the use of file structure by
|
||||
development environments. The best that we can hope for is the ability
|
||||
to combine a fixed list of source files, libraries, and predefined
|
||||
preprocessor symbols into a single target.
|
||||
|
||||
:mps:tag:`build.maint` The maintainability requirement
|
||||
(:mps:ref:`.req.maint`) implies that we don't spend time trying to
|
||||
develop a set of tools to support anything more complicated than the
|
||||
simple build function described above. The effort in constructing and
|
||||
maintaining a portable system of this kind is considerable. Such
|
||||
efforts have failed in EP.
|
||||
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
:mps:tag:`impl` The two implementation files :mps:ref:`impl.h.config`
|
||||
and :mps:ref:`impl.h.mpstd` can be seen as preprocessor programs which
|
||||
"accept" build parameters and "emit" configuration parameters
|
||||
(:mps:ref:`.fig.impl`). The build parameters are defined either by the
|
||||
builder (in the case of target detection) or by the build function (in
|
||||
the case of selecting the variety).
|
||||
|
||||
=================== ============ =======================================
|
||||
Build parameter → Header → Configuration parameters
|
||||
=================== ============ =======================================
|
||||
``CONFIG_VAR_COOL`` ``config.h`` ``AVER_AND_CHECK``, ``EVENT_ALL``, etc.
|
||||
------------------- ------------ ---------------------------------------
|
||||
``_WIN32`` ``mpstd.h`` ``MPS_OS_W3``, ``MPS_BUILD_MV``, etc.
|
||||
=================== ============ =======================================
|
||||
|
||||
:mps:tag:`impl.dep` No source code, other than the directives in
|
||||
:mps:ref:`impl.h.config` and :mps:ref:`impl.h.mpstd`, should depend on
|
||||
any build parameters. That is, identifiers beginning ``CONFIG_``
|
||||
should only appear in :mps:ref:`impl.h.config`. Code may depend on
|
||||
configuration parameters in certain, limited ways, as defined
|
||||
below (:mps:ref:`.conf`).
|
||||
|
||||
|
||||
Target Platform Detection
|
||||
.........................
|
||||
|
||||
:mps:tag:`pf` The target platform is "detected" by the preprocessor
|
||||
directives in :mps:ref:`impl.h.mpstd`.
|
||||
|
||||
:mps:tag:`pf.form` This file consists of sets of directives of the
|
||||
form::
|
||||
|
||||
#elif <conjunction of builder predefinitions>
|
||||
#define MPS_PF_<platform code>
|
||||
#define MPS_OS_<operating system code>
|
||||
#define MPS_ARCH_<architecture code>
|
||||
#define MPS_BUILD_<builder code>
|
||||
#define MPS_T_WORD <word type>
|
||||
#define MPS_WORD_SHIFT <word shift>
|
||||
#define MPS_PF_ALIGN <minimum alignment>
|
||||
|
||||
:mps:tag:`pf.detect` The conjunction of builder predefinitions is a
|
||||
constant expression which detects the target platform. It is a logical
|
||||
conjunction of expressions which look for preprocessor symbols defined
|
||||
by the build environment to indicate the target. These must be
|
||||
accompanied by a reference to the build tool documentation from which
|
||||
the symbols came. For example::
|
||||
|
||||
/* Visual C++ 2.0, Books Online, C/C++ Book, Preprocessor Reference,
|
||||
* Chapter 1: The Preprocessor, Macros, Predefined Macros.
|
||||
*/
|
||||
|
||||
#elif defined(_MSC_VER) && defined(_WIN32) && defined(_M_IX86)
|
||||
|
||||
:mps:tag:`pf.codes` The declarations of the platform, operating
|
||||
system, architecture, and builder codes define preprocessor macros
|
||||
corresponding the the target detected (:mps:ref:`.pfm.detect`). For
|
||||
example::
|
||||
|
||||
#define MPS_PF_W3I3MV
|
||||
#define MPS_OS_W3
|
||||
#define MPS_ARCH_I3
|
||||
#define MPS_BUILD_MV
|
||||
|
||||
:mps:tag:`pf.word` The declaration of :c:macro:`MPS_T_WORD` defines
|
||||
the unsigned integral type which corresponds, on the detected target,
|
||||
to the machine word. It is used to defined the MPS :c:type:`Word` type
|
||||
(:mps:ref:`design.mps.type.word`). For example::
|
||||
|
||||
#define MPS_T_WORD unsigned long
|
||||
|
||||
:mps:tag:`pf.word-width` The declaration of :c:macro:`MPS_WORD_WIDTH`
|
||||
defines the number of bits in the type defined by
|
||||
:c:macro:`MPS_T_WORD` (:mps:ref:`.pf.word`) on the target. For
|
||||
example::
|
||||
|
||||
#define MPS_WORD_WIDTH 32
|
||||
|
||||
:mps:tag:`pf.word-shift` The declaration of :c:macro:`MPS_WORD_SHIFT`
|
||||
defines the base-2 logarithm of :c:macro:`MPS_WORD_WIDTH`. For
|
||||
example::
|
||||
|
||||
#define MPS_WORD_SHIFT 5
|
||||
|
||||
:mps:tag:`pf.pf-align` The declaration of :c:macro:`MPS_PF_ALIGN`
|
||||
defines the minimum alignment which must be used for a memory block to
|
||||
permit any normal processor memory access. In other words, it is the
|
||||
maximum alignment required by the processor for normal memory access.
|
||||
For example::
|
||||
|
||||
#define MPS_PF_ALIGN 4
|
||||
|
||||
|
||||
Target varieties
|
||||
................
|
||||
|
||||
:mps:tag:`var` The target variety is handled by preprocessor directives in
|
||||
:mps:ref:`impl.h.config`.
|
||||
|
||||
:mps:tag:`var.form` The file contains sets of directives of the form::
|
||||
|
||||
#elif defined(CONFIG_VAR_DF)
|
||||
#define MPS_VAR_DF
|
||||
#define ASSERT_MPSI
|
||||
#define ASSERT_MPM
|
||||
etc.
|
||||
|
||||
:mps:tag:`var.detect` The configured variety is one of the variety
|
||||
preprocessor definitions passed to the build function
|
||||
(:mps:ref:`.build.defs`), for example, ``CONFIG_VAR_DF``. [These are
|
||||
decoupled so that it's possible to tell the difference between
|
||||
overridden settings etc. Explain.]
|
||||
|
||||
:mps:tag:`var.symbols` The directives should define whatever symbols
|
||||
are necessary to control annotations. These symbols parameterize other
|
||||
parts of the code, such as the declaration of assertions, etc. The
|
||||
symbols should all begin with the prefix ``MPS_VAR_``.
|
||||
|
||||
[Tidy this up:] Note, anything which can be configured, is configured,
|
||||
even if it's just configured to ``NONE`` meaning nothing. This makes
|
||||
sure that you can't choose something by omission. Where these symbols
|
||||
are used there will be an ``#error`` to catch the unused case.
|
||||
Exception: To allow simple building of the MPS with ``cc -c mps.c`` we
|
||||
choose :c:macro:`CONFIG_VAR_HOT` by default. [This is a general
|
||||
principle which applies to other configuration stuff too.]
|
||||
|
||||
|
||||
Source code configuration
|
||||
-------------------------
|
||||
|
||||
:mps:tag:`conf` This section describes how the configuration may
|
||||
affect the source code of the MPS.
|
||||
|
||||
:mps:tag:`conf.limit` The form of dependency allowed is carefully
|
||||
limited to ensure that code remains maintainable and portable
|
||||
(:mps:ref:`.req.impact`).
|
||||
|
||||
:mps:tag:`conf.min` The dependency of code on configuration parameters
|
||||
should be kept to a minimum in order to keep the system maintainable
|
||||
(:mps:ref:`.req.impact`).
|
||||
|
||||
|
||||
Configuration parameters
|
||||
........................
|
||||
|
||||
:mps:tag:`conf.params` The compilation of a module is parameterized
|
||||
by::
|
||||
|
||||
MPS_ARCH_<arch-code>
|
||||
MPS_OS_<os-code>
|
||||
MPS_BUILDER_<builder-code>
|
||||
MPS_PF_<platform-code>
|
||||
|
||||
|
||||
Abstract and concrete module interfaces
|
||||
.......................................
|
||||
|
||||
Basic principle: the caller must not be affected by configuration of a
|
||||
module. This reduces complexity and dependency of configuration.
|
||||
|
||||
All callers use the same abstract interface. Caller code does not
|
||||
change.
|
||||
|
||||
Abstract interface includes:
|
||||
|
||||
- method definitions (logical function prototypes which may be macro
|
||||
methods)
|
||||
- names of types
|
||||
- names of constants
|
||||
- names of structures and fields which form part of the interface, and
|
||||
possibly their types, depending on the protocol defined
|
||||
- the protocols
|
||||
|
||||
The abstract interface to a module may not be altered by a configuration
|
||||
parameter. However, the concrete interface may vary.
|
||||
|
||||
|
||||
Configuring module implementations
|
||||
..................................
|
||||
|
||||
For example, this isn't allowed, because there is a change in the
|
||||
interface::
|
||||
|
||||
#if defined(PROT_FOO)
|
||||
void ProtSpong(Foo foo, Bar bar);
|
||||
#else
|
||||
int ProtSpong(Bar bar, Foo foo);
|
||||
#endif
|
||||
|
||||
This example is allowed::
|
||||
|
||||
#ifdef PROTECTION
|
||||
void ProtSync(Space space);
|
||||
/* more decls. */
|
||||
#else /* PROTECTION not */
|
||||
#define ProtSync(space) NOOP
|
||||
/* more decls. */
|
||||
#endif /* PROTECTION */
|
||||
|
||||
And so is this::
|
||||
|
||||
#if defined(PROT_FOO)
|
||||
typedef struct ProtStruct {
|
||||
int foo;
|
||||
} ProtStruct;
|
||||
#define ProtSpong(prot) X((prot)->foo)
|
||||
#elif defined(PROT_BAR)
|
||||
typedef struct ProtStruct {
|
||||
float bar;
|
||||
} ProtStruct;
|
||||
#define ProtSpong(prot) Y((prot)->bar)
|
||||
#else
|
||||
#error "No PROT_* configured."
|
||||
#endif
|
||||
|
||||
Configuration parameters may not be used to vary implementations in
|
||||
``.c`` files. For example, this sort of thing is not allowed::
|
||||
|
||||
int map(void *base, size_t size)
|
||||
{
|
||||
#if defined(MPS_OS_W3)
|
||||
VirtualAlloc(foo, bar, base, size);
|
||||
#elif defined(MPS_OS_SU)
|
||||
mmap(base, size, frob);
|
||||
#else
|
||||
#error "No implementation of map."
|
||||
#endif
|
||||
}
|
||||
|
||||
This leads to extreme code spaghetti. In effect, it's a "candy machine
|
||||
interface" on source code. This kind of thing should be done by having
|
||||
several implementations of the same interface in separate source
|
||||
files. If this leads to duplication of code then that code should be
|
||||
placed in a separate, common module.
|
||||
|
||||
|
||||
Procedures
|
||||
----------
|
||||
|
||||
[Adding an architecture, etc.]
|
||||
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
What about constants?
|
||||
Loading…
Add table
Add a link
Reference in a new issue