| author | |
| committer | |
| log | e8a84927ab989d3c8fb6668dd242ada0a8f99585 |
| tree | e0189e9cae971e221f0b76fb4c7e7b096d23959a |
| parent | 35f0cb049e6a46c8037bab15a9debc21ad1a979e |
| parent | 99520c4e6936b69e7489262bc35a70300366d395 |
| signature |
self-hosted libc and dynamic linker detection47 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. |
| 435 | set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp") | 435 | set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp") |
| 436 | 436 | ||
| 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. |
| 438 | set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp") | 438 | set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/stage2.cpp") |
| 439 | 439 | ||
| 440 | if(ZIG_ENABLE_MEM_PROFILE) | 440 | if(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 | ) |
| 568 | 567 | ||
| 569 | add_library(compiler STATIC ${ZIG_SOURCES}) | 568 | add_library(zigcompiler STATIC ${ZIG_SOURCES}) |
| 570 | set_target_properties(compiler PROPERTIES | 569 | set_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 | ) |
| 574 | target_link_libraries(compiler LINK_PUBLIC | 573 | target_link_libraries(zigcompiler LINK_PUBLIC |
| 575 | zig_cpp | 574 | zig_cpp |
| 576 | opt_c_util | 575 | 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 | ) |
| 583 | if(NOT MSVC) | 582 | if(NOT MSVC) |
| 584 | target_link_libraries(compiler LINK_PUBLIC ${LIBXML2}) | 583 | target_link_libraries(zigcompiler LINK_PUBLIC ${LIBXML2}) |
| 585 | endif() | 584 | endif() |
| 586 | 585 | ||
| 587 | if(ZIG_DIA_GUIDS_LIB) | 586 | if(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}) |
| 589 | endif() | 588 | endif() |
| 590 | 589 | ||
| 591 | if(MSVC OR MINGW) | 590 | if(MSVC OR MINGW) |
| 592 | target_link_libraries(compiler LINK_PUBLIC version) | 591 | target_link_libraries(zigcompiler LINK_PUBLIC version) |
| 593 | endif() | 592 | endif() |
| 594 | 593 | ||
| 595 | add_executable(zig0 "${ZIG_MAIN_SRC}" "${ZIG0_SHIM_SRC}") | 594 | add_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 | ) |
| 600 | target_link_libraries(zig0 compiler) | 599 | target_link_libraries(zig0 zigcompiler) |
| 601 | 600 | ||
| 602 | if(MSVC) | 601 | if(MSVC) |
| 603 | set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.lib") | 602 | set(LIBSTAGE2 "${CMAKE_BINARY_DIR}/zigstage2.lib") |
| 604 | else() | 603 | else() |
| 605 | set(LIBUSERLAND "${CMAKE_BINARY_DIR}/libuserland.a") | 604 | set(LIBSTAGE2 "${CMAKE_BINARY_DIR}/libzigstage2.a") |
| 606 | endif() | 605 | endif() |
| 607 | if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") | 606 | if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") |
| 608 | set(LIBUSERLAND_RELEASE_MODE "false") | 607 | set(LIBSTAGE2_RELEASE_ARG "") |
| 609 | else() | 608 | else() |
| 610 | set(LIBUSERLAND_RELEASE_MODE "true") | 609 | set(LIBSTAGE2_RELEASE_ARG --release-fast --strip) |
| 610 | endif() | ||
| 611 | if(WIN32) | ||
| 612 | set(LIBSTAGE2_WINDOWS_ARGS "-lntdll") | ||
| 613 | else() | ||
| 614 | set(LIBSTAGE2_WINDOWS_ARGS "") | ||
| 611 | endif() | 615 | endif() |
| 612 | 616 | ||
| 613 | set(BUILD_LIBUSERLAND_ARGS "build" | 617 | set(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 | libuserland | 625 | --bundle-compiler-rt |
| 626 | -fPIC | ||
| 627 | -lc | ||
| 628 | ${LIBSTAGE2_WINDOWS_ARGS} | ||
| 620 | ) | 629 | ) |
| 621 | 630 | ||
| 622 | # When using Visual Studio build system generator we default to libuserland install. | 631 | add_custom_target(zig_build_libstage2 ALL |
| 623 | if(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() | ||
| 628 | endif() | ||
| 629 | |||
| 630 | add_custom_target(zig_build_libuserland ALL | ||
| 631 | COMMAND zig0 ${BUILD_LIBUSERLAND_ARGS} | ||
| 632 | DEPENDS zig0 | 633 | DEPENDS zig0 |
| 633 | BYPRODUCTS "${LIBUSERLAND}" | 634 | BYPRODUCTS "${LIBSTAGE2}" |
| 634 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" | 635 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" |
| 635 | ) | 636 | ) |
| 636 | add_executable(zig "${ZIG_MAIN_SRC}") | 637 | add_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 | ) |
| 642 | target_link_libraries(zig compiler "${LIBUSERLAND}") | 643 | target_link_libraries(zig zigcompiler "${LIBSTAGE2}") |
| 643 | if(MSVC) | 644 | if(MSVC) |
| 644 | target_link_libraries(zig ntdll.lib) | 645 | target_link_libraries(zig ntdll.lib) |
| 645 | elseif(MINGW) | 646 | elseif(MINGW) |
| 646 | target_link_libraries(zig ntdll) | 647 | target_link_libraries(zig ntdll) |
| 647 | endif() | 648 | endif() |
| 648 | add_dependencies(zig zig_build_libuserland) | 649 | add_dependencies(zig zig_build_libstage2) |
| 649 | 650 | ||
| 650 | install(TARGETS zig DESTINATION bin) | 651 | install(TARGETS zig DESTINATION bin) |
| 651 | 652 | ||
| 652 | # CODE has no effect with Visual Studio build system generator. | 653 | set(ZIG_INSTALL_ARGS "build" |
| 653 | if(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. | ||
| 663 | if(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() | ||
| 673 | else() | ||
| 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) |
| 660 | endif() | 679 | endif() |
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); |
| 66 | 66 | ||
| 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 | } |
| 176 | 174 | ||
| 177 | fn fileExists(filename: []const u8) !bool { | 175 | fn 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 | |||
| 370 | fn 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 @@ |
| 1 | message("-- Installing: ${CMAKE_INSTALL_PREFIX}/lib") | 1 | message("-- Installing: ${CMAKE_INSTALL_PREFIX}/lib") |
| 2 | 2 | ||
| 3 | if(NOT EXISTS ${zig0_EXE}) | 3 | if(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) |
| 11 | endif() | 11 | endif() |
| 12 | 12 | ||
| 13 | execute_process(COMMAND ${zig0_EXE} ${INSTALL_LIBUSERLAND_ARGS} | 13 | execute_process(COMMAND ${zig_EXE} ${ZIG_INSTALL_ARGS} |
| 14 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | 14 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} |
| 15 | RESULT_VARIABLE _result | 15 | 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)") |
| 21 | 21 | ||
| 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}") |
| 25 | 25 | ||
| 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; |
| 96 | pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int; | 96 | pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int; |
| 97 | pub extern "c" fn fork() c_int; | 97 | pub extern "c" fn fork() c_int; |
| 98 | pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int; | 98 | pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int; |
| 99 | pub extern "c" fn faccessat(dirfd: fd_t, path: [*:0]const u8, mode: c_uint, flags: c_uint) c_int; | ||
| 99 | pub extern "c" fn pipe(fds: *[2]fd_t) c_int; | 100 | pub extern "c" fn pipe(fds: *[2]fd_t) c_int; |
| 100 | pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int; | 101 | pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int; |
| 101 | pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int; | 102 | pub 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, |
| 49 | 49 | ||
| 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; | ||
| 52 | 55 | ||
| 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 { |
| 174 | 177 | ||
| 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(); |
| 186 | 210 | ||
| 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; | ||
| 192 | 217 | ||
| 193 | try child.spawn(); | 218 | try child.spawn(); |
| 194 | 219 | ||
| 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); |
| 199 | 224 | ||
| 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(); |
| 202 | 227 | ||
| 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); |
| 205 | 230 | ||
| 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 | } |
| 422 | 447 | ||
| 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 | } |
| 426 | 451 | ||
| ... | @@ -453,7 +478,6 @@ pub const ChildProcess = struct { | ... | @@ -453,7 +478,6 @@ pub const ChildProcess = struct { |
| 453 | 478 | ||
| 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; |
| 458 | 482 | ||
| 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 @@ |
| 1 | pub const Channel = @import("event/channel.zig").Channel; | 1 | pub const Channel = @import("event/channel.zig").Channel; |
| 2 | pub const Future = @import("event/future.zig").Future; | 2 | pub const Future = @import("event/future.zig").Future; |
| 3 | pub const Group = @import("event/group.zig").Group; | 3 | pub const Group = @import("event/group.zig").Group; |
| 4 | pub const Batch = @import("event/batch.zig").Batch; | ||
| 4 | pub const Lock = @import("event/lock.zig").Lock; | 5 | pub const Lock = @import("event/lock.zig").Lock; |
| 5 | pub const Locked = @import("event/locked.zig").Locked; | 6 | pub const Locked = @import("event/locked.zig").Locked; |
| 6 | pub const RwLock = @import("event/rwlock.zig").RwLock; | 7 | pub 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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const 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. | ||
| 9 | pub 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 | |||
| 110 | test "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 | |||
| 124 | fn sleepALittle(count: *usize) void { | ||
| 125 | std.time.sleep(1 * std.time.millisecond); | ||
| 126 | _ = @atomicRmw(usize, count, .Add, 1, .SeqCst); | ||
| 127 | } | ||
| 128 | |||
| 129 | fn 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 | |||
| 136 | fn doSomethingThatFails() anyerror!void {} | ||
| 137 | fn 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; |
| 5 | const Allocator = std.mem.Allocator; | 5 | const Allocator = std.mem.Allocator; |
| 6 | 6 | ||
| 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. | ||
| 8 | pub fn Group(comptime ReturnType: type) type { | 13 | pub 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 | ||
| 100 | pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { | 99 | pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { |
| 101 | const my_cwd = cwd(); | 100 | const my_cwd = cwd(); |
| 102 | 101 | ||
| ... | @@ -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; |
| 820 | 819 | ||
| 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 | }; |
| 1327 | 1371 | ||
| 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 | }; |
| 62 | 62 | ||
| 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 | } |
| 389 | 389 | ||
| 390 | /// Copies ::m to newly allocated memory. Caller is responsible to free it. | 390 | /// Copies `m` to newly allocated memory. Caller owns the memory. |
| 391 | pub fn dupe(allocator: *Allocator, comptime T: type, m: []const T) ![]T { | 391 | pub 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 | } |
| 396 | 396 | ||
| 397 | /// Copies `m` to newly allocated memory, with a null-terminated element. Caller owns the memory. | ||
| 398 | pub 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. |
| 398 | pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T { | 406 | pub 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; |
| 918 | 918 | ||
| 919 | /// Deprecated in favor of `execveZ`. | ||
| 920 | pub 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. |
| 922 | pub fn execveC(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError { | 925 | pub 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 | } |
| 944 | 947 | ||
| 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. | 949 | pub 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`. | 951 | pub const Arg0Expand = enum { |
| 949 | pub 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. | ||
| 958 | pub 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); |
| 952 | 969 | ||
| 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 | } |
| 975 | 997 | ||
| 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 null | 999 | /// 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. |
| 981 | pub fn execvpe( | 1001 | /// If `file` is an absolute path, this is the same as `execveC`. |
| 1002 | pub 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. | ||
| 1013 | pub 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); |
| 1006 | 1039 | ||
| 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. | ||
| 1051 | pub 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 | } |
| 1009 | 1058 | ||
| 1010 | pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![:null]?[*:0]u8 { | 1059 | pub 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 | } |
| 1039 | 1088 | ||
| 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 it | 1091 | /// TODO make this go through libc when we have it |
| 1043 | pub fn getenv(key: []const u8) ?[]const u8 { | 1092 | pub 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 | } |
| 1058 | 1107 | ||
| 1108 | /// Deprecated in favor of `getenvZ`. | ||
| 1109 | pub 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`. |
| 1061 | pub fn getenvC(key: [*:0]const u8) ?[]const u8 { | 1113 | pub 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, | ||
| 2455 | 2510 | ||
| 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 | } |
| 2471 | 2526 | ||
| 2527 | /// Deprecated in favor of `accessZ`. | ||
| 2528 | pub const accessC = accessZ; | ||
| 2529 | |||
| 2472 | /// Same as `access` except `path` is null-terminated. | 2530 | /// Same as `access` except `path` is null-terminated. |
| 2473 | pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void { | 2531 | pub 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 | } |
| 2512 | 2569 | ||
| 2570 | /// Check user's permissions for a file, based on an open directory handle. | ||
| 2571 | /// TODO currently this ignores `mode` and `flags` on Windows. | ||
| 2572 | pub 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. | ||
| 2582 | pub 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` | ||
| 2607 | pub 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 | |||
| 2513 | pub const PipeError = error{ | 2643 | pub 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 | } |
| 2845 | 2975 | ||
| 2846 | pub fn dl_iterate_phdr( | 2976 | pub 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"); |
| 2853 | 2985 | ||
| 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 | } |
| 2860 | 2998 | ||
| 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 | }; |
| 2879 | 3017 | ||
| 2880 | return callback(&info, @sizeOf(dl_phdr_info), data); | 3018 | return callback(&info, @sizeOf(dl_phdr_info), context); |
| 2881 | } | 3019 | } |
| 2882 | 3020 | ||
| 2883 | // Last return value from the callback function | 3021 | // 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 | }; |
| 2905 | 3042 | ||
| 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 | } |
| 2912 | 3046 | ||
| 2913 | pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError; | 3047 | pub 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" { |
| 29 | 29 | ||
| 30 | test "access file" { | 30 | test "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 | // analyzed | 165 | // analyzed |
| 166 | const dl_phdr_info = if (@hasDecl(os, "dl_phdr_info")) os.dl_phdr_info else c_void; | 166 | const dl_phdr_info = if (@hasDecl(os, "dl_phdr_info")) os.dl_phdr_info else c_void; |
| 167 | 167 | ||
| 168 | fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) callconv(.C) i32 { | 168 | const 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 | }; | ||
| 171 | 174 | ||
| 172 | var counter = data.?; | 175 | fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void { |
| 173 | // Count how many libraries are loaded | 176 | // Count how many libraries are loaded |
| 174 | counter.* += @as(usize, 1); | 177 | counter.* += @as(usize, 1); |
| 175 | 178 | ||
| 176 | // The image should contain at least a PT_LOAD segment | 179 | // 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; |
| 178 | 181 | ||
| 179 | // Quick & dirty validation of the phdr pointers, make sure we're not | 182 | // Quick & dirty validation of the phdr pointers, make sure we're not |
| 180 | // pointing to some random gibberish | 183 | // 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 header | 192 | // 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 magic | 194 | // 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 check | 196 | // 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; |
| 195 | 198 | ||
| 196 | found_load = true; | 199 | found_load = true; |
| 197 | break; | 200 | break; |
| 198 | } | 201 | } |
| 199 | 202 | ||
| 200 | if (!found_load) return -1; | 203 | if (!found_load) return error.MissingLoad; |
| 201 | |||
| 202 | return 42; | ||
| 203 | } | 204 | } |
| 204 | 205 | ||
| 205 | test "dl_iterate_phdr" { | 206 | test "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; |
| 208 | 209 | ||
| 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 | } |
| 213 | 214 |
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 | |||
| 12 | pub extern "NtDll" fn NtQueryAttributesFile( | ||
| 13 | ObjectAttributes: *OBJECT_ATTRIBUTES, | ||
| 14 | FileAttributes: *FILE_BASIC_INFORMATION, | ||
| 15 | ) callconv(.Stdcall) NTSTATUS; | ||
| 16 | |||
| 11 | pub extern "NtDll" fn NtCreateFile( | 17 | pub 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. | ||
| 618 | pub 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 | } |
| 1039 | 1039 | ||
| 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) { |
| 1189 | 1203 | ||
| 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 | }; |
| 1193 | 1374 | ||
| 1194 | test "parseCpuFeatureSet" { | 1375 | test "parseCpuFeatureSet" { |
lib/std/time.zig+1| ... | @@ -8,6 +8,7 @@ const math = std.math; | ... | @@ -8,6 +8,7 @@ const math = std.math; |
| 8 | pub const epoch = @import("time/epoch.zig"); | 8 | pub const epoch = @import("time/epoch.zig"); |
| 9 | 9 | ||
| 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 | ||
| 11 | pub fn sleep(nanoseconds: u64) void { | 12 | pub 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; |
| 6 | 6 | ||
| 7 | const warn = std.debug.warn; | 7 | const warn = std.debug.warn; |
| 8 | 8 | ||
| 9 | pub 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 result | 17 | /// Caller must free result |
| 10 | pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 { | 18 | pub 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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const event = std.event; | ||
| 4 | const util = @import("util.zig"); | 3 | const util = @import("util.zig"); |
| 5 | const Target = std.Target; | 4 | const Target = std.Target; |
| 6 | const c = @import("c.zig"); | ||
| 7 | const fs = std.fs; | 5 | const fs = std.fs; |
| 8 | const Allocator = std.mem.Allocator; | 6 | const Allocator = std.mem.Allocator; |
| 7 | const Batch = std.event.Batch; | ||
| 8 | |||
| 9 | const is_darwin = Target.current.isDarwin(); | ||
| 10 | const is_windows = Target.current.isWindows(); | ||
| 11 | const is_freebsd = Target.current.isFreeBSD(); | ||
| 12 | const is_netbsd = Target.current.isNetBSD(); | ||
| 13 | const is_linux = Target.current.isLinux(); | ||
| 14 | const is_dragonfly = Target.current.isDragonFlyBSD(); | ||
| 15 | const is_gnu = Target.current.isGnu(); | ||
| 16 | |||
| 17 | usingnamespace @import("windows_sdk.zig"); | ||
| 9 | 18 | ||
| 10 | /// See the render function implementation for documentation of the fields. | 19 | /// See the render function implementation for documentation of the fields. |
| 11 | pub const LibCInstallation = struct { | 20 | pub 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, |
| 18 | 27 | ||
| 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 | }; |
| 31 | 41 | ||
| 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 = .{}; |
| 39 | 48 | ||
| 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 | } |
| 105 | 129 | ||
| 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 | } |
| 142 | 176 | ||
| 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(); |
| 150 | 184 | 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)) { |
| 157 | 191 | .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 | } |
| 183 | 222 | ||
| 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 loop | 244 | 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 | } |
| 207 | 261 | 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 | } |
| 216 | 265 | ||
| 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 | } |
| 228 | 277 | ||
| 229 | // search in reverse order | 278 | 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 | } | ||
| 236 | 313 | ||
| 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 | } |
| 245 | 322 | ||
| 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); |
| 249 | 330 | ||
| ... | @@ -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 }); |
| 257 | 338 | ||
| 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, |
| 263 | 344 | ||
| 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 | } |
| 269 | 357 | ||
| 270 | return error.LibCStdLibHeaderNotFound; | 358 | return error.LibCStdLibHeaderNotFound; |
| 271 | } | 359 | } |
| 272 | 360 | ||
| 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); |
| 276 | 364 | ||
| 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(); |
| 279 | 367 | ||
| 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 | } | ||
| 302 | 379 | ||
| 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, | ||
| 306 | 385 | ||
| 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(); |
| 310 | 389 | ||
| 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 | } |
| 335 | 400 | ||
| 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 | }; | ||
| 340 | 404 | ||
| 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 | } |
| 350 | 408 | ||
| 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); |
| 354 | 412 | ||
| 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(); |
| 357 | 415 | ||
| 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 | } |
| 380 | 448 | ||
| 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 | }; |
| 392 | 491 | ||
| 492 | const default_cc_exe = if (is_windows) "cc.exe" else "cc"; | ||
| 493 | |||
| 393 | /// caller owns returned memory | 494 | /// caller owns returned memory |
| 394 | fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 { | 495 | fn 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 }; |
| 399 | 504 | ||
| 400 | // TODO This simulates evented I/O for the child process exec | 505 | 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 | } | ||
| 426 | 540 | ||
| 427 | if (want_dirname) { | 541 | /// Caller owns returned memory. |
| 428 | return std.mem.dupe(allocator, u8, dirname); | 542 | pub 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 | } |
| 433 | 635 | ||
| 434 | const Search = struct { | 636 | const 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 | }; |
| 438 | 640 | ||
| 439 | fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search { | 641 | fn 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 | |||
| 462 | fn 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 | |||
| 4 | const std = @import("std"); | ||
| 5 | const io = std.io; | ||
| 6 | const mem = std.mem; | ||
| 7 | const fs = std.fs; | ||
| 8 | const process = std.process; | ||
| 9 | const Allocator = mem.Allocator; | ||
| 10 | const ArrayList = std.ArrayList; | ||
| 11 | const Buffer = std.Buffer; | ||
| 12 | const Target = std.Target; | ||
| 13 | const self_hosted_main = @import("main.zig"); | ||
| 14 | const errmsg = @import("errmsg.zig"); | ||
| 15 | const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer; | ||
| 16 | const assert = std.debug.assert; | ||
| 17 | |||
| 18 | var stderr_file: fs.File = undefined; | ||
| 19 | var stderr: *io.OutStream(fs.File.WriteError) = undefined; | ||
| 20 | var stdout: *io.OutStream(fs.File.WriteError) = undefined; | ||
| 21 | |||
| 22 | comptime { | ||
| 23 | _ = @import("dep_tokenizer.zig"); | ||
| 24 | } | ||
| 25 | |||
| 26 | // ABI warning | ||
| 27 | export 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 | ||
| 34 | export fn stage2_panic(ptr: [*]const u8, len: usize) void { | ||
| 35 | @panic(ptr[0..len]); | ||
| 36 | } | ||
| 37 | |||
| 38 | // ABI warning | ||
| 39 | const 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 | |||
| 98 | const FILE = std.c.FILE; | ||
| 99 | const ast = std.zig.ast; | ||
| 100 | const translate_c = @import("translate_c.zig"); | ||
| 101 | |||
| 102 | /// Args should have a null terminating last arg. | ||
| 103 | export 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 | |||
| 124 | export 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 | |||
| 128 | export 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. | ||
| 148 | export 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 | |||
| 160 | fn 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 | |||
| 274 | const 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 | |||
| 295 | fn 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 | |||
| 358 | const 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 | |||
| 367 | fn 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 | |||
| 414 | export 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 | |||
| 422 | export fn stage2_DepTokenizer_deinit(self: *stage2_DepTokenizer) void { | ||
| 423 | self.handle.deinit(); | ||
| 424 | } | ||
| 425 | |||
| 426 | export 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 | |||
| 450 | const stage2_DepTokenizer = extern struct { | ||
| 451 | handle: *DepTokenizer, | ||
| 452 | }; | ||
| 453 | |||
| 454 | const 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 | ||
| 472 | export 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 | ||
| 479 | export 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 | ||
| 486 | export fn stage2_progress_destroy(progress: *std.Progress) void { | ||
| 487 | std.heap.c_allocator.destroy(progress); | ||
| 488 | } | ||
| 489 | |||
| 490 | // ABI warning | ||
| 491 | export 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 | ||
| 504 | export fn stage2_progress_disable_tty(progress: *std.Progress) void { | ||
| 505 | progress.terminal = null; | ||
| 506 | } | ||
| 507 | |||
| 508 | // ABI warning | ||
| 509 | export 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 | ||
| 525 | export 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 | ||
| 533 | export fn stage2_progress_complete_one(node: *std.Progress.Node) void { | ||
| 534 | node.completeOne(); | ||
| 535 | } | ||
| 536 | |||
| 537 | // ABI warning | ||
| 538 | export 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 | |||
| 545 | fn 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 | ||
| 608 | export 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 | |||
| 616 | fn 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 | |||
| 632 | const 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 | ||
| 731 | export 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 | |||
| 751 | fn 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 | ||
| 807 | export 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 | ||
| 817 | export 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 | ||
| 827 | export 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 | ||
| 832 | export 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 | |||
| 4 | const std = @import("std"); | ||
| 5 | const io = std.io; | ||
| 6 | const mem = std.mem; | ||
| 7 | const fs = std.fs; | ||
| 8 | const process = std.process; | ||
| 9 | const Allocator = mem.Allocator; | ||
| 10 | const ArrayList = std.ArrayList; | ||
| 11 | const Buffer = std.Buffer; | ||
| 12 | const Target = std.Target; | ||
| 13 | const self_hosted_main = @import("main.zig"); | ||
| 14 | const errmsg = @import("errmsg.zig"); | ||
| 15 | const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer; | ||
| 16 | const assert = std.debug.assert; | ||
| 17 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | ||
| 18 | |||
| 19 | var stderr_file: fs.File = undefined; | ||
| 20 | var stderr: *io.OutStream(fs.File.WriteError) = undefined; | ||
| 21 | var stdout: *io.OutStream(fs.File.WriteError) = undefined; | ||
| 22 | |||
| 23 | comptime { | ||
| 24 | _ = @import("dep_tokenizer.zig"); | ||
| 25 | } | ||
| 26 | |||
| 27 | // ABI warning | ||
| 28 | export 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 | ||
| 35 | export fn stage2_panic(ptr: [*]const u8, len: usize) void { | ||
| 36 | @panic(ptr[0..len]); | ||
| 37 | } | ||
| 38 | |||
| 39 | // ABI warning | ||
| 40 | const 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 | |||
| 116 | const FILE = std.c.FILE; | ||
| 117 | const ast = std.zig.ast; | ||
| 118 | const translate_c = @import("translate_c.zig"); | ||
| 119 | |||
| 120 | /// Args should have a null terminating last arg. | ||
| 121 | export 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 | |||
| 142 | export 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 | |||
| 146 | export 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. | ||
| 166 | export 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 | |||
| 178 | fn 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 | |||
| 292 | const 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 | |||
| 313 | fn 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 | |||
| 376 | const 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 | |||
| 385 | fn 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 | |||
| 432 | export 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 | |||
| 440 | export fn stage2_DepTokenizer_deinit(self: *stage2_DepTokenizer) void { | ||
| 441 | self.handle.deinit(); | ||
| 442 | } | ||
| 443 | |||
| 444 | export 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 | |||
| 468 | const stage2_DepTokenizer = extern struct { | ||
| 469 | handle: *DepTokenizer, | ||
| 470 | }; | ||
| 471 | |||
| 472 | const 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 | ||
| 490 | export 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 | ||
| 497 | export 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 | ||
| 504 | export fn stage2_progress_destroy(progress: *std.Progress) void { | ||
| 505 | std.heap.c_allocator.destroy(progress); | ||
| 506 | } | ||
| 507 | |||
| 508 | // ABI warning | ||
| 509 | export 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 | ||
| 522 | export fn stage2_progress_disable_tty(progress: *std.Progress) void { | ||
| 523 | progress.terminal = null; | ||
| 524 | } | ||
| 525 | |||
| 526 | // ABI warning | ||
| 527 | export 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 | ||
| 543 | export 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 | ||
| 551 | export fn stage2_progress_complete_one(node: *std.Progress.Node) void { | ||
| 552 | node.completeOne(); | ||
| 553 | } | ||
| 554 | |||
| 555 | // ABI warning | ||
| 556 | export 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 | |||
| 563 | fn 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 | ||
| 626 | export 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 | |||
| 634 | fn 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 | |||
| 650 | const 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 | ||
| 749 | export 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 | |||
| 769 | fn 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 | ||
| 825 | export 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 | ||
| 835 | export 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 | ||
| 845 | export 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 | ||
| 850 | export 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 | ||
| 855 | const 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 | ||
| 939 | export 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 | ||
| 979 | export 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 | ||
| 998 | export 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 | ||
| 1017 | const 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 | ||
| 1029 | const Stage2GLibCVersion = extern struct { | ||
| 1030 | major: u32, | ||
| 1031 | minor: u32, | ||
| 1032 | patch: u32, | ||
| 1033 | }; | ||
| 1034 | |||
| 1035 | // ABI warning | ||
| 1036 | export 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 | |||
| 1116 | fn 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"); |
| 2 | const Target = std.Target; | 2 | const Target = std.Target; |
| 3 | const llvm = @import("llvm.zig"); | 3 | const llvm = @import("llvm.zig"); |
| 4 | 4 | ||
| 5 | pub const FloatAbi = enum { | ||
| 6 | Hard, | ||
| 7 | Soft, | ||
| 8 | SoftFp, | ||
| 9 | }; | ||
| 10 | |||
| 11 | /// TODO expose the arch and subarch separately | ||
| 12 | pub 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 | |||
| 25 | pub fn getFloatAbi(self: Target) FloatAbi { | ||
| 26 | return switch (self.getAbi()) { | ||
| 27 | .gnueabihf, | ||
| 28 | .eabihf, | ||
| 29 | .musleabihf, | ||
| 30 | => .Hard, | ||
| 31 | else => .Soft, | ||
| 32 | }; | ||
| 33 | } | ||
| 34 | |||
| 35 | pub 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 | |||
| 142 | pub fn getDarwinArchString(self: Target) [:0]const u8 { | 5 | pub 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 | |||
| 3 | pub 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 | }; | ||
| 15 | pub const ZigFindWindowsSdkError = extern enum { | ||
| 16 | None, | ||
| 17 | OutOfMemory, | ||
| 18 | NotFound, | ||
| 19 | PathTooLong, | ||
| 20 | }; | ||
| 21 | pub extern fn zig_find_windows_sdk(out_sdk: **ZigWindowsSDK) ZigFindWindowsSdkError; | ||
| 22 | pub 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" | ||
| 22 | 21 | ||
| 23 | struct AstNode; | 22 | struct AstNode; |
| 24 | struct ZigFn; | 23 | struct 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 gets | 2138 | // 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; |
| 2144 | 2143 | ||
| 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; |
| 2222 | 2221 | ||
| 2223 | ZigLibCInstallation *libc; | 2222 | Stage2LibCInstallation *libc; |
| 2224 | 2223 | ||
| 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/MIT | 5 | * See http://opensource.org/licenses/MIT |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 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 PIC | 8382 | // 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 | } |
| 8958 | 8960 | ||
| 8959 | static void detect_dynamic_linker(CodeGen *g) { | 8961 | static 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; |
| 8966 | 8970 | ||
| 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))) { |
| 8970 | 8974 | 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 NixOS | 8976 | 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 | } |
| 9001 | 8978 | 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 | } |
| 9004 | 8982 | ||
| 9005 | static void detect_libc(CodeGen *g) { | 8983 | static 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)); |
| 9029 | 9007 | ||
| 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 | } |
| 9038 | 9016 | ||
| 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>(); |
| 9041 | 9019 | ||
| 9042 | // search for native_libc.txt in following dirs: | 9020 | // search for native_libc.txt in following dirs: |
| 9043 | // - LOCAL_CACHE_DIR | 9021 | // - 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; |
| 9084 | 9062 | ||
| 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); |
| 9121 | 9100 | ||
| 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; |
| 9124 | 9103 | ||
| 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 | } |
| 9129 | 9108 | ||
| 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; |
| 9134 | 9113 | ||
| 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)); |
| 9209 | 9188 | ||
| 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 | } |
| 9215 | 9194 | ||
| 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 | } |
| 10766 | 10745 | ||
| 10767 | CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, | 10746 | CodeGen *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 |
| 10804 | 10783 | ||
| 10805 | CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, | 10784 | CodeGen *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" | ||
| 16 | 15 | ||
| 17 | #include <stdio.h> | 16 | #include <stdio.h> |
| 18 | 17 | ||
| 19 | CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, | 18 | CodeGen *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); |
| 22 | 21 | ||
| 23 | CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, | 22 | CodeGen *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); |
| 25 | 24 | ||
| 26 | void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); | 25 | void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); |
| 27 | void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); | 26 | void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); |
src/compiler.cpp-34| ... | @@ -4,20 +4,6 @@ | ... | @@ -4,20 +4,6 @@ |
| 4 | 4 | ||
| 5 | #include <stdio.h> | 5 | #include <stdio.h> |
| 6 | 6 | ||
| 7 | static Buf saved_dynamic_linker_path = BUF_INIT; | ||
| 8 | static bool searched_for_dyn_linker = false; | ||
| 9 | |||
| 10 | static 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 | |||
| 21 | Buf *get_self_libc_path(void) { | 7 | Buf *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 | } |
| 45 | 31 | ||
| 46 | Buf *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 | |||
| 65 | Error get_compiler_id(Buf **result) { | 32 | Error get_compiler_id(Buf **result) { |
| 66 | static Buf saved_compiler_id = BUF_INIT; | 33 | static Buf saved_compiler_id = BUF_INIT; |
| 67 | 34 | ||
| ... | @@ -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" |
| 13 | 13 | ||
| 14 | Error get_compiler_id(Buf **result); | 14 | Error get_compiler_id(Buf **result); |
| 15 | Buf *get_self_dynamic_linker_path(void); | ||
| 16 | Buf *get_self_libc_path(void); | 15 | Buf *get_self_libc_path(void); |
| 17 | 16 | ||
| 18 | Buf *get_zig_lib_dir(void); | 17 | Buf *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_HPP | 8 | #ifndef ERROR_HPP |
| 9 | #define ERROR_HPP | 9 | #define ERROR_HPP |
| 10 | 10 | ||
| 11 | #include "userland.h" | 11 | #include "stage2.h" |
| 12 | 12 | ||
| 13 | const char *err_str(Error err); | 13 | const char *err_str(Error err); |
| 14 | 14 |
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 | |||
| 13 | static 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 | |||
| 22 | static const size_t zig_libc_keys_len = array_length(zig_libc_keys); | ||
| 23 | |||
| 24 | static 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 | |||
| 33 | static 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 | |||
| 43 | Error 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 | |||
| 152 | static 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 | |||
| 277 | Error 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) | ||
| 324 | static 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) | ||
| 330 | static 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 | |||
| 334 | static 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 | |||
| 345 | static 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 | |||
| 358 | static 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 | |||
| 371 | static 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 | |||
| 382 | static 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 | |||
| 411 | void 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 | |||
| 449 | Error 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 | ||
| 18 | struct 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 | |||
| 27 | Error ATTRIBUTE_MUST_USE zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, | ||
| 28 | const ZigTarget *target, bool verbose); | ||
| 29 | void zig_libc_render(ZigLibCInstallation *self, FILE *file); | ||
| 30 | |||
| 31 | Error ATTRIBUTE_MUST_USE zig_libc_find_native(ZigLibCInstallation *self, bool verbose); | ||
| 32 | |||
| 33 | Error 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 | } |
| 1752 | 1752 | ||
| 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)))); |
| 2252 | 2252 | ||
| 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))); |
| 2255 | 2255 | ||
| 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 | } |
| 2264 | 2264 |
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 | } |
| 1006 | 1005 | ||
| 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 | } |
| 1011 | 1023 | ||
| 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 | #endif | 1305 | #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 | // parent | 834 | // 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; |
| 852 | 854 | ||
| 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 | } |
| 1031 | 1037 | ||
| 1038 | static 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) | ||
| 1059 | static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) { | ||
| 1060 | mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime; | ||
| 1061 | mtime->nsec = 0; | ||
| 1062 | } | ||
| 1063 | static 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 | |||
| 1071 | static 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 | |||
| 1095 | Error 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 | |||
| 1032 | Error os_copy_file(Buf *src_path, Buf *dest_path) { | 1156 | Error 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 | } |
| 1058 | 1182 | 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 | } |
| 1083 | 1187 | ||
| 1084 | Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { | 1188 | Error 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 | } |
| 1220 | 1324 | ||
| 1221 | #if defined(ZIG_OS_WINDOWS) | ||
| 1222 | static 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 | |||
| 1228 | OsTimeStamp os_timestamp_calendar(void) { | 1325 | OsTimeStamp 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 | #endif | 1648 | #endif |
| 1552 | } | 1649 | } |
| 1553 | 1650 | ||
| 1554 | Error 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 | |||
| 1586 | Error 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 | |||
| 1602 | Error 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.zig | 1652 | // Ported from std/unicode.zig |
| 1658 | struct Utf16LeIterator { | 1653 | struct 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 | #endif | 1830 | #endif |
| 1836 | } | 1831 | } |
| 1837 | 1832 | ||
| 1838 | Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { | 1833 | Error 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 CreateFileW | 1835 | // 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); | ||
| 1842 | 1842 | ||
| 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 | } |
| 1875 | 1877 | ||
| 1876 | return ErrorNone; | 1878 | return ErrorNone; |
| 1877 | #else | 1879 | #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 | #endif | 1921 | #endif |
| 1922 | attr->mode = statbuf.st_mode; | ||
| 1923 | attr->size = statbuf.st_size; | ||
| 1918 | } | 1924 | } |
| 1919 | return ErrorNone; | 1925 | return ErrorNone; |
| 1920 | } | 1926 | } |
| 1921 | #endif | 1927 | #endif |
| 1922 | } | 1928 | } |
| 1923 | 1929 | ||
| 1930 | Error 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 | |||
| 1934 | Error 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 | |||
| 1924 | Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { | 1938 | Error 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 | #endif | 2130 | #endif |
| 2116 | } | 2131 | } |
| 2117 | |||
| 2118 | #ifdef ZIG_OS_LINUX | ||
| 2119 | const 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_UNKNOWN | 43 | #define ZIG_ARCH_UNKNOWN |
| 44 | #endif | 44 | #endif |
| 45 | 45 | ||
| 46 | #ifdef ZIG_OS_LINUX | ||
| 47 | extern 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 | #endif | 89 | #endif |
| 94 | 90 | ||
| 95 | struct OsTimeStamp { | 91 | struct OsTimeStamp { |
| 96 | uint64_t sec; | 92 | int64_t sec; |
| 97 | uint64_t nsec; | 93 | int64_t nsec; |
| 98 | }; | 94 | }; |
| 99 | 95 | ||
| 100 | struct OsFileAttr { | 96 | struct 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 | }; |
| 104 | 102 | ||
| 105 | int os_init(void); | 103 | int 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); |
| 121 | Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); | 119 | Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); |
| 122 | 120 | ||
| 123 | Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr); | 121 | Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr); |
| 122 | Error ATTRIBUTE_MUST_USE os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_t mode); | ||
| 124 | Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file); | 123 | Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file); |
| 125 | Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len); | 124 | Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len); |
| 126 | Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents); | 125 | Error 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); |
| 129 | 128 | ||
| 130 | Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents); | 129 | Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents); |
| 131 | Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path); | 130 | Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path); |
| 131 | Error ATTRIBUTE_MUST_USE os_update_file(Buf *src_path, Buf *dest_path); | ||
| 132 | 132 | ||
| 133 | Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents); | 133 | Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents); |
| 134 | Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents); | 134 | Error 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); |
| 152 | 152 | ||
| 153 | Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname); | 153 | Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname); |
| 154 | 154 | ||
| 155 | Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf); | ||
| 156 | Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); | ||
| 157 | Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); | ||
| 158 | |||
| 159 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); | 155 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); |
| 160 | 156 | ||
| 161 | #endif | 157 | #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 | |||
| 11 | Error 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 | |||
| 19 | void 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 | |||
| 24 | void stage2_zen(const char **ptr, size_t *len) { | ||
| 25 | const char *msg = "stage0 called stage2_zen"; | ||
| 26 | stage2_panic(msg, strlen(msg)); | ||
| 27 | } | ||
| 28 | |||
| 29 | void stage2_attach_segfault_handler(void) { } | ||
| 30 | |||
| 31 | void 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 | |||
| 38 | void 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 | |||
| 43 | int stage2_fmt(int argc, char **argv) { | ||
| 44 | const char *msg = "stage0 called stage2_fmt"; | ||
| 45 | stage2_panic(msg, strlen(msg)); | ||
| 46 | } | ||
| 47 | |||
| 48 | stage2_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 | |||
| 53 | void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self) { | ||
| 54 | const char *msg = "stage0 called stage2_DepTokenizer_deinit"; | ||
| 55 | stage2_panic(msg, strlen(msg)); | ||
| 56 | } | ||
| 57 | |||
| 58 | stage2_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 | |||
| 64 | struct Stage2Progress { | ||
| 65 | int trash; | ||
| 66 | }; | ||
| 67 | |||
| 68 | struct Stage2ProgressNode { | ||
| 69 | int trash; | ||
| 70 | }; | ||
| 71 | |||
| 72 | Stage2Progress *stage2_progress_create(void) { | ||
| 73 | return nullptr; | ||
| 74 | } | ||
| 75 | |||
| 76 | void stage2_progress_destroy(Stage2Progress *progress) {} | ||
| 77 | |||
| 78 | Stage2ProgressNode *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 | } | ||
| 83 | Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node, | ||
| 84 | const char *name_ptr, size_t name_len, size_t estimated_total_items) | ||
| 85 | { | ||
| 86 | return nullptr; | ||
| 87 | } | ||
| 88 | void stage2_progress_end(Stage2ProgressNode *node) {} | ||
| 89 | void stage2_progress_complete_one(Stage2ProgressNode *node) {} | ||
| 90 | void stage2_progress_disable_tty(Stage2Progress *progress) {} | ||
| 91 | void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){} | ||
| 92 | |||
| 93 | struct 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 | |||
| 100 | Error 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 | |||
| 124 | void 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 | } | ||
| 130 | const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features) { | ||
| 131 | return cpu_features->llvm_cpu_name; | ||
| 132 | } | ||
| 133 | const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features) { | ||
| 134 | return cpu_features->llvm_cpu_features; | ||
| 135 | } | ||
| 136 | void 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 | |||
| 143 | int stage2_cmd_targets(const char *zig_triple) { | ||
| 144 | const char *msg = "stage0 called stage2_cmd_targets"; | ||
| 145 | stage2_panic(msg, strlen(msg)); | ||
| 146 | } | ||
| 147 | |||
| 148 | enum 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 | |||
| 164 | enum 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 | |||
| 169 | enum 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 | |||
| 174 | enum 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 | ||
| 33 | enum 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 | ||
| 110 | struct 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 | ||
| 122 | struct Stage2Ast; | ||
| 123 | |||
| 124 | // ABI warning | ||
| 125 | ZIG_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 | ||
| 130 | ZIG_EXTERN_C void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len); | ||
| 131 | |||
| 132 | // ABI warning | ||
| 133 | ZIG_EXTERN_C void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file); | ||
| 134 | |||
| 135 | // ABI warning | ||
| 136 | ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len); | ||
| 137 | |||
| 138 | // ABI warning | ||
| 139 | ZIG_EXTERN_C void stage2_attach_segfault_handler(void); | ||
| 140 | |||
| 141 | // ABI warning | ||
| 142 | ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len); | ||
| 143 | |||
| 144 | // ABI warning | ||
| 145 | ZIG_EXTERN_C int stage2_fmt(int argc, char **argv); | ||
| 146 | |||
| 147 | // ABI warning | ||
| 148 | struct stage2_DepTokenizer { | ||
| 149 | void *handle; | ||
| 150 | }; | ||
| 151 | |||
| 152 | // ABI warning | ||
| 153 | struct 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 | ||
| 171 | ZIG_EXTERN_C stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len); | ||
| 172 | |||
| 173 | // ABI warning | ||
| 174 | ZIG_EXTERN_C void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self); | ||
| 175 | |||
| 176 | // ABI warning | ||
| 177 | ZIG_EXTERN_C stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self); | ||
| 178 | |||
| 179 | // ABI warning | ||
| 180 | struct Stage2Progress; | ||
| 181 | // ABI warning | ||
| 182 | struct Stage2ProgressNode; | ||
| 183 | // ABI warning | ||
| 184 | ZIG_EXTERN_C Stage2Progress *stage2_progress_create(void); | ||
| 185 | // ABI warning | ||
| 186 | ZIG_EXTERN_C void stage2_progress_disable_tty(Stage2Progress *progress); | ||
| 187 | // ABI warning | ||
| 188 | ZIG_EXTERN_C void stage2_progress_destroy(Stage2Progress *progress); | ||
| 189 | // ABI warning | ||
| 190 | ZIG_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 | ||
| 193 | ZIG_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 | ||
| 196 | ZIG_EXTERN_C void stage2_progress_end(Stage2ProgressNode *node); | ||
| 197 | // ABI warning | ||
| 198 | ZIG_EXTERN_C void stage2_progress_complete_one(Stage2ProgressNode *node); | ||
| 199 | // ABI warning | ||
| 200 | ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node, | ||
| 201 | size_t completed_count, size_t estimated_total_items); | ||
| 202 | |||
| 203 | // ABI warning | ||
| 204 | struct Stage2CpuFeatures; | ||
| 205 | |||
| 206 | // ABI warning | ||
| 207 | ZIG_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 | ||
| 211 | ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const struct Stage2CpuFeatures *cpu_features); | ||
| 212 | |||
| 213 | // ABI warning | ||
| 214 | ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_features(const struct Stage2CpuFeatures *cpu_features); | ||
| 215 | |||
| 216 | // ABI warning | ||
| 217 | ZIG_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 | ||
| 221 | ZIG_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 | ||
| 225 | ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple); | ||
| 226 | |||
| 227 | // ABI warning | ||
| 228 | struct 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 | ||
| 244 | ZIG_EXTERN_C enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, const char *libc_file); | ||
| 245 | // ABI warning | ||
| 246 | ZIG_EXTERN_C enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file); | ||
| 247 | // ABI warning | ||
| 248 | ZIG_EXTERN_C enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc); | ||
| 249 | |||
| 250 | // ABI warning | ||
| 251 | // Synchronize with target.cpp::os_list | ||
| 252 | enum 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 | ||
| 293 | struct ZigGLibCVersion { | ||
| 294 | uint32_t major; // always 2 | ||
| 295 | uint32_t minor; | ||
| 296 | uint32_t patch; | ||
| 297 | }; | ||
| 298 | |||
| 299 | // ABI warning | ||
| 300 | struct 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 | ||
| 312 | ZIG_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 | } |
| 1206 | 1206 | ||
| 1207 | enum FloatAbi { | ||
| 1208 | FloatAbiHard, | ||
| 1209 | FloatAbiSoft, | ||
| 1210 | FloatAbiSoftFp, | ||
| 1211 | }; | ||
| 1212 | |||
| 1213 | static 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 | |||
| 1225 | static bool is_64_bit(ZigLLVM_ArchType arch) { | ||
| 1226 | return target_arch_pointer_bit_width(arch) == 64; | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | bool target_is_android(const ZigTarget *target) { | 1207 | bool target_is_android(const ZigTarget *target) { |
| 1230 | return target->abi == ZigLLVM_Android; | 1208 | return target->abi == ZigLLVM_Android; |
| 1231 | } | 1209 | } |
| 1232 | 1210 | ||
| 1233 | const 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 | |||
| 1414 | bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target) { | 1211 | bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target) { |
| 1415 | assert(host_target != nullptr); | 1212 | assert(host_target != nullptr); |
| 1416 | 1213 |
src/target.hpp+1-61| ... | @@ -8,51 +8,10 @@ | ... | @@ -8,51 +8,10 @@ |
| 8 | #ifndef ZIG_TARGET_HPP | 8 | #ifndef ZIG_TARGET_HPP |
| 9 | #define ZIG_TARGET_HPP | 9 | #define ZIG_TARGET_HPP |
| 10 | 10 | ||
| 11 | #include <zig_llvm.h> | 11 | #include "stage2.h" |
| 12 | 12 | ||
| 13 | struct Buf; | 13 | struct Buf; |
| 14 | 14 | ||
| 15 | // Synchronize with target.cpp::os_list | ||
| 16 | enum 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_list | 15 | // Synchronize with target.cpp::subarch_list_list |
| 57 | enum SubArchList { | 16 | enum SubArchList { |
| 58 | SubArchListNone, | 17 | SubArchListNone, |
| ... | @@ -78,23 +37,6 @@ enum TargetSubsystem { | ... | @@ -78,23 +37,6 @@ enum TargetSubsystem { |
| 78 | TargetSubsystemAuto | 37 | TargetSubsystemAuto |
| 79 | }; | 38 | }; |
| 80 | 39 | ||
| 81 | struct ZigGLibCVersion { | ||
| 82 | uint32_t major; // always 2 | ||
| 83 | uint32_t minor; | ||
| 84 | uint32_t patch; | ||
| 85 | }; | ||
| 86 | |||
| 87 | struct 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 | |||
| 98 | enum CIntType { | 40 | enum 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); |
| 168 | const char *target_lib_file_ext(const ZigTarget *target, bool is_static, | 110 | const 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); |
| 170 | 112 | ||
| 171 | const char *target_dynamic_linker(const ZigTarget *target); | ||
| 172 | |||
| 173 | bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target); | 113 | bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target); |
| 174 | ZigLLVM_OSType get_llvm_os_type(Os os_type); | 114 | ZigLLVM_OSType get_llvm_os_type(Os os_type); |
| 175 | 115 |
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 | |||
| 11 | Error 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 | |||
| 19 | void 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 | |||
| 24 | void stage2_zen(const char **ptr, size_t *len) { | ||
| 25 | const char *msg = "stage0 called stage2_zen"; | ||
| 26 | stage2_panic(msg, strlen(msg)); | ||
| 27 | } | ||
| 28 | |||
| 29 | void stage2_attach_segfault_handler(void) { } | ||
| 30 | |||
| 31 | void 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 | |||
| 38 | void 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 | |||
| 43 | int stage2_fmt(int argc, char **argv) { | ||
| 44 | const char *msg = "stage0 called stage2_fmt"; | ||
| 45 | stage2_panic(msg, strlen(msg)); | ||
| 46 | } | ||
| 47 | |||
| 48 | stage2_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 | |||
| 53 | void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self) { | ||
| 54 | const char *msg = "stage0 called stage2_DepTokenizer_deinit"; | ||
| 55 | stage2_panic(msg, strlen(msg)); | ||
| 56 | } | ||
| 57 | |||
| 58 | stage2_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 | |||
| 64 | struct Stage2Progress { | ||
| 65 | int trash; | ||
| 66 | }; | ||
| 67 | |||
| 68 | struct Stage2ProgressNode { | ||
| 69 | int trash; | ||
| 70 | }; | ||
| 71 | |||
| 72 | Stage2Progress *stage2_progress_create(void) { | ||
| 73 | return nullptr; | ||
| 74 | } | ||
| 75 | |||
| 76 | void stage2_progress_destroy(Stage2Progress *progress) {} | ||
| 77 | |||
| 78 | Stage2ProgressNode *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 | } | ||
| 83 | Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node, | ||
| 84 | const char *name_ptr, size_t name_len, size_t estimated_total_items) | ||
| 85 | { | ||
| 86 | return nullptr; | ||
| 87 | } | ||
| 88 | void stage2_progress_end(Stage2ProgressNode *node) {} | ||
| 89 | void stage2_progress_complete_one(Stage2ProgressNode *node) {} | ||
| 90 | void stage2_progress_disable_tty(Stage2Progress *progress) {} | ||
| 91 | void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){} | ||
| 92 | |||
| 93 | struct 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 | |||
| 100 | Error 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 | |||
| 124 | void 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 | } | ||
| 130 | const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features) { | ||
| 131 | return cpu_features->llvm_cpu_name; | ||
| 132 | } | ||
| 133 | const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features) { | ||
| 134 | return cpu_features->llvm_cpu_features; | ||
| 135 | } | ||
| 136 | void 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 | |||
| 143 | int 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 | ||
| 31 | enum 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 | ||
| 91 | struct 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 | ||
| 103 | struct Stage2Ast; | ||
| 104 | |||
| 105 | // ABI warning | ||
| 106 | ZIG_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 | ||
| 111 | ZIG_EXTERN_C void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len); | ||
| 112 | |||
| 113 | // ABI warning | ||
| 114 | ZIG_EXTERN_C void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file); | ||
| 115 | |||
| 116 | // ABI warning | ||
| 117 | ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len); | ||
| 118 | |||
| 119 | // ABI warning | ||
| 120 | ZIG_EXTERN_C void stage2_attach_segfault_handler(void); | ||
| 121 | |||
| 122 | // ABI warning | ||
| 123 | ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len); | ||
| 124 | |||
| 125 | // ABI warning | ||
| 126 | ZIG_EXTERN_C int stage2_fmt(int argc, char **argv); | ||
| 127 | |||
| 128 | // ABI warning | ||
| 129 | struct stage2_DepTokenizer { | ||
| 130 | void *handle; | ||
| 131 | }; | ||
| 132 | |||
| 133 | // ABI warning | ||
| 134 | struct 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 | ||
| 152 | ZIG_EXTERN_C stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len); | ||
| 153 | |||
| 154 | // ABI warning | ||
| 155 | ZIG_EXTERN_C void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self); | ||
| 156 | |||
| 157 | // ABI warning | ||
| 158 | ZIG_EXTERN_C stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self); | ||
| 159 | |||
| 160 | // ABI warning | ||
| 161 | struct Stage2Progress; | ||
| 162 | // ABI warning | ||
| 163 | struct Stage2ProgressNode; | ||
| 164 | // ABI warning | ||
| 165 | ZIG_EXTERN_C Stage2Progress *stage2_progress_create(void); | ||
| 166 | // ABI warning | ||
| 167 | ZIG_EXTERN_C void stage2_progress_disable_tty(Stage2Progress *progress); | ||
| 168 | // ABI warning | ||
| 169 | ZIG_EXTERN_C void stage2_progress_destroy(Stage2Progress *progress); | ||
| 170 | // ABI warning | ||
| 171 | ZIG_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 | ||
| 174 | ZIG_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 | ||
| 177 | ZIG_EXTERN_C void stage2_progress_end(Stage2ProgressNode *node); | ||
| 178 | // ABI warning | ||
| 179 | ZIG_EXTERN_C void stage2_progress_complete_one(Stage2ProgressNode *node); | ||
| 180 | // ABI warning | ||
| 181 | ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node, | ||
| 182 | size_t completed_count, size_t estimated_total_items); | ||
| 183 | |||
| 184 | // ABI warning | ||
| 185 | struct Stage2CpuFeatures; | ||
| 186 | |||
| 187 | // ABI warning | ||
| 188 | ZIG_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 | ||
| 192 | ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const struct Stage2CpuFeatures *cpu_features); | ||
| 193 | |||
| 194 | // ABI warning | ||
| 195 | ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_features(const struct Stage2CpuFeatures *cpu_features); | ||
| 196 | |||
| 197 | // ABI warning | ||
| 198 | ZIG_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 | ||
| 202 | ZIG_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 | ||
| 206 | ZIG_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 | */ |
| 7 | 7 | ||
| 8 | #include "util.hpp" | 8 | #include "util.hpp" |
| 9 | #include "userland.h" | 9 | #include "stage2.h" |
| 10 | 10 | ||
| 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 @@ |
| 16 | 16 | ||
| 17 | #include <stddef.h> | 17 | #include <stddef.h> |
| 18 | 18 | ||
| 19 | // ABI warning - src-self-hosted/windows_sdk.zig | ||
| 19 | struct ZigWindowsSDK { | 20 | struct 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 | }; |
| 35 | 36 | ||
| 37 | // ABI warning - src-self-hosted/windows_sdk.zig | ||
| 36 | enum ZigFindWindowsSdkError { | 38 | enum 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 | }; |
| 42 | 44 | ||
| 45 | // ABI warning - src-self-hosted/windows_sdk.zig | ||
| 43 | ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk); | 46 | ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk); |
| 44 | 47 | ||
| 48 | // ABI warning - src-self-hosted/windows_sdk.zig | ||
| 45 | ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk); | 49 | ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk); |
| 46 | 50 | ||
| 47 | #endif | 51 | #endif |
src/zig_clang.h+1-1| ... | @@ -8,7 +8,7 @@ | ... | @@ -8,7 +8,7 @@ |
| 8 | #ifndef ZIG_ZIG_CLANG_H | 8 | #ifndef ZIG_ZIG_CLANG_H |
| 9 | #define ZIG_ZIG_CLANG_H | 9 | #define ZIG_ZIG_CLANG_H |
| 10 | 10 | ||
| 11 | #include "userland.h" | 11 | #include "stage2.h" |
| 12 | #include <inttypes.h> | 12 | #include <inttypes.h> |
| 13 | #include <stdbool.h> | 13 | #include <stdbool.h> |
| 14 | 14 |