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 produces libDaScript which the tutorial links against.

  • The daScript.h header — located in include/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

TextPrinter

Sends compiler/runtime messages to stdout. For an in-memory buffer, use TextWriter instead.

ModuleGroup

Holds modules available during compilation.

FsFileAccess

Provides disk-based file I/O to the compiler. Wrapped in a smart_ptr — freed automatically.

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 (daScriptC.h)

C++ API (daScript.h)

das_initialize()

NEED_ALL_DEFAULT_MODULES; Module::Initialize()

das_text_make_printer() / das_text_release()

TextPrinter tout; (stack)

das_fileaccess_make_default() / das_fileaccess_release()

make_smart<FsFileAccess>() (ref-counted)

das_program_compile() / das_program_release()

compileDaScript() (returns ProgramPtr)

das_context_make() / das_context_release()

Context ctx(stackSize); (stack)

das_context_find_function()

ctx.findFunction()

das_context_eval_with_catch()

ctx.evalWithCatch()

das_shutdown()

Module::Shutdown()

5.3.1.5. Key concepts

Smart pointers

The C++ API uses smart_ptr<T> (daslang’s own reference-counted smart pointer) and make_smart<T>() for heap-allocated objects. ProgramPtr returned by compileDaScript is one example.

Stack-allocated objects

TextPrinter, ModuleGroup, and Context can all live on the stack. Their destructors handle cleanup automatically.

getDasRoot

Returns the root of the daslang installation as a string. Use it to build paths to scripts so they resolve regardless of working directory.

verifyCall

Template 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