Blocks can run small built-in commands at well-defined points of the
install/uninstall pipeline. They are declared in a package manifest under the
scripts array and are useful for tasks the compiler does not do on its own —
for example copying resource files next to the produced DCUs.
Add a scripts array to the manifest. Each entry binds a command to a
lifecycle event, with optional args:
"scripts": [
{
"description": "Copy resources and dfm",
"event": "afterCompile",
"command": "copyres"
},
{
"description": "Tell the user where the DCUs went",
"event": "afterCompile",
"command": "echo",
"args": ["Compiled %PACKAGE% for %PLATFORM%/%CONFIG% into %DCU_PATH%"]
}
]| Field | Required | Meaning |
|---|---|---|
command |
yes | Name of the built-in command to run (see Commands). |
event |
yes | Lifecycle event the script is bound to (see Events). |
description |
no | Free-text label, for humans. |
args |
no | List of string arguments passed to the command. |
Scripts run in declaration order for a given event. A script whose event
does not match any fired event never runs.
Before a command runs, every %VAR% placeholder in its command and in each
args entry is replaced with the value of the corresponding event variable.
Unknown variables expand to an empty string.
The set of available variables depends on the event:
These fire once per package, for each platform and build config, so the output paths point at the exact location that compilation used.
| Variable | Value |
|---|---|
%PACKAGE% |
Name of the package (.dproj) being compiled. |
%PLATFORM% |
Target platform, e.g. Win32, Win64. |
%CONFIG% |
Build config, Debug or Release. |
%WORKSPACE_PATH% |
Workspace root directory. |
%PROJECT_PATH% |
Extracted project directory (<workspace>\<package name>). |
%BPL_PATH% |
BPL output dir (<workspace>\.blocks\<platform>\bpl[\debug]). |
%DCP_PATH% |
DCP output dir (<workspace>\.blocks\<platform>\dcp[\debug]). |
%DCU_PATH% |
DCU output dir (<workspace>\.blocks\lib\<name>\<platform>[\debug]). |
These fire once per manifest. Only workspace- and project-level paths are meaningful at this stage:
| Variable | Value |
|---|---|
%WORKSPACE_PATH% |
Workspace root directory. |
%PROJECT_PATH% |
Extracted project directory. |
| Event | Fires | Granularity |
|---|---|---|
beforeCompile |
Before each package is compiled. | per package |
afterCompile |
After each package is compiled (before it is registered). | per package |
beforeInstall |
After dependencies are resolved, before fetching/compiling sources. | per manifest |
afterInstall |
After the package is registered and the local database is updated. | per manifest |
beforeUninstall |
Before unregistering packages, while the project files still exist. | per manifest |
afterUninstall |
After the package has been removed from the database. | per manifest |
Notes:
- Compile events run for every platform and for both
DebugandReleaseconfigs, so a script may run several times with different%CONFIG%/%PLATFORM%/ output paths. - Because
Installresolves dependencies recursively, every manifest in the dependency tree fires its own install/uninstall events. - Install/uninstall events only fire when the operation actually proceeds (for example, they do not fire when a package is already installed and up to date).
A command may optionally be bound to a set of events. When bound, using it under any other event raises an error. Using an unknown command name also raises an error.
Prints its arguments (after variable expansion), joined by a single space, to the console. Valid for any event.
{ "event": "afterInstall", "command": "echo", "args": ["Installed into %PROJECT_PATH%"] }Copies resource files next to the compiled units. Bound to afterCompile
(it needs %DCU_PATH%).
What it does:
-
Reads the current
%PLATFORM%and looks up that platform'ssourcePathentries in the manifest:"platforms": { "Win32": { "sourcePath": ["Source"] }, "Win64": { "sourcePath": ["Source"] } }
-
Resolves each
sourcePathagainst%PROJECT_PATH%(when relative). -
Recursively copies every
.resand.dfmfound there into%DCU_PATH%, overwriting existing files.
It takes no args. Because afterCompile fires once per package, copyres
runs once per package and simply overwrites the same files — this is harmless
and intentionally produces no extra output.
{ "description": "Copy resources and dfm", "event": "afterCompile", "command": "copyres" }Commands live in Source/Blocks.Service.Script.pas. To add one:
-
Derive a class from
TScriptCommandand overrideRun:TMyCommand = class(TScriptCommand) public procedure Run(AManifest: TManifest; AArgs, AEnvironmentVariables: TStrings); override; end;
AArgsare the script args, already%VAR%-expanded.AEnvironmentVariablesholds the event variables (read extra ones directly, e.g.AEnvironmentVariables.Values['DCU_PATH']).AManifestis the owning manifest, for commands that inspect it.
-
Register it in the unit's
initializationsection. Pass a list of events to restrict where it can be used; omit it to allow any event:// valid for any event TScriptCommand.RegisterCommand('mycmd', TMyCommand); // restricted to afterCompile TScriptCommand.RegisterCommand('copyres', TCopyResCommand, [TScriptRunner.EventAfterCompile]);
Validation (unknown command, wrong event) and %VAR% expansion are handled
centrally by TScriptRunner, so commands only implement their own logic.