7.4.22. C++ Integration: Namespace Integration
This tutorial shows how to initialize daslang modules when your code lives inside a C++ namespace.
Topics covered:
Why
NEED_MODULEfails inside a namespaceDECLARE_MODULE/PULL_MODULE— the namespace-safe alternativeDECLARE_ALL_DEFAULT_MODULES/PULL_ALL_DEFAULT_MODULES
7.4.22.1. Prerequisites
Tutorial 1 completed (tutorial_integration_cpp_hello_world) — basic compile → simulate → eval cycle.
7.4.22.2. The problem
The NEED_MODULE macro expands to an extern declaration followed
by a call:
extern DAS_API das::Module * register_Module_BuiltIn();
*das::ModuleKarma += unsigned(intptr_t(register_Module_BuiltIn()));
When this macro is used inside a C++ namespace, the extern
declaration is placed in that namespace’s scope. The linker then looks
for MyApp::register_Module_BuiltIn() instead of the global
::register_Module_BuiltIn() defined in the library:
namespace MyApp {
void init() {
NEED_ALL_DEFAULT_MODULES; // FAILS: linker error!
das::Module::Initialize();
}
}
The solution is to split the declaration and the call into two separate macros.
7.4.22.3. DECLARE_MODULE / PULL_MODULE
DECLARE_MODULE(ClassName) — forward-declares the global-scope
register_* function. Must be placed at file or global scope (outside
any namespace).
PULL_MODULE(ClassName) — performs the registration call using the
:: prefix to explicitly reference the global-scope function. Safe
inside any namespace, class, or function body.
Convenience wrappers DECLARE_ALL_DEFAULT_MODULES and
PULL_ALL_DEFAULT_MODULES cover every built-in module.
7.4.22.4. The tutorial
The tutorial runs the same 01_hello_world.das script as Tutorial 1,
but all daslang calls happen inside namespace MyApp.
// Tutorial 22 — Namespace Integration
//
// Demonstrates how to initialize daslang modules inside a C++ namespace.
//
// The standard NEED_MODULE / NEED_ALL_DEFAULT_MODULES macros place an
// `extern` declaration at the current scope. When that scope is a C++
// namespace, the linker looks for MyNamespace::register_Module_BuiltIn()
// instead of the global ::register_Module_BuiltIn(), causing link errors.
//
// The solution is the DECLARE_MODULE / PULL_MODULE macro pair:
// • DECLARE_MODULE — forward-declares the register function (must be at
// file/global scope so it refers to the global symbol)
// • PULL_MODULE — calls the register function using ::qualified name
// (safe inside any namespace, class, or function body)
//
// Convenience wrappers DECLARE_ALL_DEFAULT_MODULES and PULL_ALL_DEFAULT_MODULES
// cover all built-in modules at once.
#include "daScript/daScript.h"
using namespace das;
#define SCRIPT_NAME "/tutorials/integration/cpp/01_hello_world.das"
// Step 1: Forward-declare module functions at global/file scope.
// This ensures the extern declarations refer to the global-scope symbols
// defined by REGISTER_MODULE / REGISTER_MODULE_IN_NAMESPACE in the library.
DECLARE_ALL_DEFAULT_MODULES;
// For external (plugin) modules, include the generated file:
// #include "modules/external_declare.inc"
// (mirrors external_need.inc but uses DECLARE_MODULE instead of NEED_MODULE)
// ------------------------------------------------------------------
// Everything below lives inside a namespace — PULL_MODULE works here.
// ------------------------------------------------------------------
namespace MyApp {
void runScript() {
TextPrinter tout;
ModuleGroup dummyLibGroup;
auto fAccess = make_smart<FsFileAccess>();
auto program = compileDaScript(getDasRoot() + SCRIPT_NAME,
fAccess, tout, dummyLibGroup);
if (program->failed()) {
tout << "Compilation failed:\n";
for (auto & err : program->errors) {
tout << reportError(err.at, err.what, err.extra, err.fixme, err.cerr);
}
return;
}
Context ctx(program->getContextStackSize());
if (!program->simulate(ctx, tout)) {
tout << "Simulation failed:\n";
for (auto & err : program->errors) {
tout << reportError(err.at, err.what, err.extra, err.fixme, err.cerr);
}
return;
}
auto fnTest = ctx.findFunction("test");
if (!fnTest) {
tout << "Function 'test' not found\n";
return;
}
ctx.evalWithCatch(fnTest, nullptr);
if (auto ex = ctx.getException()) {
tout << "Script exception: " << ex << "\n";
}
}
void initialize() {
// Step 2: Pull (register) the modules. PULL_ALL_DEFAULT_MODULES uses
// ::register_Module_*() — the :: prefix ensures the call resolves to
// the global-scope function regardless of the enclosing namespace.
PULL_ALL_DEFAULT_MODULES;
// For external (plugin) modules, include the generated file:
// #include "modules/external_pull.inc"
// (mirrors external_need.inc but uses PULL_MODULE instead of NEED_MODULE)
Module::Initialize();
}
void shutdown() {
Module::Shutdown();
}
} // namespace MyApp
// main() delegates to the namespaced functions.
int main(int, char * []) {
MyApp::initialize();
MyApp::runScript();
MyApp::shutdown();
return 0;
}
7.4.22.5. How it works
DECLARE_ALL_DEFAULT_MODULESat file scope forward-declares every default module’sregister_*function as a global-scope symbol.Inside
MyApp::initialize(),PULL_ALL_DEFAULT_MODULEScalls each::register_Module_*()function — the::prefix bypasses the enclosing namespace.Module::Initialize()and the rest of the daslang API continue to work normally inside the namespace — only module registration has the namespace restriction.
7.4.22.6. Custom modules
For custom modules, use DECLARE_MODULE at file scope alongside the
convenience macros:
DECLARE_ALL_DEFAULT_MODULES;
DECLARE_MODULE(Module_MyMod);
namespace MyApp {
void init() {
PULL_ALL_DEFAULT_MODULES;
PULL_MODULE(Module_MyMod);
das::Module::Initialize();
}
}
7.4.22.7. External (plugin) modules
CMake generates three .inc files for every module registered with
ADD_MODULE_CPP:
external_need.incContains
NEED_MODULE(...)— the traditional all-in-one macro (works only at global scope).external_declare.incContains
DECLARE_MODULE(...)— include at file scope.external_pull.incContains
PULL_MODULE(...)— include inside any namespace or function body.
For namespace-safe code, replace:
// old (global scope only)
#include "modules/external_need.inc"
with:
// file scope
#include "modules/external_declare.inc"
namespace MyApp {
void init() {
// inside namespace
#include "modules/external_pull.inc"
}
}
7.4.22.8. Build and run
cmake --build build --config Release --target integration_cpp_22
$ bin/Release/integration_cpp_22
Hello, World!