5.5. Project Files (.das_project)
A .das_project file is a daslang script that controls how the compiler
resolves modules, includes, and security policies. It is the primary mechanism
for customizing the build environment without modifying C++ code.
Use cases:
Custom module layout — map
require footo any file pathSandboxing — restrict which modules, options, and annotations scripts can use
Include resolution — implement custom
#includelookupMulti-project setups — each project gets its own resolution rules
5.5.1. How it works
When the compiler receives a .das_project path, it:
Compiles and simulates the project file as a regular daslang program
Looks up exported callback functions by name (
module_get,module_allowed, etc.)Sets the global variable
DAS_PAK_ROOTto the directory containing the project fileRuns
[init]functions (useful for registering module resolvers)Calls the callbacks during compilation of user scripts
The only required callback is module_get. All others are optional —
when absent, the compiler uses permissive defaults (everything allowed, standard
include resolution).
5.5.2. Using project files
5.5.2.1. From the command line
daslang -project path/to/project.das_project script.das
5.5.2.2. From C++
auto access = make_smart<FsFileAccess>("project.das_project",
make_smart<FsFileAccess>());
// use 'access' when calling compileDaScript()
5.5.2.3. From daslang (runtime compilation)
var inscope access <- make_file_access("path/to/project.das_project")
compile_file("script.das", access, unsafe(addr(mg)), cop) <| $(ok; program; issues) {
// ...
}
Pass an empty string to make_file_access("") for default filesystem access
without a project file.
5.5.3. Writing a project file
A project file is an ordinary .das file. Export the callbacks you need
using [export].
5.5.3.1. Minimal example
A minimal project file that resolves require daslib/... and relative imports:
options gen2
require strings
require daslib/strings_boost
typedef module_info = tuple<string; string; string> const
var DAS_PAK_ROOT = "./"
[export]
def module_get(req, from : string) : module_info {
let rs <- split_by_chars(req, "./")
let mod_name = rs[length(rs) - 1]
// daslib modules
if (length(rs) == 2 && rs[0] == "daslib") {
return (mod_name, "{get_das_root()}/daslib/{mod_name}.das", "")
}
// relative modules
var fr <- split_by_chars(from, "/")
if (length(fr) > 0) {
pop(fr)
}
for (se in rs) {
push(fr, se)
}
let path_name = join(fr, "/") + ".das"
return (mod_name, path_name, "")
}
The return type module_info is a tuple of three strings:
Module name — how the module is known internally
File path — filesystem path to the
.dasfileImport name — alias (empty string if none)
5.5.3.2. DAS_PAK_ROOT
If the project file declares a global variable named DAS_PAK_ROOT, the
compiler automatically sets it to the directory containing the project file.
This lets callbacks resolve paths relative to the project root:
var DAS_PAK_ROOT = "./"
[export]
def module_get(req, from : string) : module_info {
// resolve relative to project root
return (req, "{DAS_PAK_ROOT}{req}.das", "")
}
5.5.3.3. Including other project files
Project files can include other project files and .das_module descriptors
using the include directive:
include common.das_project
include foo/foo.das_module
5.5.4. Callback reference
Callback |
Description |
|---|---|
|
Required. Resolve a |
|
Resolve an |
|
Return |
|
Return |
|
Return |
|
Return |
|
Fine-grained control over |
|
Control whether |
|
Custom file path comparison (e.g. case-insensitive matching on Windows). When absent, the default comparison is used. |
|
Return the directory to scan for |
5.5.5. Sandboxing example
A project file can lock down the scripting environment by combining
module_allowed, option_allowed, and annotation_allowed:
options gen2
require strings
require daslib/strings_boost
typedef module_info = tuple<string; string; string> const
var DAS_PAK_ROOT = "./"
[export]
def module_get(req, from : string) : module_info {
let rs <- split_by_chars(req, "./")
let mod_name = rs[length(rs) - 1]
if (length(rs) == 2 && rs[0] == "daslib") {
return (mod_name, "{get_das_root()}/daslib/{mod_name}.das", "")
}
var fr <- split_by_chars(from, "/")
if (length(fr) > 0) {
pop(fr)
}
for (se in rs) {
push(fr, se)
}
return (mod_name, join(fr, "/") + ".das", "")
}
[export]
def module_allowed(mod, filename : string) : bool {
// only allow core and safe modules
return mod == "$" || mod == "math" || mod == "strings"
}
[export]
def module_allowed_unsafe(mod, filename : string) : bool {
return false // no unsafe anywhere
}
[export]
def option_allowed(opt, from : string) : bool {
return opt == "gen2" || opt == "indenting"
}
[export]
def annotation_allowed(ann, from : string) : bool {
return ann == "export" || ann == "private"
}
With this project file, user scripts cannot require daslib/fio, use unsafe
blocks, enable options rtti, or apply annotations like [function_macro].
See also
tutorial_integration_cpp_sandbox — C++ integration tutorial demonstrating sandboxing
tutorial_integration_c_sandbox — C integration tutorial with detailed callback reference
embedding_external_modules — .das_module descriptors and dynamic module loading