blob: 904f7219240790373e6857c0461a49b7a5742822 [file] [log] [blame]
/**
* Configuration options for druntime
*
* Copyright: Copyright Digital Mars 2014.
* License: Distributed under the
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Rainer Schuetze
* Source: $(DRUNTIMESRC src/rt/_config.d)
*/
module rt.config;
// The default way to configure the runtime is by passing command line arguments
// starting with "--DRT-" and followed by the option name, e.g. "--DRT-gcopt" to
// configure the GC.
// Command line options starting with "--DRT-" are filtered out before calling main,
// so the program will not see them. They are still available via rt_args().
//
// Configuration via the command line can be disabled by declaring a variable for the
// linker to pick up before using it's default from the runtime:
//
// extern(C) __gshared bool rt_cmdline_enabled = false;
//
// Likewise, declare a boolean rt_envvars_enabled to enable configuration via the
// environment variable "DRT_" followed by the option name, e.g. "DRT_GCOPT":
//
// extern(C) __gshared bool rt_envvars_enabled = true;
//
// Setting default configuration properties in the executable can be done by specifying an
// array of options named rt_options:
//
// extern(C) __gshared string[] rt_options = [ "gcopt=precise:1 profile:1"];
//
// Evaluation order of options is rt_options, then environment variables, then command
// line arguments, i.e. if command line arguments are not disabled, they can override
// options specified through the environment or embedded in the executable.
import core.demangle : cPrefix;
// put each variable in its own COMDAT by making them template instances
template rt_envvars_enabled()
{
pragma(mangle, cPrefix ~ "rt_envvars_enabled") __gshared bool rt_envvars_enabled = false;
}
template rt_cmdline_enabled()
{
pragma(mangle, cPrefix ~ "rt_cmdline_enabled") __gshared bool rt_cmdline_enabled = true;
}
template rt_options()
{
pragma(mangle, cPrefix ~ "rt_options") __gshared string[] rt_options = [];
}
import core.stdc.ctype : toupper;
import core.stdc.stdlib : getenv;
import core.stdc.string : strlen;
extern extern(C) string[] rt_args() @nogc nothrow;
alias rt_configCallBack = string delegate(string) @nogc nothrow;
/**
* get a druntime config option using standard configuration options
* opt name of the option to retreive
* dg if non-null, passes the option through this
* delegate and only returns its return value if non-null
* reverse reverse the default processing order cmdline/envvar/rt_options
* to allow overwriting settings in the delegate with values
* from higher priority
*
* returns the options' value if
* - set on the command line as "--DRT-<opt>=value" (rt_cmdline_enabled enabled)
* - the environment variable "DRT_<OPT>" is set (rt_envvars_enabled enabled)
* - rt_options[] contains an entry "<opt>=value"
* - null otherwise
*/
string rt_configOption(string opt, scope rt_configCallBack dg = null, bool reverse = false) @nogc nothrow
{
if (!dg)
dg = (string s) => s;
string s = (reverse ? rt_linkOption(opt, dg) : rt_cmdlineOption(opt, dg));
if (s != null)
return s;
s = rt_envvarsOption(opt, dg);
if (s != null)
return s;
s = (reverse ? rt_cmdlineOption(opt, dg) : rt_linkOption(opt, dg));
return s;
}
string rt_cmdlineOption(string opt, scope rt_configCallBack dg) @nogc nothrow
{
if (rt_cmdline_enabled!())
{
foreach (a; rt_args)
{
if (a.length >= opt.length + 7 && a[0..6] == "--DRT-" &&
a[6 .. 6 + opt.length] == opt && a[6 + opt.length] == '=')
{
string s = dg(a[7 + opt.length .. $]);
if (s != null)
return s;
}
}
}
return null;
}
string rt_envvarsOption(string opt, scope rt_configCallBack dg) @nogc nothrow
{
if (rt_envvars_enabled!())
{
if (opt.length >= 32)
assert(0);
char[40] var = void;
var[0 .. 4] = "DRT_";
foreach (i, c; opt)
var[4 + i] = cast(char) toupper(c);
var[4 + opt.length] = 0;
auto p = getenv(var.ptr);
if (p)
{
string s = dg(cast(string) p[0 .. strlen(p)]);
if (s != null)
return s;
}
}
return null;
}
string rt_linkOption(string opt, scope rt_configCallBack dg) @nogc nothrow
{
foreach (a; rt_options!())
{
if (a.length > opt.length && a[0..opt.length] == opt && a[opt.length] == '=')
{
string s = dg(a[opt.length + 1 .. $]);
if (s != null)
return s;
}
}
return null;
}