5.3.3. C++ Integration: Binding Functions
This tutorial shows how to expose C++ functions to daslang scripts by creating a custom module. Topics covered:
addExternwithDAS_BIND_FUN— binding free C++ functionsSideEffectsflags — telling the optimizer what a function doesaddConstant— exposing compile-time constantsContext-aware functions — receiving
Context *automatically
5.3.3.1. Prerequisites
Tutorial 02 completed (tutorial_integration_cpp_calling_functions).
Understanding of
cast<T>and the daslang calling convention.
5.3.3.2. Creating a module
A module is a class derived from Module. Its constructor registers
types, functions, and constants that scripts can use via require:
class Module_Tutorial03 : public Module {
public:
Module_Tutorial03() : Module("tutorial_03_cpp") {
ModuleLibrary lib(this);
lib.addBuiltInModule();
// ... register functions and constants here ...
}
};
REGISTER_MODULE(Module_Tutorial03);
REGISTER_MODULE makes the module available via NEED_MODULE in the
host program.
5.3.3.3. Binding constants
addConstant exposes a C++ value as a compile-time constant:
addConstant(*this, "PI", 3.14159265358979323846f);
addConstant(*this, "SQRT2", sqrtf(2.0f));
In the script:
print("PI = {PI}\n") // 3.1415927
print("SQRT2 = {SQRT2}\n") // 1.4142135
5.3.3.4. Binding functions with addExtern
addExtern is the primary way to expose a C++ function to daslang.
The DAS_BIND_FUN macro generates the template machinery needed for
automatic argument marshalling:
float xmadd(float a, float b, float c, float d) {
return a * b + c * d;
}
addExtern<DAS_BIND_FUN(xmadd)>(*this, lib, "xmadd",
SideEffects::none, "xmadd");
Parameters:
DAS_BIND_FUN(xmadd)— the C++ function to bind*this— the module being populatedlib— the module library (for type resolution)"xmadd"— the name visible in daslangSideEffects::none— optimizer hint (see below)"xmadd"— C++ function name for AOT (used in generated code)
5.3.3.5. SideEffects flags
The SideEffects enum tells the optimizer what observable effects a
function has. This controls whether calls can be eliminated, reordered,
or folded:
Flag |
Meaning |
|---|---|
|
Pure function — no side effects. Safe to eliminate if result is unused. |
|
Modifies external state (stdout, files, hardware, etc.) |
|
Modifies one or more of its arguments (passed by reference). |
|
Reads global/shared mutable state. |
|
Calls a daslang function or lambda. |
|
Combines |
Example — a function that prints to stdout needs modifyExternal:
void greet(const char * name) {
printf("Hello from C++, %s!\n", name);
}
addExtern<DAS_BIND_FUN(greet)>(*this, lib, "greet",
SideEffects::modifyExternal, "greet");
5.3.3.6. Functions that modify arguments
If a function takes a reference and modifies it, use
SideEffects::modifyArgument:
void double_it(int32_t & value) {
value *= 2;
}
addExtern<DAS_BIND_FUN(double_it)>(*this, lib, "double_it",
SideEffects::modifyArgument, "double_it");
In the script:
var val = 21
double_it(val)
print("{val}\n") // 42
5.3.3.7. Context-aware functions
If a C++ function takes Context * as its first parameter (or
LineInfoArg * as its last), daslang injects them automatically — the
script caller does not see these parameters:
void print_stack_info(Context * ctx) {
printf("Stack size: %d bytes\n", ctx->stack.size());
}
addExtern<DAS_BIND_FUN(print_stack_info)>(*this, lib, "print_stack_info",
SideEffects::modifyExternal, "print_stack_info");
In the script the function takes zero arguments:
print_stack_info() // prints "Stack size: 16384 bytes"
5.3.3.8. Activating the module in the host
The host program must request the module before Module::Initialize():
int main(int, char * []) {
NEED_ALL_DEFAULT_MODULES;
NEED_MODULE(Module_Tutorial03);
Module::Initialize();
// ... compile and run scripts ...
Module::Shutdown();
return 0;
}
The script uses require to access the module:
require tutorial_03_cpp
5.3.3.9. Building and running
cmake --build build --config Release --target integration_cpp_03
bin\Release\integration_cpp_03.exe
Expected output:
PI = 3.1415927
SQRT2 = 1.4142135
xmadd(SQRT2, SQRT2, 1.0, 1.0) = 3
factorial(10) = 3628800
Hello from C++, daslang!
double_it(21) = 42
Context stack size: 16384 bytes
See also
Full source:
03_binding_functions.cpp,
03_binding_functions.das
Previous tutorial: tutorial_integration_cpp_calling_functions
Next tutorial: tutorial_integration_cpp_binding_types
C API equivalent: tutorial_integration_c_binding_types (the C tutorials combine type and function binding in a single tutorial)