As an introductory example of backend configuration, you might want to consider the system command that must be given to compile a C++ source file. Assume the current target/platform configuration was called i386-freebsd2-aout-gcc-debug,optimize, meaning that the GNU C/C++ compiler by the Free Software Foundation is in use, and that optimized code suitable for a debugger is to be generated (cf. Section 2.1.1). In this case, the command in question may schematically be described as
g++ -c -g -O {DEFINES} {INCDIRS} {SOURCE}
with
{DEFINES}= -D<option1> ... -D<option n>
{INCDIRS}= -I<path1> ... -I<path m >, and
{SOURCE} = <source_path>,
Note that the working directory of the compilation process
is a sub-sub-directory of the package root (cf. Section 2.2.3).
That sub-sub-directory's relative path is always obtained
from the TPC name by dividing it into two string
components:
<package_root> / i386-freebsd2-aout-gcc / debug,optimize
\_________ _________/ \_____ _____/
\/ \/
<string1> <string2>
-- The path would be of the form<package_root> / i386-freebsd2-aout-gcc / DEFAULT
in case no compiler options were given. -- For these reasons, the source path has always the form
.. / .. / src / <source_name>
The conclusion is that there is a clear distinction between information from the front end -- options, include paths, and source paths -- and a TPC-dependent way of generating a compiler call from it. This transformation is essentially a simple matter of string and list manipulation. More specifically, the necessary front-end information may be represented by means of these imported variables:
Table 6-1.
| PKG_ActRoot | -- the local package root |
| PKG_ActSoure | -- the current source path |
| PKG_ImportRoots | -- list of root directories of all imported package installations |
| PKG_Decls_add_define | -- list of all external defines from the PkgDesc |
| PKG_Decls_add_include | -- list of added include paths from the PkgDesc |
DEFINES, INCDIRS, and SOURCE can then be obtained as follows:
let DEFINES = {PKG_Decls_add_define}
let INCDIRS = concat(
addsuffix(append({PKG_ImportRoots}, {PKG_ActRoot}), "/inc"),
{PKG_Decls_add_include}
)
let SOURCE = {PKG_ActSource}
In consequence, all what is left consists of stating
cc_compilation : compile = "g++ -c -g -O {DEFINES} {INCDIRS} {SOURCE}"
to declare the required action. Note that its name is cc_compilation, and that it has a type, which is called compile. The let statement declares a variable value with dynamic binding and lazy evaluation, that is, the actual value is evaluated just when it is needed in the current context of the application of the variable.
The rest of this section presents the complete picture of that. First of all, ComPact retrieves the backend configuration from a single file, which is searched according to the configpath variable from the initialization file (cf. Section 2.1.2). The file is called pkgconf.cbcl and its format is
# comment
kind declarations:
case <TPC_name>: # zero or more TPC-specific lists
<kind_decl>;
.
case <TPC_name>:
<kind_decl>;
.
default: # optional default list of kind declarations
<kind_decl>;
.
end;
derivation declarations:
case <TPC_name>: # zero or more TPC-specific lists
<derivation_decl>;
.
case <TPC_name>:
<derivation_decl>;
.
default: # optional default list
# of derivation declarations
<derivation_decl>;
.
end;
action declarations:
case <TPC_name>: # zero or more TPC-specific lists
# of variable and action declarations
<variable_decl>;
.
<action_decl>;
.
case <TPC_name>:
<variable_decl>;
.
<action_decl>;
.
default: # optional default list
# of variable and action declarations
<variable_decl>;
.
<action_decl>;
.
end.
the format of an action declaration being
<action_name> [: <type_name>] = <string_expression>
and the format of a variable declaration being
let <variable_name> = <expression>
The sections declaring kinds and derivations are means of tailoring ComPact for the use with different kinds of languages, compilers, and building procedures. Currently they are only partially evaluated, but future versions of ComPact will make extensive use of them. Usually you don't have to worry with their specifics, as ComPact comes with a variety of predeclared kinds and derivation rules for C, C++, JAVA, and other languages. The complete syntax of the ComPact Backend Configuration Language (CBCL) is given in Section 6.2.9, a short discussion of kinds and derivations is contained in Section 6.2.2 and Section 6.2.3.
Section 6.2.4 presents the complete list of imported variables; Section 6.2.5 describes the means of string and list manipulation; Section 6.2.6 describes what exported variables and actions are understood by ComPact; and Section 6.2.8 presents an example, where a backend for the TPC called i386-freebsd2-aout-gcc is configured.
All elements declared in the PkgDesc file are of a certain kind. These kinds are defined in the first section of the backend configuration file. (There are several predefined kinds as well.) ComPact knows about the following kind declarations:
program source kind -- These kinds declare files that contain program source code that can be compiled.
compilation target kind -- These kinds describe the files that are the final targets of compilation processes.
derived kind -- Theses kinds describe files that are derived from sources by compilation or formatting.
generic source kind -- These kinds describe generic source files that may be instantiated.
generic instance kind -- These kinds describe files that are the result of instantiations of generic source files.
compound kind -- These kinds are abbreviations for multiple kind declarations.
virtual kind -- Theses kinds are constants or options that are not associated with files; they are exported as variables PKG_Decls_<kind name> to the backend.
document source kind -- These kinds declare files that are document sources.
document target kind -- These kinds declare files that are document targets, i.e. the products of formatting processes.
As you may have noticed, there are three different classes of kind declarations: file kind declarations, virtual kind declarations, and compound kind declarations. The first class is by far the most often used, since it contains the descriptions of the elements that are the sources and products of the actions of ComPact. Compound kind declarations are only used to define shorthand notations for multiple other declarations, and virtual kinds are there to support additional parameters needed by the build process.
Here is a short example for every type of kind declaration:
program source kind "c_header" default extension "h" default location "inc";defines package elements of type c_header which contain program source text, use the file name extension "h" and are located in the subdirectory inc of the package by default.
File kind declarations define the name of the kind and several default attributes. Their meaning is as follows:
location defines a sub directory of the package root directory where files of this kind are expected to be found.
prefix defines a textual prefix that will be prepended to any name of a declaration of this kind in order to get the actual file name.
suffix defines a textual suffix that will be appended to any name of a declaration of this kind in order to get the actual file name.
extension is similar to suffix but not as general. It defines a textual file name extension that will be appended to any name of a declaration of this kind after a `.' character in order to get the actual file name.
compound kind "c_module" is "c_header" and "c_source";defines the kind c_module to be a shorthand for the declaration of a c_header and a c_source of the same name (but with a different file name extension).
virtual kind "add_define";defines add_define declarations to be exported as list of strings to the backend configuration system when computing build actions. To achieve this, a variable with the name PKG_Decls_add_define will be predeclared.
Derivation rules are mappings from file kinds to file kinds. A typical derivation rule is
"c_linkage" : link is "code_object_file"*, "library"* --> "program";
This derivation is of type link which means that it produces an executable program. In order to construct an executable program, zero or more code object files and zero or more libraries need to be combined by a linkage action.
Derivations in ComPact may be of one of the types compile, generate, link, archive, makedepend, instantiate, format, index, convert, translate, hook. Currently only some of them are used. The type is used by ComPact for two purposes: to select appropriate derivation rules for certain kinds of package elements and to link derivation rules to action definitions. Action definitions may be of the same type as derivation rules.
Derivation rules can be thought of as patterns for the computation of dependencies. They contain all the information that ComPact needs to know about all declared kinds to derive the desired compilation and document target files. Action definitions may be regarded as concrete implementations of derivation rules for certain target platform configurations.
All variables, imported or exported, are of type string, of type int, or of type list. A string is denoted as a sequence of characters enclosed by " characters, an int is denoted as a sequence of digits enclosed by " characters, and the elements of lists are enclosed by parentheses and separated by commas. All types are converted automatically whenever a conversion is needed and possible. Imported variables are instantiated whenever an exported variable or action is requested. The instantiation value is mostly chosen with regard to the local package and the current state of processing that package. There is only one class of exceptions, namely those variables that are instantiated according to the initialization file. This class can be found at the end of this section.
The first set of variables is of primary importance for the build process:
Table 6-2.
| PKG_Root | the package root |
| PKG_ImportRoots | list of root directories of all |
| imported package installations | |
| PKG_ActSource | the current source file |
| PKG_ActDerived | the current derived file |
| PKG_Objects | list of all object files without extensions |
| PKG_Libs | list of all libraries to link with |
| PKG_LibDirs | list of all library paths to search |
| PKG_Libraries | list of all libraries with complete pathnames |
| PKG_KindPrefix | the first element of the kind of the current file |
| PKG_Decls_add_define | list of all external defines from the PkgDesc |
The following set is also important for the build process, since it serves for providing information on external include paths, libraries, and library paths (cf. Section 4.2.6):
Table 6-3.
| PKG_Decls_add_include | list of all added include paths from the PkgDesc |
| PKG_Decls_add_library | list of all added libraries from the PkgDesc |
| PKG_Decls_add_libpath | list of all added library paths from the PkgDesc |
The following set is of primary importance for the shipping of package installations:
Table 6-4.
| PKG_ActDest | the current shipping destination path (absolute path) |
| PKG_ActFile | the current file to be shipped. |
Imported variables that provide information on file extensions (cf. Section 4.1 and Section 4.2.8):
Table 6-5.
| PKG_EXT_c_header | the C header file extension |
| PKG_EXT_c_source | the C source extension |
| PKG_EXT_cc_header | the C++ header file extension |
| PKG_EXT_cc_source | the C++ source extension |
| PKG_EXT_c_generic_header | the C generic header file extension |
| PKG_EXT_c_generic_source | the C generic source extension |
| PKG_EXT_cc_generic_header | the C++ generic header file extension |
| PKG_EXT_cc_generic_source | the C++ generic source extension |
| PKG_EXT_cc_template | the C++ template file extension |
| PKG_EXT_asm_source | the assembler source extension |
The following imported variable serves for realizing ComPact's built-in template instantiation mechanism (cf. Chapter 8).
Finally, here is the above-mentioned class, which is instantiated according to the initialization file:
Table 6-7.
| PKG_BinDir | where binaries are to be installed |
| PKG_LocalBinDir | where binaries are to be installed locally |
| PKG_ProjectBinDir | where binaries are to be installed on a project-wide scale |
| PKG_GlobalBinDir | where binaries are to be installed globally |
| PKG_DocDir | where documentation is to be installed |
| PKG_LocalDocDir | where documentation is to be installed locally |
| PKG_ProjectDocDir | where documentation is to be installed on a project-wide scale |
| PKG_GlobalDocDir | where documentation is to be installed globally |
A string expression is either a string enclosed by ", which may contain variable references, or it may be such a reference alone, or it may be built recursively on the basis of the operations shown below. Variable references are always of the form {<variable_name>}.
concat( string_arg1, string_arg2) : string
concatenating<string_arg1> and <string_arg2>
concat(list_arg1,list_arg2):list
concatenating list_arg1 and list_arg2
append(list_arg, string_arg) : list
appending string_arg to list_arg
prepend(list_arg, string_arg) : list
prepending string_arg to list_arg
addsuffix(list_arg, string_arg) : list
appending string_arg to each element of list_arg
addprefix(list_arg, string_arg) : list
prepending string_arg to each element of list_arg
subst(string_arg1, string_arg2, string_arg3) : string
substituting all occurences of string_arg2 in string_arg1 by string_arg3
subst(list_arg1, string_arg2, string_arg3) : list
the subst function applied to a list
string(list_arg, string_arg) : string
converting list_arg to a string, using string_arg as separator
split(string_arg1, string_arg2) : list
split the string_arg1 into elements at every occurrence of string_arg2 and return the resulting list
combine(list_arg1, list_arg2, int_arg) : list
insert an element of list_arg2 after every int_argth element of list_arg1
locate(list_arg1, list_arg2) : list
locate all files of list_arg1 in the paths of list_arg2 and return the combined file names
dirname(string_arg) : string
the directory prefix of pathname string_arg
dirname(list_arg) : list
the dirname function applied to a list
basename(string_arg) : string
the last member of pathname string_arg
basename(list_arg) : list
the basename function applied to a list
join(string_arg1, string_arg2) : string
the concatenation of the pathnames string_arg1 and string_arg2
ext(string_arg) : string
the file name extension of string_arg
ext(list_arg) : list
the ext function applied to a list
noext(string_arg) : string
string_arg without any file name extension
noext(list_arg) : list
the noext function applied to a list
setext( string_arg1, string_arg2) : string
string_arg1 with the file name extension set to string_arg2
env(string_arg) : string
the value of the environment variable named string_arg
pid() :int
the current process id
Every exported variable or action is given as a string expression that may, directly or indirectly, involve one or more imported variables. The precise nature of this dependency varies in accordance with the target/platform configuration. In all cases, however, what imported variables an exported entity depends on should be more or less the same. Any differences should have to do with different command names and similar things.
The following list of all entities that may be exported by the backend is rather concise. More specifically, each action is briefly described with regard to the main resource involved in it, be it a source file to be compiled, a library to be shipped, or whatever. Other resources such as, for example, external defines in case of a compilation go unmentioned, since they ought to be obvious from the entity's purpose.
File name suffixes and prefixes:
file_suffix_dep [variable] -- the name suffix for files that contain dependency information
file_suffix_obj [variable] -- the name suffix for object files
file_prefix_lib [variable] -- the name prefix for libraries
file_suffix_lib [variable] -- the name suffix for libraries
file_suffix_bin [variable] -- the name suffix for binaries
C-specific build actions:
c_compilation (action of type compile) -- the action of compiling the PKG_ActSource as a C source
c_linkage (action of type link) -- the action of linking all PKG_Objects as object files derived from C sources
c_archivation (action of type archive) -- the action of archiving all PKG_Objects as object files derived from C sources
c_depend (action of type depend) -- the action of extracting all dependencies of the PKG_ActSource as a C source
c_instantiate_header (action of type instantiate) -- the action of instantiating the PKG_ActSource as a generic C header file (cf. Chapter 8)
c_instantiate_source (action of type instantiate) -- the action of instantiating the PKG_ActSource as a generic C source (cf. Chapter 8)
C++-specific build actions:
cc_compilation [action of type compile] -- the action of compiling the PKG_ActSource as a C++ source
cc_linkage [action of type link] -- the action of linking all PKG_Objects as object files derived from C++ sources
cc_archivation [action of type archive] -- the action of archiving all PKG_Objects as object files derived from C++ sources
cc_depend [action of type depend] -- the action of extracting all dependencies of the PKG_ActSource as a C++ source
cc_instantiate_header [action of type instantiate] -- the action of instantiating the PKG_ActSource as a generic C++ header file [cf. Chapter 8]
cc_instantiate_source [action of type instantiate] -- the action of instantiating the PKG_ActSource as a generic C++ source [cf. Chapter 8]
C/C++-specific shipping actions:
install_dir (action) -- the action of creating the PKG_ActDest
install_file (action) -- the action of installing the PKG_ActFile at the PKG_ActDest, assuming that it is not a library or program
install_lib (action) -- the action of installing the PKG_ActFile as a library at the PKG_ActDest
install_bin (action) -- the action of installing the PKG_ActFile as a program at the PKG_ActDest
install_document_source (action) -- the action of installing the document source PKG_ActFile at the PKG_ActDest
install_document_target (action) -- the action of installing the document target PKG_ActFile at the PKG_ActDest
Actions used to build documentation:
tex_format (action) -- the action of compiling the PKG_ActSource as a TeX file
latex_format (action) -- the action of compiling the PKG_ActSource as a LaTeX file
sgml_format (action) -- the action of compiling the PKG_ActSource as an SGML file
docn_format, where n = 1,2,3,4 (action) -- the n'th freely definable action of compiling the PKG_ActSource as a documentation file
Make-specific variables and actions that may vary in accordance with the TPC:
make_comment_start (variable) -- the string used for indicating a comment within a makefile
make_include_directive (variable) -- the include directive used within makefiles
make_phony_directive (variable) -- the phony directive used within makefiles
make_shell_declaration (variable) -- the shell declaration used within makefiles
make (action) -- the command to be used for invoking make
gnumake (action) -- the command to be used for invoking GNU make
Miscellaneous:
asm_compile (action of type compile) -- the action of assembling the Pkg_ActSource as an assembler source
pgmn_compile, where n = 1, 2, 3, 4 (action of type compile) -- the n 'th freely definable action of compiling the Pkg_ActSource. The default for pgmn -sources is to produce an object file.
othern_compile, where n = 1, 2, 3, 4 (action) -- an n'th entirely freely definable action. By default the othern -source declarations do not produce object files.
ComPact distinguishes several types of actions. The types compile, generate, link, archive, makedepend, instantiate, format, index, convert, translate, hook are predeclared, but currently only the following types of actions are used:
compile
For all program source kind declarations in PkgDesc, the action <kind prefix>_compilation will be executed.
generate
For all program source kind declarations in PkgDesc, the action <kind prefix>_generation will be executed. After every execution of generation action, the dependency graph is updated to reflect all generated results.
link
For all library declarations in PkgDesc, the action <kind prefix>_linkage will be executed.
archive
For all program declarations in PkgDesc, the action <kind prefix>_linkage will be executed.
makedepend
For all program source kind declarations, the action <program source kind name>_compilation will be executed if it is defined.
instantiate
For all generic instance kind declarations in PkgDesc, the action <kind prefix>_instantiate<rest of kind name> will be executed.
format
For all document source kind declarations in PkgDesc, the action <kind prefix>_format will be executed, as it will be for all derived files of document sources.
The different kinds of actions are always executed in a well specified order during the building of a package. This order is defined by the evaluation of several phony targets of the package dependency graph.
First, the target instantiate is built. This target depends on all actions of type instantiate, so if it succeeds, all instances of generic files that are needed for the current package will exist. After the build, the dependency graph is updated to reflect the state of the newly generated sources.
Second, the target generate is built. This target depends on all actions of type generate. After its completion, all sources generated by other tools than the ComPact instance generator should exist. After every generation step the dependency graph is updated.
Third, the target depend is evaluated. This target depends on all actions of type makedepend. The execution of these actions produces new dependency files, which are then read in and their information added to the dependency graph.
In the main step, the target all is built. all at least depends on the target main, which represents the main section of your package description. During this step, all actions of the types compile, archive, and link are executed.
Last, the target doc is built. This target depends on all actions of the type format, which should be used to format and layout documents.
To determine wether a program target kind is a library or an executable program, the type of the derivations that produce this kind is checked. To determine the actions needed to format all enclosed documentation of a package, all derivations of type format are considered and applied to all source and derived documents.
Future versions of ComPact will only use the derivation rules and no further conventions to determine all the actions chosen to build a package.
The example shows that it is entirely possible to leave some exported entities undefined. Also, it shows how auxiliary variables can be used for enhancing comprehensibility. Please refer to Section A.3 in Elego ComPact Manual Appendices for the example file.
Here is a short summary of the ComPact Backend Configuration Language:
Here is a short summary of the language:
Root ::= TopLevelDecl "." | TopLevelDecl ";" Root
TopLevelDecl ::= KindSection | DerivationSection | ActionSection
KindSection ::= "kind" "declarations" ":" KindPart* "end"
DerivationSection ::= "derivation" "declarations" ":" DerivationPart* "end"
ActionSection ::= "action" "declarations" ":" ActionPart* "end"
KindPart ::= ( DefaultKindPart | TPCSpecificKindPart ) ";"
DefaultKindPart ::= "default" ":" KindDecl*
TPCSpecificKindPart ::= "case" String [ "," String ]* ":" KindDecl*
DerivationPart ::= ( DefaultDerivationPart | TPCSpecificDerivationPart ) ";"
DefaultDerivationPart ::= "default" ":" DerivationDecl*
TPCSpecificDerivationPart ::= "case" String [ "," String ]* ":"
DerivationDecl*
ActionPart ::= ( DefaultActionPart | TPCSpecificActionPart ) ";"
DefaultActionPart ::= "default" ":" EnvironmentBinding* ActionDecl*
TPCSpecificActionPart ::= "case" String [ "," String ]* ":"
EnvironmentBinding* ActionDecl*
KindDecl ::= ( FileKindDecl | VirtualKindDecl | CompoundKindDecl )
PkgElemAttr* ";"
FileKindDecl ::= "program" "source" "kind" FileKindAttributes
| "document" "source" "kind" FileKindAttributes
| "generic" "source" "kind" FileKindAttributes
| "generic" "instance" "kind" FileKindAttributes
| "derived" "kind" FileKindAttributes
| "compilation" "target" "kind" FileKindAttributes
| "document" "target" "kind" FileKindAttributes
| "dummy" "target" "kind" FileKindAttributes
| "unprocessed" "source" "kind" FileKindAttributes
| "unprocessed" "document" "kind" FileKindAttributes
| "unprocessed" "data" "kind" FileKindAttributes
| "unprocessed" "file" "kind" FileKindAttributes
FileKindAttributes ::= String [ "default" "prefix" String ]
[ "default" "extension" String |
"default" "suffix" String ]
[ "default" "location" String ]
PkgElemAttr ::= "preserve" "path"
| "document" "source"
| "program" "element"
| "produces" "object"
| "object"
| "source"
| "header"
| "interface"
| "generic"
| "derived"
| "compound"
| "virtual"
| "library"
| "executable"
| "program" "target"
| "document" "target"
VirtualKindDecl ::= String
CompoundKindDecl ::= String "is" String ( ( "and" | "," ) String )*
DerivationDecl ::= String [ ":" DerivationType ] "is"
DerivationSourceDecls "-->" DerivationTargetDecls ";"
DerivationType ::= Identifier
DerivationSourceDecls ::= DerivationSourceDecl
| DerivationSourceDecl "," DerivationSourceDecls
DerivationSourceDecl ::= String [ "*" ]
DerivationTargetDecls ::= DerivationTargetDecl
| DerivationTargetDecl "," DerivationTargetDecls
DerivationTargetDecl ::= String [ "*" ]
EnvironmentBinding ::= "let" Identifier "=" Expression ";"
ActionDecl ::= StringOrId [ ":" ActionType ] ( "is" | "=") String ";"
ActionType := Identifier
StringOrId ::= String | Identifier
Expression ::= String
| List
| VariableReference
| FunctionApplication
List ::= "(" ListElements ")"
ListElements ::= ListElement | ListElement "," ListElements
ListElement ::= Expression
VariableReference ::= "{" Identifier "}"
FunctionApplication ::= FunctionName "(" ArgumentList ")"
ArgumentList ::= Argument | Argument "," ArgumentList
Argument ::= Expression
FunctionName ::= "string" | "append" | "prepend" | "concat" | "subst" |
"flatten" | " split" | "addprefix" | "addsuffix" |
"combine" | "locate" | "dirname" | "basename" |
"join" | "ext" | "noext" | "setext" |
"env" | "pid" | "store" | "def" |
"val" | "file" | "fileapp" | "fileval"