3.6. env:: - environment variables / args / directories
The rok::std::env module provides a consistent entry point for accessing the process environment. Command-line arguments, environment variables and standard directory paths are gathered in one place, hiding OS differences.
3.6.1. API
The functions and types the module exposes, at a glance:
// command-line arguments
fn args() -> List<str>; // [0] = program name - the runtime captures argc/argv at startup
fn args_os() -> List<RawStr>; // non-UTF-8 preserved (rare)
// process exit
fn exit(code: i32) -> !; // exits immediately - calls the runtime's rok_exit; entry point rules in refs-lang 4.16
// environment variables
fn var(name: str) throws (VarError) -> str;
fn var_os(name: str) -> RawStr | none;
fn vars() -> Vars; // implements Iterator<Item = (str, str)>
fn vars_os() -> VarsOs; // implements Iterator<Item = (RawStr, RawStr)>
fn set_var(name: str, value: str); // caution - races under multithreading
fn remove_var(name: str);
// directories
fn current_dir() throws (IoError) -> Path;
fn set_current_dir(path: Path) throws (IoError);
fn home_dir() -> Path | none;
fn temp_dir() -> Path;
fn config_dir() -> Path | none; // macOS ~/Library/Application Support, otherwise $XDG_CONFIG_HOME / ~/.config
fn cache_dir() -> Path | none; // macOS ~/Library/Caches, otherwise $XDG_CACHE_HOME / ~/.cache
fn data_dir() -> Path | none; // macOS ~/Library/Application Support, otherwise $XDG_DATA_HOME / ~/.local/share
// splitting the PATH environment variable (OS-specific separator)
fn split_paths(paths: str) -> List<Path>; // ":" on unix, ";" on windows
fn join_paths<I: Iterator<Item = Path>>(paths: I) throws (JoinPathsError) -> str;
// the executable itself
fn current_exe() throws (IoError) -> Path;
// process ID
fn pid() -> u32;
fn parent_pid() -> u32 | none;
enum VarError {
NotPresent, // the variable does not exist
NotUnicode, // the value is not UTF-8 (read with var_os)
}
RawStr is a string holding the bytes exactly as the OS provided them (possibly not UTF-8). JoinPathsError occurs when one of the paths contains the separator (: / ;).
struct RawStr { /* OS bytes */ }
impl RawStr {
fn len(self) -> usize; // byte length
fn is_empty(self) -> bool;
fn to_str(self) throws (Utf8Error) -> str; // throws if not UTF-8
fn as_bytes(self) -> List<u8>;
}
impl PartialEq for RawStr { ... }
impl Debug for RawStr { ... }
struct JoinPathsError { path: str; } // the path containing the separator
On Windows the bytes are the OS's UTF-16 as WTF-8; there:
impl RawStr {
fn from_wide(wide: List<u16>) -> RawStr;
fn as_wide(self) -> List<u16>;
}
3.6.2. Examples
How these APIs work together in a real program. The following example shows the typical flow of command-line arguments, environment variables and PATH search in one go.
use rok::std::env;
// CLI tool
fn main() {
let args = env::args();
if args.len() < 2 {
eprintln("usage: tool <input>");
env::exit(1);
}
let input = args[1];
process(input);
}
// environment variables
let log_level = (try? env::var("LOG_LEVEL")) ?? "info";
let home = env::home_dir() ?? panic("HOME not set");
let config = home / ".config" / "myapp.toml";
// PATH search
let path_str = try env::var("PATH");
for dir in env::split_paths(path_str) {
let candidate = dir / "myprog";
if fs::exists(candidate) {
log("found at {candidate:?}");
}
}
3.6.3. Multithreading hazard of set_var
set_var, provided for convenience, has one pitfall: if another thread reads or writes environment variables at the same time, a race can occur.
// dangerous - races if another thread calls var at the same time
thread::spawn(|| { env::set_var("X", "1"); });
thread::spawn(|| { env::var("X"); });
POSIX setenv / getenv are not guaranteed thread-safe. The rok standard library attempts to protect them with a global mutex, but races remain possible inside FFI calls or signal handlers.
The recommended pattern is therefore simple: call set_var only at program start, as the first thing in main. That avoids silent corruption later in a multithreaded environment.
3.6.4. impl / target
How each platform implements the same semantics:
| Item | linux/macos/windows | wasi |
|---|---|---|
args | argc/argv / GetCommandLine | wasi:cli |
var / vars | getenv / GetEnvironmentVariable | wasi:cli |
home_dir | $HOME / SHGetKnownFolderPath | wasi (no concept) |
temp_dir | $TMPDIR / GetTempPath | wasi |
config_dir | XDG / AppData | (no) |
current_exe | /proc/self/exe / _NSGetExecutablePath / GetModuleFileName | Unsupported (wasm32) |
Standard paths use ~/Library/... on macOS, the XDG Base Directory spec on other Unix systems ($XDG_*_HOME is used only when it is an absolute path; otherwise ~/.config and so on), and Known Folders on Windows. If the home directory cannot be determined, the result is none.