authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-17 22:45:49-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-02-17 22:45:49-05:00
loge8a84927ab989d3c8fb6668dd242ada0a8f99585
treee0189e9cae971e221f0b76fb4c7e7b096d23959a
parent35f0cb049e6a46c8037bab15a9debc21ad1a979e
parent99520c4e6936b69e7489262bc35a70300366d395
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4478 from ziglang/self-host-libc-detection

self-hosted libc and dynamic linker detection

47 files changed, 3128 insertions(+), 2861 deletions(-)

CMakeLists.txt+58-39
...@@ -434,8 +434,8 @@ find_package(Threads)...@@ -434,8 +434,8 @@ find_package(Threads)
434# CMake doesn't let us create an empty executable, so we hang on to this one separately.434# CMake doesn't let us create an empty executable, so we hang on to this one separately.
435set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp")435set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp")
436436
437# This is our shim which will be replaced by libuserland written in Zig.437# This is our shim which will be replaced by libstage2 written in Zig.
438set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp")438set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/stage2.cpp")
439439
440if(ZIG_ENABLE_MEM_PROFILE)440if(ZIG_ENABLE_MEM_PROFILE)
441 set(ZIG_SOURCES_MEM_PROFILE "${CMAKE_SOURCE_DIR}/src/mem_profile.cpp")441 set(ZIG_SOURCES_MEM_PROFILE "${CMAKE_SOURCE_DIR}/src/mem_profile.cpp")
...@@ -457,7 +457,6 @@ set(ZIG_SOURCES...@@ -457,7 +457,6 @@ set(ZIG_SOURCES
457 "${CMAKE_SOURCE_DIR}/src/heap.cpp"457 "${CMAKE_SOURCE_DIR}/src/heap.cpp"
458 "${CMAKE_SOURCE_DIR}/src/ir.cpp"458 "${CMAKE_SOURCE_DIR}/src/ir.cpp"
459 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"459 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
460 "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"
461 "${CMAKE_SOURCE_DIR}/src/link.cpp"460 "${CMAKE_SOURCE_DIR}/src/link.cpp"
462 "${CMAKE_SOURCE_DIR}/src/mem.cpp"461 "${CMAKE_SOURCE_DIR}/src/mem.cpp"
463 "${CMAKE_SOURCE_DIR}/src/os.cpp"462 "${CMAKE_SOURCE_DIR}/src/os.cpp"
...@@ -566,12 +565,12 @@ set_target_properties(opt_c_util PROPERTIES...@@ -566,12 +565,12 @@ set_target_properties(opt_c_util PROPERTIES
566 COMPILE_FLAGS "${OPTIMIZED_C_FLAGS}"565 COMPILE_FLAGS "${OPTIMIZED_C_FLAGS}"
567)566)
568567
569add_library(compiler STATIC ${ZIG_SOURCES})568add_library(zigcompiler STATIC ${ZIG_SOURCES})
570set_target_properties(compiler PROPERTIES569set_target_properties(zigcompiler PROPERTIES
571 COMPILE_FLAGS ${EXE_CFLAGS}570 COMPILE_FLAGS ${EXE_CFLAGS}
572 LINK_FLAGS ${EXE_LDFLAGS}571 LINK_FLAGS ${EXE_LDFLAGS}
573)572)
574target_link_libraries(compiler LINK_PUBLIC573target_link_libraries(zigcompiler LINK_PUBLIC
575 zig_cpp574 zig_cpp
576 opt_c_util575 opt_c_util
577 ${SOFTFLOAT_LIBRARIES}576 ${SOFTFLOAT_LIBRARIES}
...@@ -581,15 +580,15 @@ target_link_libraries(compiler LINK_PUBLIC...@@ -581,15 +580,15 @@ target_link_libraries(compiler LINK_PUBLIC
581 ${CMAKE_THREAD_LIBS_INIT}580 ${CMAKE_THREAD_LIBS_INIT}
582)581)
583if(NOT MSVC)582if(NOT MSVC)
584 target_link_libraries(compiler LINK_PUBLIC ${LIBXML2})583 target_link_libraries(zigcompiler LINK_PUBLIC ${LIBXML2})
585endif()584endif()
586585
587if(ZIG_DIA_GUIDS_LIB)586if(ZIG_DIA_GUIDS_LIB)
588 target_link_libraries(compiler LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB})587 target_link_libraries(zigcompiler LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB})
589endif()588endif()
590589
591if(MSVC OR MINGW)590if(MSVC OR MINGW)
592 target_link_libraries(compiler LINK_PUBLIC version)591 target_link_libraries(zigcompiler LINK_PUBLIC version)
593endif()592endif()
594593
595add_executable(zig0 "${ZIG_MAIN_SRC}" "${ZIG0_SHIM_SRC}")594add_executable(zig0 "${ZIG_MAIN_SRC}" "${ZIG0_SHIM_SRC}")
...@@ -597,40 +596,42 @@ set_target_properties(zig0 PROPERTIES...@@ -597,40 +596,42 @@ set_target_properties(zig0 PROPERTIES
597 COMPILE_FLAGS ${EXE_CFLAGS}596 COMPILE_FLAGS ${EXE_CFLAGS}
598 LINK_FLAGS ${EXE_LDFLAGS}597 LINK_FLAGS ${EXE_LDFLAGS}
599)598)
600target_link_libraries(zig0 compiler)599target_link_libraries(zig0 zigcompiler)
601600
602if(MSVC)601if(MSVC)
603 set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.lib")602 set(LIBSTAGE2 "${CMAKE_BINARY_DIR}/zigstage2.lib")
604else()603else()
605 set(LIBUSERLAND "${CMAKE_BINARY_DIR}/libuserland.a")604 set(LIBSTAGE2 "${CMAKE_BINARY_DIR}/libzigstage2.a")
606endif()605endif()
607if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")606if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
608 set(LIBUSERLAND_RELEASE_MODE "false")607 set(LIBSTAGE2_RELEASE_ARG "")
609else()608else()
610 set(LIBUSERLAND_RELEASE_MODE "true")609 set(LIBSTAGE2_RELEASE_ARG --release-fast --strip)
610endif()
611if(WIN32)
612 set(LIBSTAGE2_WINDOWS_ARGS "-lntdll")
613else()
614 set(LIBSTAGE2_WINDOWS_ARGS "")
611endif()615endif()
612616
613set(BUILD_LIBUSERLAND_ARGS "build"617set(BUILD_LIBSTAGE2_ARGS "build-lib"
618 "src-self-hosted/stage2.zig"
619 --name zigstage2
614 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"620 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
615 "-Doutput-dir=${CMAKE_BINARY_DIR}"621 --cache on
616 "-Drelease=${LIBUSERLAND_RELEASE_MODE}"622 --output-dir "${CMAKE_BINARY_DIR}"
617 "-Dlib-files-only"623 ${LIBSTAGE2_RELEASE_ARG}
618 --prefix "${CMAKE_INSTALL_PREFIX}"624 --disable-gen-h
619 libuserland625 --bundle-compiler-rt
626 -fPIC
627 -lc
628 ${LIBSTAGE2_WINDOWS_ARGS}
620)629)
621630
622# When using Visual Studio build system generator we default to libuserland install.631add_custom_target(zig_build_libstage2 ALL
623if(MSVC)632 COMMAND zig0 ${BUILD_LIBSTAGE2_ARGS}
624 set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")
625 if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
626 set(BUILD_LIBUSERLAND_ARGS ${BUILD_LIBUSERLAND_ARGS} install)
627 endif()
628endif()
629
630add_custom_target(zig_build_libuserland ALL
631 COMMAND zig0 ${BUILD_LIBUSERLAND_ARGS}
632 DEPENDS zig0633 DEPENDS zig0
633 BYPRODUCTS "${LIBUSERLAND}"634 BYPRODUCTS "${LIBSTAGE2}"
634 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"635 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
635)636)
636add_executable(zig "${ZIG_MAIN_SRC}")637add_executable(zig "${ZIG_MAIN_SRC}")
...@@ -639,22 +640,40 @@ set_target_properties(zig PROPERTIES...@@ -639,22 +640,40 @@ set_target_properties(zig PROPERTIES
639 COMPILE_FLAGS ${EXE_CFLAGS}640 COMPILE_FLAGS ${EXE_CFLAGS}
640 LINK_FLAGS ${EXE_LDFLAGS}641 LINK_FLAGS ${EXE_LDFLAGS}
641)642)
642target_link_libraries(zig compiler "${LIBUSERLAND}")643target_link_libraries(zig zigcompiler "${LIBSTAGE2}")
643if(MSVC)644if(MSVC)
644 target_link_libraries(zig ntdll.lib)645 target_link_libraries(zig ntdll.lib)
645elseif(MINGW) 646elseif(MINGW)
646 target_link_libraries(zig ntdll)647 target_link_libraries(zig ntdll)
647endif()648endif()
648add_dependencies(zig zig_build_libuserland)649add_dependencies(zig zig_build_libstage2)
649650
650install(TARGETS zig DESTINATION bin)651install(TARGETS zig DESTINATION bin)
651652
652# CODE has no effect with Visual Studio build system generator.653set(ZIG_INSTALL_ARGS "build"
653if(NOT MSVC)654 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
654 get_target_property(zig0_BINARY_DIR zig0 BINARY_DIR)655 "-Dlib-files-only"
655 install(CODE "set(zig0_EXE \"${zig0_BINARY_DIR}/zig0\")")656 --prefix "${CMAKE_INSTALL_PREFIX}"
656 install(CODE "set(INSTALL_LIBUSERLAND_ARGS \"${BUILD_LIBUSERLAND_ARGS}\" install)")657 install
657 install(CODE "set(BUILD_LIBUSERLAND_ARGS \"${BUILD_LIBUSERLAND_ARGS}\")")658)
659
660# CODE has no effect with Visual Studio build system generator, therefore
661# when using Visual Studio build system generator we resort to running
662# `zig build install` during the build phase.
663if(MSVC)
664 set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
665 "Windows-only: Disable copying lib/ files to install prefix during the build phase")
666 if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
667 add_custom_target(zig_install_lib_files ALL
668 COMMAND zig ${ZIG_INSTALL_ARGS}
669 DEPENDS zig
670 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
671 )
672 endif()
673else()
674 get_target_property(zig_BINARY_DIR zig BINARY_DIR)
675 install(CODE "set(zig_EXE \"${zig_BINARY_DIR}/zig\")")
676 install(CODE "set(ZIG_INSTALL_ARGS \"${ZIG_INSTALL_ARGS}\")")
658 install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")677 install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")
659 install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)678 install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)
660endif()679endif()
build.zig+1-28
...@@ -64,8 +64,6 @@ pub fn build(b: *Builder) !void {...@@ -64,8 +64,6 @@ pub fn build(b: *Builder) !void {
64 try configureStage2(b, test_stage2, ctx);64 try configureStage2(b, test_stage2, ctx);
65 try configureStage2(b, exe, ctx);65 try configureStage2(b, exe, ctx);
6666
67 addLibUserlandStep(b, mode);
68
69 const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;67 const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
70 const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;68 const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;
71 const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release;69 const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release;
...@@ -175,7 +173,7 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {...@@ -175,7 +173,7 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {
175}173}
176174
177fn fileExists(filename: []const u8) !bool {175fn fileExists(filename: []const u8) !bool {
178 fs.File.access(filename) catch |err| switch (err) {176 fs.cwd().access(filename, .{}) catch |err| switch (err) {
179 error.FileNotFound => return false,177 error.FileNotFound => return false,
180 else => return err,178 else => return err,
181 };179 };
...@@ -366,28 +364,3 @@ const Context = struct {...@@ -366,28 +364,3 @@ const Context = struct {
366 dia_guids_lib: []const u8,364 dia_guids_lib: []const u8,
367 llvm: LibraryDep,365 llvm: LibraryDep,
368};366};
369
370fn addLibUserlandStep(b: *Builder, mode: builtin.Mode) void {
371 const artifact = b.addStaticLibrary("userland", "src-self-hosted/stage1.zig");
372 artifact.disable_gen_h = true;
373 artifact.bundle_compiler_rt = true;
374 artifact.setTarget(builtin.arch, builtin.os, builtin.abi);
375 artifact.setBuildMode(mode);
376 artifact.force_pic = true;
377 if (mode != .Debug) {
378 artifact.strip = true;
379 }
380 artifact.linkSystemLibrary("c");
381 if (builtin.os == .windows) {
382 artifact.linkSystemLibrary("ntdll");
383 }
384 const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");
385 libuserland_step.dependOn(&artifact.step);
386
387 const output_dir = b.option(
388 []const u8,
389 "output-dir",
390 "For libuserland step, where to put the output",
391 ) orelse return;
392 artifact.setOutputDir(output_dir);
393}
cmake/install.cmake+6-6
...@@ -1,16 +1,16 @@...@@ -1,16 +1,16 @@
1message("-- Installing: ${CMAKE_INSTALL_PREFIX}/lib")1message("-- Installing: ${CMAKE_INSTALL_PREFIX}/lib")
22
3if(NOT EXISTS ${zig0_EXE})3if(NOT EXISTS ${zig_EXE})
4 message("::")4 message("::")
5 message(":: ERROR: Executable not found")5 message(":: ERROR: Executable not found")
6 message(":: (execute_process)")6 message(":: (execute_process)")
7 message("::")7 message("::")
8 message(":: executable: ${zig0_EXE}")8 message(":: executable: ${zig_EXE}")
9 message("::")9 message("::")
10 message(FATAL_ERROR)10 message(FATAL_ERROR)
11endif()11endif()
1212
13execute_process(COMMAND ${zig0_EXE} ${INSTALL_LIBUSERLAND_ARGS}13execute_process(COMMAND ${zig_EXE} ${ZIG_INSTALL_ARGS}
14 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}14 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
15 RESULT_VARIABLE _result15 RESULT_VARIABLE _result
16)16)
...@@ -19,11 +19,11 @@ if(_result)...@@ -19,11 +19,11 @@ if(_result)
19 message(":: ERROR: ${_result}")19 message(":: ERROR: ${_result}")
20 message(":: (execute_process)")20 message(":: (execute_process)")
2121
22 string(REPLACE ";" " " s_INSTALL_LIBUSERLAND_ARGS "${INSTALL_LIBUSERLAND_ARGS}")22 string(REPLACE ";" " " s_INSTALL_LIBSTAGE2_ARGS "${ZIG_INSTALL_ARGS}")
23 message("::")23 message("::")
24 message(":: argv: ${zig0_EXE} ${s_INSTALL_LIBUSERLAND_ARGS} install")24 message(":: argv: ${zig_EXE} ${s_INSTALL_LIBSTAGE2_ARGS}")
2525
26 set(_args ${zig0_EXE} ${INSTALL_LIBUSERLAND_ARGS})26 set(_args ${zig_EXE} ${ZIG_INSTALL_ARGS})
27 list(LENGTH _args _len)27 list(LENGTH _args _len)
28 math(EXPR _len "${_len} - 1")28 math(EXPR _len "${_len} - 1")
29 message("::")29 message("::")
lib/std/c.zig+1
...@@ -96,6 +96,7 @@ pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;...@@ -96,6 +96,7 @@ pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
96pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int;96pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int;
97pub extern "c" fn fork() c_int;97pub extern "c" fn fork() c_int;
98pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int;98pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int;
99pub extern "c" fn faccessat(dirfd: fd_t, path: [*:0]const u8, mode: c_uint, flags: c_uint) c_int;
99pub extern "c" fn pipe(fds: *[2]fd_t) c_int;100pub extern "c" fn pipe(fds: *[2]fd_t) c_int;
100pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;101pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
101pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int;102pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int;
lib/std/child_process.zig+39-15
...@@ -48,7 +48,10 @@ pub const ChildProcess = struct {...@@ -48,7 +48,10 @@ pub const ChildProcess = struct {
48 cwd: ?[]const u8,48 cwd: ?[]const u8,
4949
50 err_pipe: if (builtin.os == .windows) void else [2]os.fd_t,50 err_pipe: if (builtin.os == .windows) void else [2]os.fd_t,
51 llnode: if (builtin.os == .windows) void else TailQueue(*ChildProcess).Node,51
52 expand_arg0: Arg0Expand,
53
54 pub const Arg0Expand = os.Arg0Expand;
5255
53 pub const SpawnError = error{56 pub const SpawnError = error{
54 OutOfMemory,57 OutOfMemory,
...@@ -90,7 +93,6 @@ pub const ChildProcess = struct {...@@ -90,7 +93,6 @@ pub const ChildProcess = struct {
90 .handle = undefined,93 .handle = undefined,
91 .thread_handle = undefined,94 .thread_handle = undefined,
92 .err_pipe = undefined,95 .err_pipe = undefined,
93 .llnode = undefined,
94 .term = null,96 .term = null,
95 .env_map = null,97 .env_map = null,
96 .cwd = null,98 .cwd = null,
...@@ -102,6 +104,7 @@ pub const ChildProcess = struct {...@@ -102,6 +104,7 @@ pub const ChildProcess = struct {
102 .stdin_behavior = StdIo.Inherit,104 .stdin_behavior = StdIo.Inherit,
103 .stdout_behavior = StdIo.Inherit,105 .stdout_behavior = StdIo.Inherit,
104 .stderr_behavior = StdIo.Inherit,106 .stderr_behavior = StdIo.Inherit,
107 .expand_arg0 = .no_expand,
105 };108 };
106 errdefer allocator.destroy(child);109 errdefer allocator.destroy(child);
107 return child;110 return child;
...@@ -174,34 +177,56 @@ pub const ChildProcess = struct {...@@ -174,34 +177,56 @@ pub const ChildProcess = struct {
174177
175 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.178 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
176 /// If it succeeds, the caller owns result.stdout and result.stderr memory.179 /// If it succeeds, the caller owns result.stdout and result.stderr memory.
180 /// TODO deprecate in favor of exec2
177 pub fn exec(181 pub fn exec(
178 allocator: *mem.Allocator,182 allocator: *mem.Allocator,
179 argv: []const []const u8,183 argv: []const []const u8,
180 cwd: ?[]const u8,184 cwd: ?[]const u8,
181 env_map: ?*const BufMap,185 env_map: ?*const BufMap,
182 max_output_size: usize,186 max_output_bytes: usize,
183 ) !ExecResult {187 ) !ExecResult {
184 const child = try ChildProcess.init(argv, allocator);188 return exec2(.{
189 .allocator = allocator,
190 .argv = argv,
191 .cwd = cwd,
192 .env_map = env_map,
193 .max_output_bytes = max_output_bytes,
194 });
195 }
196
197 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
198 /// If it succeeds, the caller owns result.stdout and result.stderr memory.
199 /// TODO rename to exec
200 pub fn exec2(args: struct {
201 allocator: *mem.Allocator,
202 argv: []const []const u8,
203 cwd: ?[]const u8 = null,
204 env_map: ?*const BufMap = null,
205 max_output_bytes: usize = 50 * 1024,
206 expand_arg0: Arg0Expand = .no_expand,
207 }) !ExecResult {
208 const child = try ChildProcess.init(args.argv, args.allocator);
185 defer child.deinit();209 defer child.deinit();
186210
187 child.stdin_behavior = ChildProcess.StdIo.Ignore;211 child.stdin_behavior = .Ignore;
188 child.stdout_behavior = ChildProcess.StdIo.Pipe;212 child.stdout_behavior = .Pipe;
189 child.stderr_behavior = ChildProcess.StdIo.Pipe;213 child.stderr_behavior = .Pipe;
190 child.cwd = cwd;214 child.cwd = args.cwd;
191 child.env_map = env_map;215 child.env_map = args.env_map;
216 child.expand_arg0 = args.expand_arg0;
192217
193 try child.spawn();218 try child.spawn();
194219
195 var stdout = Buffer.initNull(allocator);220 var stdout = Buffer.initNull(args.allocator);
196 var stderr = Buffer.initNull(allocator);221 var stderr = Buffer.initNull(args.allocator);
197 defer Buffer.deinit(&stdout);222 defer Buffer.deinit(&stdout);
198 defer Buffer.deinit(&stderr);223 defer Buffer.deinit(&stderr);
199224
200 var stdout_file_in_stream = child.stdout.?.inStream();225 var stdout_file_in_stream = child.stdout.?.inStream();
201 var stderr_file_in_stream = child.stderr.?.inStream();226 var stderr_file_in_stream = child.stderr.?.inStream();
202227
203 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);228 try stdout_file_in_stream.stream.readAllBuffer(&stdout, args.max_output_bytes);
204 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);229 try stderr_file_in_stream.stream.readAllBuffer(&stderr, args.max_output_bytes);
205230
206 return ExecResult{231 return ExecResult{
207 .term = try child.wait(),232 .term = try child.wait(),
...@@ -420,7 +445,7 @@ pub const ChildProcess = struct {...@@ -420,7 +445,7 @@ pub const ChildProcess = struct {
420 os.setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);445 os.setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
421 }446 }
422447
423 const err = os.execvpe(self.allocator, self.argv, env_map);448 const err = os.execvpe_expandArg0(self.allocator, self.expand_arg0, self.argv, env_map);
424 forkChildErrReport(err_pipe[1], err);449 forkChildErrReport(err_pipe[1], err);
425 }450 }
426451
...@@ -453,7 +478,6 @@ pub const ChildProcess = struct {...@@ -453,7 +478,6 @@ pub const ChildProcess = struct {
453478
454 self.pid = pid;479 self.pid = pid;
455 self.err_pipe = err_pipe;480 self.err_pipe = err_pipe;
456 self.llnode = TailQueue(*ChildProcess).Node.init(self);
457 self.term = null;481 self.term = null;
458482
459 if (self.stdin_behavior == StdIo.Pipe) {483 if (self.stdin_behavior == StdIo.Pipe) {
lib/std/event.zig+2
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1pub const Channel = @import("event/channel.zig").Channel;1pub const Channel = @import("event/channel.zig").Channel;
2pub const Future = @import("event/future.zig").Future;2pub const Future = @import("event/future.zig").Future;
3pub const Group = @import("event/group.zig").Group;3pub const Group = @import("event/group.zig").Group;
4pub const Batch = @import("event/batch.zig").Batch;
4pub const Lock = @import("event/lock.zig").Lock;5pub const Lock = @import("event/lock.zig").Lock;
5pub const Locked = @import("event/locked.zig").Locked;6pub const Locked = @import("event/locked.zig").Locked;
6pub const RwLock = @import("event/rwlock.zig").RwLock;7pub const RwLock = @import("event/rwlock.zig").RwLock;
...@@ -11,6 +12,7 @@ test "import event tests" {...@@ -11,6 +12,7 @@ test "import event tests" {
11 _ = @import("event/channel.zig");12 _ = @import("event/channel.zig");
12 _ = @import("event/future.zig");13 _ = @import("event/future.zig");
13 _ = @import("event/group.zig");14 _ = @import("event/group.zig");
15 _ = @import("event/batch.zig");
14 _ = @import("event/lock.zig");16 _ = @import("event/lock.zig");
15 _ = @import("event/locked.zig");17 _ = @import("event/locked.zig");
16 _ = @import("event/rwlock.zig");18 _ = @import("event/rwlock.zig");
lib/std/event/batch.zig created+139
...@@ -0,0 +1,139 @@
1const std = @import("../std.zig");
2const testing = std.testing;
3
4/// Performs multiple async functions in parallel, without heap allocation.
5/// Async function frames are managed externally to this abstraction, and
6/// passed in via the `add` function. Once all the jobs are added, call `wait`.
7/// This API is *not* thread-safe. The object must be accessed from one thread at
8/// a time, however, it need not be the same thread.
9pub fn Batch(
10 /// The return value for each job.
11 /// If a job slot was re-used due to maxed out concurrency, then its result
12 /// value will be overwritten. The values can be accessed with the `results` field.
13 comptime Result: type,
14 /// How many jobs to run in parallel.
15 comptime max_jobs: comptime_int,
16 /// Controls whether the `add` and `wait` functions will be async functions.
17 comptime async_behavior: enum {
18 /// Observe the value of `std.io.is_async` to decide whether `add`
19 /// and `wait` will be async functions. Asserts that the jobs do not suspend when
20 /// `std.io.mode == .blocking`. This is a generally safe assumption, and the
21 /// usual recommended option for this parameter.
22 auto_async,
23
24 /// Always uses the `noasync` keyword when using `await` on the jobs,
25 /// making `add` and `wait` non-async functions. Asserts that the jobs do not suspend.
26 never_async,
27
28 /// `add` and `wait` use regular `await` keyword, making them async functions.
29 always_async,
30 },
31) type {
32 return struct {
33 jobs: [max_jobs]Job,
34 next_job_index: usize,
35 collected_result: CollectedResult,
36
37 const Job = struct {
38 frame: ?anyframe->Result,
39 result: Result,
40 };
41
42 const Self = @This();
43
44 const CollectedResult = switch (@typeInfo(Result)) {
45 .ErrorUnion => Result,
46 else => void,
47 };
48
49 const async_ok = switch (async_behavior) {
50 .auto_async => std.io.is_async,
51 .never_async => false,
52 .always_async => true,
53 };
54
55 pub fn init() Self {
56 return Self{
57 .jobs = [1]Job{
58 .{
59 .frame = null,
60 .result = undefined,
61 },
62 } ** max_jobs,
63 .next_job_index = 0,
64 .collected_result = {},
65 };
66 }
67
68 /// Add a frame to the Batch. If all jobs are in-flight, then this function
69 /// waits until one completes.
70 /// This function is *not* thread-safe. It must be called from one thread at
71 /// a time, however, it need not be the same thread.
72 /// TODO: "select" language feature to use the next available slot, rather than
73 /// awaiting the next index.
74 pub fn add(self: *Self, frame: anyframe->Result) void {
75 const job = &self.jobs[self.next_job_index];
76 self.next_job_index = (self.next_job_index + 1) % max_jobs;
77 if (job.frame) |existing| {
78 job.result = if (async_ok) await existing else noasync await existing;
79 if (CollectedResult != void) {
80 job.result catch |err| {
81 self.collected_result = err;
82 };
83 }
84 }
85 job.frame = frame;
86 }
87
88 /// Wait for all the jobs to complete.
89 /// Safe to call any number of times.
90 /// If `Result` is an error union, this function returns the last error that occurred, if any.
91 /// Unlike the `results` field, the return value of `wait` will report any error that occurred;
92 /// hitting max parallelism will not compromise the result.
93 /// This function is *not* thread-safe. It must be called from one thread at
94 /// a time, however, it need not be the same thread.
95 pub fn wait(self: *Self) CollectedResult {
96 for (self.jobs) |*job| if (job.frame) |f| {
97 job.result = if (async_ok) await f else noasync await f;
98 if (CollectedResult != void) {
99 job.result catch |err| {
100 self.collected_result = err;
101 };
102 }
103 job.frame = null;
104 };
105 return self.collected_result;
106 }
107 };
108}
109
110test "std.event.Batch" {
111 var count: usize = 0;
112 var batch = Batch(void, 2, .auto_async).init();
113 batch.add(&async sleepALittle(&count));
114 batch.add(&async increaseByTen(&count));
115 batch.wait();
116 testing.expect(count == 11);
117
118 var another = Batch(anyerror!void, 2, .auto_async).init();
119 another.add(&async somethingElse());
120 another.add(&async doSomethingThatFails());
121 testing.expectError(error.ItBroke, another.wait());
122}
123
124fn sleepALittle(count: *usize) void {
125 std.time.sleep(1 * std.time.millisecond);
126 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
127}
128
129fn increaseByTen(count: *usize) void {
130 var i: usize = 0;
131 while (i < 10) : (i += 1) {
132 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
133 }
134}
135
136fn doSomethingThatFails() anyerror!void {}
137fn somethingElse() anyerror!void {
138 return error.ItBroke;
139}
lib/std/event/group.zig+5
...@@ -5,6 +5,11 @@ const testing = std.testing;...@@ -5,6 +5,11 @@ const testing = std.testing;
5const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
66
7/// ReturnType must be `void` or `E!void`7/// ReturnType must be `void` or `E!void`
8/// TODO This API was created back with the old design of async/await, when calling any
9/// async function required an allocator. There is an ongoing experiment to transition
10/// all uses of this API to the simpler and more resource-aware `std.event.Batch` API.
11/// If the transition goes well, all usages of `Group` will be gone, and this API
12/// will be deleted.
8pub fn Group(comptime ReturnType: type) type {13pub fn Group(comptime ReturnType: type) type {
9 return struct {14 return struct {
10 frame_stack: Stack,15 frame_stack: Stack,
lib/std/fs.zig+51-7
...@@ -96,7 +96,6 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus {...@@ -96,7 +96,6 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus {
96/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy.96/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy.
97/// Returns the previous status of the file before updating.97/// Returns the previous status of the file before updating.
98/// If any of the directories do not exist for dest_path, they are created.98/// If any of the directories do not exist for dest_path, they are created.
99/// TODO https://github.com/ziglang/zig/issues/2885
100pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus {99pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus {
101 const my_cwd = cwd();100 const my_cwd = cwd();
102101
...@@ -818,6 +817,13 @@ pub const Dir = struct {...@@ -818,6 +817,13 @@ pub const Dir = struct {
818 ) File.OpenError!File {817 ) File.OpenError!File {
819 const w = os.windows;818 const w = os.windows;
820819
820 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
821 return error.IsDir;
822 }
823 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
824 return error.IsDir;
825 }
826
821 var result = File{827 var result = File{
822 .handle = undefined,828 .handle = undefined,
823 .io_mode = .blocking,829 .io_mode = .blocking,
...@@ -839,12 +845,6 @@ pub const Dir = struct {...@@ -839,12 +845,6 @@ pub const Dir = struct {
839 .SecurityDescriptor = null,845 .SecurityDescriptor = null,
840 .SecurityQualityOfService = null,846 .SecurityQualityOfService = null,
841 };847 };
842 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
843 return error.IsDir;
844 }
845 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
846 return error.IsDir;
847 }
848 var io: w.IO_STATUS_BLOCK = undefined;848 var io: w.IO_STATUS_BLOCK = undefined;
849 const rc = w.ntdll.NtCreateFile(849 const rc = w.ntdll.NtCreateFile(
850 &result.handle,850 &result.handle,
...@@ -1323,6 +1323,50 @@ pub const Dir = struct {...@@ -1323,6 +1323,50 @@ pub const Dir = struct {
1323 defer file.close();1323 defer file.close();
1324 try file.write(data);1324 try file.write(data);
1325 }1325 }
1326
1327 pub const AccessError = os.AccessError;
1328
1329 /// Test accessing `path`.
1330 /// `path` is UTF8-encoded.
1331 /// Be careful of Time-Of-Check-Time-Of-Use race conditions when using this function.
1332 /// For example, instead of testing if a file exists and then opening it, just
1333 /// open it and handle the error for file not found.
1334 pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {
1335 if (builtin.os == .windows) {
1336 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
1337 return self.accessW(&sub_path_w, flags);
1338 }
1339 const path_c = try os.toPosixPath(sub_path);
1340 return self.accessZ(&path_c, flags);
1341 }
1342
1343 /// Same as `access` except the path parameter is null-terminated.
1344 pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {
1345 if (builtin.os == .windows) {
1346 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path);
1347 return self.accessW(&sub_path_w, flags);
1348 }
1349 const os_mode = if (flags.write and flags.read)
1350 @as(u32, os.R_OK | os.W_OK)
1351 else if (flags.write)
1352 @as(u32, os.W_OK)
1353 else
1354 @as(u32, os.F_OK);
1355 const result = if (need_async_thread)
1356 std.event.Loop.instance.?.faccessatZ(self.fd, sub_path, os_mode)
1357 else
1358 os.faccessatZ(self.fd, sub_path, os_mode, 0);
1359 return result;
1360 }
1361
1362 /// Same as `access` except asserts the target OS is Windows and the path parameter is
1363 /// * WTF-16 encoded
1364 /// * null-terminated
1365 /// * NtDll prefixed
1366 /// TODO currently this ignores `flags`.
1367 pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void {
1368 return os.faccessatW(self.fd, sub_path_w, 0, 0);
1369 }
1326};1370};
13271371
1328/// Returns an handle to the current working directory that is open for traversal.1372/// Returns an handle to the current working directory that is open for traversal.
lib/std/fs/file.zig-25
...@@ -60,31 +60,6 @@ pub const File = struct {...@@ -60,31 +60,6 @@ pub const File = struct {
60 mode: Mode = default_mode,60 mode: Mode = default_mode,
61 };61 };
6262
63 /// Test for the existence of `path`.
64 /// `path` is UTF8-encoded.
65 /// In general it is recommended to avoid this function. For example,
66 /// instead of testing if a file exists and then opening it, just
67 /// open it and handle the error for file not found.
68 /// TODO: deprecate this and move it to `std.fs.Dir`.
69 /// TODO: integrate with async I/O
70 pub fn access(path: []const u8) !void {
71 return os.access(path, os.F_OK);
72 }
73
74 /// Same as `access` except the parameter is null-terminated.
75 /// TODO: deprecate this and move it to `std.fs.Dir`.
76 /// TODO: integrate with async I/O
77 pub fn accessC(path: [*:0]const u8) !void {
78 return os.accessC(path, os.F_OK);
79 }
80
81 /// Same as `access` except the parameter is null-terminated UTF16LE-encoded.
82 /// TODO: deprecate this and move it to `std.fs.Dir`.
83 /// TODO: integrate with async I/O
84 pub fn accessW(path: [*:0]const u16) !void {
85 return os.accessW(path, os.F_OK);
86 }
87
88 /// Upon success, the stream is in an uninitialized state. To continue using it,63 /// Upon success, the stream is in an uninitialized state. To continue using it,
89 /// you must use the open() function.64 /// you must use the open() function.
90 pub fn close(self: File) void {65 pub fn close(self: File) void {
lib/std/mem.zig+9-1
...@@ -387,13 +387,21 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {...@@ -387,13 +387,21 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
387 return true;387 return true;
388}388}
389389
390/// Copies ::m to newly allocated memory. Caller is responsible to free it.390/// Copies `m` to newly allocated memory. Caller owns the memory.
391pub fn dupe(allocator: *Allocator, comptime T: type, m: []const T) ![]T {391pub fn dupe(allocator: *Allocator, comptime T: type, m: []const T) ![]T {
392 const new_buf = try allocator.alloc(T, m.len);392 const new_buf = try allocator.alloc(T, m.len);
393 copy(T, new_buf, m);393 copy(T, new_buf, m);
394 return new_buf;394 return new_buf;
395}395}
396396
397/// Copies `m` to newly allocated memory, with a null-terminated element. Caller owns the memory.
398pub fn dupeZ(allocator: *Allocator, comptime T: type, m: []const T) ![:0]T {
399 const new_buf = try allocator.alloc(T, m.len + 1);
400 copy(T, new_buf, m);
401 new_buf[m.len] = 0;
402 return new_buf[0..m.len :0];
403}
404
397/// Remove values from the beginning of a slice.405/// Remove values from the beginning of a slice.
398pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {406pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
399 var begin: usize = 0;407 var begin: usize = 0;
lib/std/os.zig+170-36
...@@ -916,10 +916,13 @@ pub const ExecveError = error{...@@ -916,10 +916,13 @@ pub const ExecveError = error{
916 NameTooLong,916 NameTooLong,
917} || UnexpectedError;917} || UnexpectedError;
918918
919/// Deprecated in favor of `execveZ`.
920pub const execveC = execveZ;
921
919/// Like `execve` except the parameters are null-terminated,922/// Like `execve` except the parameters are null-terminated,
920/// matching the syscall API on all targets. This removes the need for an allocator.923/// matching the syscall API on all targets. This removes the need for an allocator.
921/// This function ignores PATH environment variable. See `execvpeC` for that.924/// This function ignores PATH environment variable. See `execvpeZ` for that.
922pub fn execveC(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError {925pub fn execveZ(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError {
923 switch (errno(system.execve(path, child_argv, envp))) {926 switch (errno(system.execve(path, child_argv, envp))) {
924 0 => unreachable,927 0 => unreachable,
925 EFAULT => unreachable,928 EFAULT => unreachable,
...@@ -942,15 +945,29 @@ pub fn execveC(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, en...@@ -942,15 +945,29 @@ pub fn execveC(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, en
942 }945 }
943}946}
944947
945/// Like `execvpe` except the parameters are null-terminated,948/// Deprecated in favor of `execvpeZ`.
946/// matching the syscall API on all targets. This removes the need for an allocator.949pub const execvpeC = execvpeZ;
947/// This function also uses the PATH environment variable to get the full path to the executable.950
948/// If `file` is an absolute path, this is the same as `execveC`.951pub const Arg0Expand = enum {
949pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError {952 expand,
953 no_expand,
954};
955
956/// Like `execvpeZ` except if `arg0_expand` is `.expand`, then `argv` is mutable,
957/// and `argv[0]` is expanded to be the same absolute path that is passed to the execve syscall.
958pub fn execvpeZ_expandArg0(
959 comptime arg0_expand: Arg0Expand,
960 file: [*:0]const u8,
961 child_argv: switch (arg0_expand) {
962 .expand => [*:null]?[*:0]const u8,
963 .no_expand => [*:null]const ?[*:0]const u8,
964 },
965 envp: [*:null]const ?[*:0]const u8,
966) ExecveError {
950 const file_slice = mem.toSliceConst(u8, file);967 const file_slice = mem.toSliceConst(u8, file);
951 if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveC(file, child_argv, envp);968 if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveC(file, child_argv, envp);
952969
953 const PATH = getenv("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";970 const PATH = getenvZ("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
954 var path_buf: [MAX_PATH_BYTES]u8 = undefined;971 var path_buf: [MAX_PATH_BYTES]u8 = undefined;
955 var it = mem.tokenize(PATH, ":");972 var it = mem.tokenize(PATH, ":");
956 var seen_eacces = false;973 var seen_eacces = false;
...@@ -962,7 +979,12 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e...@@ -962,7 +979,12 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e
962 mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice);979 mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice);
963 const path_len = search_path.len + file_slice.len + 1;980 const path_len = search_path.len + file_slice.len + 1;
964 path_buf[path_len] = 0;981 path_buf[path_len] = 0;
965 err = execveC(path_buf[0..path_len :0].ptr, child_argv, envp);982 const full_path = path_buf[0..path_len :0].ptr;
983 switch (arg0_expand) {
984 .expand => child_argv[0] = full_path,
985 .no_expand => {},
986 }
987 err = execveC(full_path, child_argv, envp);
966 switch (err) {988 switch (err) {
967 error.AccessDenied => seen_eacces = true,989 error.AccessDenied => seen_eacces = true,
968 error.FileNotFound, error.NotDir => {},990 error.FileNotFound, error.NotDir => {},
...@@ -973,13 +995,24 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e...@@ -973,13 +995,24 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e
973 return err;995 return err;
974}996}
975997
976/// This function must allocate memory to add a null terminating bytes on path and each arg.998/// Like `execvpe` except the parameters are null-terminated,
977/// It must also convert to KEY=VALUE\0 format for environment variables, and include null999/// matching the syscall API on all targets. This removes the need for an allocator.
978/// pointers after the args and after the environment variables.
979/// `argv_slice[0]` is the executable path.
980/// This function also uses the PATH environment variable to get the full path to the executable.1000/// This function also uses the PATH environment variable to get the full path to the executable.
981pub fn execvpe(1001/// If `file` is an absolute path, this is the same as `execveC`.
1002pub fn execvpeZ(
1003 file: [*:0]const u8,
1004 argv: [*:null]const ?[*:0]const u8,
1005 envp: [*:null]const ?[*:0]const u8,
1006) ExecveError {
1007 return execvpeZ_expandArg0(.no_expand, file, argv, envp);
1008}
1009
1010/// This is the same as `execvpe` except if the `arg0_expand` parameter is set to `.expand`,
1011/// then argv[0] will be replaced with the expanded version of it, after resolving in accordance
1012/// with the PATH environment variable.
1013pub fn execvpe_expandArg0(
982 allocator: *mem.Allocator,1014 allocator: *mem.Allocator,
1015 arg0_expand: Arg0Expand,
983 argv_slice: []const []const u8,1016 argv_slice: []const []const u8,
984 env_map: *const std.BufMap,1017 env_map: *const std.BufMap,
985) (ExecveError || error{OutOfMemory}) {1018) (ExecveError || error{OutOfMemory}) {
...@@ -1004,7 +1037,23 @@ pub fn execvpe(...@@ -1004,7 +1037,23 @@ pub fn execvpe(
1004 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);1037 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
1005 defer freeNullDelimitedEnvMap(allocator, envp_buf);1038 defer freeNullDelimitedEnvMap(allocator, envp_buf);
10061039
1007 return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr);1040 switch (arg0_expand) {
1041 .expand => return execvpeZ_expandArg0(.expand, argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr),
1042 .no_expand => return execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr),
1043 }
1044}
1045
1046/// This function must allocate memory to add a null terminating bytes on path and each arg.
1047/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
1048/// pointers after the args and after the environment variables.
1049/// `argv_slice[0]` is the executable path.
1050/// This function also uses the PATH environment variable to get the full path to the executable.
1051pub fn execvpe(
1052 allocator: *mem.Allocator,
1053 argv_slice: []const []const u8,
1054 env_map: *const std.BufMap,
1055) (ExecveError || error{OutOfMemory}) {
1056 return execvpe_expandArg0(allocator, .no_expand, argv_slice, env_map);
1008}1057}
10091058
1010pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![:null]?[*:0]u8 {1059pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![:null]?[*:0]u8 {
...@@ -1038,7 +1087,7 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8)...@@ -1038,7 +1087,7 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8)
1038}1087}
10391088
1040/// Get an environment variable.1089/// Get an environment variable.
1041/// See also `getenvC`.1090/// See also `getenvZ`.
1042/// TODO make this go through libc when we have it1091/// TODO make this go through libc when we have it
1043pub fn getenv(key: []const u8) ?[]const u8 {1092pub fn getenv(key: []const u8) ?[]const u8 {
1044 for (environ) |ptr| {1093 for (environ) |ptr| {
...@@ -1056,9 +1105,12 @@ pub fn getenv(key: []const u8) ?[]const u8 {...@@ -1056,9 +1105,12 @@ pub fn getenv(key: []const u8) ?[]const u8 {
1056 return null;1105 return null;
1057}1106}
10581107
1108/// Deprecated in favor of `getenvZ`.
1109pub const getenvC = getenvZ;
1110
1059/// Get an environment variable with a null-terminated name.1111/// Get an environment variable with a null-terminated name.
1060/// See also `getenv`.1112/// See also `getenv`.
1061pub fn getenvC(key: [*:0]const u8) ?[]const u8 {1113pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {
1062 if (builtin.link_libc) {1114 if (builtin.link_libc) {
1063 const value = system.getenv(key) orelse return null;1115 const value = system.getenv(key) orelse return null;
1064 return mem.toSliceConst(u8, value);1116 return mem.toSliceConst(u8, value);
...@@ -2452,6 +2504,9 @@ pub const AccessError = error{...@@ -2452,6 +2504,9 @@ pub const AccessError = error{
2452 InputOutput,2504 InputOutput,
2453 SystemResources,2505 SystemResources,
2454 BadPathName,2506 BadPathName,
2507 FileBusy,
2508 SymLinkLoop,
2509 ReadOnlyFileSystem,
24552510
2456 /// On Windows, file paths must be valid Unicode.2511 /// On Windows, file paths must be valid Unicode.
2457 InvalidUtf8,2512 InvalidUtf8,
...@@ -2469,8 +2524,11 @@ pub fn access(path: []const u8, mode: u32) AccessError!void {...@@ -2469,8 +2524,11 @@ pub fn access(path: []const u8, mode: u32) AccessError!void {
2469 return accessC(&path_c, mode);2524 return accessC(&path_c, mode);
2470}2525}
24712526
2527/// Deprecated in favor of `accessZ`.
2528pub const accessC = accessZ;
2529
2472/// Same as `access` except `path` is null-terminated.2530/// Same as `access` except `path` is null-terminated.
2473pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void {2531pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void {
2474 if (builtin.os == .windows) {2532 if (builtin.os == .windows) {
2475 const path_w = try windows.cStrToPrefixedFileW(path);2533 const path_w = try windows.cStrToPrefixedFileW(path);
2476 _ = try windows.GetFileAttributesW(&path_w);2534 _ = try windows.GetFileAttributesW(&path_w);
...@@ -2479,12 +2537,11 @@ pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void {...@@ -2479,12 +2537,11 @@ pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void {
2479 switch (errno(system.access(path, mode))) {2537 switch (errno(system.access(path, mode))) {
2480 0 => return,2538 0 => return,
2481 EACCES => return error.PermissionDenied,2539 EACCES => return error.PermissionDenied,
2482 EROFS => return error.PermissionDenied,2540 EROFS => return error.ReadOnlyFileSystem,
2483 ELOOP => return error.PermissionDenied,2541 ELOOP => return error.SymLinkLoop,
2484 ETXTBSY => return error.PermissionDenied,2542 ETXTBSY => return error.FileBusy,
2485 ENOTDIR => return error.FileNotFound,2543 ENOTDIR => return error.FileNotFound,
2486 ENOENT => return error.FileNotFound,2544 ENOENT => return error.FileNotFound,
2487
2488 ENAMETOOLONG => return error.NameTooLong,2545 ENAMETOOLONG => return error.NameTooLong,
2489 EINVAL => unreachable,2546 EINVAL => unreachable,
2490 EFAULT => unreachable,2547 EFAULT => unreachable,
...@@ -2510,6 +2567,79 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v...@@ -2510,6 +2567,79 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v
2510 }2567 }
2511}2568}
25122569
2570/// Check user's permissions for a file, based on an open directory handle.
2571/// TODO currently this ignores `mode` and `flags` on Windows.
2572pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void {
2573 if (builtin.os == .windows) {
2574 const path_w = try windows.sliceToPrefixedFileW(path);
2575 return faccessatW(dirfd, &path_w, mode, flags);
2576 }
2577 const path_c = try toPosixPath(path);
2578 return faccessatZ(dirfd, &path_c, mode, flags);
2579}
2580
2581/// Same as `faccessat` except the path parameter is null-terminated.
2582pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void {
2583 if (builtin.os == .windows) {
2584 const path_w = try windows.cStrToPrefixedFileW(path);
2585 return faccessatW(dirfd, &path_w, mode, flags);
2586 }
2587 switch (errno(system.faccessat(dirfd, path, mode, flags))) {
2588 0 => return,
2589 EACCES => return error.PermissionDenied,
2590 EROFS => return error.ReadOnlyFileSystem,
2591 ELOOP => return error.SymLinkLoop,
2592 ETXTBSY => return error.FileBusy,
2593 ENOTDIR => return error.FileNotFound,
2594 ENOENT => return error.FileNotFound,
2595 ENAMETOOLONG => return error.NameTooLong,
2596 EINVAL => unreachable,
2597 EFAULT => unreachable,
2598 EIO => return error.InputOutput,
2599 ENOMEM => return error.SystemResources,
2600 else => |err| return unexpectedErrno(err),
2601 }
2602}
2603
2604/// Same as `faccessat` except asserts the target is Windows and the path parameter
2605/// is NtDll-prefixed, null-terminated, WTF-16 encoded.
2606/// TODO currently this ignores `mode` and `flags`
2607pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32) AccessError!void {
2608 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
2609 return;
2610 }
2611 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
2612 return;
2613 }
2614
2615 const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {
2616 error.Overflow => return error.NameTooLong,
2617 };
2618 var nt_name = windows.UNICODE_STRING{
2619 .Length = path_len_bytes,
2620 .MaximumLength = path_len_bytes,
2621 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
2622 };
2623 var attr = windows.OBJECT_ATTRIBUTES{
2624 .Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
2625 .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dirfd,
2626 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
2627 .ObjectName = &nt_name,
2628 .SecurityDescriptor = null,
2629 .SecurityQualityOfService = null,
2630 };
2631 var basic_info: windows.FILE_BASIC_INFORMATION = undefined;
2632 switch (windows.ntdll.NtQueryAttributesFile(&attr, &basic_info)) {
2633 .SUCCESS => return,
2634 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
2635 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
2636 .INVALID_PARAMETER => unreachable,
2637 .ACCESS_DENIED => return error.PermissionDenied,
2638 .OBJECT_PATH_SYNTAX_BAD => unreachable,
2639 else => |rc| return windows.unexpectedStatus(rc),
2640 }
2641}
2642
2513pub const PipeError = error{2643pub const PipeError = error{
2514 SystemFdQuotaExceeded,2644 SystemFdQuotaExceeded,
2515 ProcessFdQuotaExceeded,2645 ProcessFdQuotaExceeded,
...@@ -2844,18 +2974,26 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {...@@ -2844,18 +2974,26 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
2844}2974}
28452975
2846pub fn dl_iterate_phdr(2976pub fn dl_iterate_phdr(
2847 comptime T: type,2977 context: var,
2848 callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32,2978 comptime Error: type,
2849 data: ?*T,2979 comptime callback: fn (info: *dl_phdr_info, size: usize, context: @TypeOf(context)) Error!void,
2850) isize {2980) Error!void {
2981 const Context = @TypeOf(context);
2982
2851 if (builtin.object_format != .elf)2983 if (builtin.object_format != .elf)
2852 @compileError("dl_iterate_phdr is not available for this target");2984 @compileError("dl_iterate_phdr is not available for this target");
28532985
2854 if (builtin.link_libc) {2986 if (builtin.link_libc) {
2855 return system.dl_iterate_phdr(2987 switch (system.dl_iterate_phdr(struct {
2856 @ptrCast(std.c.dl_iterate_phdr_callback, callback),2988 fn callbackC(info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int {
2857 @ptrCast(?*c_void, data),2989 const context_ptr = @ptrCast(*const Context, @alignCast(@alignOf(*const Context), data));
2858 );2990 callback(info, size, context_ptr.*) catch |err| return @errorToInt(err);
2991 return 0;
2992 }
2993 }.callbackC, @intToPtr(?*c_void, @ptrToInt(&context)))) {
2994 0 => return,
2995 else => |err| return @errSetCast(Error, @intToError(@intCast(u16, err))), // TODO don't hardcode u16
2996 }
2859 }2997 }
28602998
2861 const elf_base = std.process.getBaseAddress();2999 const elf_base = std.process.getBaseAddress();
...@@ -2877,11 +3015,10 @@ pub fn dl_iterate_phdr(...@@ -2877,11 +3015,10 @@ pub fn dl_iterate_phdr(
2877 .dlpi_phnum = ehdr.e_phnum,3015 .dlpi_phnum = ehdr.e_phnum,
2878 };3016 };
28793017
2880 return callback(&info, @sizeOf(dl_phdr_info), data);3018 return callback(&info, @sizeOf(dl_phdr_info), context);
2881 }3019 }
28823020
2883 // Last return value from the callback function3021 // Last return value from the callback function
2884 var last_r: isize = 0;
2885 while (it.next()) |entry| {3022 while (it.next()) |entry| {
2886 var dlpi_phdr: [*]elf.Phdr = undefined;3023 var dlpi_phdr: [*]elf.Phdr = undefined;
2887 var dlpi_phnum: u16 = undefined;3024 var dlpi_phnum: u16 = undefined;
...@@ -2903,11 +3040,8 @@ pub fn dl_iterate_phdr(...@@ -2903,11 +3040,8 @@ pub fn dl_iterate_phdr(
2903 .dlpi_phnum = dlpi_phnum,3040 .dlpi_phnum = dlpi_phnum,
2904 };3041 };
29053042
2906 last_r = callback(&info, @sizeOf(dl_phdr_info), data);3043 try callback(&info, @sizeOf(dl_phdr_info), context);
2907 if (last_r != 0) break;
2908 }3044 }
2909
2910 return last_r;
2911}3045}
29123046
2913pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;3047pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
lib/std/os/test.zig+13-12
...@@ -29,7 +29,7 @@ test "makePath, put some files in it, deleteTree" {...@@ -29,7 +29,7 @@ test "makePath, put some files in it, deleteTree" {
2929
30test "access file" {30test "access file" {
31 try fs.makePath(a, "os_test_tmp");31 try fs.makePath(a, "os_test_tmp");
32 if (File.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt")) |ok| {32 if (fs.cwd().access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", .{})) |ok| {
33 @panic("expected error");33 @panic("expected error");
34 } else |err| {34 } else |err| {
35 expect(err == error.FileNotFound);35 expect(err == error.FileNotFound);
...@@ -165,16 +165,19 @@ test "sigaltstack" {...@@ -165,16 +165,19 @@ test "sigaltstack" {
165// analyzed165// analyzed
166const dl_phdr_info = if (@hasDecl(os, "dl_phdr_info")) os.dl_phdr_info else c_void;166const dl_phdr_info = if (@hasDecl(os, "dl_phdr_info")) os.dl_phdr_info else c_void;
167167
168fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) callconv(.C) i32 {168const IterFnError = error{
169 if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx)169 MissingPtLoadSegment,
170 return 0;170 MissingLoad,
171 BadElfMagic,
172 FailedConsistencyCheck,
173};
171174
172 var counter = data.?;175fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
173 // Count how many libraries are loaded176 // Count how many libraries are loaded
174 counter.* += @as(usize, 1);177 counter.* += @as(usize, 1);
175178
176 // The image should contain at least a PT_LOAD segment179 // The image should contain at least a PT_LOAD segment
177 if (info.dlpi_phnum < 1) return -1;180 if (info.dlpi_phnum < 1) return error.MissingPtLoadSegment;
178181
179 // Quick & dirty validation of the phdr pointers, make sure we're not182 // Quick & dirty validation of the phdr pointers, make sure we're not
180 // pointing to some random gibberish183 // pointing to some random gibberish
...@@ -189,17 +192,15 @@ fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) callconv(.C) i32 {...@@ -189,17 +192,15 @@ fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) callconv(.C) i32 {
189 // Find the ELF header192 // Find the ELF header
190 const elf_header = @intToPtr(*elf.Ehdr, reloc_addr - phdr.p_offset);193 const elf_header = @intToPtr(*elf.Ehdr, reloc_addr - phdr.p_offset);
191 // Validate the magic194 // Validate the magic
192 if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return -1;195 if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return error.BadElfMagic;
193 // Consistency check196 // Consistency check
194 if (elf_header.e_phnum != info.dlpi_phnum) return -1;197 if (elf_header.e_phnum != info.dlpi_phnum) return error.FailedConsistencyCheck;
195198
196 found_load = true;199 found_load = true;
197 break;200 break;
198 }201 }
199202
200 if (!found_load) return -1;203 if (!found_load) return error.MissingLoad;
201
202 return 42;
203}204}
204205
205test "dl_iterate_phdr" {206test "dl_iterate_phdr" {
...@@ -207,7 +208,7 @@ test "dl_iterate_phdr" {...@@ -207,7 +208,7 @@ test "dl_iterate_phdr" {
207 return error.SkipZigTest;208 return error.SkipZigTest;
208209
209 var counter: usize = 0;210 var counter: usize = 0;
210 expect(os.dl_iterate_phdr(usize, iter_fn, &counter) != 0);211 try os.dl_iterate_phdr(&counter, IterFnError, iter_fn);
211 expect(counter != 0);212 expect(counter != 0);
212}213}
213214
lib/std/os/windows/ntdll.zig+6
...@@ -8,6 +8,12 @@ pub extern "NtDll" fn NtQueryInformationFile(...@@ -8,6 +8,12 @@ pub extern "NtDll" fn NtQueryInformationFile(
8 Length: ULONG,8 Length: ULONG,
9 FileInformationClass: FILE_INFORMATION_CLASS,9 FileInformationClass: FILE_INFORMATION_CLASS,
10) callconv(.Stdcall) NTSTATUS;10) callconv(.Stdcall) NTSTATUS;
11
12pub extern "NtDll" fn NtQueryAttributesFile(
13 ObjectAttributes: *OBJECT_ATTRIBUTES,
14 FileAttributes: *FILE_BASIC_INFORMATION,
15) callconv(.Stdcall) NTSTATUS;
16
11pub extern "NtDll" fn NtCreateFile(17pub extern "NtDll" fn NtCreateFile(
12 FileHandle: *HANDLE,18 FileHandle: *HANDLE,
13 DesiredAccess: ACCESS_MASK,19 DesiredAccess: ACCESS_MASK,
lib/std/process.zig+56
...@@ -613,3 +613,59 @@ pub fn getBaseAddress() usize {...@@ -613,3 +613,59 @@ pub fn getBaseAddress() usize {
613 else => @compileError("Unsupported OS"),613 else => @compileError("Unsupported OS"),
614 }614 }
615}615}
616
617/// Caller owns the result value and each inner slice.
618pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 {
619 switch (builtin.link_mode) {
620 .Static => return &[_][:0]u8{},
621 .Dynamic => {},
622 }
623 const List = std.ArrayList([:0]u8);
624 switch (builtin.os) {
625 .linux,
626 .freebsd,
627 .netbsd,
628 .dragonfly,
629 => {
630 var paths = List.init(allocator);
631 errdefer {
632 const slice = paths.toOwnedSlice();
633 for (slice) |item| {
634 allocator.free(item);
635 }
636 allocator.free(slice);
637 }
638 try os.dl_iterate_phdr(&paths, error{OutOfMemory}, struct {
639 fn callback(info: *os.dl_phdr_info, size: usize, list: *List) !void {
640 const name = info.dlpi_name orelse return;
641 if (name[0] == '/') {
642 const item = try mem.dupeZ(list.allocator, u8, mem.toSliceConst(u8, name));
643 errdefer list.allocator.free(item);
644 try list.append(item);
645 }
646 }
647 }.callback);
648 return paths.toOwnedSlice();
649 },
650 .macosx, .ios, .watchos, .tvos => {
651 var paths = List.init(allocator);
652 errdefer {
653 const slice = paths.toOwnedSlice();
654 for (slice) |item| {
655 allocator.free(item);
656 }
657 allocator.free(slice);
658 }
659 const img_count = std.c._dyld_image_count();
660 var i: u32 = 0;
661 while (i < img_count) : (i += 1) {
662 const name = std.c._dyld_get_image_name(i);
663 const item = try mem.dupeZ(allocator, u8, mem.toSliceConst(u8, name));
664 errdefer allocator.free(item);
665 try paths.append(item);
666 }
667 return paths.toOwnedSlice();
668 },
669 else => @compileError("getSelfExeSharedLibPaths unimplemented for this target"),
670 }
671}
lib/std/target.zig+181
...@@ -1037,6 +1037,20 @@ pub const Target = union(enum) {...@@ -1037,6 +1037,20 @@ pub const Target = union(enum) {
1037 };1037 };
1038 }1038 }
10391039
1040 pub fn isAndroid(self: Target) bool {
1041 return switch (self.getAbi()) {
1042 .android => true,
1043 else => false,
1044 };
1045 }
1046
1047 pub fn isDragonFlyBSD(self: Target) bool {
1048 return switch (self.getOs()) {
1049 .dragonfly => true,
1050 else => false,
1051 };
1052 }
1053
1040 pub fn isUefi(self: Target) bool {1054 pub fn isUefi(self: Target) bool {
1041 return switch (self.getOs()) {1055 return switch (self.getOs()) {
1042 .uefi => true,1056 .uefi => true,
...@@ -1189,6 +1203,173 @@ pub const Target = union(enum) {...@@ -1189,6 +1203,173 @@ pub const Target = union(enum) {
11891203
1190 return .unavailable;1204 return .unavailable;
1191 }1205 }
1206
1207 pub const FloatAbi = enum {
1208 hard,
1209 soft,
1210 soft_fp,
1211 };
1212
1213 pub fn getFloatAbi(self: Target) FloatAbi {
1214 return switch (self.getAbi()) {
1215 .gnueabihf,
1216 .eabihf,
1217 .musleabihf,
1218 => .hard,
1219 else => .soft,
1220 };
1221 }
1222
1223 pub fn hasDynamicLinker(self: Target) bool {
1224 switch (self.getArch()) {
1225 .wasm32,
1226 .wasm64,
1227 => return false,
1228 else => {},
1229 }
1230 switch (self.getOs()) {
1231 .freestanding,
1232 .ios,
1233 .tvos,
1234 .watchos,
1235 .macosx,
1236 .uefi,
1237 .windows,
1238 .emscripten,
1239 .other,
1240 => return false,
1241 else => return true,
1242 }
1243 }
1244
1245 /// Caller owns returned memory.
1246 pub fn getStandardDynamicLinkerPath(
1247 self: Target,
1248 allocator: *mem.Allocator,
1249 ) error{
1250 OutOfMemory,
1251 UnknownDynamicLinkerPath,
1252 TargetHasNoDynamicLinker,
1253 }![:0]u8 {
1254 const a = allocator;
1255 if (self.isAndroid()) {
1256 return mem.dupeZ(a, u8, if (self.getArchPtrBitWidth() == 64)
1257 "/system/bin/linker64"
1258 else
1259 "/system/bin/linker");
1260 }
1261
1262 if (self.isMusl()) {
1263 var result = try std.Buffer.init(allocator, "/lib/ld-musl-");
1264 defer result.deinit();
1265
1266 var is_arm = false;
1267 switch (self.getArch()) {
1268 .arm, .thumb => {
1269 try result.append("arm");
1270 is_arm = true;
1271 },
1272 .armeb, .thumbeb => {
1273 try result.append("armeb");
1274 is_arm = true;
1275 },
1276 else => |arch| try result.append(@tagName(arch)),
1277 }
1278 if (is_arm and self.getFloatAbi() == .hard) {
1279 try result.append("hf");
1280 }
1281 try result.append(".so.1");
1282 return result.toOwnedSlice();
1283 }
1284
1285 switch (self.getOs()) {
1286 .freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"),
1287 .netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"),
1288 .dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"),
1289 .linux => switch (self.getArch()) {
1290 .i386,
1291 .sparc,
1292 .sparcel,
1293 => return mem.dupeZ(a, u8, "/lib/ld-linux.so.2"),
1294
1295 .aarch64 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64.so.1"),
1296 .aarch64_be => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_be.so.1"),
1297 .aarch64_32 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_32.so.1"),
1298
1299 .arm,
1300 .armeb,
1301 .thumb,
1302 .thumbeb,
1303 => return mem.dupeZ(a, u8, switch (self.getFloatAbi()) {
1304 .hard => "/lib/ld-linux-armhf.so.3",
1305 else => "/lib/ld-linux.so.3",
1306 }),
1307
1308 .mips,
1309 .mipsel,
1310 .mips64,
1311 .mips64el,
1312 => return error.UnknownDynamicLinkerPath,
1313
1314 .powerpc => return mem.dupeZ(a, u8, "/lib/ld.so.1"),
1315 .powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"),
1316 .s390x => return mem.dupeZ(a, u8, "/lib64/ld64.so.1"),
1317 .sparcv9 => return mem.dupeZ(a, u8, "/lib64/ld-linux.so.2"),
1318 .x86_64 => return mem.dupeZ(a, u8, switch (self.getAbi()) {
1319 .gnux32 => "/libx32/ld-linux-x32.so.2",
1320 else => "/lib64/ld-linux-x86-64.so.2",
1321 }),
1322
1323 .riscv32 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv32-ilp32.so.1"),
1324 .riscv64 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv64-lp64.so.1"),
1325
1326 .wasm32,
1327 .wasm64,
1328 => return error.TargetHasNoDynamicLinker,
1329
1330 .arc,
1331 .avr,
1332 .bpfel,
1333 .bpfeb,
1334 .hexagon,
1335 .msp430,
1336 .r600,
1337 .amdgcn,
1338 .tce,
1339 .tcele,
1340 .xcore,
1341 .nvptx,
1342 .nvptx64,
1343 .le32,
1344 .le64,
1345 .amdil,
1346 .amdil64,
1347 .hsail,
1348 .hsail64,
1349 .spir,
1350 .spir64,
1351 .kalimba,
1352 .shave,
1353 .lanai,
1354 .renderscript32,
1355 .renderscript64,
1356 => return error.UnknownDynamicLinkerPath,
1357 },
1358
1359 .freestanding,
1360 .ios,
1361 .tvos,
1362 .watchos,
1363 .macosx,
1364 .uefi,
1365 .windows,
1366 .emscripten,
1367 .other,
1368 => return error.TargetHasNoDynamicLinker,
1369
1370 else => return error.UnknownDynamicLinkerPath,
1371 }
1372 }
1192};1373};
11931374
1194test "parseCpuFeatureSet" {1375test "parseCpuFeatureSet" {
lib/std/time.zig+1
...@@ -8,6 +8,7 @@ const math = std.math;...@@ -8,6 +8,7 @@ const math = std.math;
8pub const epoch = @import("time/epoch.zig");8pub const epoch = @import("time/epoch.zig");
99
10/// Spurious wakeups are possible and no precision of timing is guaranteed.10/// Spurious wakeups are possible and no precision of timing is guaranteed.
11/// TODO integrate with evented I/O
11pub fn sleep(nanoseconds: u64) void {12pub fn sleep(nanoseconds: u64) void {
12 if (builtin.os == .windows) {13 if (builtin.os == .windows) {
13 const ns_per_ms = ns_per_s / ms_per_s;14 const ns_per_ms = ns_per_s / ms_per_s;
src-self-hosted/c.zig-1
...@@ -4,5 +4,4 @@ pub usingnamespace @cImport({...@@ -4,5 +4,4 @@ pub usingnamespace @cImport({
4 @cInclude("inttypes.h");4 @cInclude("inttypes.h");
5 @cInclude("config.h");5 @cInclude("config.h");
6 @cInclude("zig_llvm.h");6 @cInclude("zig_llvm.h");
7 @cInclude("windows_sdk.h");
8});7});
src-self-hosted/introspect.zig+8
...@@ -6,6 +6,14 @@ const fs = std.fs;...@@ -6,6 +6,14 @@ const fs = std.fs;
66
7const warn = std.debug.warn;7const warn = std.debug.warn;
88
9pub fn detectDynamicLinker(allocator: *mem.Allocator, target: std.Target) ![:0]u8 {
10 if (target == .Native) {
11 return @import("libc_installation.zig").detectNativeDynamicLinker(allocator);
12 } else {
13 return target.getStandardDynamicLinkerPath(allocator);
14 }
15}
16
9/// Caller must free result17/// Caller must free result
10pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {18pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
11 const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });19 const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });
src-self-hosted/libc_installation.zig+460-267
...@@ -1,20 +1,29 @@...@@ -1,20 +1,29 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const event = std.event;
4const util = @import("util.zig");3const util = @import("util.zig");
5const Target = std.Target;4const Target = std.Target;
6const c = @import("c.zig");
7const fs = std.fs;5const fs = std.fs;
8const Allocator = std.mem.Allocator;6const Allocator = std.mem.Allocator;
7const Batch = std.event.Batch;
8
9const is_darwin = Target.current.isDarwin();
10const is_windows = Target.current.isWindows();
11const is_freebsd = Target.current.isFreeBSD();
12const is_netbsd = Target.current.isNetBSD();
13const is_linux = Target.current.isLinux();
14const is_dragonfly = Target.current.isDragonFlyBSD();
15const is_gnu = Target.current.isGnu();
16
17usingnamespace @import("windows_sdk.zig");
918
10/// See the render function implementation for documentation of the fields.19/// See the render function implementation for documentation of the fields.
11pub const LibCInstallation = struct {20pub const LibCInstallation = struct {
12 include_dir: []const u8,21 include_dir: ?[:0]const u8 = null,
13 lib_dir: ?[]const u8,22 sys_include_dir: ?[:0]const u8 = null,
14 static_lib_dir: ?[]const u8,23 crt_dir: ?[:0]const u8 = null,
15 msvc_lib_dir: ?[]const u8,24 static_crt_dir: ?[:0]const u8 = null,
16 kernel32_lib_dir: ?[]const u8,25 msvc_lib_dir: ?[:0]const u8 = null,
17 dynamic_linker_path: ?[]const u8,26 kernel32_lib_dir: ?[:0]const u8 = null,
1827
19 pub const FindError = error{28 pub const FindError = error{
20 OutOfMemory,29 OutOfMemory,
...@@ -27,31 +36,24 @@ pub const LibCInstallation = struct {...@@ -27,31 +36,24 @@ pub const LibCInstallation = struct {
27 LibCStdLibHeaderNotFound,36 LibCStdLibHeaderNotFound,
28 LibCKernel32LibNotFound,37 LibCKernel32LibNotFound,
29 UnsupportedArchitecture,38 UnsupportedArchitecture,
39 WindowsSdkNotFound,
30 };40 };
3141
32 pub fn parse(42 pub fn parse(
33 self: *LibCInstallation,
34 allocator: *Allocator,43 allocator: *Allocator,
35 libc_file: []const u8,44 libc_file: []const u8,
36 stderr: *std.io.OutStream(fs.File.WriteError),45 stderr: *std.io.OutStream(fs.File.WriteError),
37 ) !void {46 ) !LibCInstallation {
38 self.initEmpty();47 var self: LibCInstallation = .{};
3948
40 const keys = [_][]const u8{49 const fields = std.meta.fields(LibCInstallation);
41 "include_dir",
42 "lib_dir",
43 "static_lib_dir",
44 "msvc_lib_dir",
45 "kernel32_lib_dir",
46 "dynamic_linker_path",
47 };
48 const FoundKey = struct {50 const FoundKey = struct {
49 found: bool,51 found: bool,
50 allocated: ?[]u8,52 allocated: ?[:0]u8,
51 };53 };
52 var found_keys = [1]FoundKey{FoundKey{ .found = false, .allocated = null }} ** keys.len;54 var found_keys = [1]FoundKey{FoundKey{ .found = false, .allocated = null }} ** fields.len;
53 errdefer {55 errdefer {
54 self.initEmpty();56 self = .{};
55 for (found_keys) |found_key| {57 for (found_keys) |found_key| {
56 if (found_key.allocated) |s| allocator.free(s);58 if (found_key.allocated) |s| allocator.free(s);
57 }59 }
...@@ -69,152 +71,199 @@ pub const LibCInstallation = struct {...@@ -69,152 +71,199 @@ pub const LibCInstallation = struct {
69 return error.ParseError;71 return error.ParseError;
70 };72 };
71 const value = line_it.rest();73 const value = line_it.rest();
72 inline for (keys) |key, i| {74 inline for (fields) |field, i| {
73 if (std.mem.eql(u8, name, key)) {75 if (std.mem.eql(u8, name, field.name)) {
74 found_keys[i].found = true;76 found_keys[i].found = true;
75 switch (@typeInfo(@TypeOf(@field(self, key)))) {77 if (value.len == 0) {
76 .Optional => {78 @field(self, field.name) = null;
77 if (value.len == 0) {79 } else {
78 @field(self, key) = null;80 found_keys[i].allocated = try std.mem.dupeZ(allocator, u8, value);
79 } else {81 @field(self, field.name) = found_keys[i].allocated;
80 found_keys[i].allocated = try std.mem.dupe(allocator, u8, value);
81 @field(self, key) = found_keys[i].allocated;
82 }
83 },
84 else => {
85 if (value.len == 0) {
86 try stderr.print("field cannot be empty: {}\n", .{key});
87 return error.ParseError;
88 }
89 const dupe = try std.mem.dupe(allocator, u8, value);
90 found_keys[i].allocated = dupe;
91 @field(self, key) = dupe;
92 },
93 }82 }
94 break;83 break;
95 }84 }
96 }85 }
97 }86 }
98 for (found_keys) |found_key, i| {87 inline for (fields) |field, i| {
99 if (!found_key.found) {88 if (!found_keys[i].found) {
100 try stderr.print("missing field: {}\n", .{keys[i]});89 try stderr.print("missing field: {}\n", .{field.name});
101 return error.ParseError;90 return error.ParseError;
102 }91 }
103 }92 }
93 if (self.include_dir == null) {
94 try stderr.print("include_dir may not be empty\n", .{});
95 return error.ParseError;
96 }
97 if (self.sys_include_dir == null) {
98 try stderr.print("sys_include_dir may not be empty\n", .{});
99 return error.ParseError;
100 }
101 if (self.crt_dir == null and !is_darwin) {
102 try stderr.print("crt_dir may not be empty for {}\n", .{@tagName(Target.current.getOs())});
103 return error.ParseError;
104 }
105 if (self.static_crt_dir == null and is_windows and is_gnu) {
106 try stderr.print("static_crt_dir may not be empty for {}-{}\n", .{
107 @tagName(Target.current.getOs()),
108 @tagName(Target.current.getAbi()),
109 });
110 return error.ParseError;
111 }
112 if (self.msvc_lib_dir == null and is_windows and !is_gnu) {
113 try stderr.print("msvc_lib_dir may not be empty for {}-{}\n", .{
114 @tagName(Target.current.getOs()),
115 @tagName(Target.current.getAbi()),
116 });
117 return error.ParseError;
118 }
119 if (self.kernel32_lib_dir == null and is_windows and !is_gnu) {
120 try stderr.print("kernel32_lib_dir may not be empty for {}-{}\n", .{
121 @tagName(Target.current.getOs()),
122 @tagName(Target.current.getAbi()),
123 });
124 return error.ParseError;
125 }
126
127 return self;
104 }128 }
105129
106 pub fn render(self: *const LibCInstallation, out: *std.io.OutStream(fs.File.WriteError)) !void {130 pub fn render(self: LibCInstallation, out: *std.io.OutStream(fs.File.WriteError)) !void {
107 @setEvalBranchQuota(4000);131 @setEvalBranchQuota(4000);
108 const lib_dir = self.lib_dir orelse "";132 const include_dir = self.include_dir orelse "";
109 const static_lib_dir = self.static_lib_dir orelse "";133 const sys_include_dir = self.sys_include_dir orelse "";
134 const crt_dir = self.crt_dir orelse "";
135 const static_crt_dir = self.static_crt_dir orelse "";
110 const msvc_lib_dir = self.msvc_lib_dir orelse "";136 const msvc_lib_dir = self.msvc_lib_dir orelse "";
111 const kernel32_lib_dir = self.kernel32_lib_dir orelse "";137 const kernel32_lib_dir = self.kernel32_lib_dir orelse "";
112 const dynamic_linker_path = self.dynamic_linker_path orelse util.getDynamicLinkerPath(Target{ .Native = {} });138
113 try out.print(139 try out.print(
114 \\# The directory that contains `stdlib.h`.140 \\# The directory that contains `stdlib.h`.
115 \\# On Linux, can be found with: `cc -E -Wp,-v -xc /dev/null`141 \\# On POSIX-like systems, include directories be found with: `cc -E -Wp,-v -xc /dev/null`
116 \\include_dir={}142 \\include_dir={}
117 \\143 \\
118 \\# The directory that contains `crt1.o`.144 \\# The system-specific include directory. May be the same as `include_dir`.
119 \\# On Linux, can be found with `cc -print-file-name=crt1.o`.145 \\# On Windows it's the directory that includes `vcruntime.h`.
146 \\# On POSIX it's the directory that includes `sys/errno.h`.
147 \\sys_include_dir={}
148 \\
149 \\# The directory that contains `crt1.o` or `crt2.o`.
150 \\# On POSIX, can be found with `cc -print-file-name=crt1.o`.
120 \\# Not needed when targeting MacOS.151 \\# Not needed when targeting MacOS.
121 \\lib_dir={}152 \\crt_dir={}
122 \\153 \\
123 \\# The directory that contains `crtbegin.o`.154 \\# The directory that contains `crtbegin.o`.
124 \\# On Linux, can be found with `cc -print-file-name=crtbegin.o`.155 \\# On POSIX, can be found with `cc -print-file-name=crtbegin.o`.
125 \\# Not needed when targeting MacOS or Windows.156 \\# Only needed when targeting MinGW-w64 on Windows.
126 \\static_lib_dir={}157 \\static_crt_dir={}
127 \\158 \\
128 \\# The directory that contains `vcruntime.lib`.159 \\# The directory that contains `vcruntime.lib`.
129 \\# Only needed when targeting Windows.160 \\# Only needed when targeting MSVC on Windows.
130 \\msvc_lib_dir={}161 \\msvc_lib_dir={}
131 \\162 \\
132 \\# The directory that contains `kernel32.lib`.163 \\# The directory that contains `kernel32.lib`.
133 \\# Only needed when targeting Windows.164 \\# Only needed when targeting MSVC on Windows.
134 \\kernel32_lib_dir={}165 \\kernel32_lib_dir={}
135 \\166 \\
136 \\# The full path to the dynamic linker, on the target system.167 , .{
137 \\# Only needed when targeting Linux.168 include_dir,
138 \\dynamic_linker_path={}169 sys_include_dir,
139 \\170 crt_dir,
140 , .{ self.include_dir, lib_dir, static_lib_dir, msvc_lib_dir, kernel32_lib_dir, dynamic_linker_path });171 static_crt_dir,
172 msvc_lib_dir,
173 kernel32_lib_dir,
174 });
141 }175 }
142176
143 /// Finds the default, native libc.177 /// Finds the default, native libc.
144 pub fn findNative(self: *LibCInstallation, allocator: *Allocator) !void {178 pub fn findNative(allocator: *Allocator) FindError!LibCInstallation {
145 self.initEmpty();179 var self: LibCInstallation = .{};
146 var group = event.Group(FindError!void).init(allocator);180
147 errdefer group.wait() catch {};181 if (is_windows) {
148 var windows_sdk: ?*c.ZigWindowsSDK = null;182 if (is_gnu) {
149 errdefer if (windows_sdk) |sdk| c.zig_free_windows_sdk(@ptrCast(?[*]c.ZigWindowsSDK, sdk));183 var batch = Batch(FindError!void, 3, .auto_async).init();
150184 batch.add(&async self.findNativeIncludeDirPosix(allocator));
151 switch (builtin.os) {185 batch.add(&async self.findNativeCrtDirPosix(allocator));
152 .windows => {186 batch.add(&async self.findNativeStaticCrtDirPosix(allocator));
153 var sdk: *c.ZigWindowsSDK = undefined;187 try batch.wait();
154 switch (c.zig_find_windows_sdk(@ptrCast(?[*]?[*]c.ZigWindowsSDK, &sdk))) {188 } else {
155 c.ZigFindWindowsSdkError.None => {189 var sdk: *ZigWindowsSDK = undefined;
156 windows_sdk = sdk;190 switch (zig_find_windows_sdk(&sdk)) {
157191 .None => {
158 if (sdk.msvc_lib_dir_ptr != 0) {192 defer zig_free_windows_sdk(sdk);
159 self.msvc_lib_dir = try std.mem.dupe(allocator, u8, sdk.msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]);193
160 }194 var batch = Batch(FindError!void, 5, .auto_async).init();
161 try group.call(findNativeKernel32LibDir, .{ allocator, self, sdk });195 batch.add(&async self.findNativeMsvcIncludeDir(allocator, sdk));
162 try group.call(findNativeIncludeDirWindows, .{ self, allocator, sdk });196 batch.add(&async self.findNativeMsvcLibDir(allocator, sdk));
163 try group.call(findNativeLibDirWindows, .{ self, allocator, sdk });197 batch.add(&async self.findNativeKernel32LibDir(allocator, sdk));
198 batch.add(&async self.findNativeIncludeDirWindows(allocator, sdk));
199 batch.add(&async self.findNativeCrtDirWindows(allocator, sdk));
200 try batch.wait();
164 },201 },
165 c.ZigFindWindowsSdkError.OutOfMemory => return error.OutOfMemory,202 .OutOfMemory => return error.OutOfMemory,
166 c.ZigFindWindowsSdkError.NotFound => return error.NotFound,203 .NotFound => return error.WindowsSdkNotFound,
167 c.ZigFindWindowsSdkError.PathTooLong => return error.NotFound,204 .PathTooLong => return error.WindowsSdkNotFound,
168 }205 }
169 },206 }
170 .linux => {207 } else {
171 try group.call(findNativeIncludeDirLinux, .{ self, allocator });208 try blk: {
172 try group.call(findNativeLibDirLinux, .{ self, allocator });209 var batch = Batch(FindError!void, 2, .auto_async).init();
173 try group.call(findNativeStaticLibDir, .{ self, allocator });210 errdefer batch.wait() catch {};
174 try group.call(findNativeDynamicLinker, .{ self, allocator });211 batch.add(&async self.findNativeIncludeDirPosix(allocator));
175 },212 if (is_freebsd or is_netbsd) {
176 .macosx, .freebsd, .netbsd => {213 self.crt_dir = try std.mem.dupeZ(allocator, u8, "/usr/lib");
177 self.include_dir = try std.mem.dupe(allocator, u8, "/usr/include");214 } else if (is_linux or is_dragonfly) {
178 },215 batch.add(&async self.findNativeCrtDirPosix(allocator));
179 else => @compileError("unimplemented: find libc for this OS"),216 }
217 break :blk batch.wait();
218 };
180 }219 }
181 return group.wait();220 return self;
182 }221 }
183222
184 async fn findNativeIncludeDirLinux(self: *LibCInstallation, allocator: *Allocator) FindError!void {223 /// Must be the same allocator passed to `parse` or `findNative`.
185 const cc_exe = std.os.getenv("CC") orelse "cc";224 pub fn deinit(self: *LibCInstallation, allocator: *Allocator) void {
225 const fields = std.meta.fields(LibCInstallation);
226 inline for (fields) |field| {
227 if (@field(self, field.name)) |payload| {
228 allocator.free(payload);
229 }
230 }
231 self.* = undefined;
232 }
233
234 fn findNativeIncludeDirPosix(self: *LibCInstallation, allocator: *Allocator) FindError!void {
235 const dev_null = if (is_windows) "nul" else "/dev/null";
236 const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe;
186 const argv = [_][]const u8{237 const argv = [_][]const u8{
187 cc_exe,238 cc_exe,
188 "-E",239 "-E",
189 "-Wp,-v",240 "-Wp,-v",
190 "-xc",241 "-xc",
191 "/dev/null",242 dev_null,
192 };243 };
193 // TODO make this use event loop244 const exec_res = std.ChildProcess.exec2(.{
194 const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024);245 .allocator = allocator,
195 const exec_result = if (std.debug.runtime_safety) blk: {246 .argv = &argv,
196 break :blk errorable_result catch unreachable;247 .max_output_bytes = 1024 * 1024,
197 } else blk: {248 // Some C compilers, such as Clang, are known to rely on argv[0] to find the path
198 break :blk errorable_result catch |err| switch (err) {249 // to their own executable, without even bothering to resolve PATH. This results in the message:
199 error.OutOfMemory => return error.OutOfMemory,250 // error: unable to execute command: Executable "" doesn't exist!
200 else => return error.UnableToSpawnCCompiler,251 // So we use the expandArg0 variant of ChildProcess to give them a helping hand.
201 };252 .expand_arg0 = .expand,
253 }) catch |err| switch (err) {
254 error.OutOfMemory => return error.OutOfMemory,
255 else => return error.UnableToSpawnCCompiler,
202 };256 };
203 defer {257 defer {
204 allocator.free(exec_result.stdout);258 allocator.free(exec_res.stdout);
205 allocator.free(exec_result.stderr);259 allocator.free(exec_res.stderr);
206 }260 }
207261 switch (exec_res.term) {
208 switch (exec_result.term) {262 .Exited => |code| if (code != 0) return error.CCompilerExitCode,
209 .Exited => |code| {263 else => return error.CCompilerCrashed,
210 if (code != 0) return error.CCompilerExitCode;
211 },
212 else => {
213 return error.CCompilerCrashed;
214 },
215 }264 }
216265
217 var it = std.mem.tokenize(exec_result.stderr, "\n\r");266 var it = std.mem.tokenize(exec_res.stderr, "\n\r");
218 var search_paths = std.ArrayList([]const u8).init(allocator);267 var search_paths = std.ArrayList([]const u8).init(allocator);
219 defer search_paths.deinit();268 defer search_paths.deinit();
220 while (it.next()) |line| {269 while (it.next()) |line| {
...@@ -226,16 +275,44 @@ pub const LibCInstallation = struct {...@@ -226,16 +275,44 @@ pub const LibCInstallation = struct {
226 return error.CCompilerCannotFindHeaders;275 return error.CCompilerCannotFindHeaders;
227 }276 }
228277
229 // search in reverse order278 const include_dir_example_file = "stdlib.h";
279 const sys_include_dir_example_file = if (is_windows) "sys\\types.h" else "sys/errno.h";
280
230 var path_i: usize = 0;281 var path_i: usize = 0;
231 while (path_i < search_paths.len) : (path_i += 1) {282 while (path_i < search_paths.len) : (path_i += 1) {
283 // search in reverse order
232 const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);284 const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);
233 const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");285 const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");
234 const stdlib_path = try fs.path.join(allocator, &[_][]const u8{ search_path, "stdlib.h" });286 var search_dir = fs.cwd().openDirList(search_path) catch |err| switch (err) {
235 defer allocator.free(stdlib_path);287 error.FileNotFound,
288 error.NotDir,
289 error.NoDevice,
290 => continue,
291
292 else => return error.FileSystem,
293 };
294 defer search_dir.close();
295
296 if (self.include_dir == null) {
297 if (search_dir.accessZ(include_dir_example_file, .{})) |_| {
298 self.include_dir = try std.mem.dupeZ(allocator, u8, search_path);
299 } else |err| switch (err) {
300 error.FileNotFound => {},
301 else => return error.FileSystem,
302 }
303 }
304
305 if (self.sys_include_dir == null) {
306 if (search_dir.accessZ(sys_include_dir_example_file, .{})) |_| {
307 self.sys_include_dir = try std.mem.dupeZ(allocator, u8, search_path);
308 } else |err| switch (err) {
309 error.FileNotFound => {},
310 else => return error.FileSystem,
311 }
312 }
236313
237 if (try fileExists(stdlib_path)) {314 if (self.include_dir != null and self.sys_include_dir != null) {
238 self.include_dir = try std.mem.dupe(allocator, u8, search_path);315 // Success.
239 return;316 return;
240 }317 }
241 }318 }
...@@ -243,7 +320,11 @@ pub const LibCInstallation = struct {...@@ -243,7 +320,11 @@ pub const LibCInstallation = struct {
243 return error.LibCStdLibHeaderNotFound;320 return error.LibCStdLibHeaderNotFound;
244 }321 }
245322
246 async fn findNativeIncludeDirWindows(self: *LibCInstallation, allocator: *Allocator, sdk: *c.ZigWindowsSDK) !void {323 fn findNativeIncludeDirWindows(
324 self: *LibCInstallation,
325 allocator: *Allocator,
326 sdk: *ZigWindowsSDK,
327 ) FindError!void {
247 var search_buf: [2]Search = undefined;328 var search_buf: [2]Search = undefined;
248 const searches = fillSearch(&search_buf, sdk);329 const searches = fillSearch(&search_buf, sdk);
249330
...@@ -255,180 +336,301 @@ pub const LibCInstallation = struct {...@@ -255,180 +336,301 @@ pub const LibCInstallation = struct {
255 const stream = &std.io.BufferOutStream.init(&result_buf).stream;336 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
256 try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version });337 try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version });
257338
258 const stdlib_path = try fs.path.join(339 var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {
259 allocator,340 error.FileNotFound,
260 [_][]const u8{ result_buf.toSliceConst(), "stdlib.h" },341 error.NotDir,
261 );342 error.NoDevice,
262 defer allocator.free(stdlib_path);343 => continue,
263344
264 if (try fileExists(stdlib_path)) {345 else => return error.FileSystem,
265 self.include_dir = result_buf.toOwnedSlice();346 };
266 return;347 defer dir.close();
267 }348
349 dir.accessZ("stdlib.h", .{}) catch |err| switch (err) {
350 error.FileNotFound => continue,
351 else => return error.FileSystem,
352 };
353
354 self.include_dir = result_buf.toOwnedSlice();
355 return;
268 }356 }
269357
270 return error.LibCStdLibHeaderNotFound;358 return error.LibCStdLibHeaderNotFound;
271 }359 }
272360
273 async fn findNativeLibDirWindows(self: *LibCInstallation, allocator: *Allocator, sdk: *c.ZigWindowsSDK) FindError!void {361 fn findNativeCrtDirWindows(self: *LibCInstallation, allocator: *Allocator, sdk: *ZigWindowsSDK) FindError!void {
274 var search_buf: [2]Search = undefined;362 var search_buf: [2]Search = undefined;
275 const searches = fillSearch(&search_buf, sdk);363 const searches = fillSearch(&search_buf, sdk);
276364
277 var result_buf = try std.Buffer.initSize(allocator, 0);365 var result_buf = try std.Buffer.initSize(allocator, 0);
278 defer result_buf.deinit();366 defer result_buf.deinit();
279367
368 const arch_sub_dir = switch (builtin.arch) {
369 .i386 => "x86",
370 .x86_64 => "x64",
371 .arm, .armeb => "arm",
372 else => return error.UnsupportedArchitecture,
373 };
374
280 for (searches) |search| {375 for (searches) |search| {
281 result_buf.shrink(0);376 result_buf.shrink(0);
282 const stream = &std.io.BufferOutStream.init(&result_buf).stream;377 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
283 try stream.print("{}\\Lib\\{}\\ucrt\\", .{ search.path, search.version });378 try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir });
284 switch (builtin.arch) {
285 .i386 => try stream.write("x86"),
286 .x86_64 => try stream.write("x64"),
287 .aarch64 => try stream.write("arm"),
288 else => return error.UnsupportedArchitecture,
289 }
290 const ucrt_lib_path = try fs.path.join(
291 allocator,
292 [_][]const u8{ result_buf.toSliceConst(), "ucrt.lib" },
293 );
294 defer allocator.free(ucrt_lib_path);
295 if (try fileExists(ucrt_lib_path)) {
296 self.lib_dir = result_buf.toOwnedSlice();
297 return;
298 }
299 }
300 return error.LibCRuntimeNotFound;
301 }
302379
303 async fn findNativeLibDirLinux(self: *LibCInstallation, allocator: *Allocator) FindError!void {380 var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {
304 self.lib_dir = try ccPrintFileName(allocator, "crt1.o", true);381 error.FileNotFound,
305 }382 error.NotDir,
383 error.NoDevice,
384 => continue,
306385
307 async fn findNativeStaticLibDir(self: *LibCInstallation, allocator: *Allocator) FindError!void {386 else => return error.FileSystem,
308 self.static_lib_dir = try ccPrintFileName(allocator, "crtbegin.o", true);387 };
309 }388 defer dir.close();
310389
311 async fn findNativeDynamicLinker(self: *LibCInstallation, allocator: *Allocator) FindError!void {390 dir.accessZ("ucrt.lib", .{}) catch |err| switch (err) {
312 var dyn_tests = [_]DynTest{391 error.FileNotFound => continue,
313 DynTest{392 else => return error.FileSystem,
314 .name = "ld-linux-x86-64.so.2",393 };
315 .result = null,394
316 },395 self.crt_dir = result_buf.toOwnedSlice();
317 DynTest{396 return;
318 .name = "ld-musl-x86_64.so.1",
319 .result = null,
320 },
321 };
322 var group = event.Group(FindError!void).init(allocator);
323 errdefer group.wait() catch {};
324 for (dyn_tests) |*dyn_test| {
325 try group.call(testNativeDynamicLinker, .{ self, allocator, dyn_test });
326 }
327 try group.wait();
328 for (dyn_tests) |*dyn_test| {
329 if (dyn_test.result) |result| {
330 self.dynamic_linker_path = result;
331 return;
332 }
333 }397 }
398 return error.LibCRuntimeNotFound;
334 }399 }
335400
336 const DynTest = struct {401 fn findNativeCrtDirPosix(self: *LibCInstallation, allocator: *Allocator) FindError!void {
337 name: []const u8,402 self.crt_dir = try ccPrintFileName(allocator, "crt1.o", .only_dir);
338 result: ?[]const u8,403 }
339 };
340404
341 async fn testNativeDynamicLinker(self: *LibCInstallation, allocator: *Allocator, dyn_test: *DynTest) FindError!void {405 fn findNativeStaticCrtDirPosix(self: *LibCInstallation, allocator: *Allocator) FindError!void {
342 if (ccPrintFileName(allocator, dyn_test.name, false)) |result| {406 self.static_crt_dir = try ccPrintFileName(allocator, "crtbegin.o", .only_dir);
343 dyn_test.result = result;
344 return;
345 } else |err| switch (err) {
346 error.LibCRuntimeNotFound => return,
347 else => return err,
348 }
349 }407 }
350408
351 async fn findNativeKernel32LibDir(self: *LibCInstallation, allocator: *Allocator, sdk: *c.ZigWindowsSDK) FindError!void {409 fn findNativeKernel32LibDir(self: *LibCInstallation, allocator: *Allocator, sdk: *ZigWindowsSDK) FindError!void {
352 var search_buf: [2]Search = undefined;410 var search_buf: [2]Search = undefined;
353 const searches = fillSearch(&search_buf, sdk);411 const searches = fillSearch(&search_buf, sdk);
354412
355 var result_buf = try std.Buffer.initSize(allocator, 0);413 var result_buf = try std.Buffer.initSize(allocator, 0);
356 defer result_buf.deinit();414 defer result_buf.deinit();
357415
416 const arch_sub_dir = switch (builtin.arch) {
417 .i386 => "x86",
418 .x86_64 => "x64",
419 .arm, .armeb => "arm",
420 else => return error.UnsupportedArchitecture,
421 };
422
358 for (searches) |search| {423 for (searches) |search| {
359 result_buf.shrink(0);424 result_buf.shrink(0);
360 const stream = &std.io.BufferOutStream.init(&result_buf).stream;425 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
361 try stream.print("{}\\Lib\\{}\\um\\", .{ search.path, search.version });426 try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir });
362 switch (builtin.arch) {427
363 .i386 => try stream.write("x86\\"),428 var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {
364 .x86_64 => try stream.write("x64\\"),429 error.FileNotFound,
365 .aarch64 => try stream.write("arm\\"),430 error.NotDir,
366 else => return error.UnsupportedArchitecture,431 error.NoDevice,
367 }432 => continue,
368 const kernel32_path = try fs.path.join(433
369 allocator,434 else => return error.FileSystem,
370 [_][]const u8{ result_buf.toSliceConst(), "kernel32.lib" },435 };
371 );436 defer dir.close();
372 defer allocator.free(kernel32_path);437
373 if (try fileExists(kernel32_path)) {438 dir.accessZ("kernel32.lib", .{}) catch |err| switch (err) {
374 self.kernel32_lib_dir = result_buf.toOwnedSlice();439 error.FileNotFound => continue,
375 return;440 else => return error.FileSystem,
376 }441 };
442
443 self.kernel32_lib_dir = result_buf.toOwnedSlice();
444 return;
377 }445 }
378 return error.LibCKernel32LibNotFound;446 return error.LibCKernel32LibNotFound;
379 }447 }
380448
381 fn initEmpty(self: *LibCInstallation) void {449 fn findNativeMsvcIncludeDir(
382 self.* = LibCInstallation{450 self: *LibCInstallation,
383 .include_dir = @as([*]const u8, undefined)[0..0],451 allocator: *Allocator,
384 .lib_dir = null,452 sdk: *ZigWindowsSDK,
385 .static_lib_dir = null,453 ) FindError!void {
386 .msvc_lib_dir = null,454 const msvc_lib_dir_ptr = sdk.msvc_lib_dir_ptr orelse return error.LibCStdLibHeaderNotFound;
387 .kernel32_lib_dir = null,455 const msvc_lib_dir = msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len];
388 .dynamic_linker_path = null,456 const up1 = fs.path.dirname(msvc_lib_dir) orelse return error.LibCStdLibHeaderNotFound;
457 const up2 = fs.path.dirname(up1) orelse return error.LibCStdLibHeaderNotFound;
458
459 var result_buf = try std.Buffer.init(allocator, up2);
460 defer result_buf.deinit();
461
462 try result_buf.append("\\include");
463
464 var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {
465 error.FileNotFound,
466 error.NotDir,
467 error.NoDevice,
468 => return error.LibCStdLibHeaderNotFound,
469
470 else => return error.FileSystem,
471 };
472 defer dir.close();
473
474 dir.accessZ("vcruntime.h", .{}) catch |err| switch (err) {
475 error.FileNotFound => return error.LibCStdLibHeaderNotFound,
476 else => return error.FileSystem,
389 };477 };
478
479 self.sys_include_dir = result_buf.toOwnedSlice();
480 }
481
482 fn findNativeMsvcLibDir(
483 self: *LibCInstallation,
484 allocator: *Allocator,
485 sdk: *ZigWindowsSDK,
486 ) FindError!void {
487 const msvc_lib_dir_ptr = sdk.msvc_lib_dir_ptr orelse return error.LibCRuntimeNotFound;
488 self.msvc_lib_dir = try std.mem.dupeZ(allocator, u8, msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]);
390 }489 }
391};490};
392491
492const default_cc_exe = if (is_windows) "cc.exe" else "cc";
493
393/// caller owns returned memory494/// caller owns returned memory
394fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 {495fn ccPrintFileName(
395 const cc_exe = std.os.getenv("CC") orelse "cc";496 allocator: *Allocator,
497 o_file: []const u8,
498 want_dirname: enum { full_path, only_dir },
499) ![:0]u8 {
500 const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe;
396 const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", .{o_file});501 const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", .{o_file});
397 defer allocator.free(arg1);502 defer allocator.free(arg1);
398 const argv = [_][]const u8{ cc_exe, arg1 };503 const argv = [_][]const u8{ cc_exe, arg1 };
399504
400 // TODO This simulates evented I/O for the child process exec505 const exec_res = std.ChildProcess.exec2(.{
401 event.Loop.startCpuBoundOperation();506 .allocator = allocator,
402 const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024);507 .argv = &argv,
403 const exec_result = if (std.debug.runtime_safety) blk: {508 .max_output_bytes = 1024 * 1024,
404 break :blk errorable_result catch unreachable;509 // Some C compilers, such as Clang, are known to rely on argv[0] to find the path
405 } else blk: {510 // to their own executable, without even bothering to resolve PATH. This results in the message:
406 break :blk errorable_result catch |err| switch (err) {511 // error: unable to execute command: Executable "" doesn't exist!
407 error.OutOfMemory => return error.OutOfMemory,512 // So we use the expandArg0 variant of ChildProcess to give them a helping hand.
408 else => return error.UnableToSpawnCCompiler,513 .expand_arg0 = .expand,
409 };514 }) catch |err| switch (err) {
515 error.OutOfMemory => return error.OutOfMemory,
516 else => return error.UnableToSpawnCCompiler,
410 };517 };
411 defer {518 defer {
412 allocator.free(exec_result.stdout);519 allocator.free(exec_res.stdout);
413 allocator.free(exec_result.stderr);520 allocator.free(exec_res.stderr);
414 }521 }
415 switch (exec_result.term) {522 switch (exec_res.term) {
416 .Exited => |code| {523 .Exited => |code| if (code != 0) return error.CCompilerExitCode,
417 if (code != 0) return error.CCompilerExitCode;524 else => return error.CCompilerCrashed,
418 },
419 else => {
420 return error.CCompilerCrashed;
421 },
422 }525 }
423 var it = std.mem.tokenize(exec_result.stdout, "\n\r");526
527 var it = std.mem.tokenize(exec_res.stdout, "\n\r");
424 const line = it.next() orelse return error.LibCRuntimeNotFound;528 const line = it.next() orelse return error.LibCRuntimeNotFound;
425 const dirname = fs.path.dirname(line) orelse return error.LibCRuntimeNotFound;529 // When this command fails, it returns exit code 0 and duplicates the input file name.
530 // So we detect failure by checking if the output matches exactly the input.
531 if (std.mem.eql(u8, line, o_file)) return error.LibCRuntimeNotFound;
532 switch (want_dirname) {
533 .full_path => return std.mem.dupeZ(allocator, u8, line),
534 .only_dir => {
535 const dirname = fs.path.dirname(line) orelse return error.LibCRuntimeNotFound;
536 return std.mem.dupeZ(allocator, u8, dirname);
537 },
538 }
539}
426540
427 if (want_dirname) {541/// Caller owns returned memory.
428 return std.mem.dupe(allocator, u8, dirname);542pub fn detectNativeDynamicLinker(allocator: *Allocator) error{
429 } else {543 OutOfMemory,
430 return std.mem.dupe(allocator, u8, line);544 TargetHasNoDynamicLinker,
545 UnknownDynamicLinkerPath,
546}![:0]u8 {
547 if (!comptime Target.current.hasDynamicLinker()) {
548 return error.TargetHasNoDynamicLinker;
431 }549 }
550
551 // The current target's ABI cannot be relied on for this. For example, we may build the zig
552 // compiler for target riscv64-linux-musl and provide a tarball for users to download.
553 // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined
554 // and supported by Zig. But that means that we must detect the system ABI here rather than
555 // relying on `std.Target.current`.
556
557 const LdInfo = struct {
558 ld_path: []u8,
559 abi: Target.Abi,
560 };
561 var ld_info_list = std.ArrayList(LdInfo).init(allocator);
562 defer {
563 for (ld_info_list.toSlice()) |ld_info| allocator.free(ld_info.ld_path);
564 ld_info_list.deinit();
565 }
566
567 const all_abis = comptime blk: {
568 const fields = std.meta.fields(Target.Abi);
569 var array: [fields.len]Target.Abi = undefined;
570 inline for (fields) |field, i| {
571 array[i] = @field(Target.Abi, field.name);
572 }
573 break :blk array;
574 };
575 for (all_abis) |abi| {
576 // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and
577 // skip adding it to `ld_info_list`.
578 const target: Target = .{
579 .Cross = .{
580 .arch = Target.current.getArch(),
581 .os = Target.current.getOs(),
582 .abi = abi,
583 .cpu_features = Target.current.getArch().getBaselineCpuFeatures(),
584 },
585 };
586 const standard_ld_path = target.getStandardDynamicLinkerPath(allocator) catch |err| switch (err) {
587 error.OutOfMemory => return error.OutOfMemory,
588 error.UnknownDynamicLinkerPath, error.TargetHasNoDynamicLinker => continue,
589 };
590 errdefer allocator.free(standard_ld_path);
591 try ld_info_list.append(.{
592 .ld_path = standard_ld_path,
593 .abi = abi,
594 });
595 }
596
597 // Best case scenario: the zig compiler is dynamically linked, and we can iterate
598 // over our own shared objects and find a dynamic linker.
599 {
600 const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
601 defer allocator.free(lib_paths);
602
603 // This is O(N^M) but typical case here is N=2 and M=10.
604 for (lib_paths) |lib_path| {
605 for (ld_info_list.toSlice()) |ld_info| {
606 const standard_ld_basename = fs.path.basename(ld_info.ld_path);
607 if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) {
608 return std.mem.dupeZ(allocator, u8, lib_path);
609 }
610 }
611 }
612 }
613
614 // If Zig is statically linked, such as via distributed binary static builds, the above
615 // trick won't work. What are we left with? Try to run the system C compiler and get
616 // it to tell us the dynamic linker path.
617 // TODO: instead of this, look at the shared libs of /usr/bin/env.
618 for (ld_info_list.toSlice()) |ld_info| {
619 const standard_ld_basename = fs.path.basename(ld_info.ld_path);
620
621 const full_ld_path = ccPrintFileName(allocator, standard_ld_basename, .full_path) catch |err| switch (err) {
622 error.OutOfMemory => return error.OutOfMemory,
623 error.LibCRuntimeNotFound,
624 error.CCompilerExitCode,
625 error.CCompilerCrashed,
626 error.UnableToSpawnCCompiler,
627 => continue,
628 };
629 return full_ld_path;
630 }
631
632 // Finally, we fall back on the standard path.
633 return Target.current.getStandardDynamicLinkerPath(allocator);
432}634}
433635
434const Search = struct {636const Search = struct {
...@@ -436,34 +638,25 @@ const Search = struct {...@@ -436,34 +638,25 @@ const Search = struct {
436 version: []const u8,638 version: []const u8,
437};639};
438640
439fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search {641fn fillSearch(search_buf: *[2]Search, sdk: *ZigWindowsSDK) []Search {
440 var search_end: usize = 0;642 var search_end: usize = 0;
441 if (sdk.path10_ptr != 0) {643 if (sdk.path10_ptr) |path10_ptr| {
442 if (sdk.version10_ptr != 0) {644 if (sdk.version10_ptr) |version10_ptr| {
443 search_buf[search_end] = Search{645 search_buf[search_end] = Search{
444 .path = sdk.path10_ptr[0..sdk.path10_len],646 .path = path10_ptr[0..sdk.path10_len],
445 .version = sdk.version10_ptr[0..sdk.version10_len],647 .version = version10_ptr[0..sdk.version10_len],
446 };648 };
447 search_end += 1;649 search_end += 1;
448 }650 }
449 }651 }
450 if (sdk.path81_ptr != 0) {652 if (sdk.path81_ptr) |path81_ptr| {
451 if (sdk.version81_ptr != 0) {653 if (sdk.version81_ptr) |version81_ptr| {
452 search_buf[search_end] = Search{654 search_buf[search_end] = Search{
453 .path = sdk.path81_ptr[0..sdk.path81_len],655 .path = path81_ptr[0..sdk.path81_len],
454 .version = sdk.version81_ptr[0..sdk.version81_len],656 .version = version81_ptr[0..sdk.version81_len],
455 };657 };
456 search_end += 1;658 search_end += 1;
457 }659 }
458 }660 }
459 return search_buf[0..search_end];661 return search_buf[0..search_end];
460}662}
461
462fn fileExists(path: []const u8) !bool {
463 if (fs.File.access(path)) |_| {
464 return true;
465 } else |err| switch (err) {
466 error.FileNotFound => return false,
467 else => return error.FileSystem,
468 }
469}
src-self-hosted/stage1.zig deleted-834
...@@ -1,834 +0,0 @@
1// This is Zig code that is used by both stage1 and stage2.
2// The prototypes in src/userland.h must match these definitions.
3
4const std = @import("std");
5const io = std.io;
6const mem = std.mem;
7const fs = std.fs;
8const process = std.process;
9const Allocator = mem.Allocator;
10const ArrayList = std.ArrayList;
11const Buffer = std.Buffer;
12const Target = std.Target;
13const self_hosted_main = @import("main.zig");
14const errmsg = @import("errmsg.zig");
15const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;
16const assert = std.debug.assert;
17
18var stderr_file: fs.File = undefined;
19var stderr: *io.OutStream(fs.File.WriteError) = undefined;
20var stdout: *io.OutStream(fs.File.WriteError) = undefined;
21
22comptime {
23 _ = @import("dep_tokenizer.zig");
24}
25
26// ABI warning
27export fn stage2_zen(ptr: *[*]const u8, len: *usize) void {
28 const info_zen = @import("main.zig").info_zen;
29 ptr.* = info_zen;
30 len.* = info_zen.len;
31}
32
33// ABI warning
34export fn stage2_panic(ptr: [*]const u8, len: usize) void {
35 @panic(ptr[0..len]);
36}
37
38// ABI warning
39const Error = extern enum {
40 None,
41 OutOfMemory,
42 InvalidFormat,
43 SemanticAnalyzeFail,
44 AccessDenied,
45 Interrupted,
46 SystemResources,
47 FileNotFound,
48 FileSystem,
49 FileTooBig,
50 DivByZero,
51 Overflow,
52 PathAlreadyExists,
53 Unexpected,
54 ExactDivRemainder,
55 NegativeDenominator,
56 ShiftedOutOneBits,
57 CCompileErrors,
58 EndOfFile,
59 IsDir,
60 NotDir,
61 UnsupportedOperatingSystem,
62 SharingViolation,
63 PipeBusy,
64 PrimitiveTypeNotFound,
65 CacheUnavailable,
66 PathTooLong,
67 CCompilerCannotFindFile,
68 NoCCompilerInstalled,
69 ReadingDepFile,
70 InvalidDepFile,
71 MissingArchitecture,
72 MissingOperatingSystem,
73 UnknownArchitecture,
74 UnknownOperatingSystem,
75 UnknownABI,
76 InvalidFilename,
77 DiskQuota,
78 DiskSpace,
79 UnexpectedWriteFailure,
80 UnexpectedSeekFailure,
81 UnexpectedFileTruncationFailure,
82 Unimplemented,
83 OperationAborted,
84 BrokenPipe,
85 NoSpaceLeft,
86 NotLazy,
87 IsAsync,
88 ImportOutsidePkgPath,
89 UnknownCpu,
90 UnknownSubArchitecture,
91 UnknownCpuFeature,
92 InvalidCpuFeatures,
93 InvalidLlvmCpuFeaturesFormat,
94 UnknownApplicationBinaryInterface,
95 ASTUnitFailure,
96};
97
98const FILE = std.c.FILE;
99const ast = std.zig.ast;
100const translate_c = @import("translate_c.zig");
101
102/// Args should have a null terminating last arg.
103export fn stage2_translate_c(
104 out_ast: **ast.Tree,
105 out_errors_ptr: *[*]translate_c.ClangErrMsg,
106 out_errors_len: *usize,
107 args_begin: [*]?[*]const u8,
108 args_end: [*]?[*]const u8,
109 resources_path: [*:0]const u8,
110) Error {
111 var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0];
112 out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {
113 error.SemanticAnalyzeFail => {
114 out_errors_ptr.* = errors.ptr;
115 out_errors_len.* = errors.len;
116 return Error.CCompileErrors;
117 },
118 error.ASTUnitFailure => return Error.ASTUnitFailure,
119 error.OutOfMemory => return Error.OutOfMemory,
120 };
121 return Error.None;
122}
123
124export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void {
125 translate_c.freeErrors(errors_ptr[0..errors_len]);
126}
127
128export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
129 const c_out_stream = &std.io.COutStream.init(output_file).stream;
130 _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {
131 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
132 error.SystemResources => return Error.SystemResources,
133 error.OperationAborted => return Error.OperationAborted,
134 error.BrokenPipe => return Error.BrokenPipe,
135 error.DiskQuota => return Error.DiskQuota,
136 error.FileTooBig => return Error.FileTooBig,
137 error.NoSpaceLeft => return Error.NoSpaceLeft,
138 error.AccessDenied => return Error.AccessDenied,
139 error.OutOfMemory => return Error.OutOfMemory,
140 error.Unexpected => return Error.Unexpected,
141 error.InputOutput => return Error.FileSystem,
142 };
143 return Error.None;
144}
145
146// TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377,
147// we use a blocking implementation.
148export fn stage2_fmt(argc: c_int, argv: [*]const [*:0]const u8) c_int {
149 if (std.debug.runtime_safety) {
150 fmtMain(argc, argv) catch unreachable;
151 } else {
152 fmtMain(argc, argv) catch |e| {
153 std.debug.warn("{}\n", .{@errorName(e)});
154 return -1;
155 };
156 }
157 return 0;
158}
159
160fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
161 const allocator = std.heap.c_allocator;
162 var args_list = std.ArrayList([]const u8).init(allocator);
163 const argc_usize = @intCast(usize, argc);
164 var arg_i: usize = 0;
165 while (arg_i < argc_usize) : (arg_i += 1) {
166 try args_list.append(mem.toSliceConst(u8, argv[arg_i]));
167 }
168
169 stdout = &std.io.getStdOut().outStream().stream;
170 stderr_file = std.io.getStdErr();
171 stderr = &stderr_file.outStream().stream;
172
173 const args = args_list.toSliceConst()[2..];
174
175 var color: errmsg.Color = .Auto;
176 var stdin_flag: bool = false;
177 var check_flag: bool = false;
178 var input_files = ArrayList([]const u8).init(allocator);
179
180 {
181 var i: usize = 0;
182 while (i < args.len) : (i += 1) {
183 const arg = args[i];
184 if (mem.startsWith(u8, arg, "-")) {
185 if (mem.eql(u8, arg, "--help")) {
186 try stdout.write(self_hosted_main.usage_fmt);
187 process.exit(0);
188 } else if (mem.eql(u8, arg, "--color")) {
189 if (i + 1 >= args.len) {
190 try stderr.write("expected [auto|on|off] after --color\n");
191 process.exit(1);
192 }
193 i += 1;
194 const next_arg = args[i];
195 if (mem.eql(u8, next_arg, "auto")) {
196 color = .Auto;
197 } else if (mem.eql(u8, next_arg, "on")) {
198 color = .On;
199 } else if (mem.eql(u8, next_arg, "off")) {
200 color = .Off;
201 } else {
202 try stderr.print("expected [auto|on|off] after --color, found '{}'\n", .{next_arg});
203 process.exit(1);
204 }
205 } else if (mem.eql(u8, arg, "--stdin")) {
206 stdin_flag = true;
207 } else if (mem.eql(u8, arg, "--check")) {
208 check_flag = true;
209 } else {
210 try stderr.print("unrecognized parameter: '{}'", .{arg});
211 process.exit(1);
212 }
213 } else {
214 try input_files.append(arg);
215 }
216 }
217 }
218
219 if (stdin_flag) {
220 if (input_files.len != 0) {
221 try stderr.write("cannot use --stdin with positional arguments\n");
222 process.exit(1);
223 }
224
225 const stdin_file = io.getStdIn();
226 var stdin = stdin_file.inStream();
227
228 const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size);
229 defer allocator.free(source_code);
230
231 const tree = std.zig.parse(allocator, source_code) catch |err| {
232 try stderr.print("error parsing stdin: {}\n", .{err});
233 process.exit(1);
234 };
235 defer tree.deinit();
236
237 var error_it = tree.errors.iterator(0);
238 while (error_it.next()) |parse_error| {
239 try printErrMsgToFile(allocator, parse_error, tree, "<stdin>", stderr_file, color);
240 }
241 if (tree.errors.len != 0) {
242 process.exit(1);
243 }
244 if (check_flag) {
245 const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree);
246 const code = if (anything_changed) @as(u8, 1) else @as(u8, 0);
247 process.exit(code);
248 }
249
250 _ = try std.zig.render(allocator, stdout, tree);
251 return;
252 }
253
254 if (input_files.len == 0) {
255 try stderr.write("expected at least one source file argument\n");
256 process.exit(1);
257 }
258
259 var fmt = Fmt{
260 .seen = Fmt.SeenMap.init(allocator),
261 .any_error = false,
262 .color = color,
263 .allocator = allocator,
264 };
265
266 for (input_files.toSliceConst()) |file_path| {
267 try fmtPath(&fmt, file_path, check_flag);
268 }
269 if (fmt.any_error) {
270 process.exit(1);
271 }
272}
273
274const FmtError = error{
275 SystemResources,
276 OperationAborted,
277 IoPending,
278 BrokenPipe,
279 Unexpected,
280 WouldBlock,
281 FileClosed,
282 DestinationAddressRequired,
283 DiskQuota,
284 FileTooBig,
285 InputOutput,
286 NoSpaceLeft,
287 AccessDenied,
288 OutOfMemory,
289 RenameAcrossMountPoints,
290 ReadOnlyFileSystem,
291 LinkQuotaExceeded,
292 FileBusy,
293} || fs.File.OpenError;
294
295fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
296 if (fmt.seen.exists(file_path)) return;
297 try fmt.seen.put(file_path);
298
299 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {
300 error.IsDir, error.AccessDenied => {
301 // TODO make event based (and dir.next())
302 var dir = try fs.cwd().openDirList(file_path);
303 defer dir.close();
304
305 var dir_it = dir.iterate();
306
307 while (try dir_it.next()) |entry| {
308 if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) {
309 const full_path = try fs.path.join(fmt.allocator, &[_][]const u8{ file_path, entry.name });
310 try fmtPath(fmt, full_path, check_mode);
311 }
312 }
313 return;
314 },
315 else => {
316 // TODO lock stderr printing
317 try stderr.print("unable to open '{}': {}\n", .{ file_path, err });
318 fmt.any_error = true;
319 return;
320 },
321 };
322 defer fmt.allocator.free(source_code);
323
324 const tree = std.zig.parse(fmt.allocator, source_code) catch |err| {
325 try stderr.print("error parsing file '{}': {}\n", .{ file_path, err });
326 fmt.any_error = true;
327 return;
328 };
329 defer tree.deinit();
330
331 var error_it = tree.errors.iterator(0);
332 while (error_it.next()) |parse_error| {
333 try printErrMsgToFile(fmt.allocator, parse_error, tree, file_path, stderr_file, fmt.color);
334 }
335 if (tree.errors.len != 0) {
336 fmt.any_error = true;
337 return;
338 }
339
340 if (check_mode) {
341 const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, tree);
342 if (anything_changed) {
343 try stderr.print("{}\n", .{file_path});
344 fmt.any_error = true;
345 }
346 } else {
347 const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path);
348 defer baf.destroy();
349
350 const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), tree);
351 if (anything_changed) {
352 try stderr.print("{}\n", .{file_path});
353 try baf.finish();
354 }
355 }
356}
357
358const Fmt = struct {
359 seen: SeenMap,
360 any_error: bool,
361 color: errmsg.Color,
362 allocator: *mem.Allocator,
363
364 const SeenMap = std.BufSet;
365};
366
367fn printErrMsgToFile(
368 allocator: *mem.Allocator,
369 parse_error: *const ast.Error,
370 tree: *ast.Tree,
371 path: []const u8,
372 file: fs.File,
373 color: errmsg.Color,
374) !void {
375 const color_on = switch (color) {
376 .Auto => file.isTty(),
377 .On => true,
378 .Off => false,
379 };
380 const lok_token = parse_error.loc();
381 const span = errmsg.Span{
382 .first = lok_token,
383 .last = lok_token,
384 };
385
386 const first_token = tree.tokens.at(span.first);
387 const last_token = tree.tokens.at(span.last);
388 const start_loc = tree.tokenLocationPtr(0, first_token);
389 const end_loc = tree.tokenLocationPtr(first_token.end, last_token);
390
391 var text_buf = try std.Buffer.initSize(allocator, 0);
392 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
393 try parse_error.render(&tree.tokens, out_stream);
394 const text = text_buf.toOwnedSlice();
395
396 const stream = &file.outStream().stream;
397 try stream.print("{}:{}:{}: error: {}\n", .{ path, start_loc.line + 1, start_loc.column + 1, text });
398
399 if (!color_on) return;
400
401 // Print \r and \t as one space each so that column counts line up
402 for (tree.source[start_loc.line_start..start_loc.line_end]) |byte| {
403 try stream.writeByte(switch (byte) {
404 '\r', '\t' => ' ',
405 else => byte,
406 });
407 }
408 try stream.writeByte('\n');
409 try stream.writeByteNTimes(' ', start_loc.column);
410 try stream.writeByteNTimes('~', last_token.end - first_token.start);
411 try stream.writeByte('\n');
412}
413
414export fn stage2_DepTokenizer_init(input: [*]const u8, len: usize) stage2_DepTokenizer {
415 const t = std.heap.c_allocator.create(DepTokenizer) catch @panic("failed to create .d tokenizer");
416 t.* = DepTokenizer.init(std.heap.c_allocator, input[0..len]);
417 return stage2_DepTokenizer{
418 .handle = t,
419 };
420}
421
422export fn stage2_DepTokenizer_deinit(self: *stage2_DepTokenizer) void {
423 self.handle.deinit();
424}
425
426export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextResult {
427 const otoken = self.handle.next() catch {
428 const textz = std.Buffer.init(&self.handle.arena.allocator, self.handle.error_text) catch @panic("failed to create .d tokenizer error text");
429 return stage2_DepNextResult{
430 .type_id = .error_,
431 .textz = textz.toSlice().ptr,
432 };
433 };
434 const token = otoken orelse {
435 return stage2_DepNextResult{
436 .type_id = .null_,
437 .textz = undefined,
438 };
439 };
440 const textz = std.Buffer.init(&self.handle.arena.allocator, token.bytes) catch @panic("failed to create .d tokenizer token text");
441 return stage2_DepNextResult{
442 .type_id = switch (token.id) {
443 .target => .target,
444 .prereq => .prereq,
445 },
446 .textz = textz.toSlice().ptr,
447 };
448}
449
450const stage2_DepTokenizer = extern struct {
451 handle: *DepTokenizer,
452};
453
454const stage2_DepNextResult = extern struct {
455 type_id: TypeId,
456
457 // when type_id == error --> error text
458 // when type_id == null --> undefined
459 // when type_id == target --> target pathname
460 // when type_id == prereq --> prereq pathname
461 textz: [*]const u8,
462
463 const TypeId = extern enum {
464 error_,
465 null_,
466 target,
467 prereq,
468 };
469};
470
471// ABI warning
472export fn stage2_attach_segfault_handler() void {
473 if (std.debug.runtime_safety and std.debug.have_segfault_handling_support) {
474 std.debug.attachSegfaultHandler();
475 }
476}
477
478// ABI warning
479export fn stage2_progress_create() *std.Progress {
480 const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory");
481 ptr.* = std.Progress{};
482 return ptr;
483}
484
485// ABI warning
486export fn stage2_progress_destroy(progress: *std.Progress) void {
487 std.heap.c_allocator.destroy(progress);
488}
489
490// ABI warning
491export fn stage2_progress_start_root(
492 progress: *std.Progress,
493 name_ptr: [*]const u8,
494 name_len: usize,
495 estimated_total_items: usize,
496) *std.Progress.Node {
497 return progress.start(
498 name_ptr[0..name_len],
499 if (estimated_total_items == 0) null else estimated_total_items,
500 ) catch @panic("timer unsupported");
501}
502
503// ABI warning
504export fn stage2_progress_disable_tty(progress: *std.Progress) void {
505 progress.terminal = null;
506}
507
508// ABI warning
509export fn stage2_progress_start(
510 node: *std.Progress.Node,
511 name_ptr: [*]const u8,
512 name_len: usize,
513 estimated_total_items: usize,
514) *std.Progress.Node {
515 const child_node = std.heap.c_allocator.create(std.Progress.Node) catch @panic("out of memory");
516 child_node.* = node.start(
517 name_ptr[0..name_len],
518 if (estimated_total_items == 0) null else estimated_total_items,
519 );
520 child_node.activate();
521 return child_node;
522}
523
524// ABI warning
525export fn stage2_progress_end(node: *std.Progress.Node) void {
526 node.end();
527 if (&node.context.root != node) {
528 std.heap.c_allocator.destroy(node);
529 }
530}
531
532// ABI warning
533export fn stage2_progress_complete_one(node: *std.Progress.Node) void {
534 node.completeOne();
535}
536
537// ABI warning
538export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usize, total_count: usize) void {
539 node.completed_items = done_count;
540 node.estimated_total_items = total_count;
541 node.activate();
542 node.context.maybeRefresh();
543}
544
545fn cpuFeaturesFromLLVM(
546 arch: Target.Arch,
547 llvm_cpu_name_z: ?[*:0]const u8,
548 llvm_cpu_features_opt: ?[*:0]const u8,
549) !Target.CpuFeatures {
550 var result = arch.getBaselineCpuFeatures();
551
552 if (llvm_cpu_name_z) |cpu_name_z| {
553 const llvm_cpu_name = mem.toSliceConst(u8, cpu_name_z);
554
555 for (arch.allCpus()) |cpu| {
556 const this_llvm_name = cpu.llvm_name orelse continue;
557 if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
558 // Here we use the non-dependencies-populated set,
559 // so that subtracting features later in this function
560 // affect the prepopulated set.
561 result = Target.CpuFeatures{
562 .cpu = cpu,
563 .features = cpu.features,
564 };
565 break;
566 }
567 }
568 }
569
570 const all_features = arch.allFeaturesList();
571
572 if (llvm_cpu_features_opt) |llvm_cpu_features| {
573 var it = mem.tokenize(mem.toSliceConst(u8, llvm_cpu_features), ",");
574 while (it.next()) |decorated_llvm_feat| {
575 var op: enum {
576 add,
577 sub,
578 } = undefined;
579 var llvm_feat: []const u8 = undefined;
580 if (mem.startsWith(u8, decorated_llvm_feat, "+")) {
581 op = .add;
582 llvm_feat = decorated_llvm_feat[1..];
583 } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) {
584 op = .sub;
585 llvm_feat = decorated_llvm_feat[1..];
586 } else {
587 return error.InvalidLlvmCpuFeaturesFormat;
588 }
589 for (all_features) |feature, index_usize| {
590 const this_llvm_name = feature.llvm_name orelse continue;
591 if (mem.eql(u8, llvm_feat, this_llvm_name)) {
592 const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
593 switch (op) {
594 .add => result.features.addFeature(index),
595 .sub => result.features.removeFeature(index),
596 }
597 break;
598 }
599 }
600 }
601 }
602
603 result.features.populateDependencies(all_features);
604 return result;
605}
606
607// ABI warning
608export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int {
609 cmdTargets(zig_triple) catch |err| {
610 std.debug.warn("unable to list targets: {}\n", .{@errorName(err)});
611 return -1;
612 };
613 return 0;
614}
615
616fn cmdTargets(zig_triple: [*:0]const u8) !void {
617 var target = try Target.parse(mem.toSliceConst(u8, zig_triple));
618 target.Cross.cpu_features = blk: {
619 const llvm = @import("llvm.zig");
620 const llvm_cpu_name = llvm.GetHostCPUName();
621 const llvm_cpu_features = llvm.GetNativeFeatures();
622 break :blk try cpuFeaturesFromLLVM(target.Cross.arch, llvm_cpu_name, llvm_cpu_features);
623 };
624 return @import("print_targets.zig").cmdTargets(
625 std.heap.c_allocator,
626 &[0][]u8{},
627 &std.io.getStdOut().outStream().stream,
628 target,
629 );
630}
631
632const Stage2CpuFeatures = struct {
633 allocator: *mem.Allocator,
634 cpu_features: Target.CpuFeatures,
635
636 llvm_features_str: ?[*:0]const u8,
637
638 builtin_str: [:0]const u8,
639 cache_hash: [:0]const u8,
640
641 const Self = @This();
642
643 fn createFromNative(allocator: *mem.Allocator) !*Self {
644 const arch = Target.current.getArch();
645 const llvm = @import("llvm.zig");
646 const llvm_cpu_name = llvm.GetHostCPUName();
647 const llvm_cpu_features = llvm.GetNativeFeatures();
648 const cpu_features = try cpuFeaturesFromLLVM(arch, llvm_cpu_name, llvm_cpu_features);
649 return createFromCpuFeatures(allocator, arch, cpu_features);
650 }
651
652 fn createFromCpuFeatures(
653 allocator: *mem.Allocator,
654 arch: Target.Arch,
655 cpu_features: Target.CpuFeatures,
656 ) !*Self {
657 const self = try allocator.create(Self);
658 errdefer allocator.destroy(self);
659
660 const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{}", .{
661 cpu_features.cpu.name,
662 cpu_features.features.asBytes(),
663 });
664 errdefer allocator.free(cache_hash);
665
666 const generic_arch_name = arch.genericName();
667 var builtin_str_buffer = try std.Buffer.allocPrint(allocator,
668 \\CpuFeatures{{
669 \\ .cpu = &Target.{}.cpu.{},
670 \\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
671 \\
672 , .{
673 generic_arch_name,
674 cpu_features.cpu.name,
675 generic_arch_name,
676 generic_arch_name,
677 });
678 defer builtin_str_buffer.deinit();
679
680 var llvm_features_buffer = try std.Buffer.initSize(allocator, 0);
681 defer llvm_features_buffer.deinit();
682
683 for (arch.allFeaturesList()) |feature, index_usize| {
684 const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
685 const is_enabled = cpu_features.features.isEnabled(index);
686
687 if (feature.llvm_name) |llvm_name| {
688 const plus_or_minus = "-+"[@boolToInt(is_enabled)];
689 try llvm_features_buffer.appendByte(plus_or_minus);
690 try llvm_features_buffer.append(llvm_name);
691 try llvm_features_buffer.append(",");
692 }
693
694 if (is_enabled) {
695 // TODO some kind of "zig identifier escape" function rather than
696 // unconditionally using @"" syntax
697 try builtin_str_buffer.append(" .@\"");
698 try builtin_str_buffer.append(feature.name);
699 try builtin_str_buffer.append("\",\n");
700 }
701 }
702
703 try builtin_str_buffer.append(
704 \\ }),
705 \\};
706 \\
707 );
708
709 assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ","));
710 llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
711
712 self.* = Self{
713 .allocator = allocator,
714 .cpu_features = cpu_features,
715 .llvm_features_str = llvm_features_buffer.toOwnedSlice().ptr,
716 .builtin_str = builtin_str_buffer.toOwnedSlice(),
717 .cache_hash = cache_hash,
718 };
719 return self;
720 }
721
722 fn destroy(self: *Self) void {
723 self.allocator.free(self.cache_hash);
724 self.allocator.free(self.builtin_str);
725 // TODO if (self.llvm_features_str) |llvm_features_str| self.allocator.free(llvm_features_str);
726 self.allocator.destroy(self);
727 }
728};
729
730// ABI warning
731export fn stage2_cpu_features_parse(
732 result: **Stage2CpuFeatures,
733 zig_triple: ?[*:0]const u8,
734 cpu_name: ?[*:0]const u8,
735 cpu_features: ?[*:0]const u8,
736) Error {
737 result.* = stage2ParseCpuFeatures(zig_triple, cpu_name, cpu_features) catch |err| switch (err) {
738 error.OutOfMemory => return .OutOfMemory,
739 error.UnknownArchitecture => return .UnknownArchitecture,
740 error.UnknownSubArchitecture => return .UnknownSubArchitecture,
741 error.UnknownOperatingSystem => return .UnknownOperatingSystem,
742 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
743 error.MissingOperatingSystem => return .MissingOperatingSystem,
744 error.MissingArchitecture => return .MissingArchitecture,
745 error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
746 error.InvalidCpuFeatures => return .InvalidCpuFeatures,
747 };
748 return .None;
749}
750
751fn stage2ParseCpuFeatures(
752 zig_triple_oz: ?[*:0]const u8,
753 cpu_name_oz: ?[*:0]const u8,
754 cpu_features_oz: ?[*:0]const u8,
755) !*Stage2CpuFeatures {
756 const zig_triple_z = zig_triple_oz orelse return Stage2CpuFeatures.createFromNative(std.heap.c_allocator);
757 const target = try Target.parse(mem.toSliceConst(u8, zig_triple_z));
758 const arch = target.Cross.arch;
759
760 const cpu = if (cpu_name_oz) |cpu_name_z| blk: {
761 const cpu_name = mem.toSliceConst(u8, cpu_name_z);
762 break :blk arch.parseCpu(cpu_name) catch |err| switch (err) {
763 error.UnknownCpu => {
764 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
765 cpu_name,
766 @tagName(arch),
767 });
768 for (arch.allCpus()) |cpu| {
769 std.debug.warn(" {}\n", .{cpu.name});
770 }
771 process.exit(1);
772 },
773 else => |e| return e,
774 };
775 } else target.Cross.cpu_features.cpu;
776
777 var set = if (cpu_features_oz) |cpu_features_z| blk: {
778 const cpu_features = mem.toSliceConst(u8, cpu_features_z);
779 break :blk arch.parseCpuFeatureSet(cpu, cpu_features) catch |err| switch (err) {
780 error.UnknownCpuFeature => {
781 std.debug.warn(
782 \\Unknown CPU features specified.
783 \\Available CPU features for architecture '{}':
784 \\
785 , .{@tagName(arch)});
786 for (arch.allFeaturesList()) |feature| {
787 std.debug.warn(" {}\n", .{feature.name});
788 }
789 process.exit(1);
790 },
791 else => |e| return e,
792 };
793 } else cpu.features;
794
795 if (arch.subArchFeature()) |index| {
796 set.addFeature(index);
797 }
798 set.populateDependencies(arch.allFeaturesList());
799
800 return Stage2CpuFeatures.createFromCpuFeatures(std.heap.c_allocator, arch, .{
801 .cpu = cpu,
802 .features = set,
803 });
804}
805
806// ABI warning
807export fn stage2_cpu_features_get_cache_hash(
808 cpu_features: *const Stage2CpuFeatures,
809 ptr: *[*:0]const u8,
810 len: *usize,
811) void {
812 ptr.* = cpu_features.cache_hash.ptr;
813 len.* = cpu_features.cache_hash.len;
814}
815
816// ABI warning
817export fn stage2_cpu_features_get_builtin_str(
818 cpu_features: *const Stage2CpuFeatures,
819 ptr: *[*:0]const u8,
820 len: *usize,
821) void {
822 ptr.* = cpu_features.builtin_str.ptr;
823 len.* = cpu_features.builtin_str.len;
824}
825
826// ABI warning
827export fn stage2_cpu_features_get_llvm_cpu(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 {
828 return if (cpu_features.cpu_features.cpu.llvm_name) |s| s.ptr else null;
829}
830
831// ABI warning
832export fn stage2_cpu_features_get_llvm_features(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 {
833 return cpu_features.llvm_features_str;
834}
src-self-hosted/stage2.zig created+1118
...@@ -0,0 +1,1118 @@
1// This is Zig code that is used by both stage1 and stage2.
2// The prototypes in src/userland.h must match these definitions.
3
4const std = @import("std");
5const io = std.io;
6const mem = std.mem;
7const fs = std.fs;
8const process = std.process;
9const Allocator = mem.Allocator;
10const ArrayList = std.ArrayList;
11const Buffer = std.Buffer;
12const Target = std.Target;
13const self_hosted_main = @import("main.zig");
14const errmsg = @import("errmsg.zig");
15const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;
16const assert = std.debug.assert;
17const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
18
19var stderr_file: fs.File = undefined;
20var stderr: *io.OutStream(fs.File.WriteError) = undefined;
21var stdout: *io.OutStream(fs.File.WriteError) = undefined;
22
23comptime {
24 _ = @import("dep_tokenizer.zig");
25}
26
27// ABI warning
28export fn stage2_zen(ptr: *[*]const u8, len: *usize) void {
29 const info_zen = @import("main.zig").info_zen;
30 ptr.* = info_zen;
31 len.* = info_zen.len;
32}
33
34// ABI warning
35export fn stage2_panic(ptr: [*]const u8, len: usize) void {
36 @panic(ptr[0..len]);
37}
38
39// ABI warning
40const Error = extern enum {
41 None,
42 OutOfMemory,
43 InvalidFormat,
44 SemanticAnalyzeFail,
45 AccessDenied,
46 Interrupted,
47 SystemResources,
48 FileNotFound,
49 FileSystem,
50 FileTooBig,
51 DivByZero,
52 Overflow,
53 PathAlreadyExists,
54 Unexpected,
55 ExactDivRemainder,
56 NegativeDenominator,
57 ShiftedOutOneBits,
58 CCompileErrors,
59 EndOfFile,
60 IsDir,
61 NotDir,
62 UnsupportedOperatingSystem,
63 SharingViolation,
64 PipeBusy,
65 PrimitiveTypeNotFound,
66 CacheUnavailable,
67 PathTooLong,
68 CCompilerCannotFindFile,
69 NoCCompilerInstalled,
70 ReadingDepFile,
71 InvalidDepFile,
72 MissingArchitecture,
73 MissingOperatingSystem,
74 UnknownArchitecture,
75 UnknownOperatingSystem,
76 UnknownABI,
77 InvalidFilename,
78 DiskQuota,
79 DiskSpace,
80 UnexpectedWriteFailure,
81 UnexpectedSeekFailure,
82 UnexpectedFileTruncationFailure,
83 Unimplemented,
84 OperationAborted,
85 BrokenPipe,
86 NoSpaceLeft,
87 NotLazy,
88 IsAsync,
89 ImportOutsidePkgPath,
90 UnknownCpu,
91 UnknownSubArchitecture,
92 UnknownCpuFeature,
93 InvalidCpuFeatures,
94 InvalidLlvmCpuFeaturesFormat,
95 UnknownApplicationBinaryInterface,
96 ASTUnitFailure,
97 BadPathName,
98 SymLinkLoop,
99 ProcessFdQuotaExceeded,
100 SystemFdQuotaExceeded,
101 NoDevice,
102 DeviceBusy,
103 UnableToSpawnCCompiler,
104 CCompilerExitCode,
105 CCompilerCrashed,
106 CCompilerCannotFindHeaders,
107 LibCRuntimeNotFound,
108 LibCStdLibHeaderNotFound,
109 LibCKernel32LibNotFound,
110 UnsupportedArchitecture,
111 WindowsSdkNotFound,
112 UnknownDynamicLinkerPath,
113 TargetHasNoDynamicLinker,
114};
115
116const FILE = std.c.FILE;
117const ast = std.zig.ast;
118const translate_c = @import("translate_c.zig");
119
120/// Args should have a null terminating last arg.
121export fn stage2_translate_c(
122 out_ast: **ast.Tree,
123 out_errors_ptr: *[*]translate_c.ClangErrMsg,
124 out_errors_len: *usize,
125 args_begin: [*]?[*]const u8,
126 args_end: [*]?[*]const u8,
127 resources_path: [*:0]const u8,
128) Error {
129 var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0];
130 out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {
131 error.SemanticAnalyzeFail => {
132 out_errors_ptr.* = errors.ptr;
133 out_errors_len.* = errors.len;
134 return .CCompileErrors;
135 },
136 error.ASTUnitFailure => return .ASTUnitFailure,
137 error.OutOfMemory => return .OutOfMemory,
138 };
139 return .None;
140}
141
142export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void {
143 translate_c.freeErrors(errors_ptr[0..errors_len]);
144}
145
146export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
147 const c_out_stream = &std.io.COutStream.init(output_file).stream;
148 _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {
149 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
150 error.SystemResources => return .SystemResources,
151 error.OperationAborted => return .OperationAborted,
152 error.BrokenPipe => return .BrokenPipe,
153 error.DiskQuota => return .DiskQuota,
154 error.FileTooBig => return .FileTooBig,
155 error.NoSpaceLeft => return .NoSpaceLeft,
156 error.AccessDenied => return .AccessDenied,
157 error.OutOfMemory => return .OutOfMemory,
158 error.Unexpected => return .Unexpected,
159 error.InputOutput => return .FileSystem,
160 };
161 return .None;
162}
163
164// TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377,
165// we use a blocking implementation.
166export fn stage2_fmt(argc: c_int, argv: [*]const [*:0]const u8) c_int {
167 if (std.debug.runtime_safety) {
168 fmtMain(argc, argv) catch unreachable;
169 } else {
170 fmtMain(argc, argv) catch |e| {
171 std.debug.warn("{}\n", .{@errorName(e)});
172 return -1;
173 };
174 }
175 return 0;
176}
177
178fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
179 const allocator = std.heap.c_allocator;
180 var args_list = std.ArrayList([]const u8).init(allocator);
181 const argc_usize = @intCast(usize, argc);
182 var arg_i: usize = 0;
183 while (arg_i < argc_usize) : (arg_i += 1) {
184 try args_list.append(mem.toSliceConst(u8, argv[arg_i]));
185 }
186
187 stdout = &std.io.getStdOut().outStream().stream;
188 stderr_file = std.io.getStdErr();
189 stderr = &stderr_file.outStream().stream;
190
191 const args = args_list.toSliceConst()[2..];
192
193 var color: errmsg.Color = .Auto;
194 var stdin_flag: bool = false;
195 var check_flag: bool = false;
196 var input_files = ArrayList([]const u8).init(allocator);
197
198 {
199 var i: usize = 0;
200 while (i < args.len) : (i += 1) {
201 const arg = args[i];
202 if (mem.startsWith(u8, arg, "-")) {
203 if (mem.eql(u8, arg, "--help")) {
204 try stdout.write(self_hosted_main.usage_fmt);
205 process.exit(0);
206 } else if (mem.eql(u8, arg, "--color")) {
207 if (i + 1 >= args.len) {
208 try stderr.write("expected [auto|on|off] after --color\n");
209 process.exit(1);
210 }
211 i += 1;
212 const next_arg = args[i];
213 if (mem.eql(u8, next_arg, "auto")) {
214 color = .Auto;
215 } else if (mem.eql(u8, next_arg, "on")) {
216 color = .On;
217 } else if (mem.eql(u8, next_arg, "off")) {
218 color = .Off;
219 } else {
220 try stderr.print("expected [auto|on|off] after --color, found '{}'\n", .{next_arg});
221 process.exit(1);
222 }
223 } else if (mem.eql(u8, arg, "--stdin")) {
224 stdin_flag = true;
225 } else if (mem.eql(u8, arg, "--check")) {
226 check_flag = true;
227 } else {
228 try stderr.print("unrecognized parameter: '{}'", .{arg});
229 process.exit(1);
230 }
231 } else {
232 try input_files.append(arg);
233 }
234 }
235 }
236
237 if (stdin_flag) {
238 if (input_files.len != 0) {
239 try stderr.write("cannot use --stdin with positional arguments\n");
240 process.exit(1);
241 }
242
243 const stdin_file = io.getStdIn();
244 var stdin = stdin_file.inStream();
245
246 const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size);
247 defer allocator.free(source_code);
248
249 const tree = std.zig.parse(allocator, source_code) catch |err| {
250 try stderr.print("error parsing stdin: {}\n", .{err});
251 process.exit(1);
252 };
253 defer tree.deinit();
254
255 var error_it = tree.errors.iterator(0);
256 while (error_it.next()) |parse_error| {
257 try printErrMsgToFile(allocator, parse_error, tree, "<stdin>", stderr_file, color);
258 }
259 if (tree.errors.len != 0) {
260 process.exit(1);
261 }
262 if (check_flag) {
263 const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree);
264 const code = if (anything_changed) @as(u8, 1) else @as(u8, 0);
265 process.exit(code);
266 }
267
268 _ = try std.zig.render(allocator, stdout, tree);
269 return;
270 }
271
272 if (input_files.len == 0) {
273 try stderr.write("expected at least one source file argument\n");
274 process.exit(1);
275 }
276
277 var fmt = Fmt{
278 .seen = Fmt.SeenMap.init(allocator),
279 .any_error = false,
280 .color = color,
281 .allocator = allocator,
282 };
283
284 for (input_files.toSliceConst()) |file_path| {
285 try fmtPath(&fmt, file_path, check_flag);
286 }
287 if (fmt.any_error) {
288 process.exit(1);
289 }
290}
291
292const FmtError = error{
293 SystemResources,
294 OperationAborted,
295 IoPending,
296 BrokenPipe,
297 Unexpected,
298 WouldBlock,
299 FileClosed,
300 DestinationAddressRequired,
301 DiskQuota,
302 FileTooBig,
303 InputOutput,
304 NoSpaceLeft,
305 AccessDenied,
306 OutOfMemory,
307 RenameAcrossMountPoints,
308 ReadOnlyFileSystem,
309 LinkQuotaExceeded,
310 FileBusy,
311} || fs.File.OpenError;
312
313fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
314 if (fmt.seen.exists(file_path)) return;
315 try fmt.seen.put(file_path);
316
317 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {
318 error.IsDir, error.AccessDenied => {
319 // TODO make event based (and dir.next())
320 var dir = try fs.cwd().openDirList(file_path);
321 defer dir.close();
322
323 var dir_it = dir.iterate();
324
325 while (try dir_it.next()) |entry| {
326 if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) {
327 const full_path = try fs.path.join(fmt.allocator, &[_][]const u8{ file_path, entry.name });
328 try fmtPath(fmt, full_path, check_mode);
329 }
330 }
331 return;
332 },
333 else => {
334 // TODO lock stderr printing
335 try stderr.print("unable to open '{}': {}\n", .{ file_path, err });
336 fmt.any_error = true;
337 return;
338 },
339 };
340 defer fmt.allocator.free(source_code);
341
342 const tree = std.zig.parse(fmt.allocator, source_code) catch |err| {
343 try stderr.print("error parsing file '{}': {}\n", .{ file_path, err });
344 fmt.any_error = true;
345 return;
346 };
347 defer tree.deinit();
348
349 var error_it = tree.errors.iterator(0);
350 while (error_it.next()) |parse_error| {
351 try printErrMsgToFile(fmt.allocator, parse_error, tree, file_path, stderr_file, fmt.color);
352 }
353 if (tree.errors.len != 0) {
354 fmt.any_error = true;
355 return;
356 }
357
358 if (check_mode) {
359 const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, tree);
360 if (anything_changed) {
361 try stderr.print("{}\n", .{file_path});
362 fmt.any_error = true;
363 }
364 } else {
365 const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path);
366 defer baf.destroy();
367
368 const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), tree);
369 if (anything_changed) {
370 try stderr.print("{}\n", .{file_path});
371 try baf.finish();
372 }
373 }
374}
375
376const Fmt = struct {
377 seen: SeenMap,
378 any_error: bool,
379 color: errmsg.Color,
380 allocator: *mem.Allocator,
381
382 const SeenMap = std.BufSet;
383};
384
385fn printErrMsgToFile(
386 allocator: *mem.Allocator,
387 parse_error: *const ast.Error,
388 tree: *ast.Tree,
389 path: []const u8,
390 file: fs.File,
391 color: errmsg.Color,
392) !void {
393 const color_on = switch (color) {
394 .Auto => file.isTty(),
395 .On => true,
396 .Off => false,
397 };
398 const lok_token = parse_error.loc();
399 const span = errmsg.Span{
400 .first = lok_token,
401 .last = lok_token,
402 };
403
404 const first_token = tree.tokens.at(span.first);
405 const last_token = tree.tokens.at(span.last);
406 const start_loc = tree.tokenLocationPtr(0, first_token);
407 const end_loc = tree.tokenLocationPtr(first_token.end, last_token);
408
409 var text_buf = try std.Buffer.initSize(allocator, 0);
410 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
411 try parse_error.render(&tree.tokens, out_stream);
412 const text = text_buf.toOwnedSlice();
413
414 const stream = &file.outStream().stream;
415 try stream.print("{}:{}:{}: error: {}\n", .{ path, start_loc.line + 1, start_loc.column + 1, text });
416
417 if (!color_on) return;
418
419 // Print \r and \t as one space each so that column counts line up
420 for (tree.source[start_loc.line_start..start_loc.line_end]) |byte| {
421 try stream.writeByte(switch (byte) {
422 '\r', '\t' => ' ',
423 else => byte,
424 });
425 }
426 try stream.writeByte('\n');
427 try stream.writeByteNTimes(' ', start_loc.column);
428 try stream.writeByteNTimes('~', last_token.end - first_token.start);
429 try stream.writeByte('\n');
430}
431
432export fn stage2_DepTokenizer_init(input: [*]const u8, len: usize) stage2_DepTokenizer {
433 const t = std.heap.c_allocator.create(DepTokenizer) catch @panic("failed to create .d tokenizer");
434 t.* = DepTokenizer.init(std.heap.c_allocator, input[0..len]);
435 return stage2_DepTokenizer{
436 .handle = t,
437 };
438}
439
440export fn stage2_DepTokenizer_deinit(self: *stage2_DepTokenizer) void {
441 self.handle.deinit();
442}
443
444export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextResult {
445 const otoken = self.handle.next() catch {
446 const textz = std.Buffer.init(&self.handle.arena.allocator, self.handle.error_text) catch @panic("failed to create .d tokenizer error text");
447 return stage2_DepNextResult{
448 .type_id = .error_,
449 .textz = textz.toSlice().ptr,
450 };
451 };
452 const token = otoken orelse {
453 return stage2_DepNextResult{
454 .type_id = .null_,
455 .textz = undefined,
456 };
457 };
458 const textz = std.Buffer.init(&self.handle.arena.allocator, token.bytes) catch @panic("failed to create .d tokenizer token text");
459 return stage2_DepNextResult{
460 .type_id = switch (token.id) {
461 .target => .target,
462 .prereq => .prereq,
463 },
464 .textz = textz.toSlice().ptr,
465 };
466}
467
468const stage2_DepTokenizer = extern struct {
469 handle: *DepTokenizer,
470};
471
472const stage2_DepNextResult = extern struct {
473 type_id: TypeId,
474
475 // when type_id == error --> error text
476 // when type_id == null --> undefined
477 // when type_id == target --> target pathname
478 // when type_id == prereq --> prereq pathname
479 textz: [*]const u8,
480
481 const TypeId = extern enum {
482 error_,
483 null_,
484 target,
485 prereq,
486 };
487};
488
489// ABI warning
490export fn stage2_attach_segfault_handler() void {
491 if (std.debug.runtime_safety and std.debug.have_segfault_handling_support) {
492 std.debug.attachSegfaultHandler();
493 }
494}
495
496// ABI warning
497export fn stage2_progress_create() *std.Progress {
498 const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory");
499 ptr.* = std.Progress{};
500 return ptr;
501}
502
503// ABI warning
504export fn stage2_progress_destroy(progress: *std.Progress) void {
505 std.heap.c_allocator.destroy(progress);
506}
507
508// ABI warning
509export fn stage2_progress_start_root(
510 progress: *std.Progress,
511 name_ptr: [*]const u8,
512 name_len: usize,
513 estimated_total_items: usize,
514) *std.Progress.Node {
515 return progress.start(
516 name_ptr[0..name_len],
517 if (estimated_total_items == 0) null else estimated_total_items,
518 ) catch @panic("timer unsupported");
519}
520
521// ABI warning
522export fn stage2_progress_disable_tty(progress: *std.Progress) void {
523 progress.terminal = null;
524}
525
526// ABI warning
527export fn stage2_progress_start(
528 node: *std.Progress.Node,
529 name_ptr: [*]const u8,
530 name_len: usize,
531 estimated_total_items: usize,
532) *std.Progress.Node {
533 const child_node = std.heap.c_allocator.create(std.Progress.Node) catch @panic("out of memory");
534 child_node.* = node.start(
535 name_ptr[0..name_len],
536 if (estimated_total_items == 0) null else estimated_total_items,
537 );
538 child_node.activate();
539 return child_node;
540}
541
542// ABI warning
543export fn stage2_progress_end(node: *std.Progress.Node) void {
544 node.end();
545 if (&node.context.root != node) {
546 std.heap.c_allocator.destroy(node);
547 }
548}
549
550// ABI warning
551export fn stage2_progress_complete_one(node: *std.Progress.Node) void {
552 node.completeOne();
553}
554
555// ABI warning
556export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usize, total_count: usize) void {
557 node.completed_items = done_count;
558 node.estimated_total_items = total_count;
559 node.activate();
560 node.context.maybeRefresh();
561}
562
563fn cpuFeaturesFromLLVM(
564 arch: Target.Arch,
565 llvm_cpu_name_z: ?[*:0]const u8,
566 llvm_cpu_features_opt: ?[*:0]const u8,
567) !Target.CpuFeatures {
568 var result = arch.getBaselineCpuFeatures();
569
570 if (llvm_cpu_name_z) |cpu_name_z| {
571 const llvm_cpu_name = mem.toSliceConst(u8, cpu_name_z);
572
573 for (arch.allCpus()) |cpu| {
574 const this_llvm_name = cpu.llvm_name orelse continue;
575 if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
576 // Here we use the non-dependencies-populated set,
577 // so that subtracting features later in this function
578 // affect the prepopulated set.
579 result = Target.CpuFeatures{
580 .cpu = cpu,
581 .features = cpu.features,
582 };
583 break;
584 }
585 }
586 }
587
588 const all_features = arch.allFeaturesList();
589
590 if (llvm_cpu_features_opt) |llvm_cpu_features| {
591 var it = mem.tokenize(mem.toSliceConst(u8, llvm_cpu_features), ",");
592 while (it.next()) |decorated_llvm_feat| {
593 var op: enum {
594 add,
595 sub,
596 } = undefined;
597 var llvm_feat: []const u8 = undefined;
598 if (mem.startsWith(u8, decorated_llvm_feat, "+")) {
599 op = .add;
600 llvm_feat = decorated_llvm_feat[1..];
601 } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) {
602 op = .sub;
603 llvm_feat = decorated_llvm_feat[1..];
604 } else {
605 return error.InvalidLlvmCpuFeaturesFormat;
606 }
607 for (all_features) |feature, index_usize| {
608 const this_llvm_name = feature.llvm_name orelse continue;
609 if (mem.eql(u8, llvm_feat, this_llvm_name)) {
610 const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
611 switch (op) {
612 .add => result.features.addFeature(index),
613 .sub => result.features.removeFeature(index),
614 }
615 break;
616 }
617 }
618 }
619 }
620
621 result.features.populateDependencies(all_features);
622 return result;
623}
624
625// ABI warning
626export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int {
627 cmdTargets(zig_triple) catch |err| {
628 std.debug.warn("unable to list targets: {}\n", .{@errorName(err)});
629 return -1;
630 };
631 return 0;
632}
633
634fn cmdTargets(zig_triple: [*:0]const u8) !void {
635 var target = try Target.parse(mem.toSliceConst(u8, zig_triple));
636 target.Cross.cpu_features = blk: {
637 const llvm = @import("llvm.zig");
638 const llvm_cpu_name = llvm.GetHostCPUName();
639 const llvm_cpu_features = llvm.GetNativeFeatures();
640 break :blk try cpuFeaturesFromLLVM(target.Cross.arch, llvm_cpu_name, llvm_cpu_features);
641 };
642 return @import("print_targets.zig").cmdTargets(
643 std.heap.c_allocator,
644 &[0][]u8{},
645 &std.io.getStdOut().outStream().stream,
646 target,
647 );
648}
649
650const Stage2CpuFeatures = struct {
651 allocator: *mem.Allocator,
652 cpu_features: Target.CpuFeatures,
653
654 llvm_features_str: ?[*:0]const u8,
655
656 builtin_str: [:0]const u8,
657 cache_hash: [:0]const u8,
658
659 const Self = @This();
660
661 fn createFromNative(allocator: *mem.Allocator) !*Self {
662 const arch = Target.current.getArch();
663 const llvm = @import("llvm.zig");
664 const llvm_cpu_name = llvm.GetHostCPUName();
665 const llvm_cpu_features = llvm.GetNativeFeatures();
666 const cpu_features = try cpuFeaturesFromLLVM(arch, llvm_cpu_name, llvm_cpu_features);
667 return createFromCpuFeatures(allocator, arch, cpu_features);
668 }
669
670 fn createFromCpuFeatures(
671 allocator: *mem.Allocator,
672 arch: Target.Arch,
673 cpu_features: Target.CpuFeatures,
674 ) !*Self {
675 const self = try allocator.create(Self);
676 errdefer allocator.destroy(self);
677
678 const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{}", .{
679 cpu_features.cpu.name,
680 cpu_features.features.asBytes(),
681 });
682 errdefer allocator.free(cache_hash);
683
684 const generic_arch_name = arch.genericName();
685 var builtin_str_buffer = try std.Buffer.allocPrint(allocator,
686 \\CpuFeatures{{
687 \\ .cpu = &Target.{}.cpu.{},
688 \\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
689 \\
690 , .{
691 generic_arch_name,
692 cpu_features.cpu.name,
693 generic_arch_name,
694 generic_arch_name,
695 });
696 defer builtin_str_buffer.deinit();
697
698 var llvm_features_buffer = try std.Buffer.initSize(allocator, 0);
699 defer llvm_features_buffer.deinit();
700
701 for (arch.allFeaturesList()) |feature, index_usize| {
702 const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
703 const is_enabled = cpu_features.features.isEnabled(index);
704
705 if (feature.llvm_name) |llvm_name| {
706 const plus_or_minus = "-+"[@boolToInt(is_enabled)];
707 try llvm_features_buffer.appendByte(plus_or_minus);
708 try llvm_features_buffer.append(llvm_name);
709 try llvm_features_buffer.append(",");
710 }
711
712 if (is_enabled) {
713 // TODO some kind of "zig identifier escape" function rather than
714 // unconditionally using @"" syntax
715 try builtin_str_buffer.append(" .@\"");
716 try builtin_str_buffer.append(feature.name);
717 try builtin_str_buffer.append("\",\n");
718 }
719 }
720
721 try builtin_str_buffer.append(
722 \\ }),
723 \\};
724 \\
725 );
726
727 assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ","));
728 llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
729
730 self.* = Self{
731 .allocator = allocator,
732 .cpu_features = cpu_features,
733 .llvm_features_str = llvm_features_buffer.toOwnedSlice().ptr,
734 .builtin_str = builtin_str_buffer.toOwnedSlice(),
735 .cache_hash = cache_hash,
736 };
737 return self;
738 }
739
740 fn destroy(self: *Self) void {
741 self.allocator.free(self.cache_hash);
742 self.allocator.free(self.builtin_str);
743 // TODO if (self.llvm_features_str) |llvm_features_str| self.allocator.free(llvm_features_str);
744 self.allocator.destroy(self);
745 }
746};
747
748// ABI warning
749export fn stage2_cpu_features_parse(
750 result: **Stage2CpuFeatures,
751 zig_triple: ?[*:0]const u8,
752 cpu_name: ?[*:0]const u8,
753 cpu_features: ?[*:0]const u8,
754) Error {
755 result.* = stage2ParseCpuFeatures(zig_triple, cpu_name, cpu_features) catch |err| switch (err) {
756 error.OutOfMemory => return .OutOfMemory,
757 error.UnknownArchitecture => return .UnknownArchitecture,
758 error.UnknownSubArchitecture => return .UnknownSubArchitecture,
759 error.UnknownOperatingSystem => return .UnknownOperatingSystem,
760 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
761 error.MissingOperatingSystem => return .MissingOperatingSystem,
762 error.MissingArchitecture => return .MissingArchitecture,
763 error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
764 error.InvalidCpuFeatures => return .InvalidCpuFeatures,
765 };
766 return .None;
767}
768
769fn stage2ParseCpuFeatures(
770 zig_triple_oz: ?[*:0]const u8,
771 cpu_name_oz: ?[*:0]const u8,
772 cpu_features_oz: ?[*:0]const u8,
773) !*Stage2CpuFeatures {
774 const zig_triple_z = zig_triple_oz orelse return Stage2CpuFeatures.createFromNative(std.heap.c_allocator);
775 const target = try Target.parse(mem.toSliceConst(u8, zig_triple_z));
776 const arch = target.Cross.arch;
777
778 const cpu = if (cpu_name_oz) |cpu_name_z| blk: {
779 const cpu_name = mem.toSliceConst(u8, cpu_name_z);
780 break :blk arch.parseCpu(cpu_name) catch |err| switch (err) {
781 error.UnknownCpu => {
782 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
783 cpu_name,
784 @tagName(arch),
785 });
786 for (arch.allCpus()) |cpu| {
787 std.debug.warn(" {}\n", .{cpu.name});
788 }
789 process.exit(1);
790 },
791 else => |e| return e,
792 };
793 } else target.Cross.cpu_features.cpu;
794
795 var set = if (cpu_features_oz) |cpu_features_z| blk: {
796 const cpu_features = mem.toSliceConst(u8, cpu_features_z);
797 break :blk arch.parseCpuFeatureSet(cpu, cpu_features) catch |err| switch (err) {
798 error.UnknownCpuFeature => {
799 std.debug.warn(
800 \\Unknown CPU features specified.
801 \\Available CPU features for architecture '{}':
802 \\
803 , .{@tagName(arch)});
804 for (arch.allFeaturesList()) |feature| {
805 std.debug.warn(" {}\n", .{feature.name});
806 }
807 process.exit(1);
808 },
809 else => |e| return e,
810 };
811 } else cpu.features;
812
813 if (arch.subArchFeature()) |index| {
814 set.addFeature(index);
815 }
816 set.populateDependencies(arch.allFeaturesList());
817
818 return Stage2CpuFeatures.createFromCpuFeatures(std.heap.c_allocator, arch, .{
819 .cpu = cpu,
820 .features = set,
821 });
822}
823
824// ABI warning
825export fn stage2_cpu_features_get_cache_hash(
826 cpu_features: *const Stage2CpuFeatures,
827 ptr: *[*:0]const u8,
828 len: *usize,
829) void {
830 ptr.* = cpu_features.cache_hash.ptr;
831 len.* = cpu_features.cache_hash.len;
832}
833
834// ABI warning
835export fn stage2_cpu_features_get_builtin_str(
836 cpu_features: *const Stage2CpuFeatures,
837 ptr: *[*:0]const u8,
838 len: *usize,
839) void {
840 ptr.* = cpu_features.builtin_str.ptr;
841 len.* = cpu_features.builtin_str.len;
842}
843
844// ABI warning
845export fn stage2_cpu_features_get_llvm_cpu(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 {
846 return if (cpu_features.cpu_features.cpu.llvm_name) |s| s.ptr else null;
847}
848
849// ABI warning
850export fn stage2_cpu_features_get_llvm_features(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 {
851 return cpu_features.llvm_features_str;
852}
853
854// ABI warning
855const Stage2LibCInstallation = extern struct {
856 include_dir: [*:0]const u8,
857 include_dir_len: usize,
858 sys_include_dir: [*:0]const u8,
859 sys_include_dir_len: usize,
860 crt_dir: [*:0]const u8,
861 crt_dir_len: usize,
862 static_crt_dir: [*:0]const u8,
863 static_crt_dir_len: usize,
864 msvc_lib_dir: [*:0]const u8,
865 msvc_lib_dir_len: usize,
866 kernel32_lib_dir: [*:0]const u8,
867 kernel32_lib_dir_len: usize,
868
869 fn initFromStage2(self: *Stage2LibCInstallation, libc: LibCInstallation) void {
870 if (libc.include_dir) |s| {
871 self.include_dir = s.ptr;
872 self.include_dir_len = s.len;
873 } else {
874 self.include_dir = "";
875 self.include_dir_len = 0;
876 }
877 if (libc.sys_include_dir) |s| {
878 self.sys_include_dir = s.ptr;
879 self.sys_include_dir_len = s.len;
880 } else {
881 self.sys_include_dir = "";
882 self.sys_include_dir_len = 0;
883 }
884 if (libc.crt_dir) |s| {
885 self.crt_dir = s.ptr;
886 self.crt_dir_len = s.len;
887 } else {
888 self.crt_dir = "";
889 self.crt_dir_len = 0;
890 }
891 if (libc.static_crt_dir) |s| {
892 self.static_crt_dir = s.ptr;
893 self.static_crt_dir_len = s.len;
894 } else {
895 self.static_crt_dir = "";
896 self.static_crt_dir_len = 0;
897 }
898 if (libc.msvc_lib_dir) |s| {
899 self.msvc_lib_dir = s.ptr;
900 self.msvc_lib_dir_len = s.len;
901 } else {
902 self.msvc_lib_dir = "";
903 self.msvc_lib_dir_len = 0;
904 }
905 if (libc.kernel32_lib_dir) |s| {
906 self.kernel32_lib_dir = s.ptr;
907 self.kernel32_lib_dir_len = s.len;
908 } else {
909 self.kernel32_lib_dir = "";
910 self.kernel32_lib_dir_len = 0;
911 }
912 }
913
914 fn toStage2(self: Stage2LibCInstallation) LibCInstallation {
915 var libc: LibCInstallation = .{};
916 if (self.include_dir_len != 0) {
917 libc.include_dir = self.include_dir[0..self.include_dir_len :0];
918 }
919 if (self.sys_include_dir_len != 0) {
920 libc.sys_include_dir = self.sys_include_dir[0..self.sys_include_dir_len :0];
921 }
922 if (self.crt_dir_len != 0) {
923 libc.crt_dir = self.crt_dir[0..self.crt_dir_len :0];
924 }
925 if (self.static_crt_dir_len != 0) {
926 libc.static_crt_dir = self.static_crt_dir[0..self.static_crt_dir_len :0];
927 }
928 if (self.msvc_lib_dir_len != 0) {
929 libc.msvc_lib_dir = self.msvc_lib_dir[0..self.msvc_lib_dir_len :0];
930 }
931 if (self.kernel32_lib_dir_len != 0) {
932 libc.kernel32_lib_dir = self.kernel32_lib_dir[0..self.kernel32_lib_dir_len :0];
933 }
934 return libc;
935 }
936};
937
938// ABI warning
939export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [*:0]const u8) Error {
940 stderr_file = std.io.getStdErr();
941 stderr = &stderr_file.outStream().stream;
942 const libc_file = mem.toSliceConst(u8, libc_file_z);
943 var libc = LibCInstallation.parse(std.heap.c_allocator, libc_file, stderr) catch |err| switch (err) {
944 error.ParseError => return .SemanticAnalyzeFail,
945 error.DiskQuota => return .DiskQuota,
946 error.FileTooBig => return .FileTooBig,
947 error.InputOutput => return .FileSystem,
948 error.NoSpaceLeft => return .NoSpaceLeft,
949 error.AccessDenied => return .AccessDenied,
950 error.BrokenPipe => return .BrokenPipe,
951 error.SystemResources => return .SystemResources,
952 error.OperationAborted => return .OperationAborted,
953 error.WouldBlock => unreachable,
954 error.Unexpected => return .Unexpected,
955 error.EndOfStream => return .EndOfFile,
956 error.IsDir => return .IsDir,
957 error.ConnectionResetByPeer => unreachable,
958 error.OutOfMemory => return .OutOfMemory,
959 error.Unseekable => unreachable,
960 error.SharingViolation => return .SharingViolation,
961 error.PathAlreadyExists => unreachable,
962 error.FileNotFound => return .FileNotFound,
963 error.PipeBusy => return .PipeBusy,
964 error.NameTooLong => return .PathTooLong,
965 error.InvalidUtf8 => return .BadPathName,
966 error.BadPathName => return .BadPathName,
967 error.SymLinkLoop => return .SymLinkLoop,
968 error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded,
969 error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded,
970 error.NoDevice => return .NoDevice,
971 error.NotDir => return .NotDir,
972 error.DeviceBusy => return .DeviceBusy,
973 };
974 stage1_libc.initFromStage2(libc);
975 return .None;
976}
977
978// ABI warning
979export fn stage2_libc_find_native(stage1_libc: *Stage2LibCInstallation) Error {
980 var libc = LibCInstallation.findNative(std.heap.c_allocator) catch |err| switch (err) {
981 error.OutOfMemory => return .OutOfMemory,
982 error.FileSystem => return .FileSystem,
983 error.UnableToSpawnCCompiler => return .UnableToSpawnCCompiler,
984 error.CCompilerExitCode => return .CCompilerExitCode,
985 error.CCompilerCrashed => return .CCompilerCrashed,
986 error.CCompilerCannotFindHeaders => return .CCompilerCannotFindHeaders,
987 error.LibCRuntimeNotFound => return .LibCRuntimeNotFound,
988 error.LibCStdLibHeaderNotFound => return .LibCStdLibHeaderNotFound,
989 error.LibCKernel32LibNotFound => return .LibCKernel32LibNotFound,
990 error.UnsupportedArchitecture => return .UnsupportedArchitecture,
991 error.WindowsSdkNotFound => return .WindowsSdkNotFound,
992 };
993 stage1_libc.initFromStage2(libc);
994 return .None;
995}
996
997// ABI warning
998export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: *FILE) Error {
999 var libc = stage1_libc.toStage2();
1000 const c_out_stream = &std.io.COutStream.init(output_file).stream;
1001 libc.render(c_out_stream) catch |err| switch (err) {
1002 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
1003 error.SystemResources => return .SystemResources,
1004 error.OperationAborted => return .OperationAborted,
1005 error.BrokenPipe => return .BrokenPipe,
1006 error.DiskQuota => return .DiskQuota,
1007 error.FileTooBig => return .FileTooBig,
1008 error.NoSpaceLeft => return .NoSpaceLeft,
1009 error.AccessDenied => return .AccessDenied,
1010 error.Unexpected => return .Unexpected,
1011 error.InputOutput => return .FileSystem,
1012 };
1013 return .None;
1014}
1015
1016// ABI warning
1017const Stage2Target = extern struct {
1018 arch: c_int,
1019 sub_arch: c_int,
1020 vendor: c_int,
1021 os: c_int,
1022 abi: c_int,
1023 glibc_version: ?*Stage2GLibCVersion, // null means default
1024 cpu_features: *Stage2CpuFeatures,
1025 is_native: bool,
1026};
1027
1028// ABI warning
1029const Stage2GLibCVersion = extern struct {
1030 major: u32,
1031 minor: u32,
1032 patch: u32,
1033};
1034
1035// ABI warning
1036export fn stage2_detect_dynamic_linker(in_target: *const Stage2Target, out_ptr: *[*:0]u8, out_len: *usize) Error {
1037 const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch
1038 const in_sub_arch = in_target.sub_arch - 1; // skip over ZigLLVM_NoSubArch
1039 const in_os = in_target.os;
1040 const in_abi = in_target.abi - 1; // skip over ZigLLVM_UnknownEnvironment
1041 const target: Target = if (in_target.is_native) .Native else .{
1042 .Cross = .{
1043 .arch = switch (enumInt(@TagType(Target.Arch), in_arch)) {
1044 .arm => .{ .arm = enumInt(Target.Arch.Arm32, in_sub_arch) },
1045 .armeb => .{ .armeb = enumInt(Target.Arch.Arm32, in_sub_arch) },
1046 .thumb => .{ .thumb = enumInt(Target.Arch.Arm32, in_sub_arch) },
1047 .thumbeb => .{ .thumbeb = enumInt(Target.Arch.Arm32, in_sub_arch) },
1048
1049 .aarch64 => .{ .aarch64 = enumInt(Target.Arch.Arm64, in_sub_arch) },
1050 .aarch64_be => .{ .aarch64_be = enumInt(Target.Arch.Arm64, in_sub_arch) },
1051 .aarch64_32 => .{ .aarch64_32 = enumInt(Target.Arch.Arm64, in_sub_arch) },
1052
1053 .kalimba => .{ .kalimba = enumInt(Target.Arch.Kalimba, in_sub_arch) },
1054
1055 .arc => .arc,
1056 .avr => .avr,
1057 .bpfel => .bpfel,
1058 .bpfeb => .bpfeb,
1059 .hexagon => .hexagon,
1060 .mips => .mips,
1061 .mipsel => .mipsel,
1062 .mips64 => .mips64,
1063 .mips64el => .mips64el,
1064 .msp430 => .msp430,
1065 .powerpc => .powerpc,
1066 .powerpc64 => .powerpc64,
1067 .powerpc64le => .powerpc64le,
1068 .r600 => .r600,
1069 .amdgcn => .amdgcn,
1070 .riscv32 => .riscv32,
1071 .riscv64 => .riscv64,
1072 .sparc => .sparc,
1073 .sparcv9 => .sparcv9,
1074 .sparcel => .sparcel,
1075 .s390x => .s390x,
1076 .tce => .tce,
1077 .tcele => .tcele,
1078 .i386 => .i386,
1079 .x86_64 => .x86_64,
1080 .xcore => .xcore,
1081 .nvptx => .nvptx,
1082 .nvptx64 => .nvptx64,
1083 .le32 => .le32,
1084 .le64 => .le64,
1085 .amdil => .amdil,
1086 .amdil64 => .amdil64,
1087 .hsail => .hsail,
1088 .hsail64 => .hsail64,
1089 .spir => .spir,
1090 .spir64 => .spir64,
1091 .shave => .shave,
1092 .lanai => .lanai,
1093 .wasm32 => .wasm32,
1094 .wasm64 => .wasm64,
1095 .renderscript32 => .renderscript32,
1096 .renderscript64 => .renderscript64,
1097 },
1098 .os = enumInt(Target.Os, in_os),
1099 .abi = enumInt(Target.Abi, in_abi),
1100 .cpu_features = in_target.cpu_features.cpu_features,
1101 },
1102 };
1103 const result = @import("introspect.zig").detectDynamicLinker(
1104 std.heap.c_allocator,
1105 target,
1106 ) catch |err| switch (err) {
1107 error.OutOfMemory => return .OutOfMemory,
1108 error.UnknownDynamicLinkerPath => return .UnknownDynamicLinkerPath,
1109 error.TargetHasNoDynamicLinker => return .TargetHasNoDynamicLinker,
1110 };
1111 out_ptr.* = result.ptr;
1112 out_len.* = result.len;
1113 return .None;
1114}
1115
1116fn enumInt(comptime Enum: type, int: c_int) Enum {
1117 return @intToEnum(Enum, @intCast(@TagType(Enum), int));
1118}
src-self-hosted/util.zig-137
...@@ -2,143 +2,6 @@ const std = @import("std");...@@ -2,143 +2,6 @@ const std = @import("std");
2const Target = std.Target;2const Target = std.Target;
3const llvm = @import("llvm.zig");3const llvm = @import("llvm.zig");
44
5pub const FloatAbi = enum {
6 Hard,
7 Soft,
8 SoftFp,
9};
10
11/// TODO expose the arch and subarch separately
12pub fn isArmOrThumb(self: Target) bool {
13 return switch (self.getArch()) {
14 .arm,
15 .armeb,
16 .aarch64,
17 .aarch64_be,
18 .thumb,
19 .thumbeb,
20 => true,
21 else => false,
22 };
23}
24
25pub fn getFloatAbi(self: Target) FloatAbi {
26 return switch (self.getAbi()) {
27 .gnueabihf,
28 .eabihf,
29 .musleabihf,
30 => .Hard,
31 else => .Soft,
32 };
33}
34
35pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
36 const env = self.getAbi();
37 const arch = self.getArch();
38 const os = self.getOs();
39 switch (os) {
40 .freebsd => {
41 return "/libexec/ld-elf.so.1";
42 },
43 .linux => {
44 switch (env) {
45 .android => {
46 if (self.getArchPtrBitWidth() == 64) {
47 return "/system/bin/linker64";
48 } else {
49 return "/system/bin/linker";
50 }
51 },
52 .gnux32 => {
53 if (arch == .x86_64) {
54 return "/libx32/ld-linux-x32.so.2";
55 }
56 },
57 .musl,
58 .musleabi,
59 .musleabihf,
60 => {
61 if (arch == .x86_64) {
62 return "/lib/ld-musl-x86_64.so.1";
63 }
64 },
65 else => {},
66 }
67 switch (arch) {
68 .i386,
69 .sparc,
70 .sparcel,
71 => return "/lib/ld-linux.so.2",
72
73 .aarch64 => return "/lib/ld-linux-aarch64.so.1",
74
75 .aarch64_be => return "/lib/ld-linux-aarch64_be.so.1",
76
77 .arm,
78 .thumb,
79 => return switch (getFloatAbi(self)) {
80 .Hard => return "/lib/ld-linux-armhf.so.3",
81 else => return "/lib/ld-linux.so.3",
82 },
83
84 .armeb,
85 .thumbeb,
86 => return switch (getFloatAbi(self)) {
87 .Hard => return "/lib/ld-linux-armhf.so.3",
88 else => return "/lib/ld-linux.so.3",
89 },
90
91 .mips,
92 .mipsel,
93 .mips64,
94 .mips64el,
95 => return null,
96
97 .powerpc => return "/lib/ld.so.1",
98 .powerpc64 => return "/lib64/ld64.so.2",
99 .powerpc64le => return "/lib64/ld64.so.2",
100 .s390x => return "/lib64/ld64.so.1",
101 .sparcv9 => return "/lib64/ld-linux.so.2",
102 .x86_64 => return "/lib64/ld-linux-x86-64.so.2",
103
104 .arc,
105 .avr,
106 .bpfel,
107 .bpfeb,
108 .hexagon,
109 .msp430,
110 .r600,
111 .amdgcn,
112 .riscv32,
113 .riscv64,
114 .tce,
115 .tcele,
116 .xcore,
117 .nvptx,
118 .nvptx64,
119 .le32,
120 .le64,
121 .amdil,
122 .amdil64,
123 .hsail,
124 .hsail64,
125 .spir,
126 .spir64,
127 .kalimba,
128 .shave,
129 .lanai,
130 .wasm32,
131 .wasm64,
132 .renderscript32,
133 .renderscript64,
134 .aarch64_32,
135 => return null,
136 }
137 },
138 else => return null,
139 }
140}
141
142pub fn getDarwinArchString(self: Target) [:0]const u8 {5pub fn getDarwinArchString(self: Target) [:0]const u8 {
143 const arch = self.getArch();6 const arch = self.getArch();
144 switch (arch) {7 switch (arch) {
src-self-hosted/windows_sdk.zig created+22
...@@ -0,0 +1,22 @@
1// C API bindings for src/windows_sdk.h
2
3pub const ZigWindowsSDK = extern struct {
4 path10_ptr: ?[*]const u8,
5 path10_len: usize,
6 version10_ptr: ?[*]const u8,
7 version10_len: usize,
8 path81_ptr: ?[*]const u8,
9 path81_len: usize,
10 version81_ptr: ?[*]const u8,
11 version81_len: usize,
12 msvc_lib_dir_ptr: ?[*]const u8,
13 msvc_lib_dir_len: usize,
14};
15pub const ZigFindWindowsSdkError = extern enum {
16 None,
17 OutOfMemory,
18 NotFound,
19 PathTooLong,
20};
21pub extern fn zig_find_windows_sdk(out_sdk: **ZigWindowsSDK) ZigFindWindowsSdkError;
22pub extern fn zig_free_windows_sdk(sdk: *ZigWindowsSDK) void;
src/all_types.hpp+2-3
...@@ -18,7 +18,6 @@...@@ -18,7 +18,6 @@
18#include "bigfloat.hpp"18#include "bigfloat.hpp"
19#include "target.hpp"19#include "target.hpp"
20#include "tokenizer.hpp"20#include "tokenizer.hpp"
21#include "libc_installation.hpp"
2221
23struct AstNode;22struct AstNode;
24struct ZigFn;23struct ZigFn;
...@@ -2139,7 +2138,7 @@ struct CodeGen {...@@ -2139,7 +2138,7 @@ struct CodeGen {
2139 // As an input parameter, mutually exclusive with enable_cache. But it gets2138 // As an input parameter, mutually exclusive with enable_cache. But it gets
2140 // populated in codegen_build_and_link.2139 // populated in codegen_build_and_link.
2141 Buf *output_dir;2140 Buf *output_dir;
2142 Buf **libc_include_dir_list;2141 const char **libc_include_dir_list;
2143 size_t libc_include_dir_len;2142 size_t libc_include_dir_len;
21442143
2145 Buf *zig_c_headers_dir; // Cannot be overridden; derived from zig_lib_dir.2144 Buf *zig_c_headers_dir; // Cannot be overridden; derived from zig_lib_dir.
...@@ -2220,7 +2219,7 @@ struct CodeGen {...@@ -2220,7 +2219,7 @@ struct CodeGen {
2220 ZigList<const char *> lib_dirs;2219 ZigList<const char *> lib_dirs;
2221 ZigList<const char *> framework_dirs;2220 ZigList<const char *> framework_dirs;
22222221
2223 ZigLibCInstallation *libc;2222 Stage2LibCInstallation *libc;
22242223
2225 size_t version_major;2224 size_t version_major;
2226 size_t version_minor;2225 size_t version_minor;
src/cache_hash.cpp+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5 * See http://opensource.org/licenses/MIT5 * See http://opensource.org/licenses/MIT
6 */6 */
77
8#include "userland.h"8#include "stage2.h"
9#include "cache_hash.hpp"9#include "cache_hash.hpp"
10#include "all_types.hpp"10#include "all_types.hpp"
11#include "buffer.hpp"11#include "buffer.hpp"
src/codegen.cpp+46-67
...@@ -18,7 +18,7 @@...@@ -18,7 +18,7 @@
18#include "target.hpp"18#include "target.hpp"
19#include "util.hpp"19#include "util.hpp"
20#include "zig_llvm.h"20#include "zig_llvm.h"
21#include "userland.h"21#include "stage2.h"
22#include "dump_analysis.hpp"22#include "dump_analysis.hpp"
23#include "softfloat.hpp"23#include "softfloat.hpp"
24#include "mem_profile.hpp"24#include "mem_profile.hpp"
...@@ -8375,9 +8375,11 @@ static bool detect_dynamic_link(CodeGen *g) {...@@ -8375,9 +8375,11 @@ static bool detect_dynamic_link(CodeGen *g) {
8375 return true;8375 return true;
8376 if (g->zig_target->os == OsFreestanding)8376 if (g->zig_target->os == OsFreestanding)
8377 return false;8377 return false;
8378 if (target_requires_pic(g->zig_target, g->libc_link_lib != nullptr))8378 if (target_os_requires_libc(g->zig_target->os))
8379 return true;
8380 if (g->libc_link_lib != nullptr && target_is_glibc(g->zig_target))
8379 return true;8381 return true;
8380 // If there are no dynamic libraries then we can disable PIC8382 // If there are no dynamic libraries then we can disable dynamic linking.
8381 for (size_t i = 0; i < g->link_libs_list.length; i += 1) {8383 for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
8382 LinkLib *link_lib = g->link_libs_list.at(i);8384 LinkLib *link_lib = g->link_libs_list.at(i);
8383 if (target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name)))8385 if (target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name)))
...@@ -8624,7 +8626,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -8624,7 +8626,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
8624 break;8626 break;
8625 }8627 }
8626 buf_appendf(contents, "pub const output_mode = OutputMode.%s;\n", out_type);8628 buf_appendf(contents, "pub const output_mode = OutputMode.%s;\n", out_type);
8627 const char *link_type = g->is_dynamic ? "Dynamic" : "Static";8629 const char *link_type = g->have_dynamic_link ? "Dynamic" : "Static";
8628 buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type);8630 buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type);
8629 buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));8631 buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
8630 buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));8632 buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
...@@ -8731,7 +8733,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {...@@ -8731,7 +8733,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
8731 cache_int(&cache_hash, g->build_mode);8733 cache_int(&cache_hash, g->build_mode);
8732 cache_bool(&cache_hash, g->strip_debug_symbols);8734 cache_bool(&cache_hash, g->strip_debug_symbols);
8733 cache_int(&cache_hash, g->out_type);8735 cache_int(&cache_hash, g->out_type);
8734 cache_bool(&cache_hash, g->is_dynamic);8736 cache_bool(&cache_hash, detect_dynamic_link(g));
8735 cache_bool(&cache_hash, g->is_test_build);8737 cache_bool(&cache_hash, g->is_test_build);
8736 cache_bool(&cache_hash, g->is_single_threaded);8738 cache_bool(&cache_hash, g->is_single_threaded);
8737 cache_bool(&cache_hash, g->test_is_evented);8739 cache_bool(&cache_hash, g->test_is_evented);
...@@ -8957,6 +8959,8 @@ static void init(CodeGen *g) {...@@ -8957,6 +8959,8 @@ static void init(CodeGen *g) {
8957}8959}
89588960
8959static void detect_dynamic_linker(CodeGen *g) {8961static void detect_dynamic_linker(CodeGen *g) {
8962 Error err;
8963
8960 if (g->dynamic_linker_path != nullptr)8964 if (g->dynamic_linker_path != nullptr)
8961 return;8965 return;
8962 if (!g->have_dynamic_link)8966 if (!g->have_dynamic_link)
...@@ -8964,42 +8968,16 @@ static void detect_dynamic_linker(CodeGen *g) {...@@ -8964,42 +8968,16 @@ static void detect_dynamic_linker(CodeGen *g) {
8964 if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic))8968 if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic))
8965 return;8969 return;
89668970
8967 const char *standard_ld_path = target_dynamic_linker(g->zig_target);8971 char *dynamic_linker_ptr;
8968 if (standard_ld_path == nullptr)8972 size_t dynamic_linker_len;
8969 return;8973 if ((err = stage2_detect_dynamic_linker(g->zig_target, &dynamic_linker_ptr, &dynamic_linker_len))) {
89708974 if (err == ErrorTargetHasNoDynamicLinker) return;
8971 if (g->zig_target->is_native) {8975 fprintf(stderr, "Unable to detect dynamic linker: %s\n", err_str(err));
8972 // target_dynamic_linker is usually correct. However on some systems, such as NixOS8976 exit(1);
8973 // it will be incorrect. See if we can do better by looking at what zig's own
8974 // dynamic linker path is.
8975 g->dynamic_linker_path = get_self_dynamic_linker_path();
8976 if (g->dynamic_linker_path != nullptr)
8977 return;
8978
8979 // If Zig is statically linked, such as via distributed binary static builds, the above
8980 // trick won't work. What are we left with? Try to run the system C compiler and get
8981 // it to tell us the dynamic linker path
8982#if defined(ZIG_OS_LINUX)
8983 {
8984 Error err;
8985 Buf *result = buf_alloc();
8986 for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) {
8987 const char *lib_name = possible_ld_names[i];
8988 if ((err = zig_libc_cc_print_file_name(lib_name, result, false, true))) {
8989 if (err != ErrorCCompilerCannotFindFile && err != ErrorNoCCompilerInstalled) {
8990 fprintf(stderr, "Unable to detect native dynamic linker: %s\n", err_str(err));
8991 exit(1);
8992 }
8993 continue;
8994 }
8995 g->dynamic_linker_path = result;
8996 return;
8997 }
8998 }
8999#endif
9000 }8977 }
90018978 g->dynamic_linker_path = buf_create_from_mem(dynamic_linker_ptr, dynamic_linker_len);
9002 g->dynamic_linker_path = buf_create_from_str(standard_ld_path);8979 // Skips heap::c_allocator because the memory is allocated by stage2 library.
8980 free(dynamic_linker_ptr);
9003}8981}
90048982
9005static void detect_libc(CodeGen *g) {8983static void detect_libc(CodeGen *g) {
...@@ -9028,16 +9006,16 @@ static void detect_libc(CodeGen *g) {...@@ -9028,16 +9006,16 @@ static void detect_libc(CodeGen *g) {
9028 buf_ptr(g->zig_lib_dir), target_os_name(g->zig_target->os));9006 buf_ptr(g->zig_lib_dir), target_os_name(g->zig_target->os));
90299007
9030 g->libc_include_dir_len = 4;9008 g->libc_include_dir_len = 4;
9031 g->libc_include_dir_list = heap::c_allocator.allocate<Buf*>(g->libc_include_dir_len);9009 g->libc_include_dir_list = heap::c_allocator.allocate<const char*>(g->libc_include_dir_len);
9032 g->libc_include_dir_list[0] = arch_include_dir;9010 g->libc_include_dir_list[0] = buf_ptr(arch_include_dir);
9033 g->libc_include_dir_list[1] = generic_include_dir;9011 g->libc_include_dir_list[1] = buf_ptr(generic_include_dir);
9034 g->libc_include_dir_list[2] = arch_os_include_dir;9012 g->libc_include_dir_list[2] = buf_ptr(arch_os_include_dir);
9035 g->libc_include_dir_list[3] = generic_os_include_dir;9013 g->libc_include_dir_list[3] = buf_ptr(generic_os_include_dir);
9036 return;9014 return;
9037 }9015 }
90389016
9039 if (g->zig_target->is_native) {9017 if (g->zig_target->is_native) {
9040 g->libc = heap::c_allocator.create<ZigLibCInstallation>();9018 g->libc = heap::c_allocator.create<Stage2LibCInstallation>();
90419019
9042 // search for native_libc.txt in following dirs:9020 // search for native_libc.txt in following dirs:
9043 // - LOCAL_CACHE_DIR9021 // - LOCAL_CACHE_DIR
...@@ -9082,8 +9060,8 @@ static void detect_libc(CodeGen *g) {...@@ -9082,8 +9060,8 @@ static void detect_libc(CodeGen *g) {
9082 if (libc_txt == nullptr)9060 if (libc_txt == nullptr)
9083 libc_txt = &global_libc_txt;9061 libc_txt = &global_libc_txt;
90849062
9085 if ((err = zig_libc_parse(g->libc, libc_txt, g->zig_target, false))) {9063 if ((err = stage2_libc_parse(g->libc, buf_ptr(libc_txt)))) {
9086 if ((err = zig_libc_find_native(g->libc, true))) {9064 if ((err = stage2_libc_find_native(g->libc))) {
9087 fprintf(stderr,9065 fprintf(stderr,
9088 "Unable to link against libc: Unable to find libc installation: %s\n"9066 "Unable to link against libc: Unable to find libc installation: %s\n"
9089 "See `zig libc --help` for more details.\n", err_str(err));9067 "See `zig libc --help` for more details.\n", err_str(err));
...@@ -9103,7 +9081,7 @@ static void detect_libc(CodeGen *g) {...@@ -9103,7 +9081,7 @@ static void detect_libc(CodeGen *g) {
9103 fprintf(stderr, "Unable to open %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));9081 fprintf(stderr, "Unable to open %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));
9104 exit(1);9082 exit(1);
9105 }9083 }
9106 zig_libc_render(g->libc, file);9084 stage2_libc_render(g->libc, file);
9107 if (fclose(file) != 0) {9085 if (fclose(file) != 0) {
9108 fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));9086 fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));
9109 exit(1);9087 exit(1);
...@@ -9113,27 +9091,28 @@ static void detect_libc(CodeGen *g) {...@@ -9113,27 +9091,28 @@ static void detect_libc(CodeGen *g) {
9113 exit(1);9091 exit(1);
9114 }9092 }
9115 }9093 }
9116 bool want_sys_dir = !buf_eql_buf(&g->libc->include_dir, &g->libc->sys_include_dir);9094 bool want_sys_dir = !mem_eql_mem(g->libc->include_dir, g->libc->include_dir_len,
9095 g->libc->sys_include_dir, g->libc->sys_include_dir_len);
9117 size_t want_um_and_shared_dirs = (g->zig_target->os == OsWindows) ? 2 : 0;9096 size_t want_um_and_shared_dirs = (g->zig_target->os == OsWindows) ? 2 : 0;
9118 size_t dir_count = 1 + want_sys_dir + want_um_and_shared_dirs;9097 size_t dir_count = 1 + want_sys_dir + want_um_and_shared_dirs;
9119 g->libc_include_dir_len = 0;9098 g->libc_include_dir_len = 0;
9120 g->libc_include_dir_list = heap::c_allocator.allocate<Buf*>(dir_count);9099 g->libc_include_dir_list = heap::c_allocator.allocate<const char *>(dir_count);
91219100
9122 g->libc_include_dir_list[g->libc_include_dir_len] = &g->libc->include_dir;9101 g->libc_include_dir_list[g->libc_include_dir_len] = g->libc->include_dir;
9123 g->libc_include_dir_len += 1;9102 g->libc_include_dir_len += 1;
91249103
9125 if (want_sys_dir) {9104 if (want_sys_dir) {
9126 g->libc_include_dir_list[g->libc_include_dir_len] = &g->libc->sys_include_dir;9105 g->libc_include_dir_list[g->libc_include_dir_len] = g->libc->sys_include_dir;
9127 g->libc_include_dir_len += 1;9106 g->libc_include_dir_len += 1;
9128 }9107 }
91299108
9130 if (want_um_and_shared_dirs != 0) {9109 if (want_um_and_shared_dirs != 0) {
9131 g->libc_include_dir_list[g->libc_include_dir_len] = buf_sprintf("%s" OS_SEP ".." OS_SEP "um",9110 g->libc_include_dir_list[g->libc_include_dir_len] = buf_ptr(buf_sprintf(
9132 buf_ptr(&g->libc->include_dir));9111 "%s" OS_SEP ".." OS_SEP "um", g->libc->include_dir));
9133 g->libc_include_dir_len += 1;9112 g->libc_include_dir_len += 1;
91349113
9135 g->libc_include_dir_list[g->libc_include_dir_len] = buf_sprintf("%s" OS_SEP ".." OS_SEP "shared",9114 g->libc_include_dir_list[g->libc_include_dir_len] = buf_ptr(buf_sprintf(
9136 buf_ptr(&g->libc->include_dir));9115 "%s" OS_SEP ".." OS_SEP "shared", g->libc->include_dir));
9137 g->libc_include_dir_len += 1;9116 g->libc_include_dir_len += 1;
9138 }9117 }
9139 assert(g->libc_include_dir_len == dir_count);9118 assert(g->libc_include_dir_len == dir_count);
...@@ -9208,9 +9187,9 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -9208,9 +9187,9 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
9208 args.append(buf_ptr(g->zig_c_headers_dir));9187 args.append(buf_ptr(g->zig_c_headers_dir));
92099188
9210 for (size_t i = 0; i < g->libc_include_dir_len; i += 1) {9189 for (size_t i = 0; i < g->libc_include_dir_len; i += 1) {
9211 Buf *include_dir = g->libc_include_dir_list[i];9190 const char *include_dir = g->libc_include_dir_list[i];
9212 args.append("-isystem");9191 args.append("-isystem");
9213 args.append(buf_ptr(include_dir));9192 args.append(include_dir);
9214 }9193 }
92159194
9216 if (g->zig_target->is_native) {9195 if (g->zig_target->is_native) {
...@@ -9666,7 +9645,7 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose...@@ -9666,7 +9645,7 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose
9666 cache_buf(cache_hash, compiler_id);9645 cache_buf(cache_hash, compiler_id);
9667 cache_int(cache_hash, g->err_color);9646 cache_int(cache_hash, g->err_color);
9668 cache_buf(cache_hash, g->zig_c_headers_dir);9647 cache_buf(cache_hash, g->zig_c_headers_dir);
9669 cache_list_of_buf(cache_hash, g->libc_include_dir_list, g->libc_include_dir_len);9648 cache_list_of_str(cache_hash, g->libc_include_dir_list, g->libc_include_dir_len);
9670 cache_int(cache_hash, g->zig_target->is_native);9649 cache_int(cache_hash, g->zig_target->is_native);
9671 cache_int(cache_hash, g->zig_target->arch);9650 cache_int(cache_hash, g->zig_target->arch);
9672 cache_int(cache_hash, g->zig_target->sub_arch);9651 cache_int(cache_hash, g->zig_target->sub_arch);
...@@ -10482,11 +10461,11 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -10482,11 +10461,11 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
10482 cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length);10461 cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length);
10483 cache_list_of_str(ch, g->framework_dirs.items, g->framework_dirs.length);10462 cache_list_of_str(ch, g->framework_dirs.items, g->framework_dirs.length);
10484 if (g->libc) {10463 if (g->libc) {
10485 cache_buf(ch, &g->libc->include_dir);10464 cache_str(ch, g->libc->include_dir);
10486 cache_buf(ch, &g->libc->sys_include_dir);10465 cache_str(ch, g->libc->sys_include_dir);
10487 cache_buf(ch, &g->libc->crt_dir);10466 cache_str(ch, g->libc->crt_dir);
10488 cache_buf(ch, &g->libc->msvc_lib_dir);10467 cache_str(ch, g->libc->msvc_lib_dir);
10489 cache_buf(ch, &g->libc->kernel32_lib_dir);10468 cache_str(ch, g->libc->kernel32_lib_dir);
10490 }10469 }
10491 cache_buf_opt(ch, g->dynamic_linker_path);10470 cache_buf_opt(ch, g->dynamic_linker_path);
10492 cache_buf_opt(ch, g->version_script_path);10471 cache_buf_opt(ch, g->version_script_path);
...@@ -10765,7 +10744,7 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c...@@ -10765,7 +10744,7 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c
10765}10744}
1076610745
10767CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,10746CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,
10768 ZigLibCInstallation *libc, const char *name, Stage2ProgressNode *parent_progress_node)10747 Stage2LibCInstallation *libc, const char *name, Stage2ProgressNode *parent_progress_node)
10769{10748{
10770 Stage2ProgressNode *child_progress_node = stage2_progress_start(10749 Stage2ProgressNode *child_progress_node = stage2_progress_start(
10771 parent_progress_node ? parent_progress_node : parent_gen->sub_progress_node,10750 parent_progress_node ? parent_progress_node : parent_gen->sub_progress_node,
...@@ -10804,7 +10783,7 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o...@@ -10804,7 +10783,7 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
1080410783
10805CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,10784CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
10806 OutType out_type, BuildMode build_mode, Buf *override_lib_dir,10785 OutType out_type, BuildMode build_mode, Buf *override_lib_dir,
10807 ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node)10786 Stage2LibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node)
10808{10787{
10809 CodeGen *g = heap::c_allocator.create<CodeGen>();10788 CodeGen *g = heap::c_allocator.create<CodeGen>();
10810 g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1");10789 g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1");
src/codegen.hpp+3-4
...@@ -11,17 +11,16 @@...@@ -11,17 +11,16 @@
11#include "parser.hpp"11#include "parser.hpp"
12#include "errmsg.hpp"12#include "errmsg.hpp"
13#include "target.hpp"13#include "target.hpp"
14#include "libc_installation.hpp"14#include "stage2.h"
15#include "userland.h"
1615
17#include <stdio.h>16#include <stdio.h>
1817
19CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,18CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
20 OutType out_type, BuildMode build_mode, Buf *zig_lib_dir,19 OutType out_type, BuildMode build_mode, Buf *zig_lib_dir,
21 ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node);20 Stage2LibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node);
2221
23CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,22CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,
24 ZigLibCInstallation *libc, const char *name, Stage2ProgressNode *progress_node);23 Stage2LibCInstallation *libc, const char *name, Stage2ProgressNode *progress_node);
2524
26void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);25void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
27void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);26void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
src/compiler.cpp-34
...@@ -4,20 +4,6 @@...@@ -4,20 +4,6 @@
44
5#include <stdio.h>5#include <stdio.h>
66
7static Buf saved_dynamic_linker_path = BUF_INIT;
8static bool searched_for_dyn_linker = false;
9
10static void detect_dynamic_linker(Buf *lib_path) {
11#if defined(ZIG_OS_LINUX)
12 for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) {
13 if (buf_ends_with_str(lib_path, possible_ld_names[i])) {
14 buf_init_from_buf(&saved_dynamic_linker_path, lib_path);
15 break;
16 }
17 }
18#endif
19}
20
21Buf *get_self_libc_path(void) {7Buf *get_self_libc_path(void) {
22 static Buf saved_libc_path = BUF_INIT;8 static Buf saved_libc_path = BUF_INIT;
23 static bool searched_for_libc = false;9 static bool searched_for_libc = false;
...@@ -43,25 +29,6 @@ Buf *get_self_libc_path(void) {...@@ -43,25 +29,6 @@ Buf *get_self_libc_path(void) {
43 }29 }
44}30}
4531
46Buf *get_self_dynamic_linker_path(void) {
47 for (;;) {
48 if (saved_dynamic_linker_path.list.length != 0) {
49 return &saved_dynamic_linker_path;
50 }
51 if (searched_for_dyn_linker)
52 return nullptr;
53 ZigList<Buf *> lib_paths = {};
54 Error err;
55 if ((err = os_self_exe_shared_libs(lib_paths)))
56 return nullptr;
57 for (size_t i = 0; i < lib_paths.length; i += 1) {
58 Buf *lib_path = lib_paths.at(i);
59 detect_dynamic_linker(lib_path);
60 }
61 searched_for_dyn_linker = true;
62 }
63}
64
65Error get_compiler_id(Buf **result) {32Error get_compiler_id(Buf **result) {
66 static Buf saved_compiler_id = BUF_INIT;33 static Buf saved_compiler_id = BUF_INIT;
6734
...@@ -98,7 +65,6 @@ Error get_compiler_id(Buf **result) {...@@ -98,7 +65,6 @@ Error get_compiler_id(Buf **result) {
98 return err;65 return err;
99 for (size_t i = 0; i < lib_paths.length; i += 1) {66 for (size_t i = 0; i < lib_paths.length; i += 1) {
100 Buf *lib_path = lib_paths.at(i);67 Buf *lib_path = lib_paths.at(i);
101 detect_dynamic_linker(lib_path);
102 if ((err = cache_add_file(ch, lib_path)))68 if ((err = cache_add_file(ch, lib_path)))
103 return err;69 return err;
104 }70 }
src/compiler.hpp-1
...@@ -12,7 +12,6 @@...@@ -12,7 +12,6 @@
12#include "error.hpp"12#include "error.hpp"
1313
14Error get_compiler_id(Buf **result);14Error get_compiler_id(Buf **result);
15Buf *get_self_dynamic_linker_path(void);
16Buf *get_self_libc_path(void);15Buf *get_self_libc_path(void);
1716
18Buf *get_zig_lib_dir(void);17Buf *get_zig_lib_dir(void);
src/error.cpp+17
...@@ -65,6 +65,23 @@ const char *err_str(Error err) {...@@ -65,6 +65,23 @@ const char *err_str(Error err) {
65 case ErrorInvalidLlvmCpuFeaturesFormat: return "invalid LLVM CPU features format";65 case ErrorInvalidLlvmCpuFeaturesFormat: return "invalid LLVM CPU features format";
66 case ErrorUnknownApplicationBinaryInterface: return "unknown application binary interface";66 case ErrorUnknownApplicationBinaryInterface: return "unknown application binary interface";
67 case ErrorASTUnitFailure: return "compiler bug: clang encountered a compile error, but the libclang API does not expose the error. See https://github.com/ziglang/zig/issues/4455 for more details";67 case ErrorASTUnitFailure: return "compiler bug: clang encountered a compile error, but the libclang API does not expose the error. See https://github.com/ziglang/zig/issues/4455 for more details";
68 case ErrorBadPathName: return "bad path name";
69 case ErrorSymLinkLoop: return "sym link loop";
70 case ErrorProcessFdQuotaExceeded: return "process fd quota exceeded";
71 case ErrorSystemFdQuotaExceeded: return "system fd quota exceeded";
72 case ErrorNoDevice: return "no device";
73 case ErrorDeviceBusy: return "device busy";
74 case ErrorUnableToSpawnCCompiler: return "unable to spawn system C compiler";
75 case ErrorCCompilerExitCode: return "system C compiler exited with failure code";
76 case ErrorCCompilerCrashed: return "system C compiler crashed";
77 case ErrorCCompilerCannotFindHeaders: return "system C compiler cannot find libc headers";
78 case ErrorLibCRuntimeNotFound: return "libc runtime not found";
79 case ErrorLibCStdLibHeaderNotFound: return "libc std lib headers not found";
80 case ErrorLibCKernel32LibNotFound: return "kernel32 library not found";
81 case ErrorUnsupportedArchitecture: return "unsupported architecture";
82 case ErrorWindowsSdkNotFound: return "Windows SDK not found";
83 case ErrorUnknownDynamicLinkerPath: return "unknown dynamic linker path";
84 case ErrorTargetHasNoDynamicLinker: return "target has no dynamic linker";
68 }85 }
69 return "(invalid error)";86 return "(invalid error)";
70}87}
src/error.hpp+1-1
...@@ -8,7 +8,7 @@...@@ -8,7 +8,7 @@
8#ifndef ERROR_HPP8#ifndef ERROR_HPP
9#define ERROR_HPP9#define ERROR_HPP
1010
11#include "userland.h"11#include "stage2.h"
1212
13const char *err_str(Error err);13const char *err_str(Error err);
1414
src/libc_installation.cpp deleted-498
...@@ -1,498 +0,0 @@
1/*
2 * Copyright (c) 2019 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#include "libc_installation.hpp"
9#include "os.hpp"
10#include "windows_sdk.h"
11#include "target.hpp"
12
13static const char *zig_libc_keys[] = {
14 "include_dir",
15 "sys_include_dir",
16 "crt_dir",
17 "static_crt_dir",
18 "msvc_lib_dir",
19 "kernel32_lib_dir",
20};
21
22static const size_t zig_libc_keys_len = array_length(zig_libc_keys);
23
24static bool zig_libc_match_key(Slice<uint8_t> name, Slice<uint8_t> value, bool *found_keys,
25 size_t index, Buf *field_ptr)
26{
27 if (!memEql(name, str(zig_libc_keys[index]))) return false;
28 buf_init_from_mem(field_ptr, (const char*)value.ptr, value.len);
29 found_keys[index] = true;
30 return true;
31}
32
33static void zig_libc_init_empty(ZigLibCInstallation *libc) {
34 *libc = {};
35 buf_init_from_str(&libc->include_dir, "");
36 buf_init_from_str(&libc->sys_include_dir, "");
37 buf_init_from_str(&libc->crt_dir, "");
38 buf_init_from_str(&libc->static_crt_dir, "");
39 buf_init_from_str(&libc->msvc_lib_dir, "");
40 buf_init_from_str(&libc->kernel32_lib_dir, "");
41}
42
43Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget *target, bool verbose) {
44 Error err;
45 zig_libc_init_empty(libc);
46
47 bool found_keys[array_length(zig_libc_keys)] = {};
48
49 Buf *contents = buf_alloc();
50 if ((err = os_fetch_file_path(libc_file, contents))) {
51 if (err != ErrorFileNotFound && verbose) {
52 fprintf(stderr, "Unable to read '%s': %s\n", buf_ptr(libc_file), err_str(err));
53 }
54 return err;
55 }
56
57 SplitIterator it = memSplit(buf_to_slice(contents), str("\n"));
58 for (;;) {
59 Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it);
60 if (!opt_line.is_some)
61 break;
62
63 if (opt_line.value.len == 0 || opt_line.value.ptr[0] == '#')
64 continue;
65
66 SplitIterator line_it = memSplit(opt_line.value, str("="));
67 Slice<uint8_t> name;
68 if (!SplitIterator_next(&line_it).unwrap(&name)) {
69 if (verbose) {
70 fprintf(stderr, "missing equal sign after field name\n");
71 }
72 return ErrorSemanticAnalyzeFail;
73 }
74 Slice<uint8_t> value = SplitIterator_rest(&line_it);
75 bool match = false;
76 match = match || zig_libc_match_key(name, value, found_keys, 0, &libc->include_dir);
77 match = match || zig_libc_match_key(name, value, found_keys, 1, &libc->sys_include_dir);
78 match = match || zig_libc_match_key(name, value, found_keys, 2, &libc->crt_dir);
79 match = match || zig_libc_match_key(name, value, found_keys, 3, &libc->static_crt_dir);
80 match = match || zig_libc_match_key(name, value, found_keys, 4, &libc->msvc_lib_dir);
81 match = match || zig_libc_match_key(name, value, found_keys, 5, &libc->kernel32_lib_dir);
82 }
83
84 for (size_t i = 0; i < zig_libc_keys_len; i += 1) {
85 if (!found_keys[i]) {
86 if (verbose) {
87 fprintf(stderr, "missing field: %s\n", zig_libc_keys[i]);
88 }
89 return ErrorSemanticAnalyzeFail;
90 }
91 }
92
93 if (buf_len(&libc->include_dir) == 0) {
94 if (verbose) {
95 fprintf(stderr, "include_dir may not be empty\n");
96 }
97 return ErrorSemanticAnalyzeFail;
98 }
99
100 if (buf_len(&libc->sys_include_dir) == 0) {
101 if (verbose) {
102 fprintf(stderr, "sys_include_dir may not be empty\n");
103 }
104 return ErrorSemanticAnalyzeFail;
105 }
106
107 if (buf_len(&libc->crt_dir) == 0) {
108 if (!target_os_is_darwin(target->os)) {
109 if (verbose) {
110 fprintf(stderr, "crt_dir may not be empty for %s\n", target_os_name(target->os));
111 }
112 return ErrorSemanticAnalyzeFail;
113 }
114 }
115
116 if (buf_len(&libc->static_crt_dir) == 0) {
117 if (target->os == OsWindows && target_abi_is_gnu(target->abi)) {
118 if (verbose) {
119 fprintf(stderr, "static_crt_dir may not be empty for %s\n", target_os_name(target->os));
120 }
121 return ErrorSemanticAnalyzeFail;
122 }
123 }
124
125 if (buf_len(&libc->msvc_lib_dir) == 0) {
126 if (target->os == OsWindows && !target_abi_is_gnu(target->abi)) {
127 if (verbose) {
128 fprintf(stderr, "msvc_lib_dir may not be empty for %s\n", target_os_name(target->os));
129 }
130 return ErrorSemanticAnalyzeFail;
131 }
132 }
133
134 if (buf_len(&libc->kernel32_lib_dir) == 0) {
135 if (target->os == OsWindows && !target_abi_is_gnu(target->abi)) {
136 if (verbose) {
137 fprintf(stderr, "kernel32_lib_dir may not be empty for %s\n", target_os_name(target->os));
138 }
139 return ErrorSemanticAnalyzeFail;
140 }
141 }
142
143 return ErrorNone;
144}
145
146#if defined(ZIG_OS_WINDOWS)
147#define CC_EXE "cc.exe"
148#else
149#define CC_EXE "cc"
150#endif
151
152static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, bool verbose) {
153 const char *cc_exe = getenv("CC");
154 cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe;
155 ZigList<const char *> args = {};
156 args.append(cc_exe);
157 args.append("-E");
158 args.append("-Wp,-v");
159 args.append("-xc");
160 #if defined(ZIG_OS_WINDOWS)
161 args.append("nul");
162 #else
163 args.append("/dev/null");
164 #endif
165
166 Termination term;
167 Buf *out_stderr = buf_alloc();
168 Buf *out_stdout = buf_alloc();
169 Error err;
170 if ((err = os_exec_process(args, &term, out_stderr, out_stdout))) {
171 if (verbose) {
172 fprintf(stderr, "unable to determine libc include path: executing '%s': %s\n", cc_exe, err_str(err));
173 }
174 return err;
175 }
176 if (term.how != TerminationIdClean || term.code != 0) {
177 if (verbose) {
178 fprintf(stderr, "unable to determine libc include path: executing '%s' failed\n", cc_exe);
179 }
180 return ErrorCCompileErrors;
181 }
182 char *prev_newline = buf_ptr(out_stderr);
183 ZigList<const char *> search_paths = {};
184 for (;;) {
185 char *newline = strchr(prev_newline, '\n');
186 if (newline == nullptr) {
187 break;
188 }
189
190 #if defined(ZIG_OS_WINDOWS)
191 *(newline - 1) = 0;
192 #endif
193 *newline = 0;
194
195 if (prev_newline[0] == ' ') {
196 search_paths.append(prev_newline);
197 }
198 prev_newline = newline + 1;
199 }
200 if (search_paths.length == 0) {
201 if (verbose) {
202 fprintf(stderr, "unable to determine libc include path: '%s' cannot find libc headers\n", cc_exe);
203 }
204 return ErrorCCompileErrors;
205 }
206 for (size_t i = 0; i < search_paths.length; i += 1) {
207 // search in reverse order
208 const char *search_path = search_paths.items[search_paths.length - i - 1];
209 // cut off spaces
210 while (*search_path == ' ') {
211 search_path += 1;
212 }
213
214 #if defined(ZIG_OS_WINDOWS)
215 if (buf_len(&self->include_dir) == 0) {
216 Buf *stdlib_path = buf_sprintf("%s\\stdlib.h", search_path);
217 bool exists;
218 if ((err = os_file_exists(stdlib_path, &exists))) {
219 exists = false;
220 }
221 if (exists) {
222 buf_init_from_str(&self->include_dir, search_path);
223 }
224 }
225 if (buf_len(&self->sys_include_dir) == 0) {
226 Buf *stdlib_path = buf_sprintf("%s\\sys\\types.h", search_path);
227 bool exists;
228 if ((err = os_file_exists(stdlib_path, &exists))) {
229 exists = false;
230 }
231 if (exists) {
232 buf_init_from_str(&self->sys_include_dir, search_path);
233 }
234 }
235 #else
236 if (buf_len(&self->include_dir) == 0) {
237 Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path);
238 bool exists;
239 if ((err = os_file_exists(stdlib_path, &exists))) {
240 exists = false;
241 }
242 if (exists) {
243 buf_init_from_str(&self->include_dir, search_path);
244 }
245 }
246 if (buf_len(&self->sys_include_dir) == 0) {
247 Buf *stdlib_path = buf_sprintf("%s/sys/errno.h", search_path);
248 bool exists;
249 if ((err = os_file_exists(stdlib_path, &exists))) {
250 exists = false;
251 }
252 if (exists) {
253 buf_init_from_str(&self->sys_include_dir, search_path);
254 }
255 }
256 #endif
257
258 if (buf_len(&self->include_dir) != 0 && buf_len(&self->sys_include_dir) != 0) {
259 return ErrorNone;
260 }
261 }
262 if (verbose) {
263 if (buf_len(&self->include_dir) == 0) {
264 fprintf(stderr, "unable to determine libc include path: stdlib.h not found in '%s' search paths\n", cc_exe);
265 }
266 if (buf_len(&self->sys_include_dir) == 0) {
267 #if defined(ZIG_OS_WINDOWS)
268 fprintf(stderr, "unable to determine libc include path: sys/types.h not found in '%s' search paths\n", cc_exe);
269 #else
270 fprintf(stderr, "unable to determine libc include path: sys/errno.h not found in '%s' search paths\n", cc_exe);
271 #endif
272 }
273 }
274 return ErrorFileNotFound;
275}
276
277Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose) {
278 const char *cc_exe = getenv("CC");
279 cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe;
280 ZigList<const char *> args = {};
281 args.append(cc_exe);
282 args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));
283 Termination term;
284 Buf *out_stderr = buf_alloc();
285 Buf *out_stdout = buf_alloc();
286 Error err;
287 if ((err = os_exec_process(args, &term, out_stderr, out_stdout))) {
288 if (err == ErrorFileNotFound)
289 return ErrorNoCCompilerInstalled;
290 if (verbose) {
291 fprintf(stderr, "unable to determine libc library path: executing '%s': %s\n", cc_exe, err_str(err));
292 }
293 return err;
294 }
295 if (term.how != TerminationIdClean || term.code != 0) {
296 if (verbose) {
297 fprintf(stderr, "unable to determine libc library path: executing '%s' failed\n", cc_exe);
298 }
299 return ErrorCCompileErrors;
300 }
301 #if defined(ZIG_OS_WINDOWS)
302 if (buf_ends_with_str(out_stdout, "\r\n")) {
303 buf_resize(out_stdout, buf_len(out_stdout) - 2);
304 }
305 #else
306 if (buf_ends_with_str(out_stdout, "\n")) {
307 buf_resize(out_stdout, buf_len(out_stdout) - 1);
308 }
309 #endif
310 if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) {
311 return ErrorCCompilerCannotFindFile;
312 }
313 if (want_dirname) {
314 os_path_dirname(out_stdout, out);
315 } else {
316 buf_init_from_buf(out, out_stdout);
317 }
318 return ErrorNone;
319}
320
321#undef CC_EXE
322
323#if defined(ZIG_OS_WINDOWS) || defined(ZIG_OS_LINUX) || defined(ZIG_OS_DRAGONFLY)
324static Error zig_libc_find_native_crt_dir_posix(ZigLibCInstallation *self, bool verbose) {
325 return zig_libc_cc_print_file_name("crt1.o", &self->crt_dir, true, verbose);
326}
327#endif
328
329#if defined(ZIG_OS_WINDOWS)
330static Error zig_libc_find_native_static_crt_dir_posix(ZigLibCInstallation *self, bool verbose) {
331 return zig_libc_cc_print_file_name("crtbegin.o", &self->static_crt_dir, true, verbose);
332}
333
334static Error zig_libc_find_native_include_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) {
335 Error err;
336 if ((err = os_get_win32_ucrt_include_path(sdk, &self->include_dir))) {
337 if (verbose) {
338 fprintf(stderr, "Unable to determine libc include path: %s\n", err_str(err));
339 }
340 return err;
341 }
342 return ErrorNone;
343}
344
345static Error zig_libc_find_native_crt_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target,
346 bool verbose)
347{
348 Error err;
349 if ((err = os_get_win32_ucrt_lib_path(sdk, &self->crt_dir, target->arch))) {
350 if (verbose) {
351 fprintf(stderr, "Unable to determine ucrt path: %s\n", err_str(err));
352 }
353 return err;
354 }
355 return ErrorNone;
356}
357
358static Error zig_libc_find_kernel32_lib_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target,
359 bool verbose)
360{
361 Error err;
362 if ((err = os_get_win32_kern32_path(sdk, &self->kernel32_lib_dir, target->arch))) {
363 if (verbose) {
364 fprintf(stderr, "Unable to determine kernel32 path: %s\n", err_str(err));
365 }
366 return err;
367 }
368 return ErrorNone;
369}
370
371static Error zig_libc_find_native_msvc_lib_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) {
372 if (sdk->msvc_lib_dir_ptr == nullptr) {
373 if (verbose) {
374 fprintf(stderr, "Unable to determine vcruntime.lib path\n");
375 }
376 return ErrorFileNotFound;
377 }
378 buf_init_from_mem(&self->msvc_lib_dir, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
379 return ErrorNone;
380}
381
382static Error zig_libc_find_native_msvc_include_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) {
383 Error err;
384 if (sdk->msvc_lib_dir_ptr == nullptr) {
385 if (verbose) {
386 fprintf(stderr, "Unable to determine vcruntime.h path\n");
387 }
388 return ErrorFileNotFound;
389 }
390 Buf search_path = BUF_INIT;
391 buf_init_from_mem(&search_path, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
392 buf_append_str(&search_path, "..\\..\\include");
393
394 Buf *vcruntime_path = buf_sprintf("%s\\vcruntime.h", buf_ptr(&search_path));
395 bool exists;
396 if ((err = os_file_exists(vcruntime_path, &exists))) {
397 exists = false;
398 }
399 if (exists) {
400 self->sys_include_dir = search_path;
401 return ErrorNone;
402 }
403
404 if (verbose) {
405 fprintf(stderr, "Unable to determine vcruntime.h path\n");
406 }
407 return ErrorFileNotFound;
408}
409#endif
410
411void zig_libc_render(ZigLibCInstallation *self, FILE *file) {
412 fprintf(file,
413 "# The directory that contains `stdlib.h`.\n"
414 "# On POSIX-like systems, include directories be found with: `cc -E -Wp,-v -xc /dev/null`\n"
415 "include_dir=%s\n"
416 "\n"
417 "# The system-specific include directory. May be the same as `include_dir`.\n"
418 "# On Windows it's the directory that includes `vcruntime.h`.\n"
419 "# On POSIX it's the directory that includes `sys/errno.h`.\n"
420 "sys_include_dir=%s\n"
421 "\n"
422 "# The directory that contains `crt1.o` or `crt2.o`.\n"
423 "# On POSIX, can be found with `cc -print-file-name=crt1.o`.\n"
424 "# Not needed when targeting MacOS.\n"
425 "crt_dir=%s\n"
426 "\n"
427 "# The directory that contains `crtbegin.o`.\n"
428 "# On POSIX, can be found with `cc -print-file-name=crtbegin.o`.\n"
429 "# Not needed when targeting MacOS.\n"
430 "static_crt_dir=%s\n"
431 "\n"
432 "# The directory that contains `vcruntime.lib`.\n"
433 "# Only needed when targeting MSVC on Windows.\n"
434 "msvc_lib_dir=%s\n"
435 "\n"
436 "# The directory that contains `kernel32.lib`.\n"
437 "# Only needed when targeting MSVC on Windows.\n"
438 "kernel32_lib_dir=%s\n"
439 "\n",
440 buf_ptr(&self->include_dir),
441 buf_ptr(&self->sys_include_dir),
442 buf_ptr(&self->crt_dir),
443 buf_ptr(&self->static_crt_dir),
444 buf_ptr(&self->msvc_lib_dir),
445 buf_ptr(&self->kernel32_lib_dir)
446 );
447}
448
449Error zig_libc_find_native(ZigLibCInstallation *self, bool verbose) {
450 Error err;
451 zig_libc_init_empty(self);
452#if defined(ZIG_OS_WINDOWS)
453 ZigTarget native_target;
454 get_native_target(&native_target);
455 if (target_abi_is_gnu(native_target.abi)) {
456 if ((err = zig_libc_find_native_include_dir_posix(self, verbose)))
457 return err;
458 if ((err = zig_libc_find_native_crt_dir_posix(self, verbose)))
459 return err;
460 if ((err = zig_libc_find_native_static_crt_dir_posix(self, verbose)))
461 return err;
462 return ErrorNone;
463 } else {
464 ZigWindowsSDK *sdk;
465 switch (zig_find_windows_sdk(&sdk)) {
466 case ZigFindWindowsSdkErrorNone:
467 if ((err = zig_libc_find_native_msvc_include_dir(self, sdk, verbose)))
468 return err;
469 if ((err = zig_libc_find_native_msvc_lib_dir(self, sdk, verbose)))
470 return err;
471 if ((err = zig_libc_find_kernel32_lib_dir(self, sdk, &native_target, verbose)))
472 return err;
473 if ((err = zig_libc_find_native_include_dir_windows(self, sdk, verbose)))
474 return err;
475 if ((err = zig_libc_find_native_crt_dir_windows(self, sdk, &native_target, verbose)))
476 return err;
477 return ErrorNone;
478 case ZigFindWindowsSdkErrorOutOfMemory:
479 return ErrorNoMem;
480 case ZigFindWindowsSdkErrorNotFound:
481 return ErrorFileNotFound;
482 case ZigFindWindowsSdkErrorPathTooLong:
483 return ErrorPathTooLong;
484 }
485 }
486 zig_unreachable();
487#else
488 if ((err = zig_libc_find_native_include_dir_posix(self, verbose)))
489 return err;
490#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
491 buf_init_from_str(&self->crt_dir, "/usr/lib");
492#elif defined(ZIG_OS_LINUX) || defined(ZIG_OS_DRAGONFLY)
493 if ((err = zig_libc_find_native_crt_dir_posix(self, verbose)))
494 return err;
495#endif
496 return ErrorNone;
497#endif
498}
src/libc_installation.hpp deleted-35
...@@ -1,35 +0,0 @@
1/*
2 * Copyright (c) 2019 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_LIBC_INSTALLATION_HPP
9#define ZIG_LIBC_INSTALLATION_HPP
10
11#include <stdio.h>
12
13#include "buffer.hpp"
14#include "error.hpp"
15#include "target.hpp"
16
17// Must be synchronized with zig_libc_keys
18struct ZigLibCInstallation {
19 Buf include_dir;
20 Buf sys_include_dir;
21 Buf crt_dir;
22 Buf static_crt_dir;
23 Buf msvc_lib_dir;
24 Buf kernel32_lib_dir;
25};
26
27Error ATTRIBUTE_MUST_USE zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file,
28 const ZigTarget *target, bool verbose);
29void zig_libc_render(ZigLibCInstallation *self, FILE *file);
30
31Error ATTRIBUTE_MUST_USE zig_libc_find_native(ZigLibCInstallation *self, bool verbose);
32
33Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose);
34
35#endif
src/link.cpp+7-7
...@@ -1483,7 +1483,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr...@@ -1483,7 +1483,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr
1483 } else {1483 } else {
1484 assert(parent->libc != nullptr);1484 assert(parent->libc != nullptr);
1485 Buf *out_buf = buf_alloc();1485 Buf *out_buf = buf_alloc();
1486 os_path_join(&parent->libc->crt_dir, buf_create_from_str(file), out_buf);1486 os_path_join(buf_create_from_str(parent->libc->crt_dir), buf_create_from_str(file), out_buf);
1487 return buf_ptr(out_buf);1487 return buf_ptr(out_buf);
1488 }1488 }
1489}1489}
...@@ -1747,7 +1747,7 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -1747,7 +1747,7 @@ static void construct_linker_job_elf(LinkJob *lj) {
1747 if (g->libc_link_lib != nullptr) {1747 if (g->libc_link_lib != nullptr) {
1748 if (g->libc != nullptr) {1748 if (g->libc != nullptr) {
1749 lj->args.append("-L");1749 lj->args.append("-L");
1750 lj->args.append(buf_ptr(&g->libc->crt_dir));1750 lj->args.append(g->libc->crt_dir);
1751 }1751 }
17521752
1753 if (g->have_dynamic_link && (is_dyn_lib || g->out_type == OutTypeExe)) {1753 if (g->have_dynamic_link && (is_dyn_lib || g->out_type == OutTypeExe)) {
...@@ -2251,14 +2251,14 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -2251,14 +2251,14 @@ static void construct_linker_job_coff(LinkJob *lj) {
2251 lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));2251 lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
22522252
2253 if (g->libc_link_lib != nullptr && g->libc != nullptr) {2253 if (g->libc_link_lib != nullptr && g->libc != nullptr) {
2254 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir))));2254 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->crt_dir)));
22552255
2256 if (target_abi_is_gnu(g->zig_target->abi)) {2256 if (target_abi_is_gnu(g->zig_target->abi)) {
2257 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->sys_include_dir))));2257 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->sys_include_dir)));
2258 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->include_dir))));2258 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->include_dir)));
2259 } else {2259 } else {
2260 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir))));2260 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->msvc_lib_dir)));
2261 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir))));2261 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->kernel32_lib_dir)));
2262 }2262 }
2263 }2263 }
22642264
src/main.cpp+46-14
...@@ -14,8 +14,7 @@...@@ -14,8 +14,7 @@
14#include "heap.hpp"14#include "heap.hpp"
15#include "os.hpp"15#include "os.hpp"
16#include "target.hpp"16#include "target.hpp"
17#include "libc_installation.hpp"17#include "stage2.h"
18#include "userland.h"
19#include "glibc.hpp"18#include "glibc.hpp"
20#include "dump_analysis.hpp"19#include "dump_analysis.hpp"
21#include "mem_profile.hpp"20#include "mem_profile.hpp"
...@@ -1004,9 +1003,22 @@ static int main0(int argc, char **argv) {...@@ -1004,9 +1003,22 @@ static int main0(int argc, char **argv) {
1004 return main_exit(root_progress_node, EXIT_FAILURE);1003 return main_exit(root_progress_node, EXIT_FAILURE);
1005 }1004 }
10061005
1006 // If both output_dir and enable_cache are provided, and doing build-lib, we
1007 // will just do a file copy at the end. This helps when bootstrapping zig from zig0
1008 // because we want to pass something like this:
1009 // zig0 build-lib --cache on --output-dir ${CMAKE_BINARY_DIR}
1010 // And we don't have access to `zig0 build` because that would require detecting native libc
1011 // on systems where we are not able to build a libc from source for them.
1012 // But that's the only reason this works, so otherwise we give an error here.
1013 Buf *final_output_dir_step = nullptr;
1007 if (output_dir != nullptr && enable_cache == CacheOptOn) {1014 if (output_dir != nullptr && enable_cache == CacheOptOn) {
1008 fprintf(stderr, "`--output-dir` is incompatible with --cache on.\n");1015 if (cmd == CmdBuild && out_type == OutTypeLib) {
1009 return print_error_usage(arg0);1016 final_output_dir_step = output_dir;
1017 output_dir = nullptr;
1018 } else {
1019 fprintf(stderr, "`--output-dir` is incompatible with --cache on.\n");
1020 return print_error_usage(arg0);
1021 }
1010 }1022 }
10111023
1012 if (target_requires_pic(&target, have_libc) && want_pic == WantPICDisabled) {1024 if (target_requires_pic(&target, have_libc) && want_pic == WantPICDisabled) {
...@@ -1027,15 +1039,22 @@ static int main0(int argc, char **argv) {...@@ -1027,15 +1039,22 @@ static int main0(int argc, char **argv) {
1027 switch (cmd) {1039 switch (cmd) {
1028 case CmdLibC: {1040 case CmdLibC: {
1029 if (in_file) {1041 if (in_file) {
1030 ZigLibCInstallation libc;1042 Stage2LibCInstallation libc;
1031 if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true)))1043 if ((err = stage2_libc_parse(&libc, in_file))) {
1044 fprintf(stderr, "unable to parse libc file: %s\n", err_str(err));
1032 return main_exit(root_progress_node, EXIT_FAILURE);1045 return main_exit(root_progress_node, EXIT_FAILURE);
1046 }
1033 return main_exit(root_progress_node, EXIT_SUCCESS);1047 return main_exit(root_progress_node, EXIT_SUCCESS);
1034 }1048 }
1035 ZigLibCInstallation libc;1049 Stage2LibCInstallation libc;
1036 if ((err = zig_libc_find_native(&libc, true)))1050 if ((err = stage2_libc_find_native(&libc))) {
1051 fprintf(stderr, "unable to find native libc file: %s\n", err_str(err));
1037 return main_exit(root_progress_node, EXIT_FAILURE);1052 return main_exit(root_progress_node, EXIT_FAILURE);
1038 zig_libc_render(&libc, stdout);1053 }
1054 if ((err = stage2_libc_render(&libc, stdout))) {
1055 fprintf(stderr, "unable to print libc file: %s\n", err_str(err));
1056 return main_exit(root_progress_node, EXIT_FAILURE);
1057 }
1039 return main_exit(root_progress_node, EXIT_SUCCESS);1058 return main_exit(root_progress_node, EXIT_SUCCESS);
1040 }1059 }
1041 case CmdBuiltin: {1060 case CmdBuiltin: {
...@@ -1125,10 +1144,10 @@ static int main0(int argc, char **argv) {...@@ -1125,10 +1144,10 @@ static int main0(int argc, char **argv) {
1125 if (cmd == CmdRun && buf_out_name == nullptr) {1144 if (cmd == CmdRun && buf_out_name == nullptr) {
1126 buf_out_name = buf_create_from_str("run");1145 buf_out_name = buf_create_from_str("run");
1127 }1146 }
1128 ZigLibCInstallation *libc = nullptr;1147 Stage2LibCInstallation *libc = nullptr;
1129 if (libc_txt != nullptr) {1148 if (libc_txt != nullptr) {
1130 libc = heap::c_allocator.create<ZigLibCInstallation>();1149 libc = heap::c_allocator.create<Stage2LibCInstallation>();
1131 if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) {1150 if ((err = stage2_libc_parse(libc, libc_txt))) {
1132 fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err));1151 fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err));
1133 return main_exit(root_progress_node, EXIT_FAILURE);1152 return main_exit(root_progress_node, EXIT_FAILURE);
1134 }1153 }
...@@ -1284,8 +1303,21 @@ static int main0(int argc, char **argv) {...@@ -1284,8 +1303,21 @@ static int main0(int argc, char **argv) {
1284#if defined(ZIG_OS_WINDOWS)1303#if defined(ZIG_OS_WINDOWS)
1285 buf_replace(&g->output_file_path, '/', '\\');1304 buf_replace(&g->output_file_path, '/', '\\');
1286#endif1305#endif
1287 if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0)1306 if (final_output_dir_step != nullptr) {
1288 return main_exit(root_progress_node, EXIT_FAILURE);1307 Buf *dest_basename = buf_alloc();
1308 os_path_split(&g->output_file_path, nullptr, dest_basename);
1309 Buf *dest_path = buf_alloc();
1310 os_path_join(final_output_dir_step, dest_basename, dest_path);
1311
1312 if ((err = os_update_file(&g->output_file_path, dest_path))) {
1313 fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(&g->output_file_path),
1314 buf_ptr(dest_path), err_str(err));
1315 return main_exit(root_progress_node, EXIT_FAILURE);
1316 }
1317 } else {
1318 if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0)
1319 return main_exit(root_progress_node, EXIT_FAILURE);
1320 }
1289 }1321 }
1290 return main_exit(root_progress_node, EXIT_SUCCESS);1322 return main_exit(root_progress_node, EXIT_SUCCESS);
1291 } else {1323 } else {
src/os.cpp+154-157
...@@ -826,7 +826,9 @@ static Error os_exec_process_posix(ZigList<const char *> &args,...@@ -826,7 +826,9 @@ static Error os_exec_process_posix(ZigList<const char *> &args,
826 if (errno == ENOENT) {826 if (errno == ENOENT) {
827 report_err = ErrorFileNotFound;827 report_err = ErrorFileNotFound;
828 }828 }
829 write(err_pipe[1], &report_err, sizeof(Error));829 if (write(err_pipe[1], &report_err, sizeof(Error)) == -1) {
830 zig_panic("write failed");
831 }
830 exit(1);832 exit(1);
831 } else {833 } else {
832 // parent834 // parent
...@@ -851,9 +853,13 @@ static Error os_exec_process_posix(ZigList<const char *> &args,...@@ -851,9 +853,13 @@ static Error os_exec_process_posix(ZigList<const char *> &args,
851 if (err2) return err2;853 if (err2) return err2;
852854
853 Error child_err = ErrorNone;855 Error child_err = ErrorNone;
854 write(err_pipe[1], &child_err, sizeof(Error));856 if (write(err_pipe[1], &child_err, sizeof(Error)) == -1) {
857 zig_panic("write failed");
858 }
855 close(err_pipe[1]);859 close(err_pipe[1]);
856 read(err_pipe[0], &child_err, sizeof(Error));860 if (read(err_pipe[0], &child_err, sizeof(Error)) == -1) {
861 zig_panic("write failed");
862 }
857 close(err_pipe[0]);863 close(err_pipe[0]);
858 return child_err;864 return child_err;
859 }865 }
...@@ -1029,6 +1035,124 @@ Error os_write_file(Buf *full_path, Buf *contents) {...@@ -1029,6 +1035,124 @@ Error os_write_file(Buf *full_path, Buf *contents) {
1029 return ErrorNone;1035 return ErrorNone;
1030}1036}
10311037
1038static Error copy_open_files(FILE *src_f, FILE *dest_f) {
1039 static const size_t buf_size = 2048;
1040 char buf[buf_size];
1041 for (;;) {
1042 size_t amt_read = fread(buf, 1, buf_size, src_f);
1043 if (amt_read != buf_size) {
1044 if (ferror(src_f)) {
1045 return ErrorFileSystem;
1046 }
1047 }
1048 size_t amt_written = fwrite(buf, 1, amt_read, dest_f);
1049 if (amt_written != amt_read) {
1050 return ErrorFileSystem;
1051 }
1052 if (feof(src_f)) {
1053 return ErrorNone;
1054 }
1055 }
1056}
1057
1058#if defined(ZIG_OS_WINDOWS)
1059static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) {
1060 mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
1061 mtime->nsec = 0;
1062}
1063static FILETIME windows_os_timestamp_to_filetime(OsTimeStamp mtime) {
1064 FILETIME result;
1065 result.dwHighDateTime = mtime.sec >> 32;
1066 result.dwLowDateTime = mtime.sec;
1067 return result;
1068}
1069#endif
1070
1071static Error set_file_times(OsFile file, OsTimeStamp ts) {
1072#if defined(ZIG_OS_WINDOWS)
1073 FILETIME ft = windows_os_timestamp_to_filetime(ts);
1074 if (SetFileTime(file, nullptr, &ft, &ft) == 0) {
1075 return ErrorUnexpected;
1076 }
1077 return ErrorNone;
1078#else
1079 struct timespec times[2] = {
1080 { ts.sec, ts.nsec },
1081 { ts.sec, ts.nsec },
1082 };
1083 if (futimens(file, times) == -1) {
1084 switch (errno) {
1085 case EBADF:
1086 zig_panic("futimens EBADF");
1087 default:
1088 return ErrorUnexpected;
1089 }
1090 }
1091 return ErrorNone;
1092#endif
1093}
1094
1095Error os_update_file(Buf *src_path, Buf *dst_path) {
1096 Error err;
1097
1098 OsFile src_file;
1099 OsFileAttr src_attr;
1100 if ((err = os_file_open_r(src_path, &src_file, &src_attr))) {
1101 return err;
1102 }
1103
1104 OsFile dst_file;
1105 OsFileAttr dst_attr;
1106 if ((err = os_file_open_w(dst_path, &dst_file, &dst_attr, src_attr.mode))) {
1107 os_file_close(&src_file);
1108 return err;
1109 }
1110
1111 if (src_attr.size == dst_attr.size &&
1112 src_attr.mode == dst_attr.mode &&
1113 src_attr.mtime.sec == dst_attr.mtime.sec &&
1114 src_attr.mtime.nsec == dst_attr.mtime.nsec)
1115 {
1116 os_file_close(&src_file);
1117 os_file_close(&dst_file);
1118 return ErrorNone;
1119 }
1120#if defined(ZIG_OS_WINDOWS)
1121 if (SetEndOfFile(dst_file) == 0) {
1122 return ErrorUnexpected;
1123 }
1124#else
1125 if (ftruncate(dst_file, 0) == -1) {
1126 return ErrorUnexpected;
1127 }
1128#endif
1129#if defined(ZIG_OS_WINDOWS)
1130 FILE *src_libc_file = _fdopen(_open_osfhandle((intptr_t)src_file, _O_RDONLY), "rb");
1131 FILE *dst_libc_file = _fdopen(_open_osfhandle((intptr_t)dst_file, 0), "wb");
1132#else
1133 FILE *src_libc_file = fdopen(src_file, "rb");
1134 FILE *dst_libc_file = fdopen(dst_file, "wb");
1135#endif
1136 assert(src_libc_file);
1137 assert(dst_libc_file);
1138
1139 if ((err = copy_open_files(src_libc_file, dst_libc_file))) {
1140 fclose(src_libc_file);
1141 fclose(dst_libc_file);
1142 return err;
1143 }
1144 if (fflush(src_libc_file) == -1) {
1145 return ErrorUnexpected;
1146 }
1147 if (fflush(dst_libc_file) == -1) {
1148 return ErrorUnexpected;
1149 }
1150 err = set_file_times(dst_file, src_attr.mtime);
1151 fclose(src_libc_file);
1152 fclose(dst_libc_file);
1153 return err;
1154}
1155
1032Error os_copy_file(Buf *src_path, Buf *dest_path) {1156Error os_copy_file(Buf *src_path, Buf *dest_path) {
1033 FILE *src_f = fopen(buf_ptr(src_path), "rb");1157 FILE *src_f = fopen(buf_ptr(src_path), "rb");
1034 if (!src_f) {1158 if (!src_f) {
...@@ -1055,30 +1179,10 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) {...@@ -1055,30 +1179,10 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) {
1055 return ErrorFileSystem;1179 return ErrorFileSystem;
1056 }1180 }
1057 }1181 }
10581182 Error err = copy_open_files(src_f, dest_f);
1059 static const size_t buf_size = 2048;1183 fclose(src_f);
1060 char buf[buf_size];1184 fclose(dest_f);
1061 for (;;) {1185 return err;
1062 size_t amt_read = fread(buf, 1, buf_size, src_f);
1063 if (amt_read != buf_size) {
1064 if (ferror(src_f)) {
1065 fclose(src_f);
1066 fclose(dest_f);
1067 return ErrorFileSystem;
1068 }
1069 }
1070 size_t amt_written = fwrite(buf, 1, amt_read, dest_f);
1071 if (amt_written != amt_read) {
1072 fclose(src_f);
1073 fclose(dest_f);
1074 return ErrorFileSystem;
1075 }
1076 if (feof(src_f)) {
1077 fclose(src_f);
1078 fclose(dest_f);
1079 return ErrorNone;
1080 }
1081 }
1082}1186}
10831187
1084Error os_fetch_file_path(Buf *full_path, Buf *out_contents) {1188Error os_fetch_file_path(Buf *full_path, Buf *out_contents) {
...@@ -1218,13 +1322,6 @@ Error os_rename(Buf *src_path, Buf *dest_path) {...@@ -1218,13 +1322,6 @@ Error os_rename(Buf *src_path, Buf *dest_path) {
1218 return ErrorNone;1322 return ErrorNone;
1219}1323}
12201324
1221#if defined(ZIG_OS_WINDOWS)
1222static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) {
1223 mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
1224 mtime->nsec = 0;
1225}
1226#endif
1227
1228OsTimeStamp os_timestamp_calendar(void) {1325OsTimeStamp os_timestamp_calendar(void) {
1229 OsTimeStamp result;1326 OsTimeStamp result;
1230#if defined(ZIG_OS_WINDOWS)1327#if defined(ZIG_OS_WINDOWS)
...@@ -1551,108 +1648,6 @@ void os_stderr_set_color(TermColor color) {...@@ -1551,108 +1648,6 @@ void os_stderr_set_color(TermColor color) {
1551#endif1648#endif
1552}1649}
15531650
1554Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
1555#if defined(ZIG_OS_WINDOWS)
1556 buf_resize(output_buf, 0);
1557 buf_appendf(output_buf, "%sLib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr);
1558 switch (platform_type) {
1559 case ZigLLVM_x86:
1560 buf_append_str(output_buf, "x86\\");
1561 break;
1562 case ZigLLVM_x86_64:
1563 buf_append_str(output_buf, "x64\\");
1564 break;
1565 case ZigLLVM_arm:
1566 buf_append_str(output_buf, "arm\\");
1567 break;
1568 default:
1569 zig_panic("Attempted to use vcruntime for non-supported platform.");
1570 }
1571 Buf* tmp_buf = buf_alloc();
1572 buf_init_from_buf(tmp_buf, output_buf);
1573 buf_append_str(tmp_buf, "ucrt.lib");
1574 if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
1575 return ErrorNone;
1576 }
1577 else {
1578 buf_resize(output_buf, 0);
1579 return ErrorFileNotFound;
1580 }
1581#else
1582 return ErrorFileNotFound;
1583#endif
1584}
1585
1586Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
1587#if defined(ZIG_OS_WINDOWS)
1588 buf_resize(output_buf, 0);
1589 buf_appendf(output_buf, "%sInclude\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr);
1590 if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {
1591 return ErrorNone;
1592 }
1593 else {
1594 buf_resize(output_buf, 0);
1595 return ErrorFileNotFound;
1596 }
1597#else
1598 return ErrorFileNotFound;
1599#endif
1600}
1601
1602Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
1603#if defined(ZIG_OS_WINDOWS)
1604 {
1605 buf_resize(output_buf, 0);
1606 buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr);
1607 switch (platform_type) {
1608 case ZigLLVM_x86:
1609 buf_append_str(output_buf, "x86\\");
1610 break;
1611 case ZigLLVM_x86_64:
1612 buf_append_str(output_buf, "x64\\");
1613 break;
1614 case ZigLLVM_arm:
1615 buf_append_str(output_buf, "arm\\");
1616 break;
1617 default:
1618 zig_panic("Attempted to use vcruntime for non-supported platform.");
1619 }
1620 Buf* tmp_buf = buf_alloc();
1621 buf_init_from_buf(tmp_buf, output_buf);
1622 buf_append_str(tmp_buf, "kernel32.lib");
1623 if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
1624 return ErrorNone;
1625 }
1626 }
1627 {
1628 buf_resize(output_buf, 0);
1629 buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr);
1630 switch (platform_type) {
1631 case ZigLLVM_x86:
1632 buf_append_str(output_buf, "x86\\");
1633 break;
1634 case ZigLLVM_x86_64:
1635 buf_append_str(output_buf, "x64\\");
1636 break;
1637 case ZigLLVM_arm:
1638 buf_append_str(output_buf, "arm\\");
1639 break;
1640 default:
1641 zig_panic("Attempted to use vcruntime for non-supported platform.");
1642 }
1643 Buf* tmp_buf = buf_alloc();
1644 buf_init_from_buf(tmp_buf, output_buf);
1645 buf_append_str(tmp_buf, "kernel32.lib");
1646 if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
1647 return ErrorNone;
1648 }
1649 }
1650 return ErrorFileNotFound;
1651#else
1652 return ErrorFileNotFound;
1653#endif
1654}
1655
1656#if defined(ZIG_OS_WINDOWS)1651#if defined(ZIG_OS_WINDOWS)
1657// Ported from std/unicode.zig1652// Ported from std/unicode.zig
1658struct Utf16LeIterator {1653struct Utf16LeIterator {
...@@ -1835,10 +1830,15 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {...@@ -1835,10 +1830,15 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {
1835#endif1830#endif
1836}1831}
18371832
1838Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) {1833Error os_file_open_rw(Buf *full_path, OsFile *out_file, OsFileAttr *attr, bool need_write, uint32_t mode) {
1839#if defined(ZIG_OS_WINDOWS)1834#if defined(ZIG_OS_WINDOWS)
1840 // TODO use CreateFileW1835 // TODO use CreateFileW
1841 HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);1836 HANDLE result = CreateFileA(buf_ptr(full_path),
1837 need_write ? (GENERIC_READ|GENERIC_WRITE) : GENERIC_READ,
1838 need_write ? 0 : FILE_SHARE_READ,
1839 nullptr,
1840 need_write ? OPEN_ALWAYS : OPEN_EXISTING,
1841 FILE_ATTRIBUTE_NORMAL, nullptr);
18421842
1843 if (result == INVALID_HANDLE_VALUE) {1843 if (result == INVALID_HANDLE_VALUE) {
1844 DWORD err = GetLastError();1844 DWORD err = GetLastError();
...@@ -1871,12 +1871,15 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) {...@@ -1871,12 +1871,15 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) {
1871 }1871 }
1872 windows_filetime_to_os_timestamp(&file_info.ftLastWriteTime, &attr->mtime);1872 windows_filetime_to_os_timestamp(&file_info.ftLastWriteTime, &attr->mtime);
1873 attr->inode = (((uint64_t)file_info.nFileIndexHigh) << 32) | file_info.nFileIndexLow;1873 attr->inode = (((uint64_t)file_info.nFileIndexHigh) << 32) | file_info.nFileIndexLow;
1874 attr->mode = 0;
1875 attr->size = (((uint64_t)file_info.nFileSizeHigh) << 32) | file_info.nFileSizeLow;
1874 }1876 }
18751877
1876 return ErrorNone;1878 return ErrorNone;
1877#else1879#else
1878 for (;;) {1880 for (;;) {
1879 int fd = open(buf_ptr(full_path), O_RDONLY|O_CLOEXEC);1881 int fd = open(buf_ptr(full_path),
1882 need_write ? (O_RDWR|O_CLOEXEC|O_CREAT) : (O_RDONLY|O_CLOEXEC), mode);
1880 if (fd == -1) {1883 if (fd == -1) {
1881 switch (errno) {1884 switch (errno) {
1882 case EINTR:1885 case EINTR:
...@@ -1886,6 +1889,7 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) {...@@ -1886,6 +1889,7 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) {
1886 case EFAULT:1889 case EFAULT:
1887 zig_unreachable();1890 zig_unreachable();
1888 case EACCES:1891 case EACCES:
1892 case EPERM:
1889 return ErrorAccess;1893 return ErrorAccess;
1890 case EISDIR:1894 case EISDIR:
1891 return ErrorIsDir;1895 return ErrorIsDir;
...@@ -1915,12 +1919,22 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) {...@@ -1915,12 +1919,22 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) {
1915 attr->mtime.sec = statbuf.st_mtim.tv_sec;1919 attr->mtime.sec = statbuf.st_mtim.tv_sec;
1916 attr->mtime.nsec = statbuf.st_mtim.tv_nsec;1920 attr->mtime.nsec = statbuf.st_mtim.tv_nsec;
1917#endif1921#endif
1922 attr->mode = statbuf.st_mode;
1923 attr->size = statbuf.st_size;
1918 }1924 }
1919 return ErrorNone;1925 return ErrorNone;
1920 }1926 }
1921#endif1927#endif
1922}1928}
19231929
1930Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) {
1931 return os_file_open_rw(full_path, out_file, attr, false, 0);
1932}
1933
1934Error os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_t mode) {
1935 return os_file_open_rw(full_path, out_file, attr, true, mode);
1936}
1937
1924Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {1938Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {
1925#if defined(ZIG_OS_WINDOWS)1939#if defined(ZIG_OS_WINDOWS)
1926 for (;;) {1940 for (;;) {
...@@ -1966,6 +1980,7 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {...@@ -1966,6 +1980,7 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {
1966 case EFAULT:1980 case EFAULT:
1967 zig_unreachable();1981 zig_unreachable();
1968 case EACCES:1982 case EACCES:
1983 case EPERM:
1969 return ErrorAccess;1984 return ErrorAccess;
1970 case EISDIR:1985 case EISDIR:
1971 return ErrorIsDir;1986 return ErrorIsDir;
...@@ -2114,21 +2129,3 @@ void os_file_close(OsFile *file) {...@@ -2114,21 +2129,3 @@ void os_file_close(OsFile *file) {
2114 *file = -1;2129 *file = -1;
2115#endif2130#endif
2116}2131}
2117
2118#ifdef ZIG_OS_LINUX
2119const char *possible_ld_names[] = {
2120#if defined(ZIG_ARCH_X86_64)
2121 "ld-linux-x86-64.so.2",
2122 "ld-musl-x86_64.so.1",
2123#elif defined(ZIG_ARCH_ARM64)
2124 "ld-linux-aarch64.so.1",
2125 "ld-musl-aarch64.so.1",
2126#elif defined(ZIG_ARCH_ARM)
2127 "ld-linux-armhf.so.3",
2128 "ld-musl-armhf.so.1",
2129 "ld-linux.so.3",
2130 "ld-musl-arm.so.1",
2131#endif
2132 NULL,
2133};
2134#endif
src/os.hpp+6-10
...@@ -43,10 +43,6 @@...@@ -43,10 +43,6 @@
43#define ZIG_ARCH_UNKNOWN43#define ZIG_ARCH_UNKNOWN
44#endif44#endif
4545
46#ifdef ZIG_OS_LINUX
47extern const char *possible_ld_names[];
48#endif
49
50#if defined(ZIG_OS_WINDOWS)46#if defined(ZIG_OS_WINDOWS)
51#define ZIG_PRI_usize "I64u"47#define ZIG_PRI_usize "I64u"
52#define ZIG_PRI_i64 "I64d"48#define ZIG_PRI_i64 "I64d"
...@@ -93,13 +89,15 @@ struct Termination {...@@ -93,13 +89,15 @@ struct Termination {
93#endif89#endif
9490
95struct OsTimeStamp {91struct OsTimeStamp {
96 uint64_t sec;92 int64_t sec;
97 uint64_t nsec;93 int64_t nsec;
98};94};
9995
100struct OsFileAttr {96struct OsFileAttr {
101 OsTimeStamp mtime;97 OsTimeStamp mtime;
98 uint64_t size;
102 uint64_t inode;99 uint64_t inode;
100 uint32_t mode;
103};101};
104102
105int os_init(void);103int os_init(void);
...@@ -121,6 +119,7 @@ Error ATTRIBUTE_MUST_USE os_make_path(Buf *path);...@@ -121,6 +119,7 @@ Error ATTRIBUTE_MUST_USE os_make_path(Buf *path);
121Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path);119Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path);
122120
123Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr);121Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr);
122Error ATTRIBUTE_MUST_USE os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_t mode);
124Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file);123Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file);
125Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len);124Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len);
126Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents);125Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents);
...@@ -129,6 +128,7 @@ void os_file_close(OsFile *file);...@@ -129,6 +128,7 @@ void os_file_close(OsFile *file);
129128
130Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents);129Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents);
131Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path);130Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path);
131Error ATTRIBUTE_MUST_USE os_update_file(Buf *src_path, Buf *dest_path);
132132
133Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents);133Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents);
134Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents);134Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents);
...@@ -152,10 +152,6 @@ Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path);...@@ -152,10 +152,6 @@ Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path);
152152
153Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname);153Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname);
154154
155Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
156Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
157Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
158
159Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);155Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);
160156
161#endif157#endif
src/stage2.cpp created+177
...@@ -0,0 +1,177 @@
1// This file is a shim for zig1. The real implementations of these are in
2// src-self-hosted/stage1.zig
3
4#include "stage2.h"
5#include "util.hpp"
6#include "zig_llvm.h"
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11Error stage2_translate_c(struct Stage2Ast **out_ast,
12 struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len,
13 const char **args_begin, const char **args_end, const char *resources_path)
14{
15 const char *msg = "stage0 called stage2_translate_c";
16 stage2_panic(msg, strlen(msg));
17}
18
19void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len) {
20 const char *msg = "stage0 called stage2_free_clang_errors";
21 stage2_panic(msg, strlen(msg));
22}
23
24void stage2_zen(const char **ptr, size_t *len) {
25 const char *msg = "stage0 called stage2_zen";
26 stage2_panic(msg, strlen(msg));
27}
28
29void stage2_attach_segfault_handler(void) { }
30
31void stage2_panic(const char *ptr, size_t len) {
32 fwrite(ptr, 1, len, stderr);
33 fprintf(stderr, "\n");
34 fflush(stderr);
35 abort();
36}
37
38void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file) {
39 const char *msg = "stage0 called stage2_render_ast";
40 stage2_panic(msg, strlen(msg));
41}
42
43int stage2_fmt(int argc, char **argv) {
44 const char *msg = "stage0 called stage2_fmt";
45 stage2_panic(msg, strlen(msg));
46}
47
48stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len) {
49 const char *msg = "stage0 called stage2_DepTokenizer_init";
50 stage2_panic(msg, strlen(msg));
51}
52
53void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self) {
54 const char *msg = "stage0 called stage2_DepTokenizer_deinit";
55 stage2_panic(msg, strlen(msg));
56}
57
58stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self) {
59 const char *msg = "stage0 called stage2_DepTokenizer_next";
60 stage2_panic(msg, strlen(msg));
61}
62
63
64struct Stage2Progress {
65 int trash;
66};
67
68struct Stage2ProgressNode {
69 int trash;
70};
71
72Stage2Progress *stage2_progress_create(void) {
73 return nullptr;
74}
75
76void stage2_progress_destroy(Stage2Progress *progress) {}
77
78Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
79 const char *name_ptr, size_t name_len, size_t estimated_total_items)
80{
81 return nullptr;
82}
83Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
84 const char *name_ptr, size_t name_len, size_t estimated_total_items)
85{
86 return nullptr;
87}
88void stage2_progress_end(Stage2ProgressNode *node) {}
89void stage2_progress_complete_one(Stage2ProgressNode *node) {}
90void stage2_progress_disable_tty(Stage2Progress *progress) {}
91void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
92
93struct Stage2CpuFeatures {
94 const char *llvm_cpu_name;
95 const char *llvm_cpu_features;
96 const char *builtin_str;
97 const char *cache_hash;
98};
99
100Error stage2_cpu_features_parse(struct Stage2CpuFeatures **out, const char *zig_triple,
101 const char *cpu_name, const char *cpu_features)
102{
103 if (zig_triple == nullptr) {
104 Stage2CpuFeatures *result = heap::c_allocator.create<Stage2CpuFeatures>();
105 result->llvm_cpu_name = ZigLLVMGetHostCPUName();
106 result->llvm_cpu_features = ZigLLVMGetNativeFeatures();
107 result->builtin_str = "arch.getBaselineCpuFeatures();\n";
108 result->cache_hash = "native\n\n";
109 *out = result;
110 return ErrorNone;
111 }
112 if (cpu_name == nullptr && cpu_features == nullptr) {
113 Stage2CpuFeatures *result = heap::c_allocator.create<Stage2CpuFeatures>();
114 result->builtin_str = "arch.getBaselineCpuFeatures();\n";
115 result->cache_hash = "\n\n";
116 *out = result;
117 return ErrorNone;
118 }
119
120 const char *msg = "stage0 called stage2_cpu_features_parse with non-null cpu name or features";
121 stage2_panic(msg, strlen(msg));
122}
123
124void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features,
125 const char **ptr, size_t *len)
126{
127 *ptr = cpu_features->cache_hash;
128 *len = strlen(cpu_features->cache_hash);
129}
130const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features) {
131 return cpu_features->llvm_cpu_name;
132}
133const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features) {
134 return cpu_features->llvm_cpu_features;
135}
136void stage2_cpu_features_get_builtin_str(const Stage2CpuFeatures *cpu_features,
137 const char **ptr, size_t *len)
138{
139 *ptr = cpu_features->builtin_str;
140 *len = strlen(cpu_features->builtin_str);
141}
142
143int stage2_cmd_targets(const char *zig_triple) {
144 const char *msg = "stage0 called stage2_cmd_targets";
145 stage2_panic(msg, strlen(msg));
146}
147
148enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, const char *libc_file) {
149 libc->include_dir = "/dummy/include";
150 libc->include_dir_len = strlen(libc->include_dir);
151 libc->sys_include_dir = "/dummy/sys/include";
152 libc->sys_include_dir_len = strlen(libc->sys_include_dir);
153 libc->crt_dir = "";
154 libc->crt_dir_len = strlen(libc->crt_dir);
155 libc->static_crt_dir = "";
156 libc->static_crt_dir_len = strlen(libc->static_crt_dir);
157 libc->msvc_lib_dir = "";
158 libc->msvc_lib_dir_len = strlen(libc->msvc_lib_dir);
159 libc->kernel32_lib_dir = "";
160 libc->kernel32_lib_dir_len = strlen(libc->kernel32_lib_dir);
161 return ErrorNone;
162}
163
164enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file) {
165 const char *msg = "stage0 called stage2_libc_render";
166 stage2_panic(msg, strlen(msg));
167}
168
169enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) {
170 const char *msg = "stage0 called stage2_libc_find_native";
171 stage2_panic(msg, strlen(msg));
172}
173
174enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, char **out_ptr, size_t *out_len) {
175 const char *msg = "stage0 called stage2_detect_dynamic_linker";
176 stage2_panic(msg, strlen(msg));
177}
src/stage2.h created+315
...@@ -0,0 +1,315 @@
1/*
2 * Copyright (c) 2019 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_STAGE2_H
9#define ZIG_STAGE2_H
10
11#include <stddef.h>
12#include <stdint.h>
13#include <stdio.h>
14
15#include "zig_llvm.h"
16
17#ifdef __cplusplus
18#define ZIG_EXTERN_C extern "C"
19#else
20#define ZIG_EXTERN_C
21#endif
22
23#if defined(_MSC_VER)
24#define ZIG_ATTRIBUTE_NORETURN __declspec(noreturn)
25#else
26#define ZIG_ATTRIBUTE_NORETURN __attribute__((noreturn))
27#endif
28
29// ABI warning: the types and declarations in this file must match both those in
30// stage2.cpp and src-self-hosted/stage2.zig.
31
32// ABI warning
33enum Error {
34 ErrorNone,
35 ErrorNoMem,
36 ErrorInvalidFormat,
37 ErrorSemanticAnalyzeFail,
38 ErrorAccess,
39 ErrorInterrupted,
40 ErrorSystemResources,
41 ErrorFileNotFound,
42 ErrorFileSystem,
43 ErrorFileTooBig,
44 ErrorDivByZero,
45 ErrorOverflow,
46 ErrorPathAlreadyExists,
47 ErrorUnexpected,
48 ErrorExactDivRemainder,
49 ErrorNegativeDenominator,
50 ErrorShiftedOutOneBits,
51 ErrorCCompileErrors,
52 ErrorEndOfFile,
53 ErrorIsDir,
54 ErrorNotDir,
55 ErrorUnsupportedOperatingSystem,
56 ErrorSharingViolation,
57 ErrorPipeBusy,
58 ErrorPrimitiveTypeNotFound,
59 ErrorCacheUnavailable,
60 ErrorPathTooLong,
61 ErrorCCompilerCannotFindFile,
62 ErrorNoCCompilerInstalled,
63 ErrorReadingDepFile,
64 ErrorInvalidDepFile,
65 ErrorMissingArchitecture,
66 ErrorMissingOperatingSystem,
67 ErrorUnknownArchitecture,
68 ErrorUnknownOperatingSystem,
69 ErrorUnknownABI,
70 ErrorInvalidFilename,
71 ErrorDiskQuota,
72 ErrorDiskSpace,
73 ErrorUnexpectedWriteFailure,
74 ErrorUnexpectedSeekFailure,
75 ErrorUnexpectedFileTruncationFailure,
76 ErrorUnimplemented,
77 ErrorOperationAborted,
78 ErrorBrokenPipe,
79 ErrorNoSpaceLeft,
80 ErrorNotLazy,
81 ErrorIsAsync,
82 ErrorImportOutsidePkgPath,
83 ErrorUnknownCpu,
84 ErrorUnknownSubArchitecture,
85 ErrorUnknownCpuFeature,
86 ErrorInvalidCpuFeatures,
87 ErrorInvalidLlvmCpuFeaturesFormat,
88 ErrorUnknownApplicationBinaryInterface,
89 ErrorASTUnitFailure,
90 ErrorBadPathName,
91 ErrorSymLinkLoop,
92 ErrorProcessFdQuotaExceeded,
93 ErrorSystemFdQuotaExceeded,
94 ErrorNoDevice,
95 ErrorDeviceBusy,
96 ErrorUnableToSpawnCCompiler,
97 ErrorCCompilerExitCode,
98 ErrorCCompilerCrashed,
99 ErrorCCompilerCannotFindHeaders,
100 ErrorLibCRuntimeNotFound,
101 ErrorLibCStdLibHeaderNotFound,
102 ErrorLibCKernel32LibNotFound,
103 ErrorUnsupportedArchitecture,
104 ErrorWindowsSdkNotFound,
105 ErrorUnknownDynamicLinkerPath,
106 ErrorTargetHasNoDynamicLinker,
107};
108
109// ABI warning
110struct Stage2ErrorMsg {
111 const char *filename_ptr; // can be null
112 size_t filename_len;
113 const char *msg_ptr;
114 size_t msg_len;
115 const char *source; // valid until the ASTUnit is freed. can be null
116 unsigned line; // 0 based
117 unsigned column; // 0 based
118 unsigned offset; // byte offset into source
119};
120
121// ABI warning
122struct Stage2Ast;
123
124// ABI warning
125ZIG_EXTERN_C enum Error stage2_translate_c(struct Stage2Ast **out_ast,
126 struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len,
127 const char **args_begin, const char **args_end, const char *resources_path);
128
129// ABI warning
130ZIG_EXTERN_C void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len);
131
132// ABI warning
133ZIG_EXTERN_C void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file);
134
135// ABI warning
136ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len);
137
138// ABI warning
139ZIG_EXTERN_C void stage2_attach_segfault_handler(void);
140
141// ABI warning
142ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len);
143
144// ABI warning
145ZIG_EXTERN_C int stage2_fmt(int argc, char **argv);
146
147// ABI warning
148struct stage2_DepTokenizer {
149 void *handle;
150};
151
152// ABI warning
153struct stage2_DepNextResult {
154 enum TypeId {
155 error,
156 null,
157 target,
158 prereq,
159 };
160
161 TypeId type_id;
162
163 // when ent == error --> error text
164 // when ent == null --> undefined
165 // when ent == target --> target pathname
166 // when ent == prereq --> prereq pathname
167 const char *textz;
168};
169
170// ABI warning
171ZIG_EXTERN_C stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len);
172
173// ABI warning
174ZIG_EXTERN_C void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self);
175
176// ABI warning
177ZIG_EXTERN_C stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self);
178
179// ABI warning
180struct Stage2Progress;
181// ABI warning
182struct Stage2ProgressNode;
183// ABI warning
184ZIG_EXTERN_C Stage2Progress *stage2_progress_create(void);
185// ABI warning
186ZIG_EXTERN_C void stage2_progress_disable_tty(Stage2Progress *progress);
187// ABI warning
188ZIG_EXTERN_C void stage2_progress_destroy(Stage2Progress *progress);
189// ABI warning
190ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
191 const char *name_ptr, size_t name_len, size_t estimated_total_items);
192// ABI warning
193ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
194 const char *name_ptr, size_t name_len, size_t estimated_total_items);
195// ABI warning
196ZIG_EXTERN_C void stage2_progress_end(Stage2ProgressNode *node);
197// ABI warning
198ZIG_EXTERN_C void stage2_progress_complete_one(Stage2ProgressNode *node);
199// ABI warning
200ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node,
201 size_t completed_count, size_t estimated_total_items);
202
203// ABI warning
204struct Stage2CpuFeatures;
205
206// ABI warning
207ZIG_EXTERN_C enum Error stage2_cpu_features_parse(struct Stage2CpuFeatures **result,
208 const char *zig_triple, const char *cpu_name, const char *cpu_features);
209
210// ABI warning
211ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const struct Stage2CpuFeatures *cpu_features);
212
213// ABI warning
214ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_features(const struct Stage2CpuFeatures *cpu_features);
215
216// ABI warning
217ZIG_EXTERN_C void stage2_cpu_features_get_builtin_str(const struct Stage2CpuFeatures *cpu_features,
218 const char **ptr, size_t *len);
219
220// ABI warning
221ZIG_EXTERN_C void stage2_cpu_features_get_cache_hash(const struct Stage2CpuFeatures *cpu_features,
222 const char **ptr, size_t *len);
223
224// ABI warning
225ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple);
226
227// ABI warning
228struct Stage2LibCInstallation {
229 const char *include_dir;
230 size_t include_dir_len;
231 const char *sys_include_dir;
232 size_t sys_include_dir_len;
233 const char *crt_dir;
234 size_t crt_dir_len;
235 const char *static_crt_dir;
236 size_t static_crt_dir_len;
237 const char *msvc_lib_dir;
238 size_t msvc_lib_dir_len;
239 const char *kernel32_lib_dir;
240 size_t kernel32_lib_dir_len;
241};
242
243// ABI warning
244ZIG_EXTERN_C enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, const char *libc_file);
245// ABI warning
246ZIG_EXTERN_C enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file);
247// ABI warning
248ZIG_EXTERN_C enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc);
249
250// ABI warning
251// Synchronize with target.cpp::os_list
252enum Os {
253 OsFreestanding,
254 OsAnanas,
255 OsCloudABI,
256 OsDragonFly,
257 OsFreeBSD,
258 OsFuchsia,
259 OsIOS,
260 OsKFreeBSD,
261 OsLinux,
262 OsLv2, // PS3
263 OsMacOSX,
264 OsNetBSD,
265 OsOpenBSD,
266 OsSolaris,
267 OsWindows,
268 OsHaiku,
269 OsMinix,
270 OsRTEMS,
271 OsNaCl, // Native Client
272 OsCNK, // BG/P Compute-Node Kernel
273 OsAIX,
274 OsCUDA, // NVIDIA CUDA
275 OsNVCL, // NVIDIA OpenCL
276 OsAMDHSA, // AMD HSA Runtime
277 OsPS4,
278 OsELFIAMCU,
279 OsTvOS, // Apple tvOS
280 OsWatchOS, // Apple watchOS
281 OsMesa3D,
282 OsContiki,
283 OsAMDPAL,
284 OsHermitCore,
285 OsHurd,
286 OsWASI,
287 OsEmscripten,
288 OsUefi,
289 OsOther,
290};
291
292// ABI warning
293struct ZigGLibCVersion {
294 uint32_t major; // always 2
295 uint32_t minor;
296 uint32_t patch;
297};
298
299// ABI warning
300struct ZigTarget {
301 enum ZigLLVM_ArchType arch;
302 enum ZigLLVM_SubArchType sub_arch;
303 enum ZigLLVM_VendorType vendor;
304 Os os;
305 enum ZigLLVM_EnvironmentType abi;
306 struct ZigGLibCVersion *glibc_version; // null means default
307 struct Stage2CpuFeatures *cpu_features;
308 bool is_native;
309};
310
311// ABI warning
312ZIG_EXTERN_C enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target,
313 char **out_ptr, size_t *out_len);
314
315#endif
src/target.cpp-203
...@@ -1204,213 +1204,10 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static,...@@ -1204,213 +1204,10 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
1204 }1204 }
1205}1205}
12061206
1207enum FloatAbi {
1208 FloatAbiHard,
1209 FloatAbiSoft,
1210 FloatAbiSoftFp,
1211};
1212
1213static FloatAbi get_float_abi(const ZigTarget *target) {
1214 const ZigLLVM_EnvironmentType env = target->abi;
1215 if (env == ZigLLVM_GNUEABIHF ||
1216 env == ZigLLVM_EABIHF ||
1217 env == ZigLLVM_MuslEABIHF)
1218 {
1219 return FloatAbiHard;
1220 } else {
1221 return FloatAbiSoft;
1222 }
1223}
1224
1225static bool is_64_bit(ZigLLVM_ArchType arch) {
1226 return target_arch_pointer_bit_width(arch) == 64;
1227}
1228
1229bool target_is_android(const ZigTarget *target) {1207bool target_is_android(const ZigTarget *target) {
1230 return target->abi == ZigLLVM_Android;1208 return target->abi == ZigLLVM_Android;
1231}1209}
12321210
1233const char *target_dynamic_linker(const ZigTarget *target) {
1234 if (target_is_android(target)) {
1235 return is_64_bit(target->arch) ? "/system/bin/linker64" : "/system/bin/linker";
1236 }
1237
1238 if (target_is_musl(target)) {
1239 Buf buf = BUF_INIT;
1240 buf_init_from_str(&buf, "/lib/ld-musl-");
1241 bool is_arm = false;
1242 switch (target->arch) {
1243 case ZigLLVM_arm:
1244 case ZigLLVM_thumb:
1245 buf_append_str(&buf, "arm");
1246 is_arm = true;
1247 break;
1248 case ZigLLVM_armeb:
1249 case ZigLLVM_thumbeb:
1250 buf_append_str(&buf, "armeb");
1251 is_arm = true;
1252 break;
1253 default:
1254 buf_append_str(&buf, target_arch_name(target->arch));
1255 }
1256 if (is_arm && get_float_abi(target) == FloatAbiHard) {
1257 buf_append_str(&buf, "hf");
1258 }
1259 buf_append_str(&buf, ".so.1");
1260 return buf_ptr(&buf);
1261 }
1262
1263 switch (target->os) {
1264 case OsFreeBSD:
1265 return "/libexec/ld-elf.so.1";
1266 case OsNetBSD:
1267 return "/libexec/ld.elf_so";
1268 case OsDragonFly:
1269 return "/libexec/ld-elf.so.2";
1270 case OsLinux: {
1271 const ZigLLVM_EnvironmentType abi = target->abi;
1272 switch (target->arch) {
1273 case ZigLLVM_UnknownArch:
1274 zig_unreachable();
1275 case ZigLLVM_x86:
1276 case ZigLLVM_sparc:
1277 case ZigLLVM_sparcel:
1278 return "/lib/ld-linux.so.2";
1279
1280 case ZigLLVM_aarch64:
1281 return "/lib/ld-linux-aarch64.so.1";
1282
1283 case ZigLLVM_aarch64_be:
1284 return "/lib/ld-linux-aarch64_be.so.1";
1285
1286 case ZigLLVM_aarch64_32:
1287 return "/lib/ld-linux-aarch64_32.so.1";
1288
1289 case ZigLLVM_arm:
1290 case ZigLLVM_thumb:
1291 if (get_float_abi(target) == FloatAbiHard) {
1292 return "/lib/ld-linux-armhf.so.3";
1293 } else {
1294 return "/lib/ld-linux.so.3";
1295 }
1296
1297 case ZigLLVM_armeb:
1298 case ZigLLVM_thumbeb:
1299 if (get_float_abi(target) == FloatAbiHard) {
1300 return "/lib/ld-linux-armhf.so.3";
1301 } else {
1302 return "/lib/ld-linux.so.3";
1303 }
1304
1305 case ZigLLVM_mips:
1306 case ZigLLVM_mipsel:
1307 case ZigLLVM_mips64:
1308 case ZigLLVM_mips64el:
1309 zig_panic("TODO implement target_dynamic_linker for mips");
1310
1311 case ZigLLVM_ppc:
1312 return "/lib/ld.so.1";
1313
1314 case ZigLLVM_ppc64:
1315 return "/lib64/ld64.so.2";
1316
1317 case ZigLLVM_ppc64le:
1318 return "/lib64/ld64.so.2";
1319
1320 case ZigLLVM_systemz:
1321 return "/lib64/ld64.so.1";
1322
1323 case ZigLLVM_sparcv9:
1324 return "/lib64/ld-linux.so.2";
1325
1326 case ZigLLVM_x86_64:
1327 if (abi == ZigLLVM_GNUX32) {
1328 return "/libx32/ld-linux-x32.so.2";
1329 }
1330 if (abi == ZigLLVM_Musl || abi == ZigLLVM_MuslEABI || abi == ZigLLVM_MuslEABIHF) {
1331 return "/lib/ld-musl-x86_64.so.1";
1332 }
1333 return "/lib64/ld-linux-x86-64.so.2";
1334
1335 case ZigLLVM_wasm32:
1336 case ZigLLVM_wasm64:
1337 return nullptr;
1338
1339 case ZigLLVM_riscv32:
1340 return "/lib/ld-linux-riscv32-ilp32.so.1";
1341 case ZigLLVM_riscv64:
1342 return "/lib/ld-linux-riscv64-lp64.so.1";
1343
1344 case ZigLLVM_arc:
1345 case ZigLLVM_avr:
1346 case ZigLLVM_bpfel:
1347 case ZigLLVM_bpfeb:
1348 case ZigLLVM_hexagon:
1349 case ZigLLVM_msp430:
1350 case ZigLLVM_r600:
1351 case ZigLLVM_amdgcn:
1352 case ZigLLVM_tce:
1353 case ZigLLVM_tcele:
1354 case ZigLLVM_xcore:
1355 case ZigLLVM_nvptx:
1356 case ZigLLVM_nvptx64:
1357 case ZigLLVM_le32:
1358 case ZigLLVM_le64:
1359 case ZigLLVM_amdil:
1360 case ZigLLVM_amdil64:
1361 case ZigLLVM_hsail:
1362 case ZigLLVM_hsail64:
1363 case ZigLLVM_spir:
1364 case ZigLLVM_spir64:
1365 case ZigLLVM_kalimba:
1366 case ZigLLVM_shave:
1367 case ZigLLVM_lanai:
1368 case ZigLLVM_renderscript32:
1369 case ZigLLVM_renderscript64:
1370 zig_panic("TODO implement target_dynamic_linker for this arch");
1371 }
1372 zig_unreachable();
1373 }
1374 case OsFreestanding:
1375 case OsIOS:
1376 case OsTvOS:
1377 case OsWatchOS:
1378 case OsMacOSX:
1379 case OsUefi:
1380 case OsWindows:
1381 case OsEmscripten:
1382 case OsOther:
1383 return nullptr;
1384
1385 case OsAnanas:
1386 case OsCloudABI:
1387 case OsFuchsia:
1388 case OsKFreeBSD:
1389 case OsLv2:
1390 case OsOpenBSD:
1391 case OsSolaris:
1392 case OsHaiku:
1393 case OsMinix:
1394 case OsRTEMS:
1395 case OsNaCl:
1396 case OsCNK:
1397 case OsAIX:
1398 case OsCUDA:
1399 case OsNVCL:
1400 case OsAMDHSA:
1401 case OsPS4:
1402 case OsELFIAMCU:
1403 case OsMesa3D:
1404 case OsContiki:
1405 case OsAMDPAL:
1406 case OsHermitCore:
1407 case OsHurd:
1408 case OsWASI:
1409 zig_panic("TODO implement target_dynamic_linker for this OS");
1410 }
1411 zig_unreachable();
1412}
1413
1414bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target) {1211bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target) {
1415 assert(host_target != nullptr);1212 assert(host_target != nullptr);
14161213
src/target.hpp+1-61
...@@ -8,51 +8,10 @@...@@ -8,51 +8,10 @@
8#ifndef ZIG_TARGET_HPP8#ifndef ZIG_TARGET_HPP
9#define ZIG_TARGET_HPP9#define ZIG_TARGET_HPP
1010
11#include <zig_llvm.h>11#include "stage2.h"
1212
13struct Buf;13struct Buf;
1414
15// Synchronize with target.cpp::os_list
16enum Os {
17 OsFreestanding,
18 OsAnanas,
19 OsCloudABI,
20 OsDragonFly,
21 OsFreeBSD,
22 OsFuchsia,
23 OsIOS,
24 OsKFreeBSD,
25 OsLinux,
26 OsLv2, // PS3
27 OsMacOSX,
28 OsNetBSD,
29 OsOpenBSD,
30 OsSolaris,
31 OsWindows,
32 OsHaiku,
33 OsMinix,
34 OsRTEMS,
35 OsNaCl, // Native Client
36 OsCNK, // BG/P Compute-Node Kernel
37 OsAIX,
38 OsCUDA, // NVIDIA CUDA
39 OsNVCL, // NVIDIA OpenCL
40 OsAMDHSA, // AMD HSA Runtime
41 OsPS4,
42 OsELFIAMCU,
43 OsTvOS, // Apple tvOS
44 OsWatchOS, // Apple watchOS
45 OsMesa3D,
46 OsContiki,
47 OsAMDPAL,
48 OsHermitCore,
49 OsHurd,
50 OsWASI,
51 OsEmscripten,
52 OsUefi,
53 OsOther,
54};
55
56// Synchronize with target.cpp::subarch_list_list15// Synchronize with target.cpp::subarch_list_list
57enum SubArchList {16enum SubArchList {
58 SubArchListNone,17 SubArchListNone,
...@@ -78,23 +37,6 @@ enum TargetSubsystem {...@@ -78,23 +37,6 @@ enum TargetSubsystem {
78 TargetSubsystemAuto37 TargetSubsystemAuto
79};38};
8039
81struct ZigGLibCVersion {
82 uint32_t major; // always 2
83 uint32_t minor;
84 uint32_t patch;
85};
86
87struct ZigTarget {
88 ZigLLVM_ArchType arch;
89 ZigLLVM_SubArchType sub_arch;
90 ZigLLVM_VendorType vendor;
91 Os os;
92 ZigLLVM_EnvironmentType abi;
93 ZigGLibCVersion *glibc_version; // null means default
94 Stage2CpuFeatures *cpu_features;
95 bool is_native;
96};
97
98enum CIntType {40enum CIntType {
99 CIntTypeShort,41 CIntTypeShort,
100 CIntTypeUShort,42 CIntTypeUShort,
...@@ -168,8 +110,6 @@ const char *target_lib_file_prefix(const ZigTarget *target);...@@ -168,8 +110,6 @@ const char *target_lib_file_prefix(const ZigTarget *target);
168const char *target_lib_file_ext(const ZigTarget *target, bool is_static,110const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
169 size_t version_major, size_t version_minor, size_t version_patch);111 size_t version_major, size_t version_minor, size_t version_patch);
170112
171const char *target_dynamic_linker(const ZigTarget *target);
172
173bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);113bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);
174ZigLLVM_OSType get_llvm_os_type(Os os_type);114ZigLLVM_OSType get_llvm_os_type(Os os_type);
175115
src/userland.cpp deleted-146
...@@ -1,146 +0,0 @@
1// This file is a shim for zig1. The real implementations of these are in
2// src-self-hosted/stage1.zig
3
4#include "userland.h"
5#include "util.hpp"
6#include "zig_llvm.h"
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11Error stage2_translate_c(struct Stage2Ast **out_ast,
12 struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len,
13 const char **args_begin, const char **args_end, const char *resources_path)
14{
15 const char *msg = "stage0 called stage2_translate_c";
16 stage2_panic(msg, strlen(msg));
17}
18
19void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len) {
20 const char *msg = "stage0 called stage2_free_clang_errors";
21 stage2_panic(msg, strlen(msg));
22}
23
24void stage2_zen(const char **ptr, size_t *len) {
25 const char *msg = "stage0 called stage2_zen";
26 stage2_panic(msg, strlen(msg));
27}
28
29void stage2_attach_segfault_handler(void) { }
30
31void stage2_panic(const char *ptr, size_t len) {
32 fwrite(ptr, 1, len, stderr);
33 fprintf(stderr, "\n");
34 fflush(stderr);
35 abort();
36}
37
38void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file) {
39 const char *msg = "stage0 called stage2_render_ast";
40 stage2_panic(msg, strlen(msg));
41}
42
43int stage2_fmt(int argc, char **argv) {
44 const char *msg = "stage0 called stage2_fmt";
45 stage2_panic(msg, strlen(msg));
46}
47
48stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len) {
49 const char *msg = "stage0 called stage2_DepTokenizer_init";
50 stage2_panic(msg, strlen(msg));
51}
52
53void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self) {
54 const char *msg = "stage0 called stage2_DepTokenizer_deinit";
55 stage2_panic(msg, strlen(msg));
56}
57
58stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self) {
59 const char *msg = "stage0 called stage2_DepTokenizer_next";
60 stage2_panic(msg, strlen(msg));
61}
62
63
64struct Stage2Progress {
65 int trash;
66};
67
68struct Stage2ProgressNode {
69 int trash;
70};
71
72Stage2Progress *stage2_progress_create(void) {
73 return nullptr;
74}
75
76void stage2_progress_destroy(Stage2Progress *progress) {}
77
78Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
79 const char *name_ptr, size_t name_len, size_t estimated_total_items)
80{
81 return nullptr;
82}
83Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
84 const char *name_ptr, size_t name_len, size_t estimated_total_items)
85{
86 return nullptr;
87}
88void stage2_progress_end(Stage2ProgressNode *node) {}
89void stage2_progress_complete_one(Stage2ProgressNode *node) {}
90void stage2_progress_disable_tty(Stage2Progress *progress) {}
91void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
92
93struct Stage2CpuFeatures {
94 const char *llvm_cpu_name;
95 const char *llvm_cpu_features;
96 const char *builtin_str;
97 const char *cache_hash;
98};
99
100Error stage2_cpu_features_parse(struct Stage2CpuFeatures **out, const char *zig_triple,
101 const char *cpu_name, const char *cpu_features)
102{
103 if (zig_triple == nullptr) {
104 Stage2CpuFeatures *result = heap::c_allocator.create<Stage2CpuFeatures>();
105 result->llvm_cpu_name = ZigLLVMGetHostCPUName();
106 result->llvm_cpu_features = ZigLLVMGetNativeFeatures();
107 result->builtin_str = "arch.getBaselineCpuFeatures();\n";
108 result->cache_hash = "native\n\n";
109 *out = result;
110 return ErrorNone;
111 }
112 if (cpu_name == nullptr && cpu_features == nullptr) {
113 Stage2CpuFeatures *result = heap::c_allocator.create<Stage2CpuFeatures>();
114 result->builtin_str = "arch.getBaselineCpuFeatures();\n";
115 result->cache_hash = "\n\n";
116 *out = result;
117 return ErrorNone;
118 }
119
120 const char *msg = "stage0 called stage2_cpu_features_parse with non-null cpu name or features";
121 stage2_panic(msg, strlen(msg));
122}
123
124void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features,
125 const char **ptr, size_t *len)
126{
127 *ptr = cpu_features->cache_hash;
128 *len = strlen(cpu_features->cache_hash);
129}
130const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features) {
131 return cpu_features->llvm_cpu_name;
132}
133const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features) {
134 return cpu_features->llvm_cpu_features;
135}
136void stage2_cpu_features_get_builtin_str(const Stage2CpuFeatures *cpu_features,
137 const char **ptr, size_t *len)
138{
139 *ptr = cpu_features->builtin_str;
140 *len = strlen(cpu_features->builtin_str);
141}
142
143int stage2_cmd_targets(const char *zig_triple) {
144 const char *msg = "stage0 called stage2_cmd_targets";
145 stage2_panic(msg, strlen(msg));
146}
src/userland.h deleted-209
...@@ -1,209 +0,0 @@
1/*
2 * Copyright (c) 2019 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_USERLAND_H
9#define ZIG_USERLAND_H
10
11#include <stddef.h>
12#include <stdint.h>
13#include <stdio.h>
14
15#ifdef __cplusplus
16#define ZIG_EXTERN_C extern "C"
17#else
18#define ZIG_EXTERN_C
19#endif
20
21#if defined(_MSC_VER)
22#define ZIG_ATTRIBUTE_NORETURN __declspec(noreturn)
23#else
24#define ZIG_ATTRIBUTE_NORETURN __attribute__((noreturn))
25#endif
26
27// ABI warning: the types and declarations in this file must match both those in
28// userland.cpp and src-self-hosted/stage1.zig.
29
30// ABI warning
31enum Error {
32 ErrorNone,
33 ErrorNoMem,
34 ErrorInvalidFormat,
35 ErrorSemanticAnalyzeFail,
36 ErrorAccess,
37 ErrorInterrupted,
38 ErrorSystemResources,
39 ErrorFileNotFound,
40 ErrorFileSystem,
41 ErrorFileTooBig,
42 ErrorDivByZero,
43 ErrorOverflow,
44 ErrorPathAlreadyExists,
45 ErrorUnexpected,
46 ErrorExactDivRemainder,
47 ErrorNegativeDenominator,
48 ErrorShiftedOutOneBits,
49 ErrorCCompileErrors,
50 ErrorEndOfFile,
51 ErrorIsDir,
52 ErrorNotDir,
53 ErrorUnsupportedOperatingSystem,
54 ErrorSharingViolation,
55 ErrorPipeBusy,
56 ErrorPrimitiveTypeNotFound,
57 ErrorCacheUnavailable,
58 ErrorPathTooLong,
59 ErrorCCompilerCannotFindFile,
60 ErrorNoCCompilerInstalled,
61 ErrorReadingDepFile,
62 ErrorInvalidDepFile,
63 ErrorMissingArchitecture,
64 ErrorMissingOperatingSystem,
65 ErrorUnknownArchitecture,
66 ErrorUnknownOperatingSystem,
67 ErrorUnknownABI,
68 ErrorInvalidFilename,
69 ErrorDiskQuota,
70 ErrorDiskSpace,
71 ErrorUnexpectedWriteFailure,
72 ErrorUnexpectedSeekFailure,
73 ErrorUnexpectedFileTruncationFailure,
74 ErrorUnimplemented,
75 ErrorOperationAborted,
76 ErrorBrokenPipe,
77 ErrorNoSpaceLeft,
78 ErrorNotLazy,
79 ErrorIsAsync,
80 ErrorImportOutsidePkgPath,
81 ErrorUnknownCpu,
82 ErrorUnknownSubArchitecture,
83 ErrorUnknownCpuFeature,
84 ErrorInvalidCpuFeatures,
85 ErrorInvalidLlvmCpuFeaturesFormat,
86 ErrorUnknownApplicationBinaryInterface,
87 ErrorASTUnitFailure,
88};
89
90// ABI warning
91struct Stage2ErrorMsg {
92 const char *filename_ptr; // can be null
93 size_t filename_len;
94 const char *msg_ptr;
95 size_t msg_len;
96 const char *source; // valid until the ASTUnit is freed. can be null
97 unsigned line; // 0 based
98 unsigned column; // 0 based
99 unsigned offset; // byte offset into source
100};
101
102// ABI warning
103struct Stage2Ast;
104
105// ABI warning
106ZIG_EXTERN_C enum Error stage2_translate_c(struct Stage2Ast **out_ast,
107 struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len,
108 const char **args_begin, const char **args_end, const char *resources_path);
109
110// ABI warning
111ZIG_EXTERN_C void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len);
112
113// ABI warning
114ZIG_EXTERN_C void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file);
115
116// ABI warning
117ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len);
118
119// ABI warning
120ZIG_EXTERN_C void stage2_attach_segfault_handler(void);
121
122// ABI warning
123ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len);
124
125// ABI warning
126ZIG_EXTERN_C int stage2_fmt(int argc, char **argv);
127
128// ABI warning
129struct stage2_DepTokenizer {
130 void *handle;
131};
132
133// ABI warning
134struct stage2_DepNextResult {
135 enum TypeId {
136 error,
137 null,
138 target,
139 prereq,
140 };
141
142 TypeId type_id;
143
144 // when ent == error --> error text
145 // when ent == null --> undefined
146 // when ent == target --> target pathname
147 // when ent == prereq --> prereq pathname
148 const char *textz;
149};
150
151// ABI warning
152ZIG_EXTERN_C stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len);
153
154// ABI warning
155ZIG_EXTERN_C void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self);
156
157// ABI warning
158ZIG_EXTERN_C stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self);
159
160// ABI warning
161struct Stage2Progress;
162// ABI warning
163struct Stage2ProgressNode;
164// ABI warning
165ZIG_EXTERN_C Stage2Progress *stage2_progress_create(void);
166// ABI warning
167ZIG_EXTERN_C void stage2_progress_disable_tty(Stage2Progress *progress);
168// ABI warning
169ZIG_EXTERN_C void stage2_progress_destroy(Stage2Progress *progress);
170// ABI warning
171ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
172 const char *name_ptr, size_t name_len, size_t estimated_total_items);
173// ABI warning
174ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
175 const char *name_ptr, size_t name_len, size_t estimated_total_items);
176// ABI warning
177ZIG_EXTERN_C void stage2_progress_end(Stage2ProgressNode *node);
178// ABI warning
179ZIG_EXTERN_C void stage2_progress_complete_one(Stage2ProgressNode *node);
180// ABI warning
181ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node,
182 size_t completed_count, size_t estimated_total_items);
183
184// ABI warning
185struct Stage2CpuFeatures;
186
187// ABI warning
188ZIG_EXTERN_C Error stage2_cpu_features_parse(struct Stage2CpuFeatures **result,
189 const char *zig_triple, const char *cpu_name, const char *cpu_features);
190
191// ABI warning
192ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const struct Stage2CpuFeatures *cpu_features);
193
194// ABI warning
195ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_features(const struct Stage2CpuFeatures *cpu_features);
196
197// ABI warning
198ZIG_EXTERN_C void stage2_cpu_features_get_builtin_str(const struct Stage2CpuFeatures *cpu_features,
199 const char **ptr, size_t *len);
200
201// ABI warning
202ZIG_EXTERN_C void stage2_cpu_features_get_cache_hash(const struct Stage2CpuFeatures *cpu_features,
203 const char **ptr, size_t *len);
204
205// ABI warning
206ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple);
207
208
209#endif
src/util.cpp+1-1
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
6 */6 */
77
8#include "util.hpp"8#include "util.hpp"
9#include "userland.h"9#include "stage2.h"
1010
11#include <stdio.h>11#include <stdio.h>
12#include <stdarg.h>12#include <stdarg.h>
src/windows_sdk.h+4
...@@ -16,6 +16,7 @@...@@ -16,6 +16,7 @@
1616
17#include <stddef.h>17#include <stddef.h>
1818
19// ABI warning - src-self-hosted/windows_sdk.zig
19struct ZigWindowsSDK {20struct ZigWindowsSDK {
20 const char *path10_ptr;21 const char *path10_ptr;
21 size_t path10_len;22 size_t path10_len;
...@@ -33,6 +34,7 @@ struct ZigWindowsSDK {...@@ -33,6 +34,7 @@ struct ZigWindowsSDK {
33 size_t msvc_lib_dir_len;34 size_t msvc_lib_dir_len;
34};35};
3536
37// ABI warning - src-self-hosted/windows_sdk.zig
36enum ZigFindWindowsSdkError {38enum ZigFindWindowsSdkError {
37 ZigFindWindowsSdkErrorNone,39 ZigFindWindowsSdkErrorNone,
38 ZigFindWindowsSdkErrorOutOfMemory,40 ZigFindWindowsSdkErrorOutOfMemory,
...@@ -40,8 +42,10 @@ enum ZigFindWindowsSdkError {...@@ -40,8 +42,10 @@ enum ZigFindWindowsSdkError {
40 ZigFindWindowsSdkErrorPathTooLong,42 ZigFindWindowsSdkErrorPathTooLong,
41};43};
4244
45// ABI warning - src-self-hosted/windows_sdk.zig
43ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk);46ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk);
4447
48// ABI warning - src-self-hosted/windows_sdk.zig
45ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk);49ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk);
4650
47#endif51#endif
src/zig_clang.h+1-1
...@@ -8,7 +8,7 @@...@@ -8,7 +8,7 @@
8#ifndef ZIG_ZIG_CLANG_H8#ifndef ZIG_ZIG_CLANG_H
9#define ZIG_ZIG_CLANG_H9#define ZIG_ZIG_CLANG_H
1010
11#include "userland.h"11#include "stage2.h"
12#include <inttypes.h>12#include <inttypes.h>
13#include <stdbool.h>13#include <stdbool.h>
1414