3.6. env:: - 환경 변수 / args / 디렉토리
rok::std::env 모듈은 프로세스의 environment 에 접근하기 위한 일관된 진입점을 제공합니다. 명령행 인자, 환경 변수, 표준 디렉토리 경로를 OS 차이를 가리고 한 자리에서 다룰 수 있도록 묶어 두었습니다.
3.6.1. API
먼저 모듈이 노출하는 함수와 타입을 한눈에 살펴봅니다.
// 명령행 인자
fn args() -> List<str>; // [0] = 프로그램 이름 - 런타임이 시작 시 argc/argv 를 잡아 둠
fn args_os() -> List<RawStr>; // non-UTF-8 보장 (rare)
// 프로세스 종료
fn exit(code: i32) -> !; // 즉시 종료 - 런타임 rok_exit 호출, 진입점 규칙은 refs-lang 4.16
// 환경 변수
fn var(name: str) throws (VarError) -> str;
fn var_os(name: str) -> RawStr | none;
fn vars() -> Vars; // Iterator<Item = (str, str)> 구현
fn vars_os() -> VarsOs; // Iterator<Item = (RawStr, RawStr)> 구현
fn set_var(name: str, value: str); // 주의 - multi-thread 시 race
fn remove_var(name: str);
// 디렉토리
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, 그 밖 $XDG_CONFIG_HOME / ~/.config
fn cache_dir() -> Path | none; // macOS ~/Library/Caches, 그 밖 $XDG_CACHE_HOME / ~/.cache
fn data_dir() -> Path | none; // macOS ~/Library/Application Support, 그 밖 $XDG_DATA_HOME / ~/.local/share
// PATH 환경 변수 split (OS 별 구분자)
fn split_paths(paths: str) -> List<Path>; // ":" on unix, ";" on windows
fn join_paths<I: Iterator<Item = Path>>(paths: I) throws (JoinPathsError) -> str;
// 실행 파일 자체
fn current_exe() throws (IoError) -> Path;
// 프로세스 ID
fn pid() -> u32;
fn parent_pid() -> u32 | none;
enum VarError {
NotPresent, // 변수가 없음
NotUnicode, // 값이 UTF-8 이 아님 (var_os 로 읽음)
}
RawStr 은 OS 가 준 바이트열 그대로의 문자열입니다 (UTF-8 이 아닐 수 있음). JoinPathsError 는 경로 하나가 구분자 (: / ;) 를 담고 있을 때입니다.
struct RawStr { /* OS 바이트 */ }
impl RawStr {
fn len(self) -> usize; // 바이트 길이
fn is_empty(self) -> bool;
fn to_str(self) throws (Utf8Error) -> str; // UTF-8 이 아니면 throw
fn as_bytes(self) -> List<u8>;
}
impl PartialEq for RawStr { ... }
impl Debug for RawStr { ... }
struct JoinPathsError { path: str; } // 구분자를 담은 경로
Windows 에서 바이트는 OS 의 UTF-16 을 WTF-8 로 담은 것이며, 거기서는 다음도 있습니다.
impl RawStr {
fn from_wide(wide: List<u16>) -> RawStr;
fn as_wide(self) -> List<u16>;
}
3.6.2. 사용 예
이제 실제 프로그램에서 이 API 들이 어떻게 어울려 동작하는지 살펴봅니다. 다음 예제는 명령행 인자, 환경 변수, 그리고 PATH 탐색까지 전형적인 흐름을 한 번에 보여 줍니다.
use rok::std::env;
// CLI 도구
fn main() {
let args = env::args();
if args.len() < 2 {
eprintln("usage: tool <input>");
env::exit(1);
}
let input = args[1];
process(input);
}
// 환경 변수
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 검색
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. set_var 의 multi-thread 위험
편의상 제공되는 set_var 에는 한 가지 주의해야 할 함정이 있습니다. 다른 스레드가 같은 시점에 환경 변수를 읽거나 쓰면 race 가 발생할 수 있다는 점입니다.
// 위험 - 다른 thread 가 동시에 var 호출 시 race
thread::spawn(|| { env::set_var("X", "1"); });
thread::spawn(|| { env::var("X"); });
POSIX 의 setenv / getenv 는 스레드 안전을 보장하지 않습니다. rok 표준 라이브러리가 global mutex 로 보호를 시도하기는 하지만, FFI 호출이나 signal handler 안에서는 여전히 race 가 발생할 여지가 있습니다.
따라서 권장 사용 패턴은 단순합니다. set_var 는 프로그램 시작 시점, 즉 main 의 첫 작업으로만 호출하세요. 그래야 이후 multi-thread 환경에서 silent corruption 을 피할 수 있습니다.
3.6.4. impl / target
플랫폼마다 동일한 의미를 어떻게 구현하는지는 다음 표에 정리됩니다.
| 항목 | 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) |
이때 표준 경로는 macOS 에서는 ~/Library/..., 그 밖의 Unix 에서는 XDG Base Directory spec ($XDG_*_HOME 이 절대 경로일 때만 쓰고, 아니면 ~/.config 등), Windows 에서는 Known Folders 를 사용합니다. 홈 디렉토리를 알 수 없으면 none 입니다.