act
is a build tool for Tcl that simplifies the building and
packaging of multiple packages and C extensions into a single Tcl
module file. It runs with a basic installation of Tcl 8.6 and does not
require VFS or sdx.
In addition, it uses CMake to generate build files and vcpkg to build and easily include thousands of C/C++ libraries.
It can also be used without CMake to build and deliver pure-Tcl modules as a single file which obfuscates the source code.
Compare act
with the official Tcl
SampleExtension, which
packages a single extension, does not package Tcl script packages, and
does not easily integrate with CMake and vcpkg.
See the examples
directory for a demonstration project that uses
libsodium to generate password
hashes.
This example has been tested on Linux with gcc and Windows with msvc.
$ ./act clean $ ./act build manifest.txt $ ./act install manifest.txt (optional)
Or on Windows:
PS> ./act.bat clean PS> ./act.bat build manifest.txt PS> ./act.bat install manifest.txt (optional)
act
uses a manifest file to identify the artifacts that will be
combined into a Tcl module. act
compresses each artifact using Tcl’s
zlib
module, which is available as part of a standard 8.6
distribution. It combines these artifacts into a single .tm
file,
along with a loader script. tm
files can be read by any standard
interpreter with the source
command.
act
generates the necessary package ifneeded
commands, so no
pkgIndex.tcl
files are necessary. (Indeed, they would not work,
because the act
loader script sources files from temporary
locations.)
The manifest may optionally include multiple packages, and each will
generate its own package ifneeded
.
The manifest may also include multiple native extensions, which are
loaded by the loader script with the load
command.
The manifest may include asset files, which are made available to your
program through the ::act::assets
dict. (See the example.)
And finally, the manifest may also include non-package scripts to be
loaded after everything else. This can be used to run a main.tcl
script if desired.
The loader first unpacks any asset files and adds them to the
::act::assets
dict. Then it executes load
on all shared libraries
found in the module. Next, it issues a package ifneeded
command for
each package with source files in the manifest. Finally, it executes
source
on each script found in the manifest not associated with a
package, in order.
The manifest format is based on HTTP headers, except the colon is not used to separate keys and values, since the colon is significant in Tcl namespace names.
Each line in the manifest includes a key and a value, separated by
whitespace. Reserved keys start with a dot (.
). Comments start with
a #
. All other keys are interpreted as a package name.
Package names may include ::
namespace specifiers, e.g.
myorg::mylib
. This is not required, but it’s nice if you want to
avoid name collisions with other community-developed packages.
The values of some reserved keys require their own key/value
declarations. In those cases, the =
sign is used. For example:
.vsn myorg::mylib=1.2 .vsn myorg::util=2.0
declares a version (‘vsn’) value of 1.2
for the myorg::mylib
package,
and 2.0
for the myorg::util
lib.
The .load
key accepts the root name of a load
-able binary, and a
list of search directories, separated by commas. act
will try to
find the library using the current system’s shared library extension,
with or without lib
prepended to the root name.
Key | Sample Value | Meaning |
---|---|---|
|
|
|
|
|
Path to output artifact. |
|
|
Dirs to search for |
|
|
Source |
|
|
Include files verbatim, accessible via
the |
|
|
Parent dir(s) of module when installed. |
pkgname |
|
Include |
.vsn hello = 1.0 .out hello-1.0.tm hello hello.tcl .source main.tcl
# Versions for Tcl packages included in this module .vsn example::alpha = 0.1 .vsn beta = 0.2 # The output artifact to generate .out build/bundle-1.0.tm # The parent directories within the install directory. This is # important because the Tcl module loader interprets nested namespaces # as directories. So installing under example/ would allow us to do # `package require example::bundle` to load the bundle. .install example/ # Source files for example::alpha package. # Require with `package require example::alpha` example::alpha lib/alpha/file1.tcl example::alpha lib/alpha/file2.tcl # Source files for beta package # Require with `package require beta` beta lib/beta/foo.tcl beta lib/beta/bar.tcl # Assets: included in module verbatim, and accessible via the # ::act::assets dict. .asset assets/data.txt # Source file for main (command line) app .source app/main.tcl # Note use of two search directories separated by ',', since Windows # builds tend to use CMake's Multi-Config generators .load example_cutil = build/, build/Release