implement environment variables for windows
parent
55e8bbd167
commit
8ab5313043
|
@ -308,7 +308,7 @@ pub const Builder = struct {
|
|||
}
|
||||
|
||||
fn processNixOSEnvVars(self: &Builder) {
|
||||
if (os.getEnv("NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
|
||||
if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
|
||||
var it = mem.split(nix_cflags_compile, " ");
|
||||
while (true) {
|
||||
const word = it.next() ?? break;
|
||||
|
@ -323,8 +323,10 @@ pub const Builder = struct {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else |err| {
|
||||
assert(err == error.EnvironmentVariableNotFound);
|
||||
}
|
||||
if (os.getEnv("NIX_LDFLAGS")) |nix_ldflags| {
|
||||
if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
|
||||
var it = mem.split(nix_ldflags, " ");
|
||||
while (true) {
|
||||
const word = it.next() ?? break;
|
||||
|
@ -342,6 +344,8 @@ pub const Builder = struct {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else |err| {
|
||||
assert(err == error.EnvironmentVariableNotFound);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1248,7 +1252,13 @@ pub const LibExeObjStep = struct {
|
|||
}
|
||||
|
||||
fn makeC(self: &LibExeObjStep) -> %void {
|
||||
const cc = os.getEnv("CC") ?? "cc";
|
||||
const cc = os.getEnvVarOwned(self.builder.allocator, "CC") %% |err| {
|
||||
if (err == error.EnvironmentVariableNotFound) {
|
||||
([]const u8)("cc")
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
};
|
||||
const builder = self.builder;
|
||||
|
||||
assert(!self.is_zig);
|
||||
|
|
|
@ -564,7 +564,7 @@ pub const ChildProcess = struct {
|
|||
const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;
|
||||
|
||||
const maybe_envp_buf = if (self.env_map) |env_map| {
|
||||
%return os.createNullDelimitedEnvMap(self.allocator, env_map)
|
||||
%return os.createWindowsEnvBlock(self.allocator, env_map)
|
||||
} else {
|
||||
null
|
||||
};
|
||||
|
@ -578,6 +578,7 @@ pub const ChildProcess = struct {
|
|||
const err = windows.GetLastError();
|
||||
return switch (err) {
|
||||
windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,
|
||||
windows.ERROR.INVALID_PARAMETER => unreachable,
|
||||
else => error.Unexpected,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ pub const windowsWrite = windows_util.windowsWrite;
|
|||
pub const windowsIsTty = windows_util.windowsIsTty;
|
||||
pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
|
||||
pub const windowsOpen = windows_util.windowsOpen;
|
||||
pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
|
||||
|
||||
const debug = @import("../debug.zig");
|
||||
const assert = debug.assert;
|
||||
|
@ -48,6 +49,7 @@ const io = @import("../io.zig");
|
|||
const base64 = @import("../base64.zig");
|
||||
const ArrayList = @import("../array_list.zig").ArrayList;
|
||||
const Buffer = @import("../buffer.zig").Buffer;
|
||||
const math = @import("../index.zig").math;
|
||||
|
||||
error Unexpected;
|
||||
error SystemResources;
|
||||
|
@ -362,7 +364,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
|
|||
return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr)));
|
||||
}
|
||||
|
||||
const PATH = getEnv("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
|
||||
const PATH = getEnvPosix("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
|
||||
// PATH.len because it is >= the largest search_path
|
||||
// +1 for the / to join the search path and exe_path
|
||||
// +1 for the null terminating byte
|
||||
|
@ -406,29 +408,55 @@ fn posixExecveErrnoToErr(err: usize) -> error {
|
|||
};
|
||||
}
|
||||
|
||||
pub var environ_raw: []&u8 = undefined;
|
||||
pub var posix_environ_raw: []&u8 = undefined;
|
||||
|
||||
/// Caller must free result when done.
|
||||
pub fn getEnvMap(allocator: &Allocator) -> %BufMap {
|
||||
var result = BufMap.init(allocator);
|
||||
%defer result.deinit();
|
||||
|
||||
for (environ_raw) |ptr| {
|
||||
var line_i: usize = 0;
|
||||
while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
|
||||
const key = ptr[0..line_i];
|
||||
if (is_windows) {
|
||||
const ptr = windows.GetEnvironmentStringsA() ?? return error.OutOfMemory;
|
||||
defer assert(windows.FreeEnvironmentStringsA(ptr));
|
||||
|
||||
var end_i: usize = line_i;
|
||||
while (ptr[end_i] != 0) : (end_i += 1) {}
|
||||
const value = ptr[line_i + 1..end_i];
|
||||
var i: usize = 0;
|
||||
while (true) {
|
||||
if (ptr[i] == 0)
|
||||
return result;
|
||||
|
||||
%return result.set(key, value);
|
||||
const key_start = i;
|
||||
|
||||
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
|
||||
const key = ptr[key_start..i];
|
||||
|
||||
if (ptr[i] == '=') i += 1;
|
||||
|
||||
const value_start = i;
|
||||
while (ptr[i] != 0) : (i += 1) {}
|
||||
const value = ptr[value_start..i];
|
||||
|
||||
i += 1; // skip over null byte
|
||||
|
||||
%return result.set(key, value);
|
||||
}
|
||||
} else {
|
||||
for (posix_environ_raw) |ptr| {
|
||||
var line_i: usize = 0;
|
||||
while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
|
||||
const key = ptr[0..line_i];
|
||||
|
||||
var end_i: usize = line_i;
|
||||
while (ptr[end_i] != 0) : (end_i += 1) {}
|
||||
const value = ptr[line_i + 1..end_i];
|
||||
|
||||
%return result.set(key, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn getEnv(key: []const u8) -> ?[]const u8 {
|
||||
for (environ_raw) |ptr| {
|
||||
pub fn getEnvPosix(key: []const u8) -> ?[]const u8 {
|
||||
for (posix_environ_raw) |ptr| {
|
||||
var line_i: usize = 0;
|
||||
while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
|
||||
const this_key = ptr[0..line_i];
|
||||
|
@ -444,6 +472,42 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 {
|
|||
return null;
|
||||
}
|
||||
|
||||
error EnvironmentVariableNotFound;
|
||||
|
||||
/// Caller must free returned memory.
|
||||
pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) -> %[]u8 {
|
||||
if (is_windows) {
|
||||
const key_with_null = %return cstr.addNullByte(allocator, key);
|
||||
defer allocator.free(key_with_null);
|
||||
|
||||
var buf = %return allocator.alloc(u8, 256);
|
||||
%defer allocator.free(buf);
|
||||
|
||||
while (true) {
|
||||
const windows_buf_len = %return math.cast(windows.DWORD, buf.len);
|
||||
const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len);
|
||||
|
||||
if (result == 0) {
|
||||
const err = windows.GetLastError();
|
||||
return switch (err) {
|
||||
windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
|
||||
else => error.Unexpected,
|
||||
};
|
||||
}
|
||||
|
||||
if (result > buf.len) {
|
||||
buf = %return allocator.realloc(u8, buf, result);
|
||||
continue;
|
||||
}
|
||||
|
||||
return allocator.shrink(u8, buf, result);
|
||||
}
|
||||
} else {
|
||||
const result = getEnvPosix(key) ?? return error.EnvironmentVariableNotFound;
|
||||
return mem.dupe(u8, allocator, result);
|
||||
}
|
||||
}
|
||||
|
||||
/// Caller must free the returned memory.
|
||||
pub fn getCwd(allocator: &Allocator) -> %[]u8 {
|
||||
switch (builtin.os) {
|
||||
|
|
|
@ -32,12 +32,18 @@ pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) -> bool;
|
|||
|
||||
pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) -> noreturn;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: LPCH) -> BOOL;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn GetCommandLineA() -> LPSTR;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) -> DWORD;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() -> ?LPCH;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) -> DWORD;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: &DWORD) -> BOOL;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn GetLastError() -> DWORD;
|
||||
|
@ -49,11 +55,11 @@ pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(in_hFile: HANDLE
|
|||
pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpszFilePath: LPSTR,
|
||||
cchFilePath: DWORD, dwFlags: DWORD) -> DWORD;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn GetProcessHeap() -> HANDLE;
|
||||
pub extern "kernel32" stdcallcc fn GetProcessHeap() -> ?HANDLE;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
|
||||
pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> ?LPVOID;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
|
||||
|
||||
|
@ -91,6 +97,7 @@ pub const HCRYPTPROV = ULONG_PTR;
|
|||
pub const HINSTANCE = &@OpaqueType();
|
||||
pub const INT = c_int;
|
||||
pub const LPBYTE = &BYTE;
|
||||
pub const LPCH = &CHAR;
|
||||
pub const LPCSTR = &const CHAR;
|
||||
pub const LPCTSTR = &const TCHAR;
|
||||
pub const LPCVOID = &const c_void;
|
||||
|
|
|
@ -3,6 +3,7 @@ const os = std.os;
|
|||
const windows = std.os.windows;
|
||||
const assert = std.debug.assert;
|
||||
const mem = std.mem;
|
||||
const BufMap = std.BufMap;
|
||||
|
||||
error WaitAbandoned;
|
||||
error WaitTimeOut;
|
||||
|
@ -111,3 +112,35 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Caller must free result.
|
||||
pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 {
|
||||
// count bytes needed
|
||||
const bytes_needed = {
|
||||
var bytes_needed: usize = 1; // 1 for the final null byte
|
||||
var it = env_map.iterator();
|
||||
while (it.next()) |pair| {
|
||||
// +1 for '='
|
||||
// +1 for null byte
|
||||
bytes_needed += pair.key.len + pair.value.len + 2;
|
||||
}
|
||||
bytes_needed
|
||||
};
|
||||
const result = %return allocator.alloc(u8, bytes_needed);
|
||||
%defer allocator.free(result);
|
||||
|
||||
var it = env_map.iterator();
|
||||
var i: usize = 0;
|
||||
while (it.next()) |pair| {
|
||||
mem.copy(u8, result[i..], pair.key);
|
||||
i += pair.key.len;
|
||||
result[i] = '=';
|
||||
i += 1;
|
||||
mem.copy(u8, result[i..], pair.value);
|
||||
i += pair.value.len;
|
||||
result[i] = 0;
|
||||
i += 1;
|
||||
}
|
||||
result[i] = 0;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
|
|||
|
||||
var env_count: usize = 0;
|
||||
while (envp[env_count] != null) : (env_count += 1) {}
|
||||
std.os.environ_raw = @ptrCast(&&u8, envp)[0..env_count];
|
||||
std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];
|
||||
|
||||
std.debug.user_main_fn = root.main;
|
||||
|
||||
|
|
Loading…
Reference in New Issue