5.3.1. C++ Integration: Hello World
This tutorial shows how to embed daslang in a C++ application using the
native daScript.h API. By the end you will have a standalone program that
compiles a .das script, finds a function, calls it, and prints
Hello from daslang!.
Note
If you have already read the C integration series (starting at
tutorial_integration_c_hello_world), you will notice that the
C++ API is considerably more concise: there is no manual reference
counting, strings are std::string, and smart pointers manage
lifetimes automatically.
5.3.1.1. Prerequisites
daslang built from source (
cmake --build build --config Release). The build produceslibDaScriptwhich the tutorial links against.The
daScript.hheader — located ininclude/daScript/daScript.h. This is the main C++ header that pulls in the full API (type system, compilation, contexts, module registration, etc.).
5.3.1.2. The daslang file
Create a minimal script with a single exported function:
options gen2
[export]
def test() {
print("Hello from daslang!\n")
}
The [export] annotation makes the function visible to the host application
so that Context::findFunction can locate it by name.
5.3.1.3. The C++ program
The program follows the same lifecycle as the C version, but each step uses the native C++ API directly.
5.3.1.3.1. Step 1 — Initialize
#include "daScript/daScript.h"
using namespace das;
int main(int, char * []) {
NEED_ALL_DEFAULT_MODULES;
Module::Initialize();
NEED_ALL_DEFAULT_MODULES is a macro that ensures all built-in modules
(math, strings, etc.) are linked into the executable. Module::Initialize
activates them. Both must be called once before any compilation.
5.3.1.3.2. Step 2 — Set up compilation infrastructure
TextPrinter tout;
ModuleGroup dummyLibGroup;
auto fAccess = make_smart<FsFileAccess>();
Object |
Purpose |
|---|---|
|
Sends compiler/runtime messages to stdout.
For an in-memory buffer, use |
|
Holds modules available during compilation. |
|
Provides disk-based file I/O to the compiler.
Wrapped in a |
5.3.1.3.3. Step 3 — Compile the script
auto program = compileDaScript(getDasRoot() + SCRIPT_NAME,
fAccess, tout, dummyLibGroup);
if (program->failed()) {
for (auto & err : program->errors) {
tout << reportError(err.at, err.what, err.extra,
err.fixme, err.cerr);
}
return;
}
compileDaScript reads the .das file, parses, type-checks, and returns
a ProgramPtr (a smart pointer to Program). getDasRoot() returns
the project root directory, so paths are always resolved correctly regardless
of the working directory.
Errors are stored in program->errors and can be formatted with
reportError.
5.3.1.3.4. Step 4 — Create a context and simulate
Context ctx(program->getContextStackSize());
if (!program->simulate(ctx, tout)) {
// handle errors ...
}
A Context is the runtime environment — it owns the execution stack, global
variables, and heap. Unlike the C API, the context is a stack-allocated
object here; there is no release call.
Simulation resolves function pointers, initializes globals, and prepares
everything for execution. Always check for errors after simulate.
5.3.1.3.5. Step 5 — Find and verify the function
auto fnTest = ctx.findFunction("test");
if (!fnTest) {
tout << "function 'test' not found\n";
return;
}
if (!verifyCall<void>(fnTest->debugInfo, dummyLibGroup)) {
tout << "wrong signature\n";
return;
}
findFunction returns a SimFunction * — valid for the lifetime of the
context.
verifyCall<ReturnType, ArgTypes...> is a compile-time-safe signature
check. It is slow (it walks debug info), so do it once during setup —
not on every call in a hot loop.
5.3.1.3.6. Step 6 — Call the function
ctx.evalWithCatch(fnTest, nullptr);
if (auto ex = ctx.getException()) {
tout << "exception: " << ex << "\n";
}
evalWithCatch runs the function inside a C++ try/catch so that a daslang
panic() does not crash the host. The second argument is an array of
vec4f arguments — nullptr here because test takes none.
5.3.1.3.7. Step 7 — Shut down
Module::Shutdown();
return 0;
}
Module::Shutdown frees all global state. No daslang API calls are
allowed after it. Note that unlike the C API, there is no need to manually
release the program, module group, or text printer — these are either
stack-allocated or reference-counted smart pointers.
5.3.1.4. C++ vs. C API comparison
C API ( |
C++ API ( |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5.3.1.5. Key concepts
- Smart pointers
The C++ API uses
smart_ptr<T>(daslang’s own reference-counted smart pointer) andmake_smart<T>()for heap-allocated objects.ProgramPtrreturned bycompileDaScriptis one example.- Stack-allocated objects
TextPrinter,ModuleGroup, andContextcan all live on the stack. Their destructors handle cleanup automatically.getDasRootReturns the root of the daslang installation as a
string. Use it to build paths to scripts so they resolve regardless of working directory.verifyCallTemplate function that validates a
SimFunction’s signature against expected C++ types. Use it as a development-time safety net.
5.3.1.6. Building and running
The tutorial is built automatically by CMake as part of the daslang project:
cmake --build build --config Release --target integration_cpp_01
Run from the project root so that the script path resolves correctly:
bin\Release\integration_cpp_01.exe
Expected output:
Hello from daslang!
See also
Full source:
01_hello_world.cpp,
01_hello_world.das
Next tutorial: tutorial_integration_cpp_calling_functions
C API equivalent: tutorial_integration_c_hello_world