DragonFly On-Line Manual Pages
critcl(n) C Runtime In Tcl (CriTcl) critcl(n)
______________________________________________________________________________
NAME
critcl - Critcl - Package Reference
SYNOPSIS
package require Tcl 8.4
package require critcl ?3.1.15?
package require platform ?1.0.2?
package require md5 ?2?
::critcl::ccode text
::critcl::ccommand tclname cfunname
::critcl::ccommand tclname arguments body ?option value...?
::critcl::cdata tclname data
::critcl::cconst tclname resulttype value
::critcl::cdefines definitions ?namespace?
::critcl::cproc name arguments resulttype body ?option value...?
::critcl::cproc name arguments resulttype
::critcl::cinit text externals
::critcl::include path
::critcl::api import name version
::critcl::api function resulttype name arguments
::critcl::api header ?pattern...?
::critcl::api extheader ?file...?
::critcl::license author ?text...?
::critcl::summary text
::critcl::description text
::critcl::subject ?key...?
::critcl::meta key ?word...?
::critcl::meta? key
::critcl::buildrequirement script
::critcl::cheaders ?arg...?
::critcl::csources ?pattern...?
::critcl::clibraries ?arg...?
::critcl::source path
::critcl::tsources pattern...
::critcl::owns pattern...
::critcl::cflags ?arg...?
::critcl::ldflags ?arg...?
::critcl::framework ?arg...?
::critcl::tcl version
::critcl::tk
::critcl::preload lib...
::critcl::debug area...
::critcl::check ?label? text
::critcl::checklink ?label? text
::critcl::msg ?-nonewline? msg
::critcl::print ?-nonewline? ?chan? msg
::critcl::compiled
::critcl::compiling
::critcl::done
::critcl::failed
::critcl::load
::critcl::config option ?val?
::critcl::cache ?path?
::critcl::clean_cache ?pattern...?
::critcl::readconfig path
::critcl::showconfig ?chan?
::critcl::showallconfig ?chan?
::critcl::chooseconfig target ?nomatcherr?
::critcl::setconfig target
::critcl::actualtarget
::critcl::buildforpackage ?flag?
::critcl::cnothingtodo file
::critcl::cresults ?file?
::critcl::crosscheck
::critcl::error msg
::critcl::knowntargets
::critcl::sharedlibext
::critcl::targetconfig
::critcl::buildplatform
::critcl::targetplatform
::critcl::cobjects ?arg...?
::critcl::scan path
::critcl::name2c name
::critcl::argnames arguments
::critcl::argcnames arguments
::critcl::argcsignature arguments
::critcl::argvardecls arguments
::critcl::argconversion arguments ?n?
::critcl::argoptional arguments
::critcl::argdefaults arguments
::critcl::argsupport arguments
::critcl::userconfig define name description type ?default?
::critcl::userconfig query name
::critcl::userconfig set name value
::critcl::at::caller
::critcl::at::caller offset
::critcl::at::caller offset level
::critcl::at::here
::critcl::at::get*
::critcl::at::get
::critcl::at::= file line
::critcl::at::incr n...
::critcl::at::incrt str...
::critcl::at::caller!
::critcl::at::caller! offset
::critcl::at::caller! offset level
::critcl::at::here!
::critcl::collect_begin
::critcl::collect_end
::critcl::collect script
::critcl::make path contents
::critcl::resulttype name body ?ctype?
::critcl::resulttype name = origname
::critcl::argtype name body ?ctype? ?ctypefun?
::critcl::argtype name = origname
::critcl::argtypesupport name code
::preload library
______________________________________________________________________________
DESCRIPTION
Welcome to the C Runtime In Tcl, CriTcl for short, a system to build C
extension packages for Tcl on the fly, from C code embedded within Tcl
scripts, for all who wish to make their code go faster.
This document is the reference manpage for the critcl package. This
package is the system's core, i.e. it provides the essential
functionality on top of which everything else is built. Its intended
audience are mainly developers wishing to write Tcl packages with
embedded C code. Some of its sections are however for developers
wishing to understand the package internals, and the API it provides to
the CriTcl Application. These sections will be marked, allowing package
writers to skip them. Users of critcl on the other hand are hereby
refered to the applications' manpage, i.e. CriTcl Application. If you
are in need of an overview of the whole system instead, please go and
read the Introduction To CriTcl.
This package resides in the Core Package Layer of CriTcl.
+----------------+
|Applications |
| critcl |
| critcl::app |
+----------------+
*================*
|Core Packages |
| critcl |
| critcl::util |
*================*
+----------------+
|Support Packages|
| stubs::* |
| md5, platform |
| ... |
+----------------+
API
A short note ahead of the documentation: Instead of repeatedly talking
about "a ".tcl" with embbedded C code", or "a ".tcl" containing critcl
commands", etc. we use a shorthand and simply call them ".critcl"
files, regardless of their file extension.
EMBEDDED C CODE
The package provides five commands to declare various types of C code
fragments. These are:
::critcl::ccode text
This command compiles the C code in text and makes the contained
definitions (variables, functions, macros, etc.) available to
all C code fragments specified after it. It itself can assume to
have access to all definitions which were specified before it.
See section Runtime Behaviour for more details.
The result of the command is the empty string.
::critcl::ccommand tclname cfunname
This command creates a new Tcl command named tclname which is
implemented by the C function cfunname. It is expected that
cfunname has the proper signature for a Tcl command function,
and was declared already.
The result of ::critcl::ccommand itself is the empty string.
::critcl::ccommand tclname arguments body ?option value...?
This form of critcl::ccommand creates a new Tcl command named
tclname which is implemented by the C code in body.
The command wraps the body in an invisible C function, compiles
it and makes the resulting definition available to all C code
fragments declared later on. It itself can assume to have access
to all definitions which came before it. See section Runtime
Behaviour for more details.
The result of critcl::ccommand itself is the empty string.
The list of arguments contain the names for the four parameters
required by a Tcl command function. Superfluous list elements
(i.e. beyond the fourth) are ignored. Missing elements
(parameters), and empty parameter names are handled by replacing
them with standard names. These are, in order of usage
[1] clientdata
[2] interp
[3] objc
[4] objv
The only options accepted by this command are:
-clientdata c-expression
The value of this option is the text of a single C
expression. The value of expression is used in the
generated C statement registering tclname to initialize
the client data of the new Tcl command. If not specified
the expression defaults to NULL, i.e. no client data.
-delproc c-expression
The value of this option is the text of a single C
expression. The value of this expression has to be a
function pointer of type "Tcl_CmdDeleteProc", which is
used in the generated C statement registering tclname to
initialize a deletion function for the new Tcl command,
i.e. a function which is run by Tcl when the Tcl command
is deleted again. If not specified the expression
defaults to NULL, i.e. no deletion function.
-cname boolean
The value of this option is a boolean flag. If true the
name of the command is the C identifier of the command
function. Namespaces, etc. are in that case not relevant
at all. The default value of this option is false,
causing the system to derive a name from the Tcl level
command name, including its namespace.
A ccommand is, in comparison to functions defined via
critcl::cproc, more lower level. Its advantage is that the
developer can do their own argument processing, enabling things
like variable number of arguments, options, etc., i.e. much
higher flexibility. Their disadvantage is that you have to do
your own argument processing. Where a critcl::cproc generates
the code to convert from Tcl values to C values and back a
critcl::ccommand forces the writer to do all of this on their
own. I.e. the cost of the aforementioned flexibility is a higher
complexity seen by the user.
::critcl::cdata tclname data
This command creates a new Tcl command named tclname which
returns data as a ByteArray result.
The result of critcl::cdata itself is the empty string.
::critcl::cconst tclname resulttype value
This command creates a new Tcl command named tclname which
returns the constant value as its result, with Tcl type
resulttype.
The result of critcl::cconst itself is the empty string.
The command is similar to critcl::cdata in that it returns a
constant value. Contrary to critcl::cdata however it is not
restricted to ByteArray results, but accepts all result-types
known to critcl::cproc. Its semantics are actually equivalent
to
cproc $tclname {} $resulttype "return $value ;"
Contrary to critcl::cproc however it is internally optimized to avoid
generating a superfluous C function.
Note that nothing prevents the user from using a C define for the
value. Any visible C function is actually also allowed, as long as it
does not take arguments.
::critcl::cdefines definitions ?namespace?
This command creates Tcl variables in the specified namespace
which are linked to the C enum values and #defines named as glob
patterns in the list of definitions. Each variable has the same
name as the definition which gave rise to it, and its value is
the value of the corresponding enum value or #define. The
namespace defaults to the global namespace, i.e. "::", if it
wasn't specified explicitly.
Please note that this command is only for the lifting of
existing C definitions into Tcl. The command does not create the
definitions in C. It actually goes so far to check for the
presence of the named definitions and not performing the mapping
for any which do not exist. Which is sensible, given that non-
existing defines have no value which could be used in the
mapping.
As these checks are run at the time the embedded C code of a
".critcl" file is actually compiled they have access to and
check all C fragments defined with critcl::ccode, plus all the
headers it has access to via critcl::cheaders, for that file.
::critcl::cproc name arguments resulttype body ?option value...?
This command creates a new Tcl command named tclname which is
implemented by the C code in body. In contrast to the low-level
critcl::ccommand here the arguments and result are typed and
critcl generates the code converting from Tcl_Obj's to C data
types, and vice versa. The command creates two invisible C
functions, one wrapping the body, the other a shim containing
the necessary conversions, compiles them and makes the resulting
definitions available to all C code fragments declared later on.
It itself can assume to have access to all definitions which
came before it. See section Runtime Behaviour for more details.
The result of critcl::cproc itself is the empty string.
The only options accepted by this command are:
-cname boolean
The value of this option is a boolean flag. If true the
name of the command is the C identifier of the command
function. Namespaces, etc. are in that case not relevant
at all. The default value of this option is false,
causing the system to derive a name from the Tcl level
command name, including its namespace.
-pass-cdata boolean
The value of this option is a boolean flag. If specified
and set the shim translating from Tcl to C level and back
will pass the command's ClientData to the function. If
not specified the flag defaults to false, i.e. no passing
of client data.
-arg-offset int
The value of this option is a positive integer number
specifying the number of hidden arguments preceding the
actual procedure arguments. If not specified the flag
defaults to 0. This is useful to higher-order code
generator using the command in settings with prefix
arguments which are not directly seen by the function,
but influence argument counting and extraction.
The list below shows the values which are legal for resulttype,
and details their semantics:
Tcl_Obj*
object The function returns a value of type "Tcl_Obj*". This
value becomes the interpreter result, if not 0. The Tcl
status is TCL_ERROR when a 0 is returned, and TCL_OK
otherwise.
Attention: The conversion assumes that the value belonged
to the function, with an associated reference count, and
decrements the reference count to indicate the loss of
ownership by the function. This means that it is an error
to return a value whose reference count is zero.
char*
vstring
The function returns a value of type "char*". This value
becomes the interpreter result, wrapped in a String. It
is assumed that the string is volatile in some way, with
the wrapping in a String duplicating it before making it
the result, ensuring that we will not access a dangling
pointer in the future. The Tcl status is always TCL_OK.
const char*
Like type char* above, except that the returned string is
const-qualified.
string
dstring
The function returns a value of type "char*". Contrary
to the previous string types here it is assumed that the
value is dynamically allocated, via Tcl_Alloc. This
value becomes the interpreter result, as usual, but is
not copied. The Tcl status is always TCL_OK.
double The function returns a value of type "double". This
value becomes the interpreter result, properly wrapped
(Int). The Tcl status is always TCL_OK.
float The function returns a value of type "float". This value
becomes the interpreter result, properly wrapped
(Double). The Tcl status is always TCL_OK.
boolean
bool The function returns a value of type "int", interpreted
as boolean. This value becomes the interpreter result,
properly wrapped (Int). The Tcl status is always TCL_OK.
int The function returns a value of type "int". This value
becomes the interpreter result, properly wrapped (Int).
The Tcl status is always TCL_OK.
long The function returns a value of type "long int". This
value becomes the interpreter result, properly wrapped
(Long). The Tcl status is always TCL_OK.
ok The function returns a value of type "int". It is
interpreted as the Tcl status code. The interpreter
result is left untouched (empty).
void The function does not return a value. The interpreter
result is left untouched (empty). The Tcl status is
always TCL_OK.
Please note that it is possible to extend the above with custom types
if these types are not enough. See section Advanced: Extending cproc
for details.
The arguments parameter has the overall syntax of a Tcl dictionary
value, except that keys (argument names) and values (argument types)
are specified in reverse order. Consider the example
int x int y
where mapped to type/value int.
The argument names must be valid C identifiers.
A limited form of variadic arguments is possible, through
optional arguments with default values. For these the argument
name is a 2-element list containing the actual name, and the
default value. For example, in the declaration
int {x 1}
x optional argument of type int and default value 1.
One limitation, and one caveat!
First, the set of optional arguments must be a single contiguous
segment in the argument list. This limits them to a series of
optional arguments at either the beginning, end, or middle of
the list. Multiple segments separated by non-optional arguments
are rejected, as the system cannot determine in these cases
which arguments are present and what to set where.
Second, the default value is assigned unconditionally. If a
custom argument type uses more complex validation, and the
default may be invalid according to it, then the relevant checks
have to be done in the procedure body. The argument conversion
cannot do it as it is completely bypassed when the argument is
not present. Overcoming this requires the separation of argument
conversion and validation code.
The list below shows the values which are legal for argument
types, and details their semantics:
Tcl_Obj*
object The function takes an argument of type "Tcl_Obj*". No
argument checking is done. The Tcl level word is passed
to the argument as-is.
pstring
The function takes an argument of type "critcl_pstring"
containing the original Tcl_Obj* reference of the Tcl
argument, plus the length of the string and pointer to
the characters.
typedef struct critcl_pstring {
Tcl_Obj* o;
char* s;
int len;
} critcl_pstring;
list The function takes an argument of type "critcl_list"
containing the original Tcl_Obj* reference of the Tcl
argument, plus the length of the Tcl list and pointer to
the list elements.
typedef struct critcl_list {
Tcl_Obj* o;
Tcl_Obj** v;
int c;
} critcl_list;
The Tcl argument must be convertible to List, an error is
thrown otherwise.
bytearray
rawchar*
rawchar
The function takes an argument of type "char*". The Tcl
argument must be convertible to ByteArray, an error is
thrown otherwise. Note that the length of the ByteArray
is not passed to the function.
char* The function takes an argument of type "char*". The
string representation of the Tcl argument is passed in.
double The function takes an argument of type "double". The Tcl
argument must be convertible to Double, an error is
thrown otherwise.
float The function takes an argument of type "float". The Tcl
argument must be convertible to Double, an error is
thrown otherwise.
boolean
bool The function takes an argument of type "int". The Tcl
argument must be convertible to Boolean, an error is
thrown otherwise.
int The function takes an argument of type "int". The Tcl
argument must be convertible to Int, an error is thrown
otherwise.
long The function takes an argument of type "long int". The
Tcl argument must be convertible to Long, an error is
thrown otherwise.
void*
double*
float*
int* The function takes an argument of the same-named C type.
The Tcl argument must be convertible to ByteArray, an
error is thrown otherwise. The bytes in the ByteArray
are then re-interpreted as the raw representation of a C
pointer of the given type which is then passed as
argument to the function. In other words, this is for
Tcl values somehow holding raw C pointers, i.e. memory
addresses.
Attention: These types are considered DEPRECATED. It is
planned to remove their documentation in release 3.2, and
their implementation in release 3.3. Their deprecation
can be undone if good use cases are shown.
Note that optional arguments are not possible. This restriction is
inherited from C.
Further note that the type of the first argument is allowed to be
Tcl_Interp*. In that case the argument in question is not counted as an
argument of the new Tcl command.
::critcl::cproc name arguments resulttype
This variant of critcl::cproc assumes that the functionality to
connect is implemented by the C function name which has the
signature described by the arguments and resulttype.
It creates only the shim performing the conversions required by
arguments and result.
::critcl::cinit text externals
This command compiles the C code in text and externals.
Both have access to all definitions created by the previously
listed commands, regardless of their and its placement in the
".critcl" file. See section Runtime Behaviour for more details.
The C code in text is put into the body of the initialization
function of the shared library backing the ".critcl" file, and
is executed when this library is loaded into the interpreter.
This code has access to a variable interp of type Tcl_Interp*
referencing the Tcl interpreter currently being initialized.
The code in externals on the other hand is placed outside and
just before the initialization function, making this is a good
place for any external symbols required by initialization
function which should not be accessible by any other parts of
the C code.
The result of the command is the empty string.
::critcl::include path
This command is a convenient shorthand for
critcl::code {
#include <${path}>
}
STUBS TABLE MANAGEMENT
Newly introduced with critcl version 3 is the support for stubs tables,
Tcl's dynamic linking mechanism handling the resolution of symbols
between C extensions. We won't go into its details here. See
http://wiki.tcl.tk/285 for an introduction in general, and section
Stubs Tables for the details of critcl's particular variant.
Critcl supports this via a single command, critcl::api, and its
methods.
First, importing stubs tables, i.e. APIs, from another extension:
::critcl::api import name version
Critcl prepares the ".critcl" file and its companion ".c" files
by including the headers
[1] "name/nameDecls.h"
[2] "name/nameStubLib.h"
in the appropriate places. It is checked that the compiler will
be able to find these header files somewhere on the include
search path, using the paths defined so far (See
critcl::cheaders, and the critcl application's -I and
-includedir options). Note how critcl expects the headers of
package foo to reside in a sub-directory "foo" of the known
include search paths.
Important: If foo is a namespaced package name, like, for
example "c::stack", then the namespace separators "::" are
converted into underscores ("_") in path names, C code, etc.
The first header is expected to contain contains all the
necessary stubs table type declarations, mapping macros, etc.,
and may include package specific headers (See critcl::api header
below). This header is included at the beginning of the C code
backing the ".critcl" file, and at the beginning of all
companion ".c" files. This means that the writer of these files
doesn't have to write the necessary #include directory, critcl
does it for them.
The second header is expected to contain the stubs table
variable definition, and the C code, i.e. definition, of the
function to initialize it. This, and a call to this initializer
function are added to the ".critcl" file's initialization code.
If the directory containing the aforementioned headers also
contains the file "name/name.decls" then it is assumed that this
file contains the external representation of the stubs table
used to generate the headers. The file is read and the internal
representation of the stubs table returned as result of the
command, for the importing package to use as it sees fit. If no
such file is present the command returns the empty string as its
result.
One possible use would be the automatic generation of C code
calling on the functions listed in the imported API.
When generating a TEA wrapper the names of the imported APIs are
used to declare configure options with which the user can
declare a non-standard location for the headers of the API. Any
API FOO is translated a single configure option
--with-FOO-include.
Second, declaration and export of a stubs table, i.e. API, for the
current package, foo:
::critcl::api function resulttype name arguments
This method declares that the function name is in the public API
of the package, and its signature (type of the result, number,
names and types of its arguments). Using this method
automatically causes critcl to generate both the code for a
stubs table in the package, the headers needed by packages using
this API, and a ".decls" file containing the stubs table implied
by the exports, usable by critcl::api import.
arguments is a list of C types and associated argument names.
Like a dictionary, except that keys (argument names) and values
(argument types) are swapped. The resulttype is a C type as
well.
::critcl::api header ?pattern...?
This method notifies critcl of companion header files which have
to be exported together with the generated stubs headers.
All arguments are interpreted as glob pattern and the matching
files are copied into the directory containing the generated
headers well. As an importing package uses only "fooDecls.h" to
access the API this generated header will contain the necessary
#include directives to make these companion header files and
their declarations available too. Patterns matching no file or
non-existing files cause the command to throw an error.
Note that patterns which are not beginning with an absolute path
are interpreted relative to the directory containing the current
".critcl" file.
::critcl::api extheader ?file...?
This method is similar ::critcl::api header, in that it notifies
critcl of companion header files which have to be exported
together with the generated stubs headers.
The difference is that these headers will be expected to exist
in the external development environment. As such they will be
#included in the generated header for the package, but not
copied to the package header directory. Nor are they allowed to
be glob patterns, as critcl has no context, i.e directory, in
which to expand such patterns.
Note that the generated headers for an exported API are included in the
package like it is done when importing it somewhere else. To repeat:
The "fooDecls.h" header is included at the beginning of the C code
backing the ".critcl" file, and at the beginning of all companion ".c"
files. This means that the writer of these files doesn't have to write
the necessary #include directory, critcl does it for them.
In mode "compile & run" the generated header files, and their companion
headers, if any, are placed in the subdirectory "foo" of the Result
Cache. As this location is implicitly added to the include search path
any other package importing this API and and build in mode "compile &
run" as well will find the these headers.
For mode "generate package" the application was extended with a new
option -includedir which specifies the location to place the generated
headers in (again in subdirectory "foo" of that path). This path is
also be added to the include search paths, ensuring that a package
importing an API will find it if the package exporting that API used
the same setting for -includedir.
For mode "generate TEA" the static scanner was extended to recognize
critcl::api header as a source of companion files. It further uses
data about critcl::api import commands to put proper support for
--with-foo-include options into the generate "configure(.in)" so that a
user may specify custom locations for the headers of any imported API.
PACKAGE META DATA
Newly introduced with critcl version 3 is support for TEApot meta-data.
While, from the package developer's perspective, some meta data support
was already present in critcl v2, through the command
::critcl::license, this was only used to generate and place a file
"license.txt" into the built package.
Now critcl supports the declaration of arbitrary meta data, which will
be placed into a file "teapot.txt" in a format suitable for use by the
TEApot tools [http://docs.activestate.com/activetcl/8.5/tpm/toc.html].
::critcl::license author ?text...?
This command provides information about the author of the
package, and its license.
If no text is present the command expects to find a file
"license.terms" in the same directory as the ".critcl" file and
reads the license from that. Otherwise the license is the joined
texts.
This information, the license, is ignored in mode "compile &
run", only mode "generate package" uses it. In that case the
information is written to a file "license.terms", a sibling to
the "pkgIndex.tcl" file in the directory hierarchy of the
generated package.
This information is additionally placed into the meta data file
"teapot.txt", under the keys as::author and license.
The data specified by this command has priority over any
information specified through the generic API ::critcl::meta.
::critcl::summary text
Declares a short (one line is recommended) description of the
package.
This information is ignored in mode "compile & run", only mode
"generate package" uses it. In that case the information is
placed into the meta data file "teapot.txt", under the key
summary.
The data specified by this command has priority over any
information specified through the generic API ::critcl::meta.
::critcl::description text
Declares a longer description of the package.
This information is ignored in mode "compile & run", only mode
"generate package" uses it. In that case the information is
placed into the meta data file "teapot.txt", under the key
description.
The data specified by this command has priority over any
information specified through the generic API ::critcl::meta.
::critcl::subject ?key...?
Declares one or more keywords and key-phrases describing the
package, for an index.
Multiple calls of this command accumulate keywords and phrases.
This information is ignored in mode "compile & run", only mode
"generate package" uses it. In that case the information is
placed into the meta data file "teapot.txt", under the key
subject.
The data specified by this command has priority over any
information specified through the generic API ::critcl::meta.
::critcl::meta key ?word...?
This command is for the declaration of arbitrary meta data
outside of the reserved keys as::author, as::build::date,
description, license, name, platform, require subject, summary,
and version, Its behaviour is like ::critcl::subject, in that it
treats all keys as list of words, with each call declaring one
or more words for the key, and multiple calls extending the data
for an existing key, if not reserved.
While it is possible to declare information for one of the
reserved keys with this command such data is ignored when the
final meta data is assembled and written.
Use the commands ::critcl::license, ::critcl::summary,
::critcl::description ::critcl::subject, package require, and
package provide to declare data for the reserved keys.
The information for the reserved keys as::build::date and
platform is automatically generated by critcl itself.
::critcl::meta? key
This command enables the retrieval of meta data information from
with the code defining a critcl based package. Given the key the
associated value is returned as the result of the command.
The envisioned main use is the retrieval of the package's name
from within utility packages having to adapt C code templates to
their environment. An example of a package using this command
for exactly this purpose is critcl::class.
::critcl::buildrequirement script
This command provides control over the capturing of dependencies
declared via package require. It runs the script, and any
dependencies declared within are ignored, i.e. not recorded in
the meta data.
CONTROL & INTERFACE
The package provides thirteen commands to control the details of
compilation and linking, enabling ".critcl" files to provide custom
information about their environment and dependencies.
In important thing to note about all these commands is that the package
manages their information on a per-file basis. I.e. information
provided by and in a file "FOO.tcl" is kept separate from the
information provided by and in a file "BAR.tcl", preventing them from
interfering with each other.
The commands are:
::critcl::cheaders ?arg...?
This command provides the compile step with additional header
files and header locations.
All arguments matching the glob pattern -* are forwarded to the
compiler's command line when it is invoked for the current
".critcl" file.
All other arguments are interpreted as glob pattern and the
matching files are made available to the compiler when it is
invoked for the current ".critcl" file. Patterns matching no
file or non-existing files cause the command to throw an error.
Note that patterns which are not beginning with an absolute path
are interpreted relative to the directory containing the current
".critcl" file.
Note further that this declaration does not cause the specified
header files to be #include'd automatically. This still has to
be done via critcl::ccode where necessary. It does simply
ensure that the compiler will be able to find these files when
invoked, by providing the necessary command line flags extending
the compiler's search paths.
Multiple invocations of this command accumulate their
information.
::critcl::csources ?pattern...?
This command provides the compile step with additional C source
files.
All arguments are intepreted as glob patterns. Patterns matching
no file or non-existing files cause the command to throw an
error. The files matching the patterns are made available to the
compiler when it is invoked for the current ".critcl" file. This
means that the files in question are compiled together with the
".c" file backing the ".critcl" file into a single object.
Note that patterns which are not beginning with an absolute path
are interpreted relative to the directory containing the current
".critcl" file.
Multiple invocations of this command accumulate their
information.
::critcl::clibraries ?arg...?
This command provides the link step with additional libraries to
link and library locations.
All arguments matching the glob pattern -* are forwarded to the
linkers's command line when it is invoked for the current
".critcl" file.
All other arguments are interpreted glob patterns. Patterns
matching no file or non-existing files cause the command to
throw an error. The files matching the patterns are made
available to the linker when it is invoked for the current
".critcl" file. This means that the files in question are linked
together with the object file backing the ".critcl" file into a
single shared library.
Note that patterns which are not beginning with an absolute path
are interpreted relative to the directory containing the current
".critcl" file.
Multiple invocations of this command accumulate their
information.
::critcl::source path
This command evaluates the critcl commands in the file specified
by path in the context of the current ".critcl" file.
The argument is actually considered as glob pattern and all
matching files are evaluated. A pattern matching no file or non-
existing files cause the command to throw an error.
Note that a pattern not beginning with an absolute path is
interpreted relative to the directory containing the current
".critcl" file.
::critcl::tsources pattern...
This command provides the critcl package with information about
additional Tcl script files to source when the shared library is
loaded.
All arguments are considered as glob patterns and the matching
files are made available to generated shared library when it is
loaded for the current ".critcl" file. Patterns matching no file
or non-existing files cause the command to throw an error.
Note that patterns which are not beginning with an absolute path
are interpreted relative to the directory containing the current
".critcl" file.
Multiple invocations of this command accumulate their
information.
The declared files are sourced after the shared library has been
loaded, in the same order they were provided to
critcl::tsources.
::critcl::owns pattern...
This command is ignored by the regular build modes, i.e. both
"compile and run", and "generate package". It is present to
support the static code scanner of critcl v3's new mode to
"generate TEA" packages.
In that situation it provides the critcl package with
information about any files which have to be wrapped and could
not be figured out from the previous commands (i.e.
critcl::csources, critcl::tsources) because of getting specified
dynamically, or getting directly sourced and this not visible to
critcl in any other way.
::critcl::cflags ?arg...?
This command provides the compile step with additional compiler
flags.
All arguments are forwarded to the compiler's command line when
it is invoked for the current ".critcl" file.
Multiple invocations of this command accumulate their
information.
::critcl::ldflags ?arg...?
This command provides the link step with additional linker
flags.
All arguments are forwarded to the linkers's command line when
it is invoked for the current ".critcl" file.
Multiple invocations of this command accumulate their
information.
::critcl::framework ?arg...?
This command provides the link step with the names of additional
frameworks to link on MacOS X. The command is ignored if we are
not building for OS X. This means that it is possible to declare
the OS X specific frameworks unconditionally. The package itself
takes care to not use them when building for non-OS X platforms.
All arguments are forwarded to the linkers's command line when
it is invoked for the current ".critcl" file.
Multiple invocations of this command accumulate their
information.
::critcl::tcl version
This command tells critcl for what minimum version of the Tcl
runtime to compile and link the package for. If not specified
critcl falls back to the default of 8.4.
::critcl::tk
This command informs critcl that the package in question is
based on Tk, and therefore needs the Tk headers for compilation,
and the Tk stubs for linking.
::critcl::preload lib...
This command arranges that the named dependent external shared
library is loaded before the generated package's shared library.
Multiple invocations of this command accumulate their
information.
Each library FOO named for preload will be searched at the
locations listed below, in the order listed, and the search will
stop on the first existing path. Additional notes:
o platform is the placeholder for the target platform of
the package.
o The extension ".so" is the placeholder for whatever
actual extension is used by the target platform for its
shared libraries.
o Note how the search is relative to the current working
directory.
And now the paths, depending on the exact form of the library
name:
FOO
[1] FOO.so
[2] FOO/FOO.so
[3] FOO/platform/FOO.so
PATH/FOO
For this form the exact set searched depends on the
existence of directory "PATH/FOO". If it does not exist
critcl searches
[1] FOO.so
[2] PATH/FOO.so
[3] PATH/platform/FOO.so
Otherwise it searches
[1] FOO.so
[2] PATH/FOO/FOO.so
[3] PATH/FOO/platform/FOO.so
instead.
/PATH/FOO
Even when specifying FOO with an absolute path the first
path searched is relative to the current working
directory.
[1] FOO.so
[2] /PATH/FOO.so
[3] /PATH/platform/FOO.so
If you are a developer wishing to understand or modify the
internals of the critcl package then you possibly should read
the section explaining how the Preloading functionality is
implemented.
::critcl::debug area...
This tells critcl if the package is to be compiled for
debugging, and which areas to activate. Internally each area is
translated into area-specific flags for the compiler which are
then handed over to critcl::cflags.
memory Specification of this area activates Tcl memory debugging
for the package code.
symbols
Specification of this area activates compilation and
linking with debugging symbols, for use by a debugger or
other tool.
all Specification of this area translates ino the activation
of all other legal areas.
INTROSPECTION
The package provides six commands to control compilation and linking.
These are:
::critcl::check ?label? text
This command is useful to test if some functionality is
available in the build environment, and then select other C code
fragments based on that information. It immediately compiles
the C code in text and returns a boolean value based on the
result of the compilation. The command returns true on success,
and false otherwise. If specified, the label is used to
uniquely mark the check in the generated log.
::critcl::checklink ?label? text
This command is an extenson of critcl::check above, useful to
test if some functionality is available in the build
environment, and then select other C code fragments based on
that information. It immediately compiles and links the C code
in text and returns a boolean value based on the result of
compilation and linking. The command returns true on success,
and false otherwise. If specified, the label is used to
uniquely mark the check in the generated log.
::critcl::msg ?-nonewline? msg
This command can be used by critc-based code to report results
from critcl::check and critcl::checklink. The default
implementation used by mode compile & run ignores any calls.
Tools like the CriTcl Application are allowed to redefine this
procedure to perform their own way of message reporting. The
package critcl::app and the application on top print such
messages to stdout, for example.
::critcl::print ?-nonewline? ?chan? msg
This command is used by the critcl internals to report its
activity. Its signature is equivalent to the Tcl builtin
command ::puts. The default implementation is effectively
::puts.
Tools directly using either the critcl package, or the critcl
application package are allowed to redefine this procedure to
perform their own way of printing.
An example of this is Kettle
[https://chiselapp.com/user/andreas_kupries/repository/Kettle/index]
where the newest revisions use this to highlight build warnings.
::critcl::compiled
This command returns a boolean value. It returns true if the C
code of the current ".critcl" file is already compiled, and
false otherwise.
This predicate effectively enables a ".critcl" file used as its
own Tcl companion file (see critcl::tsources) to distinguish
between sourced by mode "compile & run" for compilation and
sourced from either the result of mode "generate package" or
during the load phase of "compile & run". In case of the two
latter possibilities the result is true, and false for the
first.
::critcl::compiling
This command returns a boolean value. It returns true if C code
can be compiled on this platform in general, i.e. if a C
compiler is available, and false otherwise.
::critcl::done
This command returns a boolean value. It returns true when
critcl has built the embedded C code, and false otherwise.
This enables the Tcl code of a critcl-based package to
distinguish between it getting used as a prebuilt package,
versus dynamic compile & run, and take action based on that.
Note that this command is only useful from within a ".critcl"
file. The result is managed on a per-file basis, like is done
for the commands embedding C code and controlling the behaviour
of compiler and linker.
See also section Modes Of Operation/Use.
::critcl::failed
This command returns a boolean value. It returns true if critcl
has failed to build the package, and false otherwise, i.e.
success. As part of this it forces the building of the package,
but not its loading. Note that it will attempt to build the
package only on the first call; future calls for the same
package will return a cached result.
This enables a critcl-based package to check itself for
availability and throw an error if it could not be built. Note
that the command does not throw such an error itself.
Note further that this command is only useful from within in a
".critcl" file. The result is managed on a per-file basis, like
is done for the commands embedding C code and controlling the
behaviour of compiler and linker.
::critcl::load
This command is like critcl::failed, except that it also forces
the loading of the generated shared library, if it was built,
and that its result has reversed sense.
It returns true if critcl succeeded in building and loading the
package, and false otherwise, i.e. build- or load-failure.
This enables a critcl-based package to to not only check itself
for availability and throw an error if it could not be built,
but also force an immediate load, circumventing the default
behaviour, which is lazy. See also section Runtime Behaviour.
Note that the command does not throw any error itself.
Note further that this command is only useful from within in a
".critcl" file. The result is managed on a per-file basis, like
is done for the commands embedding C code and controlling the
behaviour of compiler and linker.
BUILD MANAGEMENT
The package provides a single command for the management of global
settings, i.e. configuration options which are independent of any
".critcl" file.
It is expected that this command is irrelevant to anybody just wishing
to write a ".critcl" file. It is a management command which is only
useful to the CriTcl Application or similar tools.
::critcl::config option ?val?
This command sets and returns critcl's global configuration
options. These are
force bool
This flag tells the package whether it should force the
building of C files despite having a cached shared
library (when true, or not. The default is off.
lines bool
This flag tells the package whether to embed #line
directives into the generated C code (when true) or not.
By default this is on.
Side note: This facility requires the use of a tclsh
supporting the builtin info frame command. If critcl is
run by a tclsh not supporting this no #line directives
will be emitted. The command is supported by Tcl 8.5 and
higher. It is also supported by Tcl 8.4 provided that it
was compiled with the define -DTCL_TIP280. An example of
such is ActiveState's ActiveTcl.
Developers of higher-level packages generating their own
C code, either directly, or indirectly, by using critcl
commands, should also read section Advanced: Location
management to see how critcl helps them in generating
their directives. Examples of such packages come with
critcl itself, see the packages critcl::iassoc and
critcl::class.
I path A single global include path to use for all files. Not
set by default.
combine enum
dynamic
Object files have the suffix _pic.
static Object files have the suffix _stub.
standalone
Object files have no suffix, and the generated C
files are compiled without using Tcl/Tk stubs. The
result are object files usable for static linking
into a big shell.
The default is dynamic.
language string
keepsrc bool
This flag tells the package whether to keep the generated
".c" files after it has build their ".o" files (when
true), or not. The default is off.
outdir path
The path where to place a generated shared library. Not
set by default, causing placement into the Result Cache.
RESULT CACHE MANAGEMENT
This package provides two commands for the management of the Result
Cache. See that section for background information.
NOTE that these commands are irrelevant to anybody just wishing to
write a package using critcl for the C parts. They are management
commands which are only useful to the CriTcl Application or similar
tools.
::critcl::cache ?path?
This command sets and returns the path to the directory for the
package's result cache.
The default location is "~/.critcl/[platform::generic]" and
usually does not require any changes.
::critcl::clean_cache ?pattern...?
This command cleans the result cache, i.e. removes any and all
files and directories in it. If one or more patterns are
specified then only the files and directories matching them are
removed.
BUILD CONFIGURATION
This package provides four commands for the management of the build
configuration, i.e. the per-platform information about compilers,
linkers, and their commandline options.
NOTE that these commands are irrelevant to anybody just wishing to
write a package using critcl for the C parts. They are management
commands which are only useful to the CriTcl Application or similar
tools.
::critcl::readconfig path
This command reads the build configuration file at path and
configures the package using the information for the currently
set target platform.
::critcl::showconfig ?chan?
This command converts the currently active build configuration
into a human-readable string and prints the result to the
channel chan. If chan is not present the string is instead
returned as the result of the command.
::critcl::showallconfig ?chan?
This command converts the set of all known build configurations
(from the currently active build configuration file last set
with critcl::readconfig) into a string and print the result to
the channel chan. If chan is not present the string is instead
returned as the result of the command.
::critcl::chooseconfig target ?nomatcherr?
This command takes a target identifier and matches it against
all known targets, returning a list containing all the matching
ones. This search is first done on an exact basis, and then via
glob matching. If no known target matches the argument the
default is to return an empty list. However, if the boolean
nomatcherr is specified and set, and error will be thrown
instead, using critcl::error.
::critcl::setconfig target
This command takes a target identifier and configures the
package to use all its settings.
TOOL API
The twelve commands in this section provide tools like CriTcl
Application or similar with deeper access to the package's internals.
These commands are irrelevant to anybody just wishing to write a
".critcl" file.
::critcl::actualtarget
This command returns the platform identifier of the target
platform, i.e. the platform the generated code will be built
for. In contrast to ::critcl::targetplatform this is the true
target, with any cross-compilation information resolved.
::critcl::buildforpackage ?flag?
This command signals whether the next file to be build is built
for inclusion into a package or not. If not specified the flag
defaults to true, i.e. building for a package. This disables a
number of things in the backend, namely the linking of that file
into a shared library, and loading such. It is expected that the
build results are later wrapped into a larger collection.
::critcl::cnothingtodo file
This command checks whether there is anything to build for file.
::critcl::cresults ?file?
This command returns the build result information for the
specified file. If no file is specified the information is
taken from info script. The result in question is a Tcl
dictionary with the following keys, and their meanings:
clibraries
The list of external shared libraries, and/or locations
thereof to link the file needs for successful linking.
ldflags
The list of linker flags needed by the file for
successful linking.
license
The license the package in the file is under. A string.
mintcl The minimum version of Tcl required by the package in the
file to run successfully. A proper Tcl version number.
objects
The list of object files backing the file, to be linked.
preload
The list of libraries the generated package has to
preload to allow the package in the file to run
successfully.
tk A boolean indicating whether the package in the file has
to be linked against Tk or not.
tsources
The list of companion ".tcl" files to source for the
package in the ".critcl" file to run successfully.
log The full build log generated by the compiler/linker,
including command line data from critcl, and other
things.
exl The raw build log generated by the compiler/linker. This
key contains only the output generated by the invoked
applications.
::critcl::crosscheck
This command checks if the package is configured for cross-
compilation and prints a message to the standard error channel
if so.
::critcl::error msg
This command is used by the package to report internal errors.
The default implementation simply throws the error. Tools like
the CriTcl Application are allowed to redefine this procedure to
perform their own way of error reporting. There is one
constraint they are not allowed to change: The procedure must
not return to the caller.
::critcl::knowntargets
This command returns a list containing the identifiers of all
targets found during the last invocation of critcl::readconfig.
::critcl::sharedlibext
This command returns the file extension used by shared libraries
on the target platform.
::critcl::targetconfig
This command returns the target identifier chosen to by either
system or user to build code for.
::critcl::buildplatform
This command returns the platform identifier of the build
platform, i.e. where the package is running on.
::critcl::targetplatform
This command returns the platform identifier of the target
platform, i.e. the platform the generated code will be built
for. In contrast to ::critcl::actualtarget this may be the name
of a cross-compilation target.
::critcl::cobjects ?arg...?
This command is like ::critcl::clibraries, provides the link
step with additional information. Instead of libraries the
arguments are object files however. Despite this similarity it
is not listed in section Control & Interface because it is of no
use to package writers. Only tools like the CriTcl Application
have need of it.
All arguments are interpreted glob patterns. Patterns matching
no file or non-existing files cause the command to throw an
error. The files matching the patterns are made available to the
linker when it is invoked for the current ".critcl" file. This
means that the files in question are linked together with the
object file backing the ".critcl" file into a single shared
library.
Note that patterns which are not beginning with an absolute path
are interpreted relative to the directory containing the current
".critcl" file.
Multiple invocations of this command accumulate their
information.
::critcl::scan path
This command is the main entry point to critcl's static code
scanner. Invoked for a single ".critcl" file it returns a
dictionary providing the following pieces information about it:
version
Package version.
org Author(ing organization).
files List of the companion files. The paths in this list are
all relative to the location (directory) of the input
file.
This command and the information it returns can be used by tools
to implement processing modes like the assembly of a directory
hierarchy containing a TEA-lookalike buildystem, etc.
::critcl::name2c name
This command exposes the conversion of a Tcl level identifier of
commands into various C-level pieces, i.e. Tcl namespace prefix,
C namespace prefix, Tcl base name, and C base name.
The result of the command is a list of 4 elements providing the
above mentioned information, in the named order.
The envisioned main use is from within utility packages
providing Tcl commands without going through the standard
commands, i.e. critcl::ccommand, or critcl::cproc. An example of
a package using this command for exactly this purpose is
critcl::class.
ADVANCED: EMBEDDED C CODE
For the advanced user five commands used inside of critcl::cproc are
exposed. These are:
::critcl::argnames arguments
This command takes an argument declaration as taken by
critcl::cproc and returns a list of the user visible arguments
found in the declaration.
::critcl::argcnames arguments
This command takes an argument declaration as taken by
critcl::cproc and returns a list of the C side variable names
for the user visible arguments found in the declaration. The
names returned here match the names used in the declarations and
code returned by ::critcl::argvardecls and
::critcl::argconversion.
::critcl::argcsignature arguments
This command takes an argument declaration as taken by
critcl::cproc and returns a list of C parameter declarations for
all arguments found in the declaration.
::critcl::argvardecls arguments
This command takes an argument declaration as taken by
critcl::cproc and returns a list of C side variable declarations
for the user visible arguments found in the declaration. The
names used in these declarations match the names returned by
::critcl::argcnames.
::critcl::argconversion arguments ?n?
This command takes an argument declaration as taken by
critcl::cproc and returns a list of C code fragments converting
the user visible arguments found in the declaration from
Tcl_Obj* to C types. The names used in these statements match
the names returned by ::critcl::argcnames.
The generated code assumes that the procedure arguments start at
index n of the objv array. If this argument is not specified 1
will be assumed.
::critcl::argoptional arguments
This command takes an argument declaration as taken by
critcl::cproc and returns a list of boolean values indicating
which arguments are optional (true) and not (false).
::critcl::argdefaults arguments
This command takes an argument declaration as taken by
critcl::cproc and returns a list containing the default values
for all optional arguments.
::critcl::argsupport arguments
This command takes an argument declaration as taken by
critcl::cproc and returns a list of C code fragments needed to
define the necessary supporting types.
CUSTOM BUILD CONFIGURATION
This package provides one command for the management of package-
specific, i.e. developer-specified custom build configuration options.
::critcl::userconfig define name description type ?default?
This command defines custom build configuration option, with
description, type and optional default value.
The type can be either bool, or a list of values.
[1] For bool the default value, if specified, must be a
boolean. If it is not specified it defaults to true.
[2] For a list of values the default value, if specified,
must be a value found in this list. If it is not
specified it defaults to the first value of the list.
The description serves as in-code documentation of the meaning of the
option and is otherwise ignored. When generating a TEA wrapper the
description is used for the configure option derived from the option
declared by the command.
A boolean option FOO are translated into a pair of configure options,
--enable-FOO and --disable-FOO, whereas an option whose type is a list
of values is translated into a single configure option --with-FOO.
::critcl::userconfig query name
This command queries the database of custom build configuration
option for the current ".critcl" file and returns the chosen
value. This may be the default if no value was set via
::critcl::userconfig set.
It is at this point that definitions and set values are brought
together, with the latter validated against the definition.
::critcl::userconfig set name value
This command is for use by a tool, like the critcl application,
to specify values for custom build configuration options.
At the time this command is used only the association between
option name and value is recorded, and nothing else is done.
This behaviour is necessary as the system may not know if an
option of the specified name exists when the command is invoked,
nor its type.
Any and all validation is defered to when the value of an option
is asked for via ::critcl::userconfig query.
This means that it is possible to set values for any option we
like, and the value will take effect only if such an option is
both defined and used later on.
ADVANCED: LOCATION MANAGEMENT
First a small introduction for whose asking themselves 'what is
location management' ?
By default critcl embeds #line directives into the generated C code so
that any errors, warnings and notes found by the C compiler during
compilation will refer to the ".critcl" file the faulty code comes
from, instead of the generated ".c" file.
Side note: This facility requires the use of a tclsh supporting the
builtin info frame command. If critcl is run by a tclsh not supporting
this no #line directives will be emitted. The command is supported by
Tcl 8.5 and higher. It is also supported by Tcl 8.4 provided that it
was compiled with the define -DTCL_TIP280. An example of such is
ActiveState's ActiveTcl.
Most users will not care about this feature beyond simply wanting it to
work and getting proper code references when reading compiler output.
Developers of higher-level packages generating their own C code however
should care about this, to ensure that their generated code contains
proper references as well. Especially as this is key to separating bugs
concerning code generated by the package itself and bug in the user's
code going into the package, if any.
Examples of such packages come with critcl itself, see the
implementation of packages critcl::iassoc and critcl::class.
To help such developers eight commands are provided to manage such
location information. These are listed below.
A main concept is that they all operate on a single stored location,
setting, returning and clearing it. Note that this location
information is completely independent of the generation of #line
directives within critcl itself.
::critcl::at::caller
This command stores the location of the caller of the current
procedure as a tuple of file name and linenumber. Any previously
stored location is overwritten. The result of the command is
the empty string.
::critcl::at::caller offset
As above, the stored line number is modified by the specified
offset. In essence an implicit call of critcl::at::incr.
::critcl::at::caller offset level
As above, but the level the location information is taken from
is modified as well. Level 0 is the caller, -1 its caller, etc.
::critcl::at::here
This command stores the current location in the current
procedure as a tuple of file name and linenumber. Any previously
stored location is overwritten. The result of the command is
the empty string.
In terms of ::critcl::at::caller] this is equivalent to
critcl::at::caller 0 1
::critcl::at::get*
This command takes the stored location and returns a formatted
#line directive ready for embedding into some C code. The stored
location is left untouched. Note that the directive contains
its own closing newline.
For proper nesting and use it is recommended that such
directives are always added to the beginning of a code fragment.
This way, should deeper layers add their own directives these
will come before ours and thus be inactive. End result is that
the outermost layer generating a directive will 'win', i.e. have
its directive used. As it should be.
::critcl::at::get
This command is like the above, except that it also clears the
stored location.
::critcl::at::= file line
This command allows the caller to set the stored location to
anything they want, outside of critcl's control. The result of
the command is the empty string.
::critcl::at::incr n...
::critcl::at::incrt str...
These commands allow the user to modify the line number of the
stored location, changing it incrementally. The increment is
specified as either a series of integer numbers (incr), or a
series of strings to consider (incrt). In case of the latter the
delta is the number of lines endings found in the strings.
::critcl::at::caller!
::critcl::at::caller! offset
::critcl::at::caller! offset level
::critcl::at::here!
These are convenience commands combining caller and here with
get. I.e. they store the location and immediately return it
formatted as proper #line directive. Also note that after their
use the stored location is cleared.
ADVANCED: DIVERSIONS
Diversions are for higher-level packages generating their own C code,
to make their use of critcl's commands generating Embedded C Code
easier.
These commands normally generate all of their C code for the current
".critcl" file, which may not be what is wanted by a higher-level
package.
With a diversion the generator output can be redirected into memory and
from there on then handled and processed as the caller desires before
it is committed to an actual ".c" file.
An example of such a package comes with critcl itself, see the
implementation of package critcl::class.
To help such developers three commands are provided to manage
diversions and the collection of C code in memory. These are:
::critcl::collect_begin
This command starts the diversion of C code collection into
memory.
The result of the command is the empty string.
Multiple calls are allowed, with each call opening a new nesting
level of diversion.
::critcl::collect_end
This command end the diversion of C code collection into memory
and returns the collected C code.
If multiple levels of diversion are open the call only closes
and returns the data from the last level.
The command will throw an error if no diversion is active,
indicating a mismatch in the pairing of collect_begin and
collect_end.
::critcl::collect script
This is a convenience command which runs the script under
diversion and returns the collected C code, ensuring the correct
pairing of collect_begin and collect_end.
ADVANCED: FILE GENERATION
While file generation is related to the diversions explained in the
previous section they are not the same. Even so, like diversions this
feature is for higher-level packages generating their own C code.
Three examples of utility packages using this facility comes with
critcl itself. See the implementations of packages critcl::literals,
critcl::bitmap, and critcl::enum.
When splitting a package implementation into pieces it is often
sensible to have a number of pure C companion files containing low-
level code, yet these files may require information about the code in
the main ".critcl" file. Such declarations are normally not exportable
and using the stub table support does not make sense, as this is
completely internal to the package.
With the file generation command below the main ".critcl" file can
generate any number of header files for the C companions to pick up.
::critcl::make path contents
This command creates the file path in a location where the C
companion files of the package are able to pick it up by simple
inclusion of path during their compilation, without interfering
with the outer system at all.
The generated file will contain the specified contents.
ADVANCED: EXTENDING CPROC
While the critcl::cproc command understands the most common C types
(see section Embedded C Code), sometimes this is not enough.
To get around this limitation the commands in this section enable users
of critcl to extend the set of argument and result types understood by
critcl::cproc. In other words, to define their own custom types.
::critcl::resulttype name body ?ctype?
This command defines the result type name, and associates it
with the C code doing the conversion (body) from C to Tcl. The
C return type of the associated function, also the C type of the
result variable, is ctype. This type defaults to name if it is
not specified.
If name is declared already an error will be thrown. Attention!
The standard result type void is special as it has no
accompanying result variable. This cannot be expressed by the
this extension command.
The body's responsibility is the conversion of the functions
result into a Tcl result and a Tcl status. The first has to be
set into the interpreter we are in, and the second has to be
returned.
The C code of body is guaranteed to be called last in the
wrapper around the actual implementation of the cproc in
question and has access to the following environment:
interp A Tcl_Interp* typed C variable referencing the
interpreter the result has to be stored into.
rv The C variable holding the result to convert, of type
ctype.
As examples here are the definitions of two standard result
types:
resulttype int {
Tcl_SetObjResult(interp, Tcl_NewIntObj(rv));
return TCL_OK;
}
resulttype ok {
/* interp result must be set by cproc body */
return rv;
} int
::critcl::resulttype name = origname
This form of the resulttype command declares name as an alias of
result type origname, which has to be defined already. If this
is not the case an error is thrown.
::critcl::argtype name body ?ctype? ?ctypefun?
This command defines the argument type name, and associates it
with the C code doing the conversion (body) from Tcl to C The C
type of the variable to hold the conversion result is ctype and
the type of the function argument itself is ctypefun. Both
types default to name if they are not specified (or the empty
string).
If name is declared already an error will be thrown.
The body's responsibility is the conversion of a command's
Tcl_Obj* argument into a C value for the underlying function and
its storage in a helper variable.
The C code of body is guaranteed to be called inside of a
separate C code block (thus allowing the use of local variables)
which has access to the following environment:
interp A Tcl_Interp* typed C variable referencing the
interpreter the code is running in.
@@ A placeholder for the Tcl_Obj*-valued C expression
providing the value of the argument to convert.
@A A placeholder for the name of the C variable to store the
converted argument into.
As examples here are the definitions of two standard argument
types:
argtype int {
if (Tcl_GetIntFromObj(interp, @@, &@A) != TCL_OK) return TCL_ERROR;
}
argtype float {
double t;
if (Tcl_GetDoubleFromObj(interp, @@, &t) != TCL_OK) return TCL_ERROR;
@A = (float) t;
}
::critcl::argtype name = origname
This form of the argtype command declares name as an alias of
argument type origname, which has to be defined already. If this
is not the case an error is thrown.
::critcl::argtypesupport name code
This command defines a C code fragment for the already defined
argument type name which will be inserted before all functions
using that type. Its purpose is the definition of any supporting
C types needed by the argument type. If the type is used by
many functions the system ensure that only the first of the
multiple insertions of the code fragment is active, and the
others disabled.
CONCEPTS
MODES OF OPERATION/USE
CriTcl can be used in three different modes of operation, called
[1] Compile & Run, and
[2] Generate Package
[3] Generate TEA Package
Of these three Compile & Run came first and is the default when using
the package directly. In that case the package collects the C
fragments, builds them as needed, and caches the results for quick
reuse when the same code is used in the future again.
The second mode, Generate Package, was introduced to enable the
creation of (prebuilt) deliverable packages which do not depend on the
existence of a build system, i.e. C compiler, on the target machine.
This was originally done through the experimental Critbind tool, and is
now handled by the CriTcl Application, also named critcl.
Newly introduced with Critcl version 3 is Generate TEA Package. This
mode constructs a directory hierarchy from the package which can later
be built like a regular TEA package, i.e. using
.../configure --prefix ...
make all isntall
Regarding the caching of results please read the section about the
Result Cache fore more details.
RUNTIME BEHAVIOUR
The default behaviour of critcl, the package is to defer the
compilation, linking, and loading of any C code as much as possible,
given that this is an expensive operation, mainly in the time required.
In other words, the C code embedded into a ".critcl" file is built only
when the first C command or procedure it provides is invoked. This
part of the system uses standard functionality built into the Tcl core,
i.e. the auto_index variable to map from commands to scripts providing
them and the unknown command using this information when the command is
needed.
A limitation of this behaviour is that it is not possible to just use
info commands check for the existence of a critcl defined command. It
is also necessary to search in the auto_index array, in case it has not
been build yet.
This behaviour can be changed by using the control command
critcl::load. When invoked, the building, including loading of the
result, is forced. After this command has been invoked for a ".critcl"
file further definition of C code in this file is not allowed any
longer.
FILE MAPPING
Each ".critcl" file is backed by a single private ".c" file containing
that code, plus the boilerplate necessary for its compilation and
linking as a single shared library.
The Embedded C Code fragments appear in that file in the exact same
order they were defined in the ".critcl" file, with one exception. The
C code provided via critcl::cinit is put after all other fragments. In
other words all fragments have access to the symbols defined by earlier
fragments, and the critcl::cinit fragment has access to all, regardless
of its placement in the ".critcl" file.
Note: A limitation of the current system is the near impossibility of C
level access between different critcl-based packages. The issue is not
the necessity of writing and sharing the proper extern statements, but
that the management (export and import) of package-specific stubs-
tables is not supported. This means that dependent parts have to be
forcibly loaded before their user, with all that entails. See section
Runtime Behaviour for the relevant critcl limitation, and remember that
many older platforms do not support the necessary resolution of
symbols, the reason why stubs were invented for Tcl in the first place.
RESULT CACHE
The compilation of C code is time-consuming critcl not only defers it
as much as possible, as described in section Runtime Behaviour, but
also caches the results.
This means that on the first use of a ".critcl" file "FOO.tcl" the
resulting object file and shared library are saved into the cache, and
on future uses of the same file reused, i.e. loaded directly without
requiring compilation, provided that the contents of "FOO.tcl" did not
change.
The change detection is based MD5 hashes. A single hash is computed for
each ".critcl" file, based on hashes for all C code fragments and
configuration options, i.e. everything which affects the resulting
binary.
As long as the input file doesn't change as per the hash a previously
built shared library found in the cache is reused, bypassing the
compilation and link stages.
The command to manage the cache are found in section Result Cache
Management. Note however that they are useful only to tools based on
the package, like the CriTcl Application. Package writers have no need
of them.
As a last note, the default directory for the cache is chosen based on
the chosen build target. This means that the cache can be put on a
shared (network) filesystem without having to fear interference between
machines of different architectures.
PRELOADING FUNCTIONALITY
The audience of this section are developers wishing to understand and
possibly modify the internals of critcl package and application.
Package writers can skip this section.
It explains how the preloading of external libraries is realized.
Whenever a package declares libraries for preloading critcl will build
a supporting shared library providing a Tcl package named "preload".
This package is not distributed separately, but as part of the package
requiring the preload functionality. This support package exports a
single Tcl command
::preload library
which is invoked once per libraries to preload, with the
absolute path of that library. The command then loads the
library.
On windows the command will further use the Tcl command
::critcl::runtime::precopy to copy the library to the disk,
should its path be in a virtual filesystem which doesn't
directly support the loading of a shared library from it.
The command ::critcl::runtime::precopy is provided by the file "critcl-
rt.tcl" in the generated package, as is the command
::critcl::runtime::loadlib which generates the ifneeded script expected
by Tcl's package management. This generated ifneeded script contains
the invocations of ::preload.
The C code for the supporting library is found in the file
"critcl_c/preload.c", which is part of the critcl package.
The Tcl code for the supporting runtime "critcl-rt.tcl" is found in the
file "runtime.tcl", which is part of the critcl::app package.
CONFIGURATION INTERNALS
The audience of this section are developers wishing to understand and
possibly modify the internals of critcl package and application.
Package writers can skip this section.
It explains the syntax of configuration files and the configuration
keys used by critcl to configure its build backend, i.e. how this part
of the system accesses compiler, linker, etc.
It is recommended to open the file containing the standard
configurations ("path/to/critcl/Config") in the editor of your choice
when reading this section of the documentation, using it as an extended
set of examples going beyond the simple defaults shown here.
First, the keys and the meaning of their values, plus examples drawn
from the standard configurations distributed with the package. Note
that when writing a custom configuration it is not necessary to specify
all the keys listed below, but only those whose default values are
wrong or insufficient for the platform in question.
version
The command to print the compiler version number. Defaults to
gcc -v
compile
The command to compile a single C source file to an object file.
Defaults to
gcc -c -fPIC
debug_memory
The list of flags for the compiler to enable memory debugging in
Tcl. Defaults to
-DTCL_MEM_DEBUG
debug_symbols
The list of flags for the compiler to add symbols to the object
files and the resulting library. Defaults to
-g
include
The compiler flag to add an include directory. Defaults to
-I
tclstubs
The compiler flag to set USE_TCL_STUBS. Defaults to
-DUSE_TCL_STUBS
tkstubs
The compiler flag to set USE_TK_STUBS. Defaults to
-DUSE_TK_STUBS
threadflags
The list of compiler flags to enable a threaded build. Defaults
to
-DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1
-DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1 -DHAVE_READDIR_R=1
-DTCL_THREADS=1
.
noassert
The compiler flag to turn off assertions in Tcl code. Defaults
to
-DNDEBUG
optimize
The compiler flag to specify optimization level. Defaults to
-O2
output The compiler flags to set the output file of a compilation.
Defaults to
-o [list $outfile]
NOTE the use of Tcl commands and variables here. At the time critcl
uses the value of this key the value of the referenced variable is
substituted into it. The named variable is the only variable whose
value is defined for this substitution.
object The file extension for object files on the platform. Defaults
to
.o
preproc_define
The command to preprocess a C source file without compiling it,
but leaving #define's in the output. Defaults to
gcc -E -dM
preproc_enum
See preproc_define, except that #define's are not left in the
output. Defaults to
gcc -E
link The command to link one or more object files and create a shared
library. Defaults to
gcc -shared
link_preload
The list of linker flags to use when dependent libraries are
pre-loaded. Defaults to
--unresolved-symbols=ignore-in-shared-libs
strip The flag to tell the linker to strip symbols from the shared
library. Defaults to
-Wl,-s
ldoutput
Like output, but for the linker. Defaults to the value of
output.
link_debug
The list of linker flags needed to build a shared library with
symbols. Defaults to the empty string. One platform requiring
this are all variants of Windows, which uses
-debug:full -debugtype:cv
link_release
The list of linker flags needed to build a shared library
without symbols, i.e. a regular build. Defaults to the empty
string. One platform requiring this are all variants of
Windows, which uses
-release -opt:ref -opt:icf,3 -ws:aggressive
sharedlibext
The file extension for shared library files on the platform.
Defaults to
[info sharedlibextension]
platform
The identifier of the platform used in generated packages.
Defaults to
[platform::generic]
target The presence of this key marks the configuration as a cross-
compilation target and the value is the actual platform
identifier of the target. No default.
The syntax expected from configuration files is governed by the rules
below. Again, it is recommended to open the file containing the
standard configurations ("path/to/critcl/Config") in the editor of your
choice when reading this section of the documentation, using it as an
extended set of examples for the syntax>
[1] Each logical line of the configuration file consists of one or
more physical lines. In case of the latter the physical lines
have to follow each other and all but the first must be marked
by a trailing backslash. This is the same marker for
continuation lines as used by Tcl itself.
[2] A (logical) line starting with the character "#" (modulo
whitespace) is a comment which runs until the end of the line,
and is otherwise ignored.
[3] A (logical) line starting with the word "if" (modulo whitespace)
is interpreted as Tcl's if command and executed as such. I.e.
this command has to follow Tcl's syntax for the command, which
may stretch across multiple logical lines. The command will be
run in a save interpreter.
[4] A (logical) line starting with the word "set" (modulo
whitespace) is interpreted as Tcl's set command and executed as
such. I.e. this command has to follow Tcl's syntax for the
command, which may stretch across multiple logical lines. The
command will be run in a save interpreter.
[5] A line of the form "platform variable value" defines a platform
specific configuration variable and value. The variable has to
be the name of one of the configuration keys listed earlier in
this section, and the platform string identifies the platform
the setting is for. All settings with the same identification
string form the configuration block for this platform.
[6] A line of the special form "platform when expression" marks the
platform and all the settings in its configuration block as
conditional on the expression.
If the build platform is not a prefix of platform, nor vice
versa the whole block is ignored. Otherwise the expression is
evaluated via expr, in the same safe interpreter used to run any
set and if commands found in the configuration file (see above).
If the expression evaluates to true this configuration block is
considered to be the build platform fo the host and chosen as
the default configuration. An large example of of this feature
is the handling of OS X found in the standard configuration
file, where it selects the architectures to build based on the
version of the operating system, the available SDK, etc. I.e. it
chooses whether the output is universal or not, and whether it
is old-style (ix86 + ppc) versus new-style (ix86 32+64) of
universality.
[7] A line of the special form "platform copy sourceplatform" copies
the configuration variables and values currently defined in the
configuration block for sourceplatform to that of platform,
overwriting existing values, and creating missing ones.
Variables of platform not defined by by sourceplatform are not
touched.
The copied values can be overridden later in the configuration
file. Multiple copy lines may exist for a platform and be
intermixed with normal configuration definitions. If a variable
is defined multiple times, the last definition will be used.
[8] At last, a line of the form "variable value" defines a default
configuration variable and value.
STUBS TABLES This section is for developers of extensions not based on
critcl, yet
also wishing to interface with stubs as they are understood and used by
critcl, either by exporting their own stubs table to a critcl-based
extension, or importing a stubs table of a critcl-based extension into
their own.
To this end we describe the stubs table information of a package foo.
[1] Note that the differences in the capitalization of "foo", "Foo",
"FOO", etc. below demonstrate how to capitalize the actual
package name in each context.
[2] All relevant files must be available in a sub-directory "foo"
which can be found on the include search paths.
[3] The above directory may contain a file "foo.decls". If present
it is assumed to contain the external representation of the
stubs table the headers mentioned in the following items are
based on.
critcl is able to use such a file to give the importing package
programmatic access to the imported API, for automatic code
generation and the like.
[4] The above directory must contain a header file "fooDecls.h".
This file declares the exported API. It is used by both
exporting and importing packages. It is usually generated and
must contain (in the order specified):
[1] the declarations of the exported, i.e. public, functions
of foo,
[2] the declaration of structure "FooStubs" for the stub
table,
[3] the C preprocessor macros which route the invocations of
the public functions through the stubs table.
These macros must be defined if, and only if, the C
preprocessor macro USE_FOO_STUBS is defined. Package foo
does not define this macro, as it is allowed to use the
exported functions directly. All importing packages
however must define this macro, to ensure that they do
not use any of the exported functions directly, but only
through the stubs table.
[4] If the exported functions need additional types for their
proper declaration then these types should be put into a
separate header file (of arbitrary name) and "fooDecls.h"
should contain an #include directive to this header at
the top.
A very reduced, yet also complete example, from a package for low-level
random number generator functions can be found at the end of this
section.
[5] The above directory must contain a header file "fooStubLib.h".
This file defines everything needed to use the API of foo.
Consequently it is used only by importing packages. It is
usually generated and must contain (in the order specified):
[1] An #include directive for "tcl.h", with USE_TCL_STUBS
surely defined.
[2] An #include directive for "fooDecls.h", with
USE_FOO_STUBS surely defined.
[3] A definition of the stubs table variable, i.e.
const FooStubs* fooStubsPtr;
[4] A definition of the stubs initializer function, like
char *
Foo_InitStubs(Tcl_Interp *interp, CONST char *version, int exact)
{
/*
* Boiler plate C code initalizing the stubs table variable,
* i.e. "fooStubsPtr".
*/
CONST char *actualVersion;
actualVersion = Tcl_PkgRequireEx(interp, "foo", version,
exact, (ClientData *) &fooStubsPtr);
if (!actualVersion) {
return NULL;
}
if (!fooStubsPtr) {
Tcl_SetResult(interp,
"This implementation of Foo does not support stubs",
TCL_STATIC);
return NULL;
}
return (char*) actualVersion;
}
This header file must be included by an importing package
exactly once, so that it contains only one definition of both
stubs table and stubs initializer function.
The importing package's initialization function must further
contain a statement like
if (!Foo_InitStubs (ip, "1", 0)) {
return TCL_ERROR;
}
which invokes foo's stubs initializer function to set the local
stub table up.
For a complete example of such a header file see below, at the
end of this section.
[6] The last item above, about "fooStubLib.h" differs from the
regular stub stable system used by Tcl. The regular system
assumes that a static library "libfoostub.a" was installed by
package foo, and links it.
IMVHO critcl's approach is simpler, using only header files
found in a single location, vs. header files and static library
found in multiple, different locations.
A second simplification is that we avoid having to extend
critcl's compiler backend with settings for the creation of
static libraries.
Below is a complete set of example header files, reduced, yet still
complete, from a package for low-level random number generator
functions:
"rngDecls.h":
#ifndef rng_DECLS_H
#define rng_DECLS_H
#include <tcl.h>
/*
* Exported function declarations:
*/
/* 0 */
EXTERN void rng_bernoulli(double p, int*v);
typedef struct RngStubs {
int magic;
const struct RngStubHooks *hooks;
void (*rng_bernoulli) (double p, int*v); /* 0 */
} RngStubs;
#ifdef __cplusplus
extern "C" {
#endif
extern const RngStubs *rngStubsPtr;
#ifdef __cplusplus
}
#endif
#if defined(USE_RNG_STUBS)
/*
* Inline function declarations:
*/
#define rng_bernoulli (rngStubsPtr->rng_bernoulli) /* 0 */
#endif /* defined(USE_RNG_STUBS) */
#endif /* rng_DECLS_H */
"rngStubLib.h":
/*
* rngStubLib.c --
*
* Stub object that will be statically linked into extensions that wish
* to access rng.
*/
#ifndef USE_TCL_STUBS
#define USE_TCL_STUBS
#endif
#undef USE_TCL_STUB_PROCS
#include <tcl.h>
#ifndef USE_RNG_STUBS
#define USE_RNG_STUBS
#endif
#undef USE_RNG_STUB_PROCS
#include "rngDecls.h"
/*
* Ensure that Rng_InitStubs is built as an exported symbol. The other stub
* functions should be built as non-exported symbols.
*/
#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLEXPORT
const RngStubs* rngStubsPtr;
?
/*
*----------------------------------------------------------------------
*
* Rng_InitStubs --
*
* Checks that the correct version of Rng is loaded and that it
* supports stubs. It then initialises the stub table pointers.
*
* Results:
* The actual version of Rng that satisfies the request, or
* NULL to indicate that an error occurred.
*
* Side effects:
* Sets the stub table pointers.
*
*----------------------------------------------------------------------
*/
#ifdef Rng_InitStubs
#undef Rng_InitStubs
#endif
char *
Rng_InitStubs(Tcl_Interp *interp, CONST char *version, int exact)
{
CONST char *actualVersion;
actualVersion = Tcl_PkgRequireEx(interp, "rng", version,
exact, (ClientData *) &rngStubsPtr);
if (!actualVersion) {
return NULL;
}
if (!rngStubsPtr) {
Tcl_SetResult(interp,
"This implementation of Rng does not support stubs",
TCL_STATIC);
return NULL;
}
return (char*) actualVersion;
}
EXAMPLES
As the set of examples is a bit large, and growing, it has been put
into a separate document. Please see section "Embedding C" in the
document about Using CriTcl.
The latest changes are found at the top.
CHANGES FOR VERSION 3.1.15
[1] Fixed version number bogosity with 3.1.14.
CHANGES FOR VERSION 3.1.14
[1] Fixed issue #36. Added message to target all of the Makefile
generated for TEA mode. Additionally tweaked other parts of the
output to be less noisy.
[2] Accepted request implied in issue #54. Unconditionally save the
compiler/linker build log into key log of the dictionary
returned by cresults, and save a copy of only the execution
output in the new key exl ("execution log").
[3] Fixed issue #53. Clarified the documentation of commands
critcl::load and critcl::failed with regard to their results and
the throwing of errors (does not happen).
[4] Fixed issue #48. Modified mode "compile & run" to allow new
declarations in a file, after it was build, instead of erroring
out. The new decls are build when needed. Mode "precompile" is
unchanged and will continue to trap the situation.
[5] Fixed issue #52. Updated the local Tcl/Tk headers to 8.4.20,
8.5.13, and 8.6.4.
[6] Fixed issue #45. New feature command critcl::cconst.
[7] critcl::util: New command locate to find a file across a set of
paths, and report an error when not found. This is for use in
autoconf-like header-searches and similar configuration tests.
[8] Modified 'AbortWhenCalledAfterBuild' to dump the entire stack
(info frame!). This should make it easier to determine the
location of the troubling declaration.
CHANGES FOR VERSION 3.1.13
[1] Merged PR #43. Fixed bug loading adjunct Tcl sources.
[2] Fixes in documentation and generated code of package
"critcl::enum". Bumped to version 1.0.1.
[3] Fixes in documentation of package "critcl::bitmap".
[4] New package "critcl::emap". In essence a variant or cross of
"critcl::bitmap" with behaviour like "critcl::enum".
[5] Merged PR #49. Fixed documentation typo.
[6] Merged PR #46. Fixed documentation typo.
[7] Merged PR #47. Fixes to test results to match the accumulated
code changes. Also made portable across Tcl versions (varying
error syntax).
[8] New predefined argument- and result-type "wideint" mapping to
Tcl_WideInt.
[9] New predefined argument-type "bytes" mapping to tuple of byte-
array data and length. Note: The existing "bytearray" type (and
its aliases) was left untouched, to keep backward compatibility.
[10] Modified the internal interface between the Tcl shim and C
function underneath "critcl::cproc" with respect to the handling
of optional arguments. An optional argument "X" now induces the
use of two C arguments, "X" and "has_X". The new argument
"has_X" is of boolean (int) type. It is set to true when X is
set, and set to false when X has the default value. C code which
cares about knowing if the argument is default or not is now
able to check that quickly, without having to code the default
value inside. NOTE: This change is visible in the output of the
advanced commands "argcnames", "argcsignature", "argvardecls",
and "argconversion".
[11] Fixed issue #50 and documented the availability of variable
"interp" (type Tcl_Interp*) within "critcl::cinit" C code
fragments. Note that while the old, undocumented name of the
variable, "ip", is still usable, it is deprecated. It will be
fully removed in two releases, i.e. for release 3.1.15. The
variable name was changed to be consistent with other code
environments.
[12] Fixed issue #51. Disabled the generation of #line directives for
"critcl::config lines 0" coming from template files, or code
generated with them before the final value of this setting was
known.
[13] Fixed issue with handling of namespaced package names in
"critcl::iassoc". Equivalent to a bug in "critcl::class" fixed
for critcl 3.1.1, critcl::class 1.0.1. Note: "literals",
"enum", "emap", and "bitmap" do not require a fix as they are
all built on top of "iassoc".
CHANGES FOR VERSION 3.1.12
[1] Fixed issue 42. Clear ::errorInfo immediately after startup to
prevent leakage of irrelevant (caught) errors into our script
and confusing the usage code.
[2] Fixed issue 40. Keep the order of libraries, and allow
duplicates. Both are things which are occasionally required for
proper linking.
[3] Extended the utility package critcl::literals to declare a cproc
result-type for a pool.
Further fixed the generated header to handle multiple inclusion.
Bumped version to 1.1.
[4] Fixed issue with utility package critcl::bitmap.
Fixed the generated header to handle multiple inclusion.
Bumped version to 1.0.1.
[5] Created new utility package critcl::enum for the quick and easy
setup and use of mappings between C values and Tcl strings.
Built on top of critcl::literals.
[6] Added examples demonstrating the use of the utility packages
critcl::literals, critcl::bitmap, and critcl::enum
CHANGES FOR VERSION 3.1.11
[1] Fixed issue #37, via pull request #38, with thanks to Jos
DeCoster. Information was stored into the v::delproc and
v::clientdata arrays using a different key than when retrieving
the same information, thus failing the latter.
[2] New convenience command critcl::include for easy inclusion of
headers and other C files.
[3] New command critcl::make to generate a local header of other C
files for use by other parts of a package through inclusion.
[4] New utility package critcl::literals for quick and easy setup of
and access to pools of fixed Tcl_Obj* strings. Built on top of
critcl::iassoc.
[5] New utility package critcl::bitmap for quick and easy setup and
use of mappings between C bitsets and Tcl lists whose string
elements represent that set. Built on top of critcl::iassoc.
CHANGES FOR VERSION 3.1.10
[1] Fixed code version numbering forgotten with 3.1.9.
[2] Fixed issue #35. In package mode (-pkg) the object cache
directory is unique to the process, thus we do not need content-
hashing to generate unique file names. A simple counter is
sufficient and much faster.
Note that mode "compile & run" is not as blessed and still uses
content-hasing with md5 to ensure unique file names in its per-
user object cache.
[3] Fixed issue where the ccommand forgot to use its body as input
for the UUID generation. Thus ignoring changes to it in mode
compile & run, and not rebuilding a library for changed sources.
Bug and fix reported by Peter Spjuth.
CHANGES FOR VERSION 3.1.9
[1] Fixed issue #27. Added missing platform definitions for various
alternate linux and OS X targets.
[2] Fixed issue #28. Added missing -mXX flags for linking at the
linux-{32,64}-* targets.
[3] Fixed issue #29. Replaced the use of raw "cheaders" information
in the processing of "cdefines" with the proper include
directives derived from it.
[4] Fixed the issue behind rejected pull request #30 by Andrew
Shadura. Dynamically extract the stubs variable declarations
from the Tcl header files and generate matching variable
definitions for use in the package code. The generated code will
now be always consistent with the headers, even when critcl's
own copy of them is replaced by system headers.
[5] Fixed issue #31. Accepted patch by Andrew Shadura, with changes
(comments), for easier integration of critcl with OS package
systems, replacing critcl's copies of Tcl headers with their
own.
[6] Fixed issue #32. Merged pull request by Andrew Shadura. Various
typos in documentation and comments.
[7] Fixed issue #34. Handle files starting with a dot better.
CHANGES FOR VERSION 3.1.8
[1] Fixed issue with package indices generated for Tcl 8.4. Join
the list of commands with semi-colon, not newline.
[2] Fixed issue #26 which brought up use-cases I had forgotten to
consider while fixing bug #21 (see critcl 3.1.6).
CHANGES FOR VERSION 3.1.7
[1] Fixed issue #24. Extract and unconditionally display compiler
warnings found in the build log. Prevents users from missing
warnings which, while not causing the build to fail, may still
indicate problems.
[2] New feature. Output hook. All non-messaging user output is now
routed through the command critcl::print, and users are allowed
to override it when using the critcl application-as-package.
[3] New feature, by Ashok P. Nadkarni. Platform configurations can
inherit values from configurations defined before them.
CHANGES FOR VERSION 3.1.6
[1] Fixed issue #21. While the multi-definition of the stub-table
pointer variables was ok with for all the C linkers seen so far
C++ linkers did not like this at all. Reworked the code to
ensure that this set of variables is generated only once, in the
wrapper around all the pieces to assemble.
[2] Fixed issue #22, the handling of the command identifier
arguments of critcl::ccommand, critcl::cproc, and critcl::cdata.
We now properly allow any Tcl identifier and generate proper
internal C identifiers from them.
As part of this the signature of command critcl::name2c changed.
The command now delivers a list of four values instead of three.
The new value was added at the end.
Further adapted the implementation of package critcl::class, a
user of critcl::name2c. This package is now at version 1.0.6
and requires critcl 3.1.6
Lastly fixed the mis-handling of option -cname in
critcl::ccommand, and critcl::cproc.
[3] Fixed issue #23.
CHANGES FOR VERSION 3.1.5
[1] Fixed issue #19. Made the regular expression extracting the MSVC
version number more general to make it work on german language
systems. This may have to be revisited in the future, for other
Windows locales.
[2] Fixed issue #20. Made option -tea work on windows, at least in a
unix emulation environment like msys/mingw.
CHANGES FOR VERSION 3.1.4
[1] Bugfix in package critcl::class. Generate a dummy field in the
class structure if the class has no class variables. Without
this change the structure would be empty, and a number of
compilers are not able to handle such a type.
[2] Fixed a typo which broke the win64 configuration.
[3] Fixed issue #16, a typo in the documentation of command
critcl::class.
CHANGES FOR VERSION 3.1.3
[1] Enhancement. In detail:
[2] Added new argument type "pstring", for "Pascal String", a
counted string, i.e. a combination of string pointer and string
length.
[3] Added new methods critcl::argtypesupport and
::critcl::argsupport to define and use additional supporting
code for an argument type, here used by "pstring" above to
define the necessary structure.
[4] Semi-bugfixes in the packages critcl::class and critcl::iassoc.
Pragmas for the AS meta data scanner to ensure that the template
files are made part of the package. Versions bumped to 1.0.4
and 1.0.1 respectively.
CHANGES FOR VERSION 3.1.2
[1] Enhancement. In detail:
[2] Extended critcl::cproc to be able to handle optional arguments,
in a limited way. This is automatically available to
critcl::class cproc-based methods as well.
[3] Bugfix in lassign emulation for Tcl 8.4. Properly set unused
variables to the empty string. Bumped version of emulation
package lassign84 to 1.0.1.
CHANGES FOR VERSION 3.1.1
[1] Bugfixes all around. In detail:
[2] Fixed the generation of wrong#args errors for critcl::cproc and
derived code (critcl::class cproc-based methods). Use NULL if
there are no arguments, and take the offset into account.
[3] Fixed the handling of package names by critcl::class. Forgot
that they may contain namespace separators. Bumped to version
1.0.1.
[4] Extended a critcl::class generated error message in instance
creation for clarity. Bumped to version 1.0.2.
CHANGES FOR VERSION 3.1
[1] Added a new higher-level package critcl::iassoc.
This package simplifies the creation of code associating data
with an interpreter via Tcl's Tcl_(Get|Set)AssocData() APIs. The
user can concentrate on his data while all the necessary
boilerplate C code to support this is generated by the package.
This package uses several of the new features which were added
to the core critcl package, see below.
[2] Added the higher-level package critcl::class.
This package simplifies the creation of C level objects with
class and instance commands. The user can write a class
definition with class- and instance-variables and -methods
similar to a TclOO class, with all the necessary boilerplate C
code to support this generated by the package.
This package uses several of the new features which were added
to the core critcl package, see below.
[3] Extended the API for handling TEApot metadata. Added the command
critcl::meta? to query the stored information. Main use
currently envisioned is retrieval of the current package's name
by utility commands, for use in constructed names. This
particular information is always available due to the static
scan of the package file on execution of the first critcl
command.
The new packages critcl::iassoc and critcl::class (see above)
are users of this command.
[4] Extended the API with a command, critcl::name2c, exposing the
process of converting a Tcl name into base name, namespace, and
C namespace. This enables higher-level code generators to
generate the same type of C identifiers as critcl itself.
The new package critcl::class (see above) is a user of this
command.
[5] Extended the API with a command, critcl::source, executing
critcl commands found in a separate file in the context of the
current file. This enables easier management of larger bodies of
code as it allows the user to split such up into easier to
digest smaller chunks without causing the generation of multiple
packages.
[6] Related to the previous item, extended the API with commands to
divert collection of generated C code into memory. This makes it
easier to use the commands for embedded C code in higher-level
code generators.
See the section Advanced: Diversions for details of the provided
commands.
The new package critcl::class (see above) is a user of these
facilities.
[7] Extended the API with commands helping developers with the
generation of proper C #line directives. This allows higher-
level code generators to generate and insert their own
directives, ensuring that compile errors in their code are
properly attributed.
See the section Advanced: Location management for details of the
provided commands.
The new packages critcl::iassoc and critcl::class (see above)
are users of these facilities.
[8] Extended the API with commands giving users the ability to
define custom argument and result types for ::critcl::cproc.
See the section Advanced: Extending cproc for details of the
provided commands.
CHANGES FOR VERSION 3.0.7
[1] Fixed the code generated by critcl::c++command. The emitted
code handed a non-static string table to Tcl_GetIndexFromObj, in
violation of the contract, which requires the table to have a
fixed address. This was a memory smash waiting to happen. Thanks
to Brian Griffin for alrerting us to the general problem.
CHANGES FOR VERSION 3.0.6
[1] Fixed github issue 10. The critcl application now delivers a
proper exit code (1) on build failure, instead of always
indicating success (status 0).
[2] Fixed github issue 13. Handling of bufferoverflowU.lib for
release builds was inconsistent with handling for debug builds.
It is now identically handled (conditional) by both cases.
[3] Documentation cleanup, mainly in the installation guide, and the
README.md shown by github
CHANGES FOR VERSION 3.0.5
[1] Fixed bug in the new code for #line pragmas triggered when
specifying C code without leading whitespace.
[2] Extended the documentation to have manpages for the license,
source retrieval, installer, and developer's guides.
CHANGES FOR VERSION 3.0.4
[1] Fixed generation of the package's initname when the incoming
code is read from stdin and has no proper path.
[2] Fixed github issue 11. Now using /LIBPATH instead of -L on
Windows (libinclude configuration setting).
[3] Extended critcl to handle -l:path format of -l options. GNU ld
2.22+ handles this by searching for the path as is. Good when
specifying static libraries, as plain -l looks for shared
libraries in preference over static. critcl handles it now, as
older GNU ld's do not understand it, nor the various vendor-
specific linkers.
[4] Fixed github issue #12. Critcl now determines the version of
MSVC in use and uses it to switch between various link debug
options. Simplified the handling of bufferoverflowU.lib also,
making use of the same mechanism and collapsing the two
configurations sections we had back into one.
[5] Reworked the insertion of #line pragmas into the generated C
code to avoid limitations on the line number argument imposed by
various compilers, and be more accurate.
[6] Modified argument processing. Option -libdir now also implies -L
for its argument.
[7] Extended handling of option -show (critcl::showconfig) to list
the path of the configuration file the data is coming from. Good
for debugging configuration processing.
[8] Extended the build script with targets to regenerate the
embedded documentation, and diagrams, and to generate a release.
CHANGES FOR VERSION 3.0.3
[1] Fixed github issues 5 and 8, for the example build.tcl scripts.
Working around a missing variable ::errorInfo. It should always
be present, however there seem to be revisions of Tcl around
which violate this assumption.
CHANGES FOR VERSION 3.0.2
[1] Fixed issue in compile-and-run mode where commands put into the
auto_index are not found by Tcl's [unknown] command.
[2] Fixed an array key mismatch breaking usage of client data and
delete function for procedure. Reported by Jos DeCoster, with
patch.
[3] Implemented a command line option -L, an equivalent of option
-I, just for library search paths.
[4] Fixed github issues 5 and 8. Working around a missing variable
::errorInfo. It should always be present, however there seem to
be revisions of Tcl around which violate this assumption.
CHANGES FOR VERSION 3.0.1
[1] Bugfixes all around. In detail:
[2] Fixed recording of Tcl version requirements. Keep package name
and version together, unbreaking generated meta data and
generated package load command.
[3] Fixed the build scripts: When installing, or wrapping for TEA,
generate any missing directories
[4] Modified the build scripts to properly exit the application when
the window of their GUI is closed through the (X) button.
[5] Removed an 8.5-ism (open wb) which had slipped into the main
build script.
[6] Modified the example build scripts to separate the output for
the different examples (and packages) by adding empty lines.
[7] stack::c example bugfix: Include API declarations for use in the
companion files.
[8] Extended the documentation: Noted the need for a working
installation of a C compiler.
[9] Extended the Windows target definitions and code to handle the
manifest files used by modern MS development environments. Note
that this code handles both possibilities, environment using
manifests, and (old(er)) environments without.
[10] Extended the Windows 64bit target definitions and code to auto-
detect the need for the helper library "bufferoverflowU.lib" and
reconfigure the compile and link commands appropriately. We
assume that the library must be linked when present. This should
be no harm if the library is present, yet not needed. Just
superfluous. We search for the library in the paths specified by
the environment variable LIB.
CHANGES FOR VERSION 3
[1] The command critcl::platform was deprecated in version 2.1,
superceded by critcl::targetplatform, yet kept for
compatibility. Now it has been removed.
[2] The command critcl::compiled was kept with in version 2.1 with
semantics in contradiction to its, for compatibility. This
contradiction has been removed, changing the visible semantics
of the command to be in line with its name.
[3] The change to version 3 became necessary because of the two
incompatible visible changes above.
[4] Extended the application package with code handling a new option
-tea. Specifying this option invokes a special mode where critcl
generates a TEA package, i.e. wraps the input into a directory
hierarchy and support files which provide it TEA-lookalike
buildsystem.
This new option, and -pkg, exclude each other. If both are
specified the last used option takes precedence.
The generated package directory hierarchy is mostly self-
contained, but not fully. It requires not only a working
installation of Tcl, but also working installations of the
packages md5 and cmdline. Both of these are provided by the
Tcllib bundle. Not required, but recommended to have installed
are any of the packages which can accelerate md5's operation,
i.e. cryptkit, tcllibc, or Trf.
[5] Extended the critcl package with a new command critcl::scan
taking the path to a ".critcl" file, statically scanning it, and
returning license, version, a list of its companion files, list
of imported APIs, and list of developer-specified custom
configuration options. This data is the foundation for the TEA
wrapping described above.
Note that this is a static scan. While the other build modes can
(must) execute the ".critcl" file and make platform-specific
decisions regarding the assembled C code, companion files, etc.
the TEA wrap mode is not in a position to make platform-specific
decisions. It has to wrap everything which might conceivably be
needed when actually building. Hence the static scan. This has
however its own set of problems, namely the inability to figure
out any dynamic construction of companion file paths, at least
on its own. Thus:
[6] Extended the API used by critcl-based packages with the command
critcl::owns. While this command is ignored by the regular build
modes the static scanner described above takes its arguments as
the names of companion files which have to be wrapped into the
TEA package and could not be figured by the scanner otherwise,
like because of dynamic paths to critcl::tsources,
critcl::csources, getting sourced directly, or simply being
adjunct datafiles.
[7] Extended the API used by critcl-based packages with the command
critcl::api for the management of stubs tables, be it their use,
and/or declaration and export.
Please see section Stubs Table Management of the critcl package
documentation for details.
[8] Extended the API used by critcl-based packages with the command
critcl::userconfig for the management of developer-specified
custom configuration options, be it their use and/or
declaration.
Please see section Custom Build Configuration of the critcl
package documentation for details.
[9] Extended the API used by critcl-based packages with the commands
critcl::description, critcl::summary, critcl::subject,
critcl::meta, and critcl::buildrequirement for the declaration
of TEApot meta data for/about the package.
Please see section Package Meta Data of the critcl package
documentation for details.
CHANGES FOR VERSION 2.1
[1] Fixed bug where critcl::tsources interpreted relative paths as
relative to the current working directory instead of relative to
the ".critcl" file using the command, as all other commands of
this type do.
[2] Fixed internals, preventing information collected for multiple
".critcl" files to leak between them. Notably, critcl::tk is not
a global configuration option anymore.
[3] Fixed the command critcl::license to be a null-operation in mode
"compile & run", instead of throwing an error.
[4] Fixed the critcl application's interference with the "compile &
run" result cache in -pkg mode by having it use a wholly
separate (and by default transient) directory for that mode.
[5] Fixed bug where changes to a ".critcl" file did not result in a
rebuild for mode "compile & run". All relevant API commands now
ensure UUID changes.
[6] Fixed bug in the backend handling of critcl::debug where the
companion c-sources of a ".critcl" file were not compiled with
debug options, although the ".critcl" file was.
[7] Fixed bug in critcl::debug which prevented recognition of mode
"all" when it was not the first argument to the command.
[8] Fixed bug in "preload.c" preventing its compilation on non-
windows platforms.
[9] Fixed long-standing bug in the handling of namespace qualifiers
in the command name argument of critcl::cproc and
critcl::ccommand. It is now possible to specify a fully
qualified command name without issues.
[10] Extended/reworked critcl::tsources to be the canonical way of
declaring ".tcl" companion files even for mode "compile & run".
[11] Extended/reworked critcl::tsources to allow the use of a
".critcl" file as its own Tcl companion file.
[12] Extended critcl::framework to internally check for OS X build
target, and to ignore the declaration if its not.
[13] Extended critcl::failed to be callable more than once in a
".critcl" file. The first call forces the build, if it was not
done already, to get the result. Further calls return the cached
result of the first call.
[14] Extended the handling of environment variable CC in the code
determining the compiler to use to deal with (i.e. remove) paths
to the compiler, compiler file extensions, and compiler options
specified after the compiler itself, leaving only the bare name
of the compiler.
[15] Extended the code handling the search for preloaded libraries to
print the paths it searched, making debugging of a search
failure easier.
[16] A new command critcl::tcl can be used to declare the version of
Tcl minimally needed to build and run the ".critcl" file and
package. Defaults to 8.4 if not declared. Extended critcl to
have the stubs and headers for all of Tcl 8.4, 8.5, and 8.6.
[17] A new command critcl::load forces the build and load of a
".critcl" file. This is the official way for overriding critcl's
default lazy-build-&-load-on-demand scheme for mode "compile &
run".
Note that after using critcl::load / critcl::failed in a
".critcl" file it is not possible to use critcl commands in that
file anymore. Doing so will throw an error.
[18] Extended the generation of '#line' pragmas to use info frame (if
available) to provide the C compiler with exact line numbers
into the ".critcl" file for the reporting of warnings and
errors.
[19] Extended critcl::check with logging to help with debugging
build-time checks of the environment, plus an additional
optional argument to provide labeling.
[20] Added a new command critcl::checklink which not only tries to
check the environment via compiling the code, but also its
linkability.
[21] Added a new command critcl::msg for messaging, like command
critcl::error is for error reporting. Likewise this is a hook a
user of the package is allowed to override. The default
implementation, used by mode compile & run does nothing. The
implementation for mode generate package prints the message to
stdout.
Envisioned use is for the reporting of results determined by
critcl::check and critcl::checklink during building, to help
with debugging when something goes wrong with a check.
[22] Exposed the argument processing internals of critcl::proc for
use by advanced users. The new commands are
[1] critcl::argnames
[2] critcl::argcnames
[3] critcl::argcsignature
[4] critcl::argvardecls
[5] critcl::argconversion
Please see section Advanced Embedded C Code of the critcl
package documentation for details.
[23] Extended the critcl package to intercept package provide and
record the file -> package name mapping. Plus other internal
changes now allow the use of namespaced package names while
still using proper path names and init function.
[24] Dropped the unused commands critcl::optimize and
critcl::include.
[25] Dropped -lib mode from the critcl application.
[26] Dropped remnants of support for Tcl 8.3 and before.
AUTHORS
Jean Claude Wippler, Steve Landers, Andreas Kupries
BUGS, IDEAS, FEEDBACK
This document, and the package it describes, will undoubtedly contain
bugs and other problems. Please report them at
https://github.com/andreas-kupries/critcl/issues. Ideas for
enhancements you may have for either package, application, and/or the
documentation are also very welcome and should be reported at
https://github.com/andreas-kupries/critcl/issues as well.
KEYWORDS
C code, Embedded C Code, code generator, compile & run, compiler,
dynamic code generation, dynamic compilation, generate package, linker,
on demand compilation, on-the-fly compilation
CATEGORY
Glueing/Embedded C code
COPYRIGHT
Copyright (c) Jean-Claude Wippler
Copyright (c) Steve Landers
Copyright (c) 2011-2015 Andreas Kupries
doc 3.1.15 critcl(n)