authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-03 04:58:19-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-03 05:04:46-04:00
logc400cb429abf2980962739731f5b64861a54ab61
treeafb244401d3aa18547ea7e6a5bf5fbe141472cee
parenta1363b52278b68f59aa72adf985f11e6c1d02cf9

zig build system: add setLinkerScript and setTarget

* See #204 - zig build system * allow builtin types Os, Environ, Arch to be used at runtime. they have zero_bits=false and debug info now. * Eradicate use of `@alloca` in std for syscalls. See #225 * add `std.io.writeFile` * `std.debug.panic` adds a newline to format

10 files changed, 374 insertions(+), 148 deletions(-)

src/all_types.hpp+1
......@@ -944,6 +944,7 @@ struct TypeTableEntryEnum {
944944 AstNode *decl_node;
945945 ContainerLayout layout;
946946 uint32_t src_field_count;
947 // number of fields in the union. 0 if enum with no payload
947948 uint32_t gen_field_count;
948949 TypeEnumField *fields;
949950 bool is_invalid; // true if any fields are invalid
src/codegen.cpp+33-20
......@@ -3802,6 +3802,35 @@ static const GlobalLinkageValue global_linkage_values[] = {
38023802 {GlobalLinkageIdLinkOnce, "LinkOnce"},
38033803};
38043804
3805static void init_enum_debug_info(CodeGen *g, TypeTableEntry *enum_type) {
3806 uint32_t field_count = enum_type->data.enumeration.src_field_count;
3807
3808 TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
3809 enum_type->data.enumeration.tag_type = tag_type_entry;
3810
3811 ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
3812 for (uint32_t i = 0; i < field_count; i += 1) {
3813 TypeEnumField *field = &enum_type->data.enumeration.fields[i];
3814 di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field->name), i);
3815 }
3816
3817 // create debug type for tag
3818 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
3819 uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, tag_type_entry->type_ref);
3820 enum_type->di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
3821 nullptr, buf_ptr(&enum_type->name),
3822 nullptr, 0,
3823 tag_debug_size_in_bits,
3824 tag_debug_align_in_bits,
3825 di_enumerators, field_count,
3826 tag_type_entry->di_type, "");
3827
3828 enum_type->type_ref = tag_type_entry->type_ref;
3829
3830 enum_type->data.enumeration.complete = true;
3831 enum_type->data.enumeration.zero_bits_known = true;
3832}
3833
38053834static void define_builtin_types(CodeGen *g) {
38063835 {
38073836 // if this type is anywhere in the AST, we should never hit codegen.
......@@ -4022,7 +4051,6 @@ static void define_builtin_types(CodeGen *g) {
40224051
40234052 {
40244053 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
4025 entry->zero_bits = true; // only allowed at compile time
40264054 buf_init_from_str(&entry->name, "Os");
40274055 uint32_t field_count = target_os_count();
40284056 entry->data.enumeration.src_field_count = field_count;
......@@ -4038,11 +4066,8 @@ static void define_builtin_types(CodeGen *g) {
40384066 g->target_os_index = i;
40394067 }
40404068 }
4041 entry->data.enumeration.complete = true;
4042 entry->data.enumeration.zero_bits_known = true;
40434069
4044 TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
4045 entry->data.enumeration.tag_type = tag_type_entry;
4070 init_enum_debug_info(g, entry);
40464071
40474072 g->builtin_types.entry_os_enum = entry;
40484073 g->primitive_type_table.put(&entry->name, entry);
......@@ -4050,7 +4075,6 @@ static void define_builtin_types(CodeGen *g) {
40504075
40514076 {
40524077 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
4053 entry->zero_bits = true; // only allowed at compile time
40544078 buf_init_from_str(&entry->name, "Arch");
40554079 uint32_t field_count = target_arch_count();
40564080 entry->data.enumeration.src_field_count = field_count;
......@@ -4072,11 +4096,8 @@ static void define_builtin_types(CodeGen *g) {
40724096 g->target_arch_index = i;
40734097 }
40744098 }
4075 entry->data.enumeration.complete = true;
4076 entry->data.enumeration.zero_bits_known = true;
40774099
4078 TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
4079 entry->data.enumeration.tag_type = tag_type_entry;
4100 init_enum_debug_info(g, entry);
40804101
40814102 g->builtin_types.entry_arch_enum = entry;
40824103 g->primitive_type_table.put(&entry->name, entry);
......@@ -4084,7 +4105,6 @@ static void define_builtin_types(CodeGen *g) {
40844105
40854106 {
40864107 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
4087 entry->zero_bits = true; // only allowed at compile time
40884108 buf_init_from_str(&entry->name, "Environ");
40894109 uint32_t field_count = target_environ_count();
40904110 entry->data.enumeration.src_field_count = field_count;
......@@ -4100,11 +4120,8 @@ static void define_builtin_types(CodeGen *g) {
41004120 g->target_environ_index = i;
41014121 }
41024122 }
4103 entry->data.enumeration.complete = true;
4104 entry->data.enumeration.zero_bits_known = true;
41054123
4106 TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
4107 entry->data.enumeration.tag_type = tag_type_entry;
4124 init_enum_debug_info(g, entry);
41084125
41094126 g->builtin_types.entry_environ_enum = entry;
41104127 g->primitive_type_table.put(&entry->name, entry);
......@@ -4112,7 +4129,6 @@ static void define_builtin_types(CodeGen *g) {
41124129
41134130 {
41144131 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
4115 entry->zero_bits = true; // only allowed at compile time
41164132 buf_init_from_str(&entry->name, "ObjectFormat");
41174133 uint32_t field_count = target_oformat_count();
41184134 entry->data.enumeration.src_field_count = field_count;
......@@ -4128,11 +4144,8 @@ static void define_builtin_types(CodeGen *g) {
41284144 g->target_oformat_index = i;
41294145 }
41304146 }
4131 entry->data.enumeration.complete = true;
4132 entry->data.enumeration.zero_bits_known = true;
41334147
4134 TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
4135 entry->data.enumeration.tag_type = tag_type_entry;
4148 init_enum_debug_info(g, entry);
41364149
41374150 g->builtin_types.entry_oformat_enum = entry;
41384151 g->primitive_type_table.put(&entry->name, entry);
std/build.zig+202
......@@ -32,6 +32,8 @@ pub const Builder = struct {
3232 *exe = Exe {
3333 .root_src = root_src,
3434 .name = name,
35 .target = Target.Native,
36 .linker_script = LinkerScript.None,
3537 };
3638 %return self.exe_list.append(exe);
3739 return exe;
......@@ -53,9 +55,43 @@ pub const Builder = struct {
5355
5456 %return zig_args.append("build_exe"[0...]); // TODO issue #296
5557 %return zig_args.append(exe.root_src);
58
59 if (verbose) {
60 %return zig_args.append("--verbose"[0...]); // TODO issue #296
61 }
62
5663 %return zig_args.append("--name"[0...]); // TODO issue #296
5764 %return zig_args.append(exe.name);
5865
66 switch (exe.target) {
67 Target.Native => {},
68 Target.Cross => |cross_target| {
69 %return zig_args.append("--target-arch"[0...]); // TODO issue #296
70 %return zig_args.append(targetArchName(cross_target.arch));
71
72 %return zig_args.append("--target-os"[0...]); // TODO issue #296
73 %return zig_args.append(targetOsName(cross_target.os));
74
75 %return zig_args.append("--target-environ"[0...]); // TODO issue #296
76 %return zig_args.append(targetEnvironName(cross_target.environ));
77 },
78 }
79
80 switch (exe.linker_script) {
81 LinkerScript.None => {},
82 LinkerScript.Embed => |script| {
83 const tmp_file_name = "linker.ld.tmp"; // TODO issue #298
84 io.writeFile(tmp_file_name, script, self.allocator)
85 %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err));
86 %return zig_args.append("--linker-script"[0...]); // TODO issue #296
87 %return zig_args.append(tmp_file_name[0...]); // TODO issue #296
88 },
89 LinkerScript.Path => |path| {
90 %return zig_args.append("--linker-script"[0...]); // TODO issue #296
91 %return zig_args.append(path);
92 },
93 }
94
5995 printInvocation(self.zig_exe, zig_args);
6096 var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), os.environ,
6197 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator);
......@@ -72,9 +108,48 @@ pub const Builder = struct {
72108 }
73109};
74110
111const CrossTarget = struct {
112 arch: Arch,
113 os: Os,
114 environ: Environ,
115};
116
117const Target = enum {
118 Native,
119 Cross: CrossTarget,
120};
121
122const LinkerScript = enum {
123 None,
124 Embed: []const u8,
125 Path: []const u8,
126};
127
75128const Exe = struct {
76129 root_src: []const u8,
77130 name: []const u8,
131 target: Target,
132 linker_script: LinkerScript,
133
134 fn setTarget(self: &Exe, target_arch: Arch, target_os: Os, target_environ: Environ) {
135 self.target = Target.Cross {
136 CrossTarget {
137 .arch = target_arch,
138 .os = target_os,
139 .environ = target_environ,
140 }
141 };
142 }
143
144 /// Exe keeps a reference to script for its lifetime or until this function
145 /// is called again.
146 fn setLinkerScriptContents(self: &Exe, script: []const u8) {
147 self.linker_script = LinkerScript.Embed { script };
148 }
149
150 fn setLinkerScriptPath(self: &Exe, path: []const u8) {
151 self.linker_script = LinkerScript.Path { path };
152 }
78153};
79154
80155fn handleErr(err: error) -> noreturn {
......@@ -88,3 +163,130 @@ fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) {
88163 }
89164 %%io.stderr.printf("\n");
90165}
166
167// TODO issue #299
168fn targetOsName(target_os: Os) -> []const u8 {
169 return switch (target_os) {
170 Os.freestanding => ([]const u8)("freestanding"),
171 Os.cloudabi => ([]const u8)("cloudabi"),
172 Os.darwin => ([]const u8)("darwin"),
173 Os.dragonfly => ([]const u8)("dragonfly"),
174 Os.freebsd => ([]const u8)("freebsd"),
175 Os.ios => ([]const u8)("ios"),
176 Os.kfreebsd => ([]const u8)("kfreebsd"),
177 Os.linux => ([]const u8)("linux"),
178 Os.lv2 => ([]const u8)("lv2"),
179 Os.macosx => ([]const u8)("macosx"),
180 Os.netbsd => ([]const u8)("netbsd"),
181 Os.openbsd => ([]const u8)("openbsd"),
182 Os.solaris => ([]const u8)("solaris"),
183 Os.windows => ([]const u8)("windows"),
184 Os.haiku => ([]const u8)("haiku"),
185 Os.minix => ([]const u8)("minix"),
186 Os.rtems => ([]const u8)("rtems"),
187 Os.nacl => ([]const u8)("nacl"),
188 Os.cnk => ([]const u8)("cnk"),
189 Os.bitrig => ([]const u8)("bitrig"),
190 Os.aix => ([]const u8)("aix"),
191 Os.cuda => ([]const u8)("cuda"),
192 Os.nvcl => ([]const u8)("nvcl"),
193 Os.amdhsa => ([]const u8)("amdhsa"),
194 Os.ps4 => ([]const u8)("ps4"),
195 Os.elfiamcu => ([]const u8)("elfiamcu"),
196 Os.tvos => ([]const u8)("tvos"),
197 Os.watchos => ([]const u8)("watchos"),
198 Os.mesa3d => ([]const u8)("mesa3d"),
199 };
200}
201
202// TODO issue #299
203fn targetArchName(target_arch: Arch) -> []const u8 {
204 return switch (target_arch) {
205 Arch.armv8_2a => ([]const u8)("armv8_2a"),
206 Arch.armv8_1a => ([]const u8)("armv8_1a"),
207 Arch.armv8 => ([]const u8)("armv8"),
208 Arch.armv8m_baseline => ([]const u8)("armv8m_baseline"),
209 Arch.armv8m_mainline => ([]const u8)("armv8m_mainline"),
210 Arch.armv7 => ([]const u8)("armv7"),
211 Arch.armv7em => ([]const u8)("armv7em"),
212 Arch.armv7m => ([]const u8)("armv7m"),
213 Arch.armv7s => ([]const u8)("armv7s"),
214 Arch.armv7k => ([]const u8)("armv7k"),
215 Arch.armv6 => ([]const u8)("armv6"),
216 Arch.armv6m => ([]const u8)("armv6m"),
217 Arch.armv6k => ([]const u8)("armv6k"),
218 Arch.armv6t2 => ([]const u8)("armv6t2"),
219 Arch.armv5 => ([]const u8)("armv5"),
220 Arch.armv5te => ([]const u8)("armv5te"),
221 Arch.armv4t => ([]const u8)("armv4t"),
222 Arch.armeb => ([]const u8)("armeb"),
223 Arch.aarch64 => ([]const u8)("aarch64"),
224 Arch.aarch64_be => ([]const u8)("aarch64_be"),
225 Arch.avr => ([]const u8)("avr"),
226 Arch.bpfel => ([]const u8)("bpfel"),
227 Arch.bpfeb => ([]const u8)("bpfeb"),
228 Arch.hexagon => ([]const u8)("hexagon"),
229 Arch.mips => ([]const u8)("mips"),
230 Arch.mipsel => ([]const u8)("mipsel"),
231 Arch.mips64 => ([]const u8)("mips64"),
232 Arch.mips64el => ([]const u8)("mips64el"),
233 Arch.msp430 => ([]const u8)("msp430"),
234 Arch.powerpc => ([]const u8)("powerpc"),
235 Arch.powerpc64 => ([]const u8)("powerpc64"),
236 Arch.powerpc64le => ([]const u8)("powerpc64le"),
237 Arch.r600 => ([]const u8)("r600"),
238 Arch.amdgcn => ([]const u8)("amdgcn"),
239 Arch.sparc => ([]const u8)("sparc"),
240 Arch.sparcv9 => ([]const u8)("sparcv9"),
241 Arch.sparcel => ([]const u8)("sparcel"),
242 Arch.s390x => ([]const u8)("s390x"),
243 Arch.tce => ([]const u8)("tce"),
244 Arch.thumb => ([]const u8)("thumb"),
245 Arch.thumbeb => ([]const u8)("thumbeb"),
246 Arch.i386 => ([]const u8)("i386"),
247 Arch.x86_64 => ([]const u8)("x86_64"),
248 Arch.xcore => ([]const u8)("xcore"),
249 Arch.nvptx => ([]const u8)("nvptx"),
250 Arch.nvptx64 => ([]const u8)("nvptx64"),
251 Arch.le32 => ([]const u8)("le32"),
252 Arch.le64 => ([]const u8)("le64"),
253 Arch.amdil => ([]const u8)("amdil"),
254 Arch.amdil64 => ([]const u8)("amdil64"),
255 Arch.hsail => ([]const u8)("hsail"),
256 Arch.hsail64 => ([]const u8)("hsail64"),
257 Arch.spir => ([]const u8)("spir"),
258 Arch.spir64 => ([]const u8)("spir64"),
259 Arch.kalimbav3 => ([]const u8)("kalimbav3"),
260 Arch.kalimbav4 => ([]const u8)("kalimbav4"),
261 Arch.kalimbav5 => ([]const u8)("kalimbav5"),
262 Arch.shave => ([]const u8)("shave"),
263 Arch.lanai => ([]const u8)("lanai"),
264 Arch.wasm32 => ([]const u8)("wasm32"),
265 Arch.wasm64 => ([]const u8)("wasm64"),
266 Arch.renderscript32 => ([]const u8)("renderscript32"),
267 Arch.renderscript64 => ([]const u8)("renderscript64"),
268 };
269}
270
271// TODO issue #299
272fn targetEnvironName(target_environ: Environ) -> []const u8 {
273 return switch (target_environ) {
274 Environ.gnu => ([]const u8)("gnu"),
275 Environ.gnuabi64 => ([]const u8)("gnuabi64"),
276 Environ.gnueabi => ([]const u8)("gnueabi"),
277 Environ.gnueabihf => ([]const u8)("gnueabihf"),
278 Environ.gnux32 => ([]const u8)("gnux32"),
279 Environ.code16 => ([]const u8)("code16"),
280 Environ.eabi => ([]const u8)("eabi"),
281 Environ.eabihf => ([]const u8)("eabihf"),
282 Environ.android => ([]const u8)("android"),
283 Environ.musl => ([]const u8)("musl"),
284 Environ.musleabi => ([]const u8)("musleabi"),
285 Environ.musleabihf => ([]const u8)("musleabihf"),
286 Environ.msvc => ([]const u8)("msvc"),
287 Environ.itanium => ([]const u8)("itanium"),
288 Environ.cygnus => ([]const u8)("cygnus"),
289 Environ.amdopencl => ([]const u8)("amdopencl"),
290 Environ.coreclr => ([]const u8)("coreclr"),
291 };
292}
std/debug.zig+3-3
......@@ -28,7 +28,7 @@ pub coldcc fn panic(comptime format: []const u8, args: ...) -> noreturn {
2828 panicking = true;
2929 }
3030
31 %%io.stderr.printf(format, args);
31 %%io.stderr.printf(format ++ "\n", args);
3232 %%printStackTrace();
3333
3434 os.abort();
......@@ -52,8 +52,8 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
5252 .compile_unit_list = List(CompileUnit).init(&global_allocator),
5353 };
5454 const st = &stack_trace;
55 %return io.openSelfExe(&st.self_exe_stream);
56 defer st.self_exe_stream.close() %% {};
55 st.self_exe_stream = %return io.openSelfExe();
56 defer st.self_exe_stream.close();
5757
5858 %return st.elf.openStream(&global_allocator, &st.self_exe_stream);
5959 defer st.elf.close();
std/io.zig+64-78
......@@ -69,6 +69,27 @@ pub const OutStream = struct {
6969 buffer: [buffer_size]u8,
7070 index: usize,
7171
72 /// `path` may need to be copied in memory to add a null terminating byte. In this case
73 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
74 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
75 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
76 /// Call close to clean up.
77 pub fn open(path: []const u8, allocator: ?&mem.Allocator) -> %OutStream {
78 switch (@compileVar("os")) {
79 Os.linux, Os.darwin, Os.macosx, Os.ios => {
80 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;
81 const fd = %return os.posixOpen(path, flags, 0o666, allocator);
82 return OutStream {
83 .fd = fd,
84 .index = 0,
85 .buffer = undefined,
86 };
87 },
88 else => @compileError("Unsupported OS"),
89 }
90
91 }
92
7293 pub fn writeByte(self: &OutStream, b: u8) -> %void {
7394 if (self.buffer.len == self.index) %return self.flush();
7495 self.buffer[self.index] = b;
......@@ -76,6 +97,11 @@ pub const OutStream = struct {
7697 }
7798
7899 pub fn write(self: &OutStream, bytes: []const u8) -> %void {
100 if (bytes.len >= buffer_size) {
101 %return self.flush();
102 return os.posixWrite(self.fd, bytes);
103 }
104
79105 var src_index: usize = 0;
80106
81107 while (src_index < bytes.len) {
......@@ -119,35 +145,15 @@ pub const OutStream = struct {
119145 }
120146
121147 pub fn flush(self: &OutStream) -> %void {
122 while (true) {
123 const write_ret = system.write(self.fd, &self.buffer[0], self.index);
124 const write_err = system.getErrno(write_ret);
125 if (write_err > 0) {
126 return switch (write_err) {
127 errno.EINTR => continue,
128 errno.EINVAL => unreachable,
129 errno.EDQUOT => error.DiskQuota,
130 errno.EFBIG => error.FileTooBig,
131 errno.EIO => error.Io,
132 errno.ENOSPC => error.NoSpaceLeft,
133 errno.EPERM => error.BadPerm,
134 errno.EPIPE => error.PipeFail,
135 else => error.Unexpected,
136 }
137 }
148 if (self.index != 0) {
149 %return os.posixWrite(self.fd, self.buffer[0...self.index]);
138150 self.index = 0;
139 return;
140151 }
141152 }
142153
143154 pub fn close(self: &OutStream) {
144 while (true) {
145 const close_ret = system.close(self.fd);
146 const close_err = system.getErrno(close_ret);
147 if (close_err > 0 and close_err == errno.EINTR)
148 continue;
149 return;
150 }
155 assert(self.index == 0);
156 os.posixClose(self.fd);
151157 }
152158};
153159
......@@ -156,65 +162,32 @@ pub const OutStream = struct {
156162pub const InStream = struct {
157163 fd: i32,
158164
165 /// `path` may need to be copied in memory to add a null terminating byte. In this case
166 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
167 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
168 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
159169 /// Call close to clean up.
160 pub fn open(is: &InStream, path: []const u8) -> %void {
170 pub fn open(path: []const u8, allocator: ?&mem.Allocator) -> %InStream {
161171 switch (@compileVar("os")) {
162 Os.linux, Os.darwin => {
163 while (true) {
164 const result = system.open(path, system.O_LARGEFILE|system.O_RDONLY, 0);
165 const err = system.getErrno(result);
166 if (err > 0) {
167 return switch (err) {
168 errno.EINTR => continue,
169
170 errno.EFAULT => unreachable,
171 errno.EINVAL => unreachable,
172 errno.EACCES => error.BadPerm,
173 errno.EFBIG, errno.EOVERFLOW => error.FileTooBig,
174 errno.EISDIR => error.IsDir,
175 errno.ELOOP => error.SymLinkLoop,
176 errno.EMFILE => error.ProcessFdQuotaExceeded,
177 errno.ENAMETOOLONG => error.NameTooLong,
178 errno.ENFILE => error.SystemFdQuotaExceeded,
179 errno.ENODEV => error.NoDevice,
180 errno.ENOENT => error.PathNotFound,
181 errno.ENOMEM => error.NoMem,
182 errno.ENOSPC => error.NoSpaceLeft,
183 errno.ENOTDIR => error.NotDir,
184 errno.EPERM => error.BadPerm,
185 else => error.Unexpected,
186 }
187 }
188 is.fd = i32(result);
189 return;
190 }
172 Os.linux, Os.darwin, Os.macosx, Os.ios => {
173 const flags = system.O_LARGEFILE|system.O_RDONLY;
174 const fd = %return os.posixOpen(path, flags, 0, allocator);
175 return InStream {
176 .fd = fd,
177 };
191178 },
192 else => @compileError("unsupported OS"),
179 else => @compileError("Unsupported OS"),
193180 }
194
195181 }
196182
197183 /// Upon success, the stream is in an uninitialized state. To continue using it,
198184 /// you must use the open() function.
199 pub fn close(is: &InStream) -> %void {
185 pub fn close(self: &InStream) {
200186 switch (@compileVar("os")) {
201 Os.linux, Os.darwin => {
202 while (true) {
203 const close_ret = system.close(is.fd);
204 const close_err = system.getErrno(close_ret);
205 if (close_err > 0) {
206 return switch (close_err) {
207 errno.EINTR => continue,
208
209 errno.EIO => error.Io,
210 errno.EBADF => error.BadFd,
211 else => error.Unexpected,
212 }
213 }
214 return;
215 }
187 Os.linux, Os.darwin, Os.macosx, Os.ios => {
188 os.posixClose(self.fd);
216189 },
217 else => @compileError("unsupported OS"),
190 else => @compileError("Unsupported OS"),
218191 }
219192 }
220193
......@@ -373,15 +346,28 @@ pub const InStream = struct {
373346 }
374347};
375348
376pub fn openSelfExe(stream: &InStream) -> %void {
349pub fn openSelfExe() -> %InStream {
377350 switch (@compileVar("os")) {
378351 Os.linux => {
379 %return stream.open("/proc/self/exe");
352 return InStream.open("/proc/self/exe", null);
380353 },
381354 Os.darwin => {
382 %%stderr.printf("TODO: openSelfExe on Darwin\n");
383 os.abort();
355 debug.panic("TODO: openSelfExe on Darwin");
384356 },
385 else => @compileError("unsupported os"),
357 else => @compileError("Unsupported OS"),
386358 }
387359}
360
361/// `path` may need to be copied in memory to add a null terminating byte. In this case
362/// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
363/// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
364/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
365pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) -> %void {
366 // TODO have an unbuffered File abstraction and use that here.
367 // Then a buffered out stream abstraction can go on top of that for
368 // use cases like stdout and stderr.
369 var out_stream = %return OutStream.open(path, allocator);
370 defer out_stream.close();
371 %return out_stream.write(data);
372 %return out_stream.flush();
373}
std/os/darwin.zig+1-8
......@@ -71,17 +71,10 @@ pub fn close(fd: i32) -> usize {
7171 arch.syscall1(arch.SYS_close, usize(fd))
7272}
7373
74pub fn open_c(path: &const u8, flags: usize, perm: usize) -> usize {
74pub fn open(path: &const u8, flags: usize, perm: usize) -> usize {
7575 arch.syscall3(arch.SYS_open, usize(path), flags, perm)
7676}
7777
78pub fn open(path: []const u8, flags: usize, perm: usize) -> usize {
79 const buf = @alloca(u8, path.len + 1);
80 @memcpy(&buf[0], &path[0], path.len);
81 buf[path.len] = 0;
82 return open_c(buf.ptr, flags, perm);
83}
84
8578pub fn read(fd: i32, buf: &u8, count: usize) -> usize {
8679 arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count)
8780}
std/os/index.zig+64-14
......@@ -8,6 +8,8 @@ pub const posix = switch(@compileVar("os")) {
88 else => @compileError("Unsupported OS"),
99};
1010
11pub const max_noalloc_path_len = 1024;
12
1113const debug = @import("../debug.zig");
1214const assert = debug.assert;
1315
......@@ -105,11 +107,12 @@ fn makePipe() -> %[2]i32 {
105107}
106108
107109fn destroyPipe(pipe: &const [2]i32) {
108 closeNoIntr((*pipe)[0]);
109 closeNoIntr((*pipe)[1]);
110 posixClose((*pipe)[0]);
111 posixClose((*pipe)[1]);
110112}
111113
112fn closeNoIntr(fd: i32) {
114/// Calls POSIX close, and keeps trying if it gets interrupted.
115pub fn posixClose(fd: i32) {
113116 while (true) {
114117 const err = posix.getErrno(posix.close(fd));
115118 if (err == errno.EINTR) {
......@@ -120,9 +123,56 @@ fn closeNoIntr(fd: i32) {
120123 }
121124}
122125
123fn openNoIntr(path: []const u8, flags: usize, perm: usize) -> %i32 {
126/// Calls POSIX write, and keeps trying if it gets interrupted.
127pub fn posixWrite(fd: i32, bytes: []const u8) -> %void {
128 while (true) {
129 const write_ret = posix.write(fd, bytes.ptr, bytes.len);
130 const write_err = posix.getErrno(write_ret);
131 if (write_err > 0) {
132 return switch (write_err) {
133 errno.EINTR => continue,
134 errno.EINVAL => unreachable,
135 errno.EDQUOT => error.DiskQuota,
136 errno.EFBIG => error.FileTooBig,
137 errno.EIO => error.Io,
138 errno.ENOSPC => error.NoSpaceLeft,
139 errno.EPERM => error.BadPerm,
140 errno.EPIPE => error.PipeFail,
141 else => error.Unexpected,
142 }
143 }
144 return;
145 }
146}
147
148
149/// ::path may need to be copied in memory to add a null terminating byte. In this case
150/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
151/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
152/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
153/// Calls POSIX open, keeps trying if it gets interrupted, and translates
154/// the return value into zig errors.
155pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Allocator) -> %i32 {
156 var stack_buf: [max_noalloc_path_len]u8 = undefined;
157 var path0: []u8 = undefined;
158 var need_free = false;
159
160 if (path.len < stack_buf.len) {
161 path0 = stack_buf[0...path.len + 1];
162 } else if (const a ?= allocator) {
163 path0 = %return a.alloc(u8, path.len + 1);
164 need_free = true;
165 } else {
166 return error.NameTooLong;
167 }
168 defer if (need_free) {
169 (??allocator).free(path0);
170 };
171 mem.copy(u8, path0, path);
172 path0[path.len] = 0;
173
124174 while (true) {
125 const result = posix.open(path, flags, perm);
175 const result = posix.open(path0.ptr, flags, perm);
126176 const err = posix.getErrno(result);
127177 if (err > 0) {
128178 return switch (err) {
......@@ -247,8 +297,8 @@ pub const ChildProcess = struct {
247297
248298 pub fn wait(self: &ChildProcess) -> %Term {
249299 defer {
250 closeNoIntr(self.err_pipe[0]);
251 closeNoIntr(self.err_pipe[1]);
300 posixClose(self.err_pipe[0]);
301 posixClose(self.err_pipe[1]);
252302 };
253303
254304 var status: i32 = undefined;
......@@ -328,13 +378,13 @@ pub const ChildProcess = struct {
328378 const any_ignore = (stdin == StdIo.Ignore or stdout == StdIo.Ignore or stderr == StdIo.Ignore);
329379 // TODO issue #295
330380 //const dev_null_fd = if (any_ignore) {
331 // %return openNoIntr("/dev/null", posix.O_RDWR, 0)
381 // %return posixOpen("/dev/null", posix.O_RDWR, 0, null)
332382 //} else {
333383 // undefined
334384 //};
335385 var dev_null_fd: i32 = undefined;
336386 if (any_ignore)
337 dev_null_fd = %return openNoIntr("/dev/null", posix.O_RDWR, 0);
387 dev_null_fd = %return posixOpen("/dev/null", posix.O_RDWR, 0, null);
338388
339389 // This pipe is used to communicate errors between the time of fork
340390 // and execve from the child process to the parent process.
......@@ -374,10 +424,10 @@ pub const ChildProcess = struct {
374424 }
375425
376426 // we are the parent
377 if (stdin == StdIo.Pipe) { closeNoIntr(stdin_pipe[0]); }
378 if (stdout == StdIo.Pipe) { closeNoIntr(stdout_pipe[1]); }
379 if (stderr == StdIo.Pipe) { closeNoIntr(stderr_pipe[1]); }
380 if (any_ignore) { closeNoIntr(dev_null_fd); }
427 if (stdin == StdIo.Pipe) { posixClose(stdin_pipe[0]); }
428 if (stdout == StdIo.Pipe) { posixClose(stdout_pipe[1]); }
429 if (stderr == StdIo.Pipe) { posixClose(stderr_pipe[1]); }
430 if (any_ignore) { posixClose(dev_null_fd); }
381431
382432 return ChildProcess {
383433 .pid = i32(pid),
......@@ -412,7 +462,7 @@ pub const ChildProcess = struct {
412462 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void {
413463 switch (stdio) {
414464 StdIo.Pipe => %return dup2NoIntr(pipe_fd, std_fileno),
415 StdIo.Close => closeNoIntr(std_fileno),
465 StdIo.Close => posixClose(std_fileno),
416466 StdIo.Inherit => {},
417467 StdIo.Ignore => %return dup2NoIntr(dev_null_fd, std_fileno),
418468 }
std/os/linux.zig+3-24
......@@ -303,39 +303,18 @@ pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize {
303303 arch.syscall4(arch.SYS_pwrite, usize(fd), usize(buf), count, offset)
304304}
305305
306pub fn open_c(path: &const u8, flags: usize, perm: usize) -> usize {
306pub fn open(path: &const u8, flags: usize, perm: usize) -> usize {
307307 arch.syscall3(arch.SYS_open, usize(path), flags, perm)
308308}
309309
310pub fn open(path: []const u8, flags: usize, perm: usize) -> usize {
311 const buf = @alloca(u8, path.len + 1);
312 @memcpy(&buf[0], &path[0], path.len);
313 buf[path.len] = 0;
314 return open_c(buf.ptr, flags, perm);
315}
316
317pub fn create_c(path: &const u8, perm: usize) -> usize {
310pub fn create(path: &const u8, perm: usize) -> usize {
318311 arch.syscall2(arch.SYS_creat, usize(path), perm)
319312}
320313
321pub fn create(path: []const u8, perm: usize) -> usize {
322 const buf = @alloca(u8, path.len + 1);
323 @memcpy(&buf[0], &path[0], path.len);
324 buf[path.len] = 0;
325 return create_c(buf.ptr, perm);
326}
327
328pub fn openat_c(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize {
314pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize {
329315 arch.syscall4(arch.SYS_openat, usize(dirfd), usize(path), flags, mode)
330316}
331317
332pub fn openat(dirfd: i32, path: []const u8, flags: usize, mode: usize) -> usize {
333 const buf = @alloca(u8, path.len + 1);
334 @memcpy(&buf[0], &path[0], path.len);
335 buf[path.len] = 0;
336 return openat_c(dirfd, buf.ptr, flags, mode);
337}
338
339318pub fn close(fd: i32) -> usize {
340319 arch.syscall1(arch.SYS_close, usize(fd))
341320}
std/special/bootstrap.zig+2
......@@ -33,6 +33,7 @@ export nakedcc fn _start() -> noreturn {
3333}
3434
3535fn callMain(envp: &?&u8) -> %void {
36 // TODO issue #225
3637 const args = @alloca([]u8, argc);
3738 for (args) |_, i| {
3839 const ptr = argv[i];
......@@ -41,6 +42,7 @@ fn callMain(envp: &?&u8) -> %void {
4142
4243 var env_count: usize = 0;
4344 while (envp[env_count] != null; env_count += 1) {}
45 // TODO issue #225
4446 const environ = @alloca(std.os.EnvPair, env_count);
4547 for (environ) |_, env_i| {
4648 const ptr = ??envp[env_i];
std/special/zigrt.zig+1-1
......@@ -11,6 +11,6 @@ export coldcc fn __zig_panic(message_ptr: &const u8, message_len: usize) -> nore
1111 } else if (@compileVar("os") == Os.freestanding) {
1212 while (true) {}
1313 } else {
14 @import("std").debug.panic("{}\n", message_ptr[0...message_len]);
14 @import("std").debug.panic("{}", message_ptr[0...message_len]);
1515 }
1616}