mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 08:33:06 +00:00
Merge remote-tracking branch 'origin/master' into llvm8
This commit is contained in:
commit
2dcf1a2392
@ -4,7 +4,7 @@ packages:
|
||||
- ninja
|
||||
- llvm70
|
||||
sources:
|
||||
- https://github.com/ziglang/zig.git
|
||||
- https://github.com/ziglang/zig
|
||||
tasks:
|
||||
- build: |
|
||||
cd zig && mkdir build && cd build
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -10,6 +10,6 @@
|
||||
# -andrewrk
|
||||
|
||||
zig-cache/
|
||||
build/
|
||||
build-*/
|
||||
docgen_tmp/
|
||||
/build/
|
||||
/build-*/
|
||||
/docgen_tmp/
|
||||
|
@ -417,6 +417,7 @@ set(ZIG_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/error.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/ir.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/link.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/main.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/os.cpp"
|
||||
@ -432,6 +433,10 @@ set(BLAKE_SOURCES
|
||||
)
|
||||
set(ZIG_CPP_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/zig_clang.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/zig_clang_driver.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/zig_clang_cc1_main.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/zig_clang_cc1as_main.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
|
||||
)
|
||||
|
||||
@ -446,10 +451,12 @@ set(ZIG_STD_FILES
|
||||
"buf_set.zig"
|
||||
"buffer.zig"
|
||||
"build.zig"
|
||||
"build/fmt.zig"
|
||||
"c/darwin.zig"
|
||||
"c/freebsd.zig"
|
||||
"c/index.zig"
|
||||
"c/linux.zig"
|
||||
"c/netbsd.zig"
|
||||
"c/windows.zig"
|
||||
"coff.zig"
|
||||
"crypto/blake2.zig"
|
||||
@ -485,6 +492,7 @@ set(ZIG_STD_FILES
|
||||
"fmt/errol/index.zig"
|
||||
"fmt/errol/lookup.zig"
|
||||
"fmt/index.zig"
|
||||
"fmt/parse_float.zig"
|
||||
"hash/adler.zig"
|
||||
"hash/crc.zig"
|
||||
"hash/fnv.zig"
|
||||
@ -589,6 +597,8 @@ set(ZIG_STD_FILES
|
||||
"os/linux/index.zig"
|
||||
"os/linux/vdso.zig"
|
||||
"os/linux/x86_64.zig"
|
||||
"os/netbsd/errno.zig"
|
||||
"os/netbsd/index.zig"
|
||||
"os/path.zig"
|
||||
"os/time.zig"
|
||||
"os/uefi.zig"
|
||||
@ -603,6 +613,7 @@ set(ZIG_STD_FILES
|
||||
"os/windows/util.zig"
|
||||
"os/zen.zig"
|
||||
"pdb.zig"
|
||||
"priority_queue.zig"
|
||||
"rand/index.zig"
|
||||
"rand/ziggurat.zig"
|
||||
"segmented_list.zig"
|
||||
@ -611,6 +622,7 @@ set(ZIG_STD_FILES
|
||||
"special/bootstrap_lib.zig"
|
||||
"special/build_runner.zig"
|
||||
"special/builtin.zig"
|
||||
"special/compiler_rt/addXf3.zig"
|
||||
"special/compiler_rt/aulldiv.zig"
|
||||
"special/compiler_rt/aullrem.zig"
|
||||
"special/compiler_rt/comparetf2.zig"
|
||||
@ -653,6 +665,7 @@ set(ZIG_STD_FILES
|
||||
"special/compiler_rt/udivmodti4.zig"
|
||||
"special/compiler_rt/udivti3.zig"
|
||||
"special/compiler_rt/umodti3.zig"
|
||||
"special/fmt_runner.zig"
|
||||
"special/init-exe/build.zig"
|
||||
"special/init-exe/src/main.zig"
|
||||
"special/init-lib/build.zig"
|
||||
@ -906,3 +919,7 @@ foreach(file ${ZIG_STD_FILES})
|
||||
get_filename_component(file_dir "${ZIG_STD_DEST}/${file}" DIRECTORY)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/${file}" DESTINATION "${file_dir}")
|
||||
endforeach()
|
||||
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/arg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/main.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/errmsg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
|
||||
|
62
README.md
62
README.md
@ -3,7 +3,7 @@
|
||||
A programming language designed for robustness, optimality, and
|
||||
clarity.
|
||||
|
||||
[ziglang.org](https://ziglang.org)
|
||||
[Download & Documentation](https://ziglang.org/download/)
|
||||
|
||||
## Feature Highlights
|
||||
|
||||
@ -77,36 +77,54 @@ clarity.
|
||||
- what sizes are the C integer types
|
||||
- C ABI calling convention for this target
|
||||
- bootstrap code and default panic handler
|
||||
* `zig targets` is guaranteed to include this target.
|
||||
|
||||
#### Tier 4 Support
|
||||
|
||||
* Support for these targets is entirely experimental.
|
||||
* LLVM may have the target as an experimental target, which means that you
|
||||
need to use Zig-provided binaries for the target to be available, or
|
||||
build LLVM from source with special configure flags.
|
||||
build LLVM from source with special configure flags. `zig targets` will
|
||||
display the target if it is available.
|
||||
* This target may be considered deprecated by an official party,
|
||||
[such as macosx/i386](https://support.apple.com/en-us/HT208436) in which
|
||||
case this target will remain forever stuck in Tier 4.
|
||||
* This target may only support `--emit asm` and cannot emit object files.
|
||||
|
||||
#### Support Table
|
||||
|
||||
| | freestanding | linux | macosx | windows | freebsd | UEFI | other |
|
||||
|--------|--------------|--------|--------|---------|---------|--------|--------|
|
||||
|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 2 | Tier 3 |
|
||||
|i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|r600 | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|spir | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A |
|
||||
|wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A |
|
||||
|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 |
|
||||
|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 |
|
||||
| | freestanding | linux | macosx | windows | freebsd | netbsd | UEFI | other |
|
||||
|-------------|--------------|--------|--------|---------|---------|------- | -------|--------|
|
||||
|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 2 | Tier 2 | Tier 3 |
|
||||
|i386 | Tier 2 | Tier 2 | Tier 4 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|avr | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|
||||
|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|
||||
|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|
||||
|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|
||||
|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|
||||
|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|
||||
|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|
||||
|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|
||||
|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|
||||
|wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
|
||||
|wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
|
||||
|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 | Tier 4 |
|
||||
|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 | Tier 4 |
|
||||
|xcore | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|nvptx | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|msp430 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|r600 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|arc | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|tce | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|le | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|amdil | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|hsail | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|spir | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|kalimba | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|shave | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|renderscript | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|
||||
|
||||
## Community
|
||||
|
||||
|
11
build.zig
11
build.zig
@ -49,13 +49,14 @@ pub fn build(b: *Builder) !void {
|
||||
.c_header_files = nextValue(&index, build_info),
|
||||
.dia_guids_lib = nextValue(&index, build_info),
|
||||
.llvm = undefined,
|
||||
.no_rosegment = b.option(bool, "no-rosegment", "Workaround to enable valgrind builds") orelse false,
|
||||
};
|
||||
ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
|
||||
|
||||
var test_stage2 = b.addTest("src-self-hosted/test.zig");
|
||||
test_stage2.setBuildMode(builtin.Mode.Debug);
|
||||
|
||||
const fmt_build_zig = b.addFmt([][]const u8{"build.zig"});
|
||||
|
||||
var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
|
||||
exe.setBuildMode(mode);
|
||||
|
||||
@ -107,6 +108,11 @@ pub fn build(b: *Builder) !void {
|
||||
}
|
||||
const modes = chosen_modes[0..chosen_mode_index];
|
||||
|
||||
// run stage1 `zig fmt` on this build.zig file just to make sure it works
|
||||
test_step.dependOn(&fmt_build_zig.step);
|
||||
const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
|
||||
fmt_step.dependOn(&fmt_build_zig.step);
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes));
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes));
|
||||
@ -289,8 +295,6 @@ fn nextValue(index: *usize, build_info: []const u8) []const u8 {
|
||||
}
|
||||
|
||||
fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
|
||||
exe.setNoRoSegment(ctx.no_rosegment);
|
||||
|
||||
exe.addIncludeDir("src");
|
||||
exe.addIncludeDir(ctx.cmake_binary_dir);
|
||||
addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
|
||||
@ -375,5 +379,4 @@ const Context = struct {
|
||||
c_header_files: []const u8,
|
||||
dia_guids_lib: []const u8,
|
||||
llvm: LibraryDep,
|
||||
no_rosegment: bool,
|
||||
};
|
||||
|
@ -11,17 +11,28 @@ if(MSVC)
|
||||
find_package(CLANG REQUIRED CONFIG)
|
||||
|
||||
set(CLANG_LIBRARIES
|
||||
clangFrontendTool
|
||||
clangCodeGen
|
||||
clangFrontend
|
||||
clangDriver
|
||||
clangSerialization
|
||||
clangSema
|
||||
clangStaticAnalyzerFrontend
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangAnalysis
|
||||
clangASTMatchers
|
||||
clangAST
|
||||
clangParse
|
||||
clangSema
|
||||
clangBasic
|
||||
clangEdit
|
||||
clangLex
|
||||
clangARCMigrate
|
||||
clangRewriteFrontend
|
||||
clangRewrite
|
||||
clangCrossTU
|
||||
clangIndex
|
||||
)
|
||||
|
||||
else()
|
||||
@ -50,17 +61,28 @@ else()
|
||||
endif()
|
||||
endmacro(FIND_AND_ADD_CLANG_LIB)
|
||||
|
||||
FIND_AND_ADD_CLANG_LIB(clangFrontendTool)
|
||||
FIND_AND_ADD_CLANG_LIB(clangCodeGen)
|
||||
FIND_AND_ADD_CLANG_LIB(clangFrontend)
|
||||
FIND_AND_ADD_CLANG_LIB(clangDriver)
|
||||
FIND_AND_ADD_CLANG_LIB(clangSerialization)
|
||||
FIND_AND_ADD_CLANG_LIB(clangSema)
|
||||
FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerFrontend)
|
||||
FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerCheckers)
|
||||
FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerCore)
|
||||
FIND_AND_ADD_CLANG_LIB(clangAnalysis)
|
||||
FIND_AND_ADD_CLANG_LIB(clangASTMatchers)
|
||||
FIND_AND_ADD_CLANG_LIB(clangAST)
|
||||
FIND_AND_ADD_CLANG_LIB(clangParse)
|
||||
FIND_AND_ADD_CLANG_LIB(clangSema)
|
||||
FIND_AND_ADD_CLANG_LIB(clangBasic)
|
||||
FIND_AND_ADD_CLANG_LIB(clangEdit)
|
||||
FIND_AND_ADD_CLANG_LIB(clangLex)
|
||||
FIND_AND_ADD_CLANG_LIB(clangARCMigrate)
|
||||
FIND_AND_ADD_CLANG_LIB(clangRewriteFrontend)
|
||||
FIND_AND_ADD_CLANG_LIB(clangRewrite)
|
||||
FIND_AND_ADD_CLANG_LIB(clangCrossTU)
|
||||
FIND_AND_ADD_CLANG_LIB(clangIndex)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
@ -916,6 +916,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
|
||||
std.zig.Token.Id.AngleBracketAngleBracketRightEqual,
|
||||
std.zig.Token.Id.Tilde,
|
||||
std.zig.Token.Id.BracketStarBracket,
|
||||
std.zig.Token.Id.BracketStarCBracket,
|
||||
=> try writeEscaped(out, src[token.start..token.end]),
|
||||
|
||||
std.zig.Token.Id.Invalid => return parseError(
|
||||
@ -1104,14 +1105,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
},
|
||||
}
|
||||
if (code.target_windows) {
|
||||
try test_args.appendSlice([][]const u8{
|
||||
"--target-os",
|
||||
"windows",
|
||||
"--target-arch",
|
||||
"x86_64",
|
||||
"--target-environ",
|
||||
"msvc",
|
||||
});
|
||||
try test_args.appendSlice([][]const u8{ "-target", "x86_64-windows" });
|
||||
}
|
||||
const result = exec(allocator, &env_map, test_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "test failed");
|
||||
const escaped_stderr = try escapeHtml(allocator, result.stderr);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
|
||||
pub fn build(b: *Builder) void {
|
||||
const obj = b.addObject("base64", "base64.zig");
|
||||
|
||||
const exe = b.addCExecutable("test");
|
||||
exe.addCompileFlags([][]const u8{"-std=c99"});
|
||||
exe.addSourceFile("test.c");
|
||||
const exe = b.addExecutable("test", null);
|
||||
exe.addCSourceFile("test.c",[][]const u8{"-std=c99"});
|
||||
exe.addObject(obj);
|
||||
exe.linkSystemLibrary("c");
|
||||
|
||||
b.default_step.dependOn(&exe.step);
|
||||
|
||||
|
@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
|
||||
pub fn build(b: *Builder) void {
|
||||
const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
|
||||
|
||||
const exe = b.addCExecutable("test");
|
||||
exe.addCompileFlags([][]const u8{"-std=c99"});
|
||||
exe.addSourceFile("test.c");
|
||||
const exe = b.addExecutable("test", null);
|
||||
exe.addCSourceFile("test.c", [][]const u8{"-std=c99"});
|
||||
exe.linkLibrary(lib);
|
||||
exe.linkSystemLibrary("c");
|
||||
|
||||
b.default_step.dependOn(&exe.step);
|
||||
|
||||
|
@ -1,12 +1,3 @@
|
||||
// TODO Remove this workaround
|
||||
comptime {
|
||||
const builtin = @import("builtin");
|
||||
if (builtin.os == builtin.Os.macosx) {
|
||||
@export("__mh_execute_header", _mh_execute_header, builtin.GlobalLinkage.Weak);
|
||||
}
|
||||
}
|
||||
var _mh_execute_header = extern struct {x: usize}{.x = 0};
|
||||
|
||||
export fn add(a: i32, b: i32) i32 {
|
||||
return a + b;
|
||||
}
|
||||
|
@ -137,10 +137,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
|
||||
|
||||
pub const ObjectFile = struct {
|
||||
comp: *Compilation,
|
||||
module: llvm.ModuleRef,
|
||||
builder: llvm.BuilderRef,
|
||||
module: *llvm.Module,
|
||||
builder: *llvm.Builder,
|
||||
dibuilder: *llvm.DIBuilder,
|
||||
context: llvm.ContextRef,
|
||||
context: *llvm.Context,
|
||||
lock: event.Lock,
|
||||
arena: *std.mem.Allocator,
|
||||
|
||||
@ -323,7 +323,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
|
||||
|
||||
fn addLLVMAttr(
|
||||
ofile: *ObjectFile,
|
||||
val: llvm.ValueRef,
|
||||
val: *llvm.Value,
|
||||
attr_index: llvm.AttributeIndex,
|
||||
attr_name: []const u8,
|
||||
) !void {
|
||||
@ -335,7 +335,7 @@ fn addLLVMAttr(
|
||||
|
||||
fn addLLVMAttrStr(
|
||||
ofile: *ObjectFile,
|
||||
val: llvm.ValueRef,
|
||||
val: *llvm.Value,
|
||||
attr_index: llvm.AttributeIndex,
|
||||
attr_name: []const u8,
|
||||
attr_val: []const u8,
|
||||
@ -351,7 +351,7 @@ fn addLLVMAttrStr(
|
||||
}
|
||||
|
||||
fn addLLVMAttrInt(
|
||||
val: llvm.ValueRef,
|
||||
val: *llvm.Value,
|
||||
attr_index: llvm.AttributeIndex,
|
||||
attr_name: []const u8,
|
||||
attr_val: u64,
|
||||
@ -362,25 +362,25 @@ fn addLLVMAttrInt(
|
||||
llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
|
||||
}
|
||||
|
||||
fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8) !void {
|
||||
fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8) !void {
|
||||
return addLLVMAttr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name);
|
||||
}
|
||||
|
||||
fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: []const u8) !void {
|
||||
fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: []const u8) !void {
|
||||
return addLLVMAttrStr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val);
|
||||
}
|
||||
|
||||
fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void {
|
||||
fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: u64) !void {
|
||||
return addLLVMAttrInt(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val);
|
||||
}
|
||||
|
||||
fn renderLoadUntyped(
|
||||
ofile: *ObjectFile,
|
||||
ptr: llvm.ValueRef,
|
||||
ptr: *llvm.Value,
|
||||
alignment: Type.Pointer.Align,
|
||||
vol: Type.Pointer.Vol,
|
||||
name: [*]const u8,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
|
||||
switch (vol) {
|
||||
Type.Pointer.Vol.Non => {},
|
||||
@ -390,11 +390,11 @@ fn renderLoadUntyped(
|
||||
return result;
|
||||
}
|
||||
|
||||
fn renderLoad(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer, name: [*]const u8) !llvm.ValueRef {
|
||||
fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*]const u8) !*llvm.Value {
|
||||
return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);
|
||||
}
|
||||
|
||||
pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer) !?llvm.ValueRef {
|
||||
pub fn getHandleValue(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer) !?*llvm.Value {
|
||||
const child_type = ptr_type.key.child_type;
|
||||
if (!child_type.hasBits()) {
|
||||
return null;
|
||||
@ -407,11 +407,11 @@ pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Po
|
||||
|
||||
pub fn renderStoreUntyped(
|
||||
ofile: *ObjectFile,
|
||||
value: llvm.ValueRef,
|
||||
ptr: llvm.ValueRef,
|
||||
value: *llvm.Value,
|
||||
ptr: *llvm.Value,
|
||||
alignment: Type.Pointer.Align,
|
||||
vol: Type.Pointer.Vol,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory;
|
||||
switch (vol) {
|
||||
Type.Pointer.Vol.Non => {},
|
||||
@ -423,10 +423,10 @@ pub fn renderStoreUntyped(
|
||||
|
||||
pub fn renderStore(
|
||||
ofile: *ObjectFile,
|
||||
value: llvm.ValueRef,
|
||||
ptr: llvm.ValueRef,
|
||||
value: *llvm.Value,
|
||||
ptr: *llvm.Value,
|
||||
ptr_type: *Type.Pointer,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol);
|
||||
}
|
||||
|
||||
@ -435,7 +435,7 @@ pub fn renderAlloca(
|
||||
var_type: *Type,
|
||||
name: []const u8,
|
||||
alignment: Type.Pointer.Align,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
|
||||
const name_with_null = try std.cstr.addNullByte(ofile.arena, name);
|
||||
const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory;
|
||||
@ -443,7 +443,7 @@ pub fn renderAlloca(
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: llvm.TypeRef) u32 {
|
||||
pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: *llvm.Type) u32 {
|
||||
return switch (alignment) {
|
||||
Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type),
|
||||
Type.Pointer.Align.Override => |a| a,
|
||||
|
@ -37,7 +37,7 @@ const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
|
||||
/// Data that is local to the event loop.
|
||||
pub const ZigCompiler = struct {
|
||||
loop: *event.Loop,
|
||||
llvm_handle_pool: std.atomic.Stack(llvm.ContextRef),
|
||||
llvm_handle_pool: std.atomic.Stack(*llvm.Context),
|
||||
lld_lock: event.Lock,
|
||||
|
||||
/// TODO pool these so that it doesn't have to lock
|
||||
@ -60,7 +60,7 @@ pub const ZigCompiler = struct {
|
||||
return ZigCompiler{
|
||||
.loop = loop,
|
||||
.lld_lock = event.Lock.init(loop),
|
||||
.llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(),
|
||||
.llvm_handle_pool = std.atomic.Stack(*llvm.Context).init(),
|
||||
.prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)),
|
||||
.native_libc = event.Future(LibCInstallation).init(loop),
|
||||
};
|
||||
@ -70,7 +70,7 @@ pub const ZigCompiler = struct {
|
||||
fn deinit(self: *ZigCompiler) void {
|
||||
self.lld_lock.deinit();
|
||||
while (self.llvm_handle_pool.pop()) |node| {
|
||||
c.LLVMContextDispose(node.data);
|
||||
llvm.ContextDispose(node.data);
|
||||
self.loop.allocator.destroy(node);
|
||||
}
|
||||
}
|
||||
@ -80,11 +80,11 @@ pub const ZigCompiler = struct {
|
||||
pub fn getAnyLlvmContext(self: *ZigCompiler) !LlvmHandle {
|
||||
if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node };
|
||||
|
||||
const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory;
|
||||
errdefer c.LLVMContextDispose(context_ref);
|
||||
const context_ref = llvm.ContextCreate() orelse return error.OutOfMemory;
|
||||
errdefer llvm.ContextDispose(context_ref);
|
||||
|
||||
const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node);
|
||||
node.* = std.atomic.Stack(llvm.ContextRef).Node{
|
||||
const node = try self.loop.allocator.create(std.atomic.Stack(*llvm.Context).Node);
|
||||
node.* = std.atomic.Stack(*llvm.Context).Node{
|
||||
.next = undefined,
|
||||
.data = context_ref,
|
||||
};
|
||||
@ -114,7 +114,7 @@ pub const ZigCompiler = struct {
|
||||
};
|
||||
|
||||
pub const LlvmHandle = struct {
|
||||
node: *std.atomic.Stack(llvm.ContextRef).Node,
|
||||
node: *std.atomic.Stack(*llvm.Context).Node,
|
||||
|
||||
pub fn release(self: LlvmHandle, zig_compiler: *ZigCompiler) void {
|
||||
zig_compiler.llvm_handle_pool.push(self.node);
|
||||
@ -128,7 +128,7 @@ pub const Compilation = struct {
|
||||
llvm_triple: Buffer,
|
||||
root_src_path: ?[]const u8,
|
||||
target: Target,
|
||||
llvm_target: llvm.TargetRef,
|
||||
llvm_target: *llvm.Target,
|
||||
build_mode: builtin.Mode,
|
||||
zig_lib_dir: []const u8,
|
||||
zig_std_dir: []const u8,
|
||||
@ -212,8 +212,8 @@ pub const Compilation = struct {
|
||||
false_value: *Value.Bool,
|
||||
noreturn_value: *Value.NoReturn,
|
||||
|
||||
target_machine: llvm.TargetMachineRef,
|
||||
target_data_ref: llvm.TargetDataRef,
|
||||
target_machine: *llvm.TargetMachine,
|
||||
target_data_ref: *llvm.TargetData,
|
||||
target_layout_str: [*]u8,
|
||||
target_ptr_bits: u32,
|
||||
|
||||
|
@ -67,7 +67,7 @@ pub const Inst = struct {
|
||||
parent: ?*Inst,
|
||||
|
||||
/// populated durign codegen
|
||||
llvm_value: ?llvm.ValueRef,
|
||||
llvm_value: ?*llvm.Value,
|
||||
|
||||
pub fn cast(base: *Inst, comptime T: type) ?*T {
|
||||
if (base.id == comptime typeToId(T)) {
|
||||
@ -129,7 +129,7 @@ pub const Inst = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
|
||||
pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?*llvm.Value) {
|
||||
switch (base.id) {
|
||||
Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
|
||||
Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
|
||||
@ -313,10 +313,10 @@ pub const Inst = struct {
|
||||
return new_inst;
|
||||
}
|
||||
|
||||
pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
const fn_ref = self.params.fn_ref.llvm_value.?;
|
||||
|
||||
const args = try ofile.arena.alloc(llvm.ValueRef, self.params.args.len);
|
||||
const args = try ofile.arena.alloc(*llvm.Value, self.params.args.len);
|
||||
for (self.params.args) |arg, i| {
|
||||
args[i] = arg.llvm_value.?;
|
||||
}
|
||||
@ -360,7 +360,7 @@ pub const Inst = struct {
|
||||
return new_inst;
|
||||
}
|
||||
|
||||
pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
return self.base.val.KnownValue.getLlvmConst(ofile);
|
||||
}
|
||||
};
|
||||
@ -392,7 +392,7 @@ pub const Inst = struct {
|
||||
return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });
|
||||
}
|
||||
|
||||
pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
const value = self.params.return_value.llvm_value;
|
||||
const return_type = self.params.return_value.getKnownType();
|
||||
|
||||
@ -540,7 +540,7 @@ pub const Inst = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) llvm.ValueRef {
|
||||
pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) *llvm.Value {
|
||||
switch (self.params.var_scope.data) {
|
||||
Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass
|
||||
Scope.Var.Data.Param => |param| return param.llvm_value,
|
||||
@ -596,7 +596,7 @@ pub const Inst = struct {
|
||||
return new_inst;
|
||||
}
|
||||
|
||||
pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
const child_type = self.base.getKnownType();
|
||||
if (!child_type.hasBits()) {
|
||||
return null;
|
||||
@ -935,8 +935,8 @@ pub const BasicBlock = struct {
|
||||
ref_instruction: ?*Inst,
|
||||
|
||||
/// for codegen
|
||||
llvm_block: llvm.BasicBlockRef,
|
||||
llvm_exit_block: llvm.BasicBlockRef,
|
||||
llvm_block: *llvm.BasicBlock,
|
||||
llvm_exit_block: *llvm.BasicBlock,
|
||||
|
||||
/// the basic block that is derived from this one in analysis
|
||||
child: ?*BasicBlock,
|
||||
|
@ -154,8 +154,8 @@ pub const LibCInstallation = struct {
|
||||
c.ZigFindWindowsSdkError.None => {
|
||||
windows_sdk = sdk;
|
||||
|
||||
if (sdk.msvc_lib_dir_ptr) |ptr| {
|
||||
self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, ptr[0..sdk.msvc_lib_dir_len]);
|
||||
if (sdk.msvc_lib_dir_ptr != 0) {
|
||||
self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, sdk.msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]);
|
||||
}
|
||||
try group.call(findNativeKernel32LibDir, self, loop, sdk);
|
||||
try group.call(findNativeIncludeDirWindows, self, loop, sdk);
|
||||
@ -172,7 +172,7 @@ pub const LibCInstallation = struct {
|
||||
try group.call(findNativeStaticLibDir, self, loop);
|
||||
try group.call(findNativeDynamicLinker, self, loop);
|
||||
},
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
|
||||
},
|
||||
else => @compileError("unimplemented: find libc for this OS"),
|
||||
@ -283,7 +283,7 @@ pub const LibCInstallation = struct {
|
||||
switch (builtin.arch) {
|
||||
builtin.Arch.i386 => try stream.write("x86"),
|
||||
builtin.Arch.x86_64 => try stream.write("x64"),
|
||||
builtin.Arch.aarch64v8 => try stream.write("arm"),
|
||||
builtin.Arch.aarch64 => try stream.write("arm"),
|
||||
else => return error.UnsupportedArchitecture,
|
||||
}
|
||||
const ucrt_lib_path = try std.os.path.join(
|
||||
@ -361,7 +361,7 @@ pub const LibCInstallation = struct {
|
||||
switch (builtin.arch) {
|
||||
builtin.Arch.i386 => try stream.write("x86\\"),
|
||||
builtin.Arch.x86_64 => try stream.write("x64\\"),
|
||||
builtin.Arch.aarch64v8 => try stream.write("arm\\"),
|
||||
builtin.Arch.aarch64 => try stream.write("arm\\"),
|
||||
else => return error.UnsupportedArchitecture,
|
||||
}
|
||||
const kernel32_path = try std.os.path.join(
|
||||
@ -437,20 +437,20 @@ const Search = struct {
|
||||
|
||||
fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search {
|
||||
var search_end: usize = 0;
|
||||
if (sdk.path10_ptr) |path10_ptr| {
|
||||
if (sdk.version10_ptr) |ver10_ptr| {
|
||||
if (sdk.path10_ptr != 0) {
|
||||
if (sdk.version10_ptr != 0) {
|
||||
search_buf[search_end] = Search{
|
||||
.path = path10_ptr[0..sdk.path10_len],
|
||||
.version = ver10_ptr[0..sdk.version10_len],
|
||||
.path = sdk.path10_ptr[0..sdk.path10_len],
|
||||
.version = sdk.version10_ptr[0..sdk.version10_len],
|
||||
};
|
||||
search_end += 1;
|
||||
}
|
||||
}
|
||||
if (sdk.path81_ptr) |path81_ptr| {
|
||||
if (sdk.version81_ptr) |ver81_ptr| {
|
||||
if (sdk.path81_ptr != 0) {
|
||||
if (sdk.version81_ptr != 0) {
|
||||
search_buf[search_end] = Search{
|
||||
.path = path81_ptr[0..sdk.path81_len],
|
||||
.version = ver81_ptr[0..sdk.version81_len],
|
||||
.path = sdk.path81_ptr[0..sdk.path81_len],
|
||||
.version = sdk.version81_ptr[0..sdk.version81_len],
|
||||
};
|
||||
search_end += 1;
|
||||
}
|
||||
|
@ -145,10 +145,6 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
|
||||
// lj->args.append("-T");
|
||||
// lj->args.append(g->linker_script);
|
||||
//}
|
||||
|
||||
//if (g->no_rosegment_workaround) {
|
||||
// lj->args.append("--no-rosegment");
|
||||
//}
|
||||
try ctx.args.append(c"--gc-sections");
|
||||
|
||||
//lj->args.append("-m");
|
||||
@ -330,7 +326,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
|
||||
switch (ctx.comp.target.getArch()) {
|
||||
builtin.Arch.i386 => try ctx.args.append(c"-MACHINE:X86"),
|
||||
builtin.Arch.x86_64 => try ctx.args.append(c"-MACHINE:X64"),
|
||||
builtin.Arch.aarch64v8 => try ctx.args.append(c"-MACHINE:ARM"),
|
||||
builtin.Arch.aarch64 => try ctx.args.append(c"-MACHINE:ARM"),
|
||||
else => return error.UnsupportedLinkArchitecture,
|
||||
}
|
||||
|
||||
@ -556,7 +552,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
|
||||
}
|
||||
},
|
||||
DarwinPlatform.Kind.IPhoneOS => {
|
||||
if (ctx.comp.target.getArch() == builtin.Arch.aarch64v8) {
|
||||
if (ctx.comp.target.getArch() == builtin.Arch.aarch64) {
|
||||
// iOS does not need any crt1 files for arm64
|
||||
} else if (platform.versionLessThan(3, 1)) {
|
||||
try ctx.args.append(c"-lcrt1.o");
|
||||
|
@ -11,45 +11,31 @@ const assert = @import("std").debug.assert;
|
||||
pub const AttributeIndex = c_uint;
|
||||
pub const Bool = c_int;
|
||||
|
||||
pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
|
||||
pub const ContextRef = removeNullability(c.LLVMContextRef);
|
||||
pub const ModuleRef = removeNullability(c.LLVMModuleRef);
|
||||
pub const ValueRef = removeNullability(c.LLVMValueRef);
|
||||
pub const TypeRef = removeNullability(c.LLVMTypeRef);
|
||||
pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef);
|
||||
pub const AttributeRef = removeNullability(c.LLVMAttributeRef);
|
||||
pub const TargetRef = removeNullability(c.LLVMTargetRef);
|
||||
pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);
|
||||
pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);
|
||||
pub const Builder = c.LLVMBuilderRef.Child.Child;
|
||||
pub const Context = c.LLVMContextRef.Child.Child;
|
||||
pub const Module = c.LLVMModuleRef.Child.Child;
|
||||
pub const Value = c.LLVMValueRef.Child.Child;
|
||||
pub const Type = c.LLVMTypeRef.Child.Child;
|
||||
pub const BasicBlock = c.LLVMBasicBlockRef.Child.Child;
|
||||
pub const Attribute = c.LLVMAttributeRef.Child.Child;
|
||||
pub const Target = c.LLVMTargetRef.Child.Child;
|
||||
pub const TargetMachine = c.LLVMTargetMachineRef.Child.Child;
|
||||
pub const TargetData = c.LLVMTargetDataRef.Child.Child;
|
||||
pub const DIBuilder = c.ZigLLVMDIBuilder;
|
||||
pub const DIFile = c.ZigLLVMDIFile;
|
||||
pub const DICompileUnit = c.ZigLLVMDICompileUnit;
|
||||
|
||||
pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
|
||||
pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
|
||||
pub const AddFunction = c.LLVMAddFunction;
|
||||
pub const AddGlobal = c.LLVMAddGlobal;
|
||||
pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
|
||||
pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
|
||||
pub const ArrayType = c.LLVMArrayType;
|
||||
pub const BuildLoad = c.LLVMBuildLoad;
|
||||
pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
|
||||
pub const ConstAllOnes = c.LLVMConstAllOnes;
|
||||
pub const ConstArray = c.LLVMConstArray;
|
||||
pub const ConstBitCast = c.LLVMConstBitCast;
|
||||
pub const ConstInt = c.LLVMConstInt;
|
||||
pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
|
||||
pub const ConstNeg = c.LLVMConstNeg;
|
||||
pub const ConstNull = c.LLVMConstNull;
|
||||
pub const ConstStringInContext = c.LLVMConstStringInContext;
|
||||
pub const ConstStructInContext = c.LLVMConstStructInContext;
|
||||
pub const CopyStringRepOfTargetData = c.LLVMCopyStringRepOfTargetData;
|
||||
pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;
|
||||
pub const CreateCompileUnit = c.ZigLLVMCreateCompileUnit;
|
||||
pub const CreateDIBuilder = c.ZigLLVMCreateDIBuilder;
|
||||
pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute;
|
||||
pub const CreateFile = c.ZigLLVMCreateFile;
|
||||
pub const CreateStringAttribute = c.LLVMCreateStringAttribute;
|
||||
pub const CreateTargetDataLayout = c.LLVMCreateTargetDataLayout;
|
||||
pub const CreateTargetMachine = c.LLVMCreateTargetMachine;
|
||||
pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize;
|
||||
pub const DisposeBuilder = c.LLVMDisposeBuilder;
|
||||
pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder;
|
||||
@ -62,9 +48,7 @@ pub const DumpModule = c.LLVMDumpModule;
|
||||
pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
|
||||
pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
|
||||
pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
|
||||
pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
|
||||
pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
|
||||
pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
|
||||
pub const GetUndef = c.LLVMGetUndef;
|
||||
pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
|
||||
pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
|
||||
@ -81,14 +65,11 @@ pub const Int64TypeInContext = c.LLVMInt64TypeInContext;
|
||||
pub const Int8TypeInContext = c.LLVMInt8TypeInContext;
|
||||
pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext;
|
||||
pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext;
|
||||
pub const IntTypeInContext = c.LLVMIntTypeInContext;
|
||||
pub const LabelTypeInContext = c.LLVMLabelTypeInContext;
|
||||
pub const MDNodeInContext = c.LLVMMDNodeInContext;
|
||||
pub const MDStringInContext = c.LLVMMDStringInContext;
|
||||
pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
|
||||
pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
|
||||
pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
|
||||
pub const PointerType = c.LLVMPointerType;
|
||||
pub const SetAlignment = c.LLVMSetAlignment;
|
||||
pub const SetDataLayout = c.LLVMSetDataLayout;
|
||||
pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
|
||||
@ -99,50 +80,146 @@ pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
|
||||
pub const SetVolatile = c.LLVMSetVolatile;
|
||||
pub const StructTypeInContext = c.LLVMStructTypeInContext;
|
||||
pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
|
||||
pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
|
||||
pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
|
||||
pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
|
||||
|
||||
pub const AddGlobal = LLVMAddGlobal;
|
||||
extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*]const u8) ?*Value;
|
||||
|
||||
pub const ConstStringInContext = LLVMConstStringInContext;
|
||||
extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value;
|
||||
|
||||
pub const ConstInt = LLVMConstInt;
|
||||
extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value;
|
||||
|
||||
pub const BuildLoad = LLVMBuildLoad;
|
||||
extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*]const u8) ?*Value;
|
||||
|
||||
pub const ConstNull = LLVMConstNull;
|
||||
extern fn LLVMConstNull(Ty: *Type) ?*Value;
|
||||
|
||||
pub const CreateStringAttribute = LLVMCreateStringAttribute;
|
||||
extern fn LLVMCreateStringAttribute(
|
||||
C: *Context,
|
||||
K: [*]const u8,
|
||||
KLength: c_uint,
|
||||
V: [*]const u8,
|
||||
VLength: c_uint,
|
||||
) ?*Attribute;
|
||||
|
||||
pub const CreateEnumAttribute = LLVMCreateEnumAttribute;
|
||||
extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute;
|
||||
|
||||
pub const AddFunction = LLVMAddFunction;
|
||||
extern fn LLVMAddFunction(M: *Module, Name: [*]const u8, FunctionTy: *Type) ?*Value;
|
||||
|
||||
pub const CreateCompileUnit = ZigLLVMCreateCompileUnit;
|
||||
extern fn ZigLLVMCreateCompileUnit(
|
||||
dibuilder: *DIBuilder,
|
||||
lang: c_uint,
|
||||
difile: *DIFile,
|
||||
producer: [*]const u8,
|
||||
is_optimized: bool,
|
||||
flags: [*]const u8,
|
||||
runtime_version: c_uint,
|
||||
split_name: [*]const u8,
|
||||
dwo_id: u64,
|
||||
emit_debug_info: bool,
|
||||
) ?*DICompileUnit;
|
||||
|
||||
pub const CreateFile = ZigLLVMCreateFile;
|
||||
extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*]const u8, directory: [*]const u8) ?*DIFile;
|
||||
|
||||
pub const ArrayType = LLVMArrayType;
|
||||
extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type;
|
||||
|
||||
pub const CreateDIBuilder = ZigLLVMCreateDIBuilder;
|
||||
extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) ?*DIBuilder;
|
||||
|
||||
pub const PointerType = LLVMPointerType;
|
||||
extern fn LLVMPointerType(ElementType: *Type, AddressSpace: c_uint) ?*Type;
|
||||
|
||||
pub const CreateBuilderInContext = LLVMCreateBuilderInContext;
|
||||
extern fn LLVMCreateBuilderInContext(C: *Context) ?*Builder;
|
||||
|
||||
pub const IntTypeInContext = LLVMIntTypeInContext;
|
||||
extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type;
|
||||
|
||||
pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext;
|
||||
extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*]const u8, C: *Context) ?*Module;
|
||||
|
||||
pub const VoidTypeInContext = LLVMVoidTypeInContext;
|
||||
extern fn LLVMVoidTypeInContext(C: *Context) ?*Type;
|
||||
|
||||
pub const ContextCreate = LLVMContextCreate;
|
||||
extern fn LLVMContextCreate() ?*Context;
|
||||
|
||||
pub const ContextDispose = LLVMContextDispose;
|
||||
extern fn LLVMContextDispose(C: *Context) void;
|
||||
|
||||
pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData;
|
||||
extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*]u8;
|
||||
|
||||
pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout;
|
||||
extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData;
|
||||
|
||||
pub const CreateTargetMachine = LLVMCreateTargetMachine;
|
||||
extern fn LLVMCreateTargetMachine(
|
||||
T: *Target,
|
||||
Triple: [*]const u8,
|
||||
CPU: [*]const u8,
|
||||
Features: [*]const u8,
|
||||
Level: CodeGenOptLevel,
|
||||
Reloc: RelocMode,
|
||||
CodeModel: CodeModel,
|
||||
) ?*TargetMachine;
|
||||
|
||||
pub const GetHostCPUName = LLVMGetHostCPUName;
|
||||
extern fn LLVMGetHostCPUName() ?[*]u8;
|
||||
|
||||
pub const GetNativeFeatures = ZigLLVMGetNativeFeatures;
|
||||
extern fn ZigLLVMGetNativeFeatures() ?[*]u8;
|
||||
|
||||
pub const GetElementType = LLVMGetElementType;
|
||||
extern fn LLVMGetElementType(Ty: TypeRef) TypeRef;
|
||||
extern fn LLVMGetElementType(Ty: *Type) *Type;
|
||||
|
||||
pub const TypeOf = LLVMTypeOf;
|
||||
extern fn LLVMTypeOf(Val: ValueRef) TypeRef;
|
||||
extern fn LLVMTypeOf(Val: *Value) *Type;
|
||||
|
||||
pub const BuildStore = LLVMBuildStore;
|
||||
extern fn LLVMBuildStore(arg0: BuilderRef, Val: ValueRef, Ptr: ValueRef) ?ValueRef;
|
||||
extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value;
|
||||
|
||||
pub const BuildAlloca = LLVMBuildAlloca;
|
||||
extern fn LLVMBuildAlloca(arg0: BuilderRef, Ty: TypeRef, Name: ?[*]const u8) ?ValueRef;
|
||||
extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*]const u8) ?*Value;
|
||||
|
||||
pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
|
||||
pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef;
|
||||
pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value;
|
||||
|
||||
pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
|
||||
extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;
|
||||
extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: **Target, ErrorMessage: ?*[*]u8) Bool;
|
||||
|
||||
pub const VerifyModule = LLVMVerifyModule;
|
||||
extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
|
||||
extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
|
||||
|
||||
pub const GetInsertBlock = LLVMGetInsertBlock;
|
||||
extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef;
|
||||
extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock;
|
||||
|
||||
pub const FunctionType = LLVMFunctionType;
|
||||
extern fn LLVMFunctionType(
|
||||
ReturnType: TypeRef,
|
||||
ParamTypes: [*]TypeRef,
|
||||
ReturnType: *Type,
|
||||
ParamTypes: [*]*Type,
|
||||
ParamCount: c_uint,
|
||||
IsVarArg: Bool,
|
||||
) ?TypeRef;
|
||||
) ?*Type;
|
||||
|
||||
pub const GetParam = LLVMGetParam;
|
||||
extern fn LLVMGetParam(Fn: ValueRef, Index: c_uint) ValueRef;
|
||||
extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value;
|
||||
|
||||
pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext;
|
||||
extern fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: [*]const u8) ?BasicBlockRef;
|
||||
extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*]const u8) ?*BasicBlock;
|
||||
|
||||
pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd;
|
||||
extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void;
|
||||
extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void;
|
||||
|
||||
pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction;
|
||||
pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction;
|
||||
@ -190,17 +267,17 @@ pub const FnInline = extern enum {
|
||||
};
|
||||
|
||||
fn removeNullability(comptime T: type) type {
|
||||
comptime assert(@typeId(T) == builtin.TypeId.Optional);
|
||||
return T.Child;
|
||||
comptime assert(@typeInfo(T).Pointer.size == @import("builtin").TypeInfo.Pointer.Size.C);
|
||||
return *T.Child;
|
||||
}
|
||||
|
||||
pub const BuildRet = LLVMBuildRet;
|
||||
extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef;
|
||||
extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value;
|
||||
|
||||
pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
|
||||
extern fn ZigLLVMTargetMachineEmitToFile(
|
||||
targ_machine_ref: TargetMachineRef,
|
||||
module_ref: ModuleRef,
|
||||
targ_machine_ref: *TargetMachine,
|
||||
module_ref: *Module,
|
||||
filename: [*]const u8,
|
||||
output_type: EmitOutputType,
|
||||
error_message: *[*]u8,
|
||||
@ -209,6 +286,6 @@ extern fn ZigLLVMTargetMachineEmitToFile(
|
||||
) bool;
|
||||
|
||||
pub const BuildCall = ZigLLVMBuildCall;
|
||||
extern fn ZigLLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: [*]ValueRef, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?ValueRef;
|
||||
extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?*Value;
|
||||
|
||||
pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;
|
||||
|
@ -24,7 +24,7 @@ var stderr_file: os.File = undefined;
|
||||
var stderr: *io.OutStream(os.File.WriteError) = undefined;
|
||||
var stdout: *io.OutStream(os.File.WriteError) = undefined;
|
||||
|
||||
const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
|
||||
pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
|
||||
|
||||
const usage =
|
||||
\\usage: zig [command] [options]
|
||||
@ -154,9 +154,7 @@ const usage_build_generic =
|
||||
\\ release-small optimize for small binary, safety off
|
||||
\\ --static Output will be statically linked
|
||||
\\ --strip Exclude debug symbols
|
||||
\\ --target-arch [name] Specify target architecture
|
||||
\\ --target-environ [name] Specify target environment
|
||||
\\ --target-os [name] Specify target operating system
|
||||
\\ -target [name] <arch><sub>-<os>-<abi> see the targets command
|
||||
\\ --verbose-tokenize Turn on compiler debug output for tokenization
|
||||
\\ --verbose-ast-tree Turn on compiler debug output for parsing into an AST (tree view)
|
||||
\\ --verbose-ast-fmt Turn on compiler debug output for parsing into an AST (render source)
|
||||
@ -220,9 +218,7 @@ const args_build_generic = []Flag{
|
||||
Flag.Bool("--pkg-end"),
|
||||
Flag.Bool("--static"),
|
||||
Flag.Bool("--strip"),
|
||||
Flag.Arg1("--target-arch"),
|
||||
Flag.Arg1("--target-environ"),
|
||||
Flag.Arg1("--target-os"),
|
||||
Flag.Arg1("-target"),
|
||||
Flag.Bool("--verbose-tokenize"),
|
||||
Flag.Bool("--verbose-ast-tree"),
|
||||
Flag.Bool("--verbose-ast-fmt"),
|
||||
@ -510,7 +506,7 @@ fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void {
|
||||
return buildOutputType(allocator, args, Compilation.Kind.Obj);
|
||||
}
|
||||
|
||||
const usage_fmt =
|
||||
pub const usage_fmt =
|
||||
\\usage: zig fmt [file]...
|
||||
\\
|
||||
\\ Formats the input files and modifies them in-place.
|
||||
@ -527,7 +523,7 @@ const usage_fmt =
|
||||
\\
|
||||
;
|
||||
|
||||
const args_fmt_spec = []Flag{
|
||||
pub const args_fmt_spec = []Flag{
|
||||
Flag.Bool("--help"),
|
||||
Flag.Bool("--check"),
|
||||
Flag.Option("--color", []const []const u8{
|
||||
@ -839,15 +835,15 @@ fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void {
|
||||
}
|
||||
try stdout.write("\n");
|
||||
|
||||
try stdout.write("Environments:\n");
|
||||
try stdout.write("C ABIs:\n");
|
||||
{
|
||||
comptime var i: usize = 0;
|
||||
inline while (i < @memberCount(builtin.Environ)) : (i += 1) {
|
||||
comptime const environ_tag = @memberName(builtin.Environ, i);
|
||||
inline while (i < @memberCount(builtin.Abi)) : (i += 1) {
|
||||
comptime const abi_tag = @memberName(builtin.Abi, i);
|
||||
// NOTE: Cannot use empty string, see #918.
|
||||
comptime const native_str = if (comptime mem.eql(u8, environ_tag, @tagName(builtin.environ))) " (native)\n" else "\n";
|
||||
comptime const native_str = if (comptime mem.eql(u8, abi_tag, @tagName(builtin.abi))) " (native)\n" else "\n";
|
||||
|
||||
try stdout.print(" {}{}", environ_tag, native_str);
|
||||
try stdout.print(" {}{}", abi_tag, native_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ pub const Scope = struct {
|
||||
pub const Param = struct {
|
||||
index: usize,
|
||||
typ: *Type,
|
||||
llvm_value: llvm.ValueRef,
|
||||
llvm_value: *llvm.Value,
|
||||
};
|
||||
|
||||
pub fn createParam(
|
||||
|
@ -16,7 +16,7 @@ pub const Target = union(enum) {
|
||||
pub const Cross = struct {
|
||||
arch: builtin.Arch,
|
||||
os: builtin.Os,
|
||||
environ: builtin.Environ,
|
||||
abi: builtin.Abi,
|
||||
object_format: builtin.ObjectFormat,
|
||||
};
|
||||
|
||||
@ -49,16 +49,16 @@ pub const Target = union(enum) {
|
||||
}
|
||||
|
||||
pub fn getArch(self: Target) builtin.Arch {
|
||||
return switch (self) {
|
||||
Target.Native => builtin.arch,
|
||||
@TagType(Target).Cross => |t| t.arch,
|
||||
};
|
||||
switch (self) {
|
||||
Target.Native => return builtin.arch,
|
||||
@TagType(Target).Cross => |t| return t.arch,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getEnviron(self: Target) builtin.Environ {
|
||||
pub fn getAbi(self: Target) builtin.Abi {
|
||||
return switch (self) {
|
||||
Target.Native => builtin.environ,
|
||||
@TagType(Target).Cross => |t| t.environ,
|
||||
Target.Native => builtin.abi,
|
||||
@TagType(Target).Cross => |t| t.abi,
|
||||
};
|
||||
}
|
||||
|
||||
@ -93,50 +93,10 @@ pub const Target = union(enum) {
|
||||
/// TODO expose the arch and subarch separately
|
||||
pub fn isArmOrThumb(self: Target) bool {
|
||||
return switch (self.getArch()) {
|
||||
builtin.Arch.armv8_5a,
|
||||
builtin.Arch.armv8_4a,
|
||||
builtin.Arch.armv8_3a,
|
||||
builtin.Arch.armv8_2a,
|
||||
builtin.Arch.armv8_1a,
|
||||
builtin.Arch.armv8,
|
||||
builtin.Arch.armv8r,
|
||||
builtin.Arch.armv8m_baseline,
|
||||
builtin.Arch.armv8m_mainline,
|
||||
builtin.Arch.armv7,
|
||||
builtin.Arch.armv7em,
|
||||
builtin.Arch.armv7m,
|
||||
builtin.Arch.armv7s,
|
||||
builtin.Arch.armv7k,
|
||||
builtin.Arch.armv7ve,
|
||||
builtin.Arch.armv6,
|
||||
builtin.Arch.armv6m,
|
||||
builtin.Arch.armv6k,
|
||||
builtin.Arch.armv6t2,
|
||||
builtin.Arch.armv5,
|
||||
builtin.Arch.armv5te,
|
||||
builtin.Arch.armv4t,
|
||||
builtin.Arch.armebv8_5a,
|
||||
builtin.Arch.armebv8_4a,
|
||||
builtin.Arch.armebv8_3a,
|
||||
builtin.Arch.armebv8_2a,
|
||||
builtin.Arch.armebv8_1a,
|
||||
builtin.Arch.armebv8,
|
||||
builtin.Arch.armebv8r,
|
||||
builtin.Arch.armebv8m_baseline,
|
||||
builtin.Arch.armebv8m_mainline,
|
||||
builtin.Arch.armebv7,
|
||||
builtin.Arch.armebv7em,
|
||||
builtin.Arch.armebv7m,
|
||||
builtin.Arch.armebv7s,
|
||||
builtin.Arch.armebv7k,
|
||||
builtin.Arch.armebv7ve,
|
||||
builtin.Arch.armebv6,
|
||||
builtin.Arch.armebv6m,
|
||||
builtin.Arch.armebv6k,
|
||||
builtin.Arch.armebv6t2,
|
||||
builtin.Arch.armebv5,
|
||||
builtin.Arch.armebv5te,
|
||||
builtin.Arch.armebv4t,
|
||||
builtin.Arch.arm,
|
||||
builtin.Arch.armeb,
|
||||
builtin.Arch.aarch64,
|
||||
builtin.Arch.aarch64_be,
|
||||
builtin.Arch.thumb,
|
||||
builtin.Arch.thumbeb,
|
||||
=> true,
|
||||
@ -159,14 +119,14 @@ pub const Target = union(enum) {
|
||||
// LLVM WebAssembly output support requires the target to be activated at
|
||||
// build type with -DCMAKE_LLVM_EXPIERMENTAL_TARGETS_TO_BUILD=WebAssembly.
|
||||
//
|
||||
// LLVM determines the output format based on the environment suffix,
|
||||
// LLVM determines the output format based on the abi suffix,
|
||||
// defaulting to an object based on the architecture. The default format in
|
||||
// LLVM 6 sets the wasm arch output incorrectly to ELF. We need to
|
||||
// explicitly set this ourself in order for it to work.
|
||||
//
|
||||
// This is fixed in LLVM 7 and you will be able to get wasm output by
|
||||
// using the target triple `wasm32-unknown-unknown-unknown`.
|
||||
const env_name = if (self.isWasm()) "wasm" else @tagName(self.getEnviron());
|
||||
const env_name = if (self.isWasm()) "wasm" else @tagName(self.getAbi());
|
||||
|
||||
var out = &std.io.BufferOutStream.init(&result).stream;
|
||||
try out.print("{}-unknown-{}-{}", @tagName(self.getArch()), @tagName(self.getOs()), env_name);
|
||||
@ -185,50 +145,8 @@ pub const Target = union(enum) {
|
||||
=> return 16,
|
||||
|
||||
builtin.Arch.arc,
|
||||
builtin.Arch.armv8_5a,
|
||||
builtin.Arch.armv8_4a,
|
||||
builtin.Arch.armv8_3a,
|
||||
builtin.Arch.armv8_2a,
|
||||
builtin.Arch.armv8_1a,
|
||||
builtin.Arch.armv8,
|
||||
builtin.Arch.armv8r,
|
||||
builtin.Arch.armv8m_baseline,
|
||||
builtin.Arch.armv8m_mainline,
|
||||
builtin.Arch.armv7,
|
||||
builtin.Arch.armv7em,
|
||||
builtin.Arch.armv7m,
|
||||
builtin.Arch.armv7s,
|
||||
builtin.Arch.armv7k,
|
||||
builtin.Arch.armv7ve,
|
||||
builtin.Arch.armv6,
|
||||
builtin.Arch.armv6m,
|
||||
builtin.Arch.armv6k,
|
||||
builtin.Arch.armv6t2,
|
||||
builtin.Arch.armv5,
|
||||
builtin.Arch.armv5te,
|
||||
builtin.Arch.armv4t,
|
||||
builtin.Arch.armebv8_5a,
|
||||
builtin.Arch.armebv8_4a,
|
||||
builtin.Arch.armebv8_3a,
|
||||
builtin.Arch.armebv8_2a,
|
||||
builtin.Arch.armebv8_1a,
|
||||
builtin.Arch.armebv8,
|
||||
builtin.Arch.armebv8r,
|
||||
builtin.Arch.armebv8m_baseline,
|
||||
builtin.Arch.armebv8m_mainline,
|
||||
builtin.Arch.armebv7,
|
||||
builtin.Arch.armebv7em,
|
||||
builtin.Arch.armebv7m,
|
||||
builtin.Arch.armebv7s,
|
||||
builtin.Arch.armebv7k,
|
||||
builtin.Arch.armebv7ve,
|
||||
builtin.Arch.armebv6,
|
||||
builtin.Arch.armebv6m,
|
||||
builtin.Arch.armebv6k,
|
||||
builtin.Arch.armebv6t2,
|
||||
builtin.Arch.armebv5,
|
||||
builtin.Arch.armebv5te,
|
||||
builtin.Arch.armebv4t,
|
||||
builtin.Arch.arm,
|
||||
builtin.Arch.armeb,
|
||||
builtin.Arch.hexagon,
|
||||
builtin.Arch.le32,
|
||||
builtin.Arch.mipsr6,
|
||||
@ -248,35 +166,17 @@ pub const Target = union(enum) {
|
||||
builtin.Arch.amdil,
|
||||
builtin.Arch.hsail,
|
||||
builtin.Arch.spir,
|
||||
builtin.Arch.kalimbav3,
|
||||
builtin.Arch.kalimbav4,
|
||||
builtin.Arch.kalimbav5,
|
||||
builtin.Arch.kalimba,
|
||||
builtin.Arch.shave,
|
||||
builtin.Arch.lanai,
|
||||
builtin.Arch.wasm32,
|
||||
builtin.Arch.renderscript32,
|
||||
=> return 32,
|
||||
|
||||
builtin.Arch.aarch64v8_5a,
|
||||
builtin.Arch.aarch64v8_4a,
|
||||
builtin.Arch.aarch64v8_3a,
|
||||
builtin.Arch.aarch64v8_2a,
|
||||
builtin.Arch.aarch64v8_1a,
|
||||
builtin.Arch.aarch64v8,
|
||||
builtin.Arch.aarch64v8r,
|
||||
builtin.Arch.aarch64v8m_baseline,
|
||||
builtin.Arch.aarch64v8m_mainline,
|
||||
builtin.Arch.aarch64_bev8_5a,
|
||||
builtin.Arch.aarch64_bev8_4a,
|
||||
builtin.Arch.aarch64_bev8_3a,
|
||||
builtin.Arch.aarch64_bev8_2a,
|
||||
builtin.Arch.aarch64_bev8_1a,
|
||||
builtin.Arch.aarch64_bev8,
|
||||
builtin.Arch.aarch64_bev8r,
|
||||
builtin.Arch.aarch64_bev8m_baseline,
|
||||
builtin.Arch.aarch64_bev8m_mainline,
|
||||
builtin.Arch.mips64r6,
|
||||
builtin.Arch.mips64elr6,
|
||||
builtin.Arch.aarch64,
|
||||
builtin.Arch.aarch64_be,
|
||||
builtin.Arch.mips64,
|
||||
builtin.Arch.mips64el,
|
||||
builtin.Arch.powerpc64,
|
||||
builtin.Arch.powerpc64le,
|
||||
builtin.Arch.riscv64,
|
||||
@ -298,17 +198,17 @@ pub const Target = union(enum) {
|
||||
}
|
||||
|
||||
pub fn getFloatAbi(self: Target) FloatAbi {
|
||||
return switch (self.getEnviron()) {
|
||||
builtin.Environ.gnueabihf,
|
||||
builtin.Environ.eabihf,
|
||||
builtin.Environ.musleabihf,
|
||||
return switch (self.getAbi()) {
|
||||
builtin.Abi.gnueabihf,
|
||||
builtin.Abi.eabihf,
|
||||
builtin.Abi.musleabihf,
|
||||
=> FloatAbi.Hard,
|
||||
else => FloatAbi.Soft,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
|
||||
const env = self.getEnviron();
|
||||
const env = self.getAbi();
|
||||
const arch = self.getArch();
|
||||
const os = self.getOs();
|
||||
switch (os) {
|
||||
@ -317,21 +217,21 @@ pub const Target = union(enum) {
|
||||
},
|
||||
builtin.Os.linux => {
|
||||
switch (env) {
|
||||
builtin.Environ.android => {
|
||||
builtin.Abi.android => {
|
||||
if (self.is64bit()) {
|
||||
return "/system/bin/linker64";
|
||||
} else {
|
||||
return "/system/bin/linker";
|
||||
}
|
||||
},
|
||||
builtin.Environ.gnux32 => {
|
||||
builtin.Abi.gnux32 => {
|
||||
if (arch == builtin.Arch.x86_64) {
|
||||
return "/libx32/ld-linux-x32.so.2";
|
||||
}
|
||||
},
|
||||
builtin.Environ.musl,
|
||||
builtin.Environ.musleabi,
|
||||
builtin.Environ.musleabihf,
|
||||
builtin.Abi.musl,
|
||||
builtin.Abi.musleabi,
|
||||
builtin.Abi.musleabihf,
|
||||
=> {
|
||||
if (arch == builtin.Arch.x86_64) {
|
||||
return "/lib/ld-musl-x86_64.so.1";
|
||||
@ -345,73 +245,18 @@ pub const Target = union(enum) {
|
||||
builtin.Arch.sparcel,
|
||||
=> return "/lib/ld-linux.so.2",
|
||||
|
||||
builtin.Arch.aarch64v8_5a,
|
||||
builtin.Arch.aarch64v8_4a,
|
||||
builtin.Arch.aarch64v8_3a,
|
||||
builtin.Arch.aarch64v8_2a,
|
||||
builtin.Arch.aarch64v8_1a,
|
||||
builtin.Arch.aarch64v8,
|
||||
builtin.Arch.aarch64v8r,
|
||||
builtin.Arch.aarch64v8m_baseline,
|
||||
builtin.Arch.aarch64v8m_mainline,
|
||||
=> return "/lib/ld-linux-aarch64.so.1",
|
||||
builtin.Arch.aarch64 => return "/lib/ld-linux-aarch64.so.1",
|
||||
|
||||
builtin.Arch.aarch64_bev8_5a,
|
||||
builtin.Arch.aarch64_bev8_4a,
|
||||
builtin.Arch.aarch64_bev8_3a,
|
||||
builtin.Arch.aarch64_bev8_2a,
|
||||
builtin.Arch.aarch64_bev8_1a,
|
||||
builtin.Arch.aarch64_bev8,
|
||||
builtin.Arch.aarch64_bev8r,
|
||||
builtin.Arch.aarch64_bev8m_baseline,
|
||||
builtin.Arch.aarch64_bev8m_mainline,
|
||||
=> return "/lib/ld-linux-aarch64_be.so.1",
|
||||
builtin.Arch.aarch64_be => return "/lib/ld-linux-aarch64_be.so.1",
|
||||
|
||||
builtin.Arch.armv8_5a,
|
||||
builtin.Arch.armv8_4a,
|
||||
builtin.Arch.armv8_3a,
|
||||
builtin.Arch.armv8_2a,
|
||||
builtin.Arch.armv8_1a,
|
||||
builtin.Arch.armv8,
|
||||
builtin.Arch.armv8r,
|
||||
builtin.Arch.armv8m_baseline,
|
||||
builtin.Arch.armv8m_mainline,
|
||||
builtin.Arch.armv7,
|
||||
builtin.Arch.armv7em,
|
||||
builtin.Arch.armv7m,
|
||||
builtin.Arch.armv7s,
|
||||
builtin.Arch.armv7k,
|
||||
builtin.Arch.armv7ve,
|
||||
builtin.Arch.armv6,
|
||||
builtin.Arch.armv6m,
|
||||
builtin.Arch.armv6k,
|
||||
builtin.Arch.armv6t2,
|
||||
builtin.Arch.armv5,
|
||||
builtin.Arch.armv5te,
|
||||
builtin.Arch.armv4t,
|
||||
builtin.Arch.arm,
|
||||
builtin.Arch.thumb,
|
||||
builtin.Arch.armebv8_5a,
|
||||
builtin.Arch.armebv8_4a,
|
||||
builtin.Arch.armebv8_3a,
|
||||
builtin.Arch.armebv8_2a,
|
||||
builtin.Arch.armebv8_1a,
|
||||
builtin.Arch.armebv8,
|
||||
builtin.Arch.armebv8r,
|
||||
builtin.Arch.armebv8m_baseline,
|
||||
builtin.Arch.armebv8m_mainline,
|
||||
builtin.Arch.armebv7,
|
||||
builtin.Arch.armebv7em,
|
||||
builtin.Arch.armebv7m,
|
||||
builtin.Arch.armebv7s,
|
||||
builtin.Arch.armebv7k,
|
||||
builtin.Arch.armebv7ve,
|
||||
builtin.Arch.armebv6,
|
||||
builtin.Arch.armebv6m,
|
||||
builtin.Arch.armebv6k,
|
||||
builtin.Arch.armebv6t2,
|
||||
builtin.Arch.armebv5,
|
||||
builtin.Arch.armebv5te,
|
||||
builtin.Arch.armebv4t,
|
||||
=> return switch (self.getFloatAbi()) {
|
||||
FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
|
||||
else => return "/lib/ld-linux.so.3",
|
||||
},
|
||||
|
||||
builtin.Arch.armeb,
|
||||
builtin.Arch.thumbeb,
|
||||
=> return switch (self.getFloatAbi()) {
|
||||
FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
|
||||
@ -454,9 +299,7 @@ pub const Target = union(enum) {
|
||||
builtin.Arch.hsail64,
|
||||
builtin.Arch.spir,
|
||||
builtin.Arch.spir64,
|
||||
builtin.Arch.kalimbav3,
|
||||
builtin.Arch.kalimbav4,
|
||||
builtin.Arch.kalimbav5,
|
||||
builtin.Arch.kalimba,
|
||||
builtin.Arch.shave,
|
||||
builtin.Arch.lanai,
|
||||
builtin.Arch.wasm32,
|
||||
@ -470,8 +313,8 @@ pub const Target = union(enum) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef {
|
||||
var result: llvm.TargetRef = undefined;
|
||||
pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target {
|
||||
var result: *llvm.Target = undefined;
|
||||
var err_msg: [*]u8 = undefined;
|
||||
if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) {
|
||||
std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg);
|
||||
@ -582,39 +425,9 @@ pub const Target = union(enum) {
|
||||
pub fn getDarwinArchString(self: Target) []const u8 {
|
||||
const arch = self.getArch();
|
||||
switch (arch) {
|
||||
builtin.Arch.aarch64v8_5a,
|
||||
builtin.Arch.aarch64v8_4a,
|
||||
builtin.Arch.aarch64v8_3a,
|
||||
builtin.Arch.aarch64v8_2a,
|
||||
builtin.Arch.aarch64v8_1a,
|
||||
builtin.Arch.aarch64v8,
|
||||
builtin.Arch.aarch64v8r,
|
||||
builtin.Arch.aarch64v8m_baseline,
|
||||
builtin.Arch.aarch64v8m_mainline,
|
||||
=> return "arm64",
|
||||
builtin.Arch.aarch64 => return "arm64",
|
||||
builtin.Arch.thumb,
|
||||
builtin.Arch.armv8_5a,
|
||||
builtin.Arch.armv8_4a,
|
||||
builtin.Arch.armv8_3a,
|
||||
builtin.Arch.armv8_2a,
|
||||
builtin.Arch.armv8_1a,
|
||||
builtin.Arch.armv8,
|
||||
builtin.Arch.armv8r,
|
||||
builtin.Arch.armv8m_baseline,
|
||||
builtin.Arch.armv8m_mainline,
|
||||
builtin.Arch.armv7,
|
||||
builtin.Arch.armv7em,
|
||||
builtin.Arch.armv7m,
|
||||
builtin.Arch.armv7s,
|
||||
builtin.Arch.armv7k,
|
||||
builtin.Arch.armv7ve,
|
||||
builtin.Arch.armv6,
|
||||
builtin.Arch.armv6m,
|
||||
builtin.Arch.armv6k,
|
||||
builtin.Arch.armv6t2,
|
||||
builtin.Arch.armv5,
|
||||
builtin.Arch.armv5te,
|
||||
builtin.Arch.armv4t,
|
||||
builtin.Arch.arm,
|
||||
=> return "arm",
|
||||
builtin.Arch.powerpc => return "ppc",
|
||||
builtin.Arch.powerpc64 => return "ppc64",
|
||||
|
@ -51,8 +51,8 @@ pub const Type = struct {
|
||||
pub fn getLlvmType(
|
||||
base: *Type,
|
||||
allocator: *Allocator,
|
||||
llvm_context: llvm.ContextRef,
|
||||
) (error{OutOfMemory}!llvm.TypeRef) {
|
||||
llvm_context: *llvm.Context,
|
||||
) (error{OutOfMemory}!*llvm.Type) {
|
||||
switch (base.id) {
|
||||
Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
|
||||
Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
|
||||
@ -196,7 +196,7 @@ pub const Type = struct {
|
||||
}
|
||||
|
||||
/// If you have an llvm conext handy, you can use it here.
|
||||
pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
|
||||
pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
|
||||
if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
|
||||
|
||||
base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
|
||||
@ -205,7 +205,7 @@ pub const Type = struct {
|
||||
}
|
||||
|
||||
/// Lower level function that does the work. See getAbiAlignment.
|
||||
async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
|
||||
async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
|
||||
const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);
|
||||
return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
|
||||
}
|
||||
@ -218,7 +218,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -496,13 +496,13 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
const normal = &self.key.data.Normal;
|
||||
const llvm_return_type = switch (normal.return_type.id) {
|
||||
Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
|
||||
else => try normal.return_type.getLlvmType(allocator, llvm_context),
|
||||
};
|
||||
const llvm_param_types = try allocator.alloc(llvm.TypeRef, normal.params.len);
|
||||
const llvm_param_types = try allocator.alloc(*llvm.Type, normal.params.len);
|
||||
defer allocator.free(llvm_param_types);
|
||||
for (llvm_param_types) |*llvm_param_type, i| {
|
||||
llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context);
|
||||
@ -559,7 +559,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -658,7 +658,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory;
|
||||
}
|
||||
};
|
||||
@ -670,7 +670,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -794,6 +794,7 @@ pub const Type = struct {
|
||||
Size.One => "*",
|
||||
Size.Many => "[*]",
|
||||
Size.Slice => "[]",
|
||||
Size.C => "[*c]",
|
||||
};
|
||||
const mut_str = switch (self.key.mut) {
|
||||
Mut.Const => "const ",
|
||||
@ -835,7 +836,7 @@ pub const Type = struct {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context);
|
||||
return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory;
|
||||
}
|
||||
@ -903,7 +904,7 @@ pub const Type = struct {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context);
|
||||
return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory;
|
||||
}
|
||||
@ -916,7 +917,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -966,7 +967,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -978,7 +979,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -990,7 +991,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1002,7 +1003,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1014,7 +1015,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1034,7 +1035,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1054,7 +1055,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1066,7 +1067,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1088,6 +1089,7 @@ fn hashAny(x: var, comptime seed: u64) u32 {
|
||||
builtin.TypeInfo.Pointer.Size.One => return hashAny(@ptrToInt(x), seed),
|
||||
builtin.TypeInfo.Pointer.Size.Many => @compileError("implement hash function"),
|
||||
builtin.TypeInfo.Pointer.Size.Slice => @compileError("implement hash function"),
|
||||
builtin.TypeInfo.Pointer.Size.C => unreachable,
|
||||
}
|
||||
},
|
||||
builtin.TypeId.Enum => return hashAny(@enumToInt(x), seed),
|
||||
|
@ -57,7 +57,7 @@ pub const Value = struct {
|
||||
std.debug.warn("{}", @tagName(base.id));
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) {
|
||||
pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?*llvm.Value) {
|
||||
switch (base.id) {
|
||||
Id.Type => unreachable,
|
||||
Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile),
|
||||
@ -153,7 +153,7 @@ pub const Value = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
const llvm_fn = llvm.AddFunction(
|
||||
ofile.module,
|
||||
@ -238,7 +238,7 @@ pub const Value = struct {
|
||||
/// We know that the function definition will end up in an .o file somewhere.
|
||||
/// Here, all we have to do is generate a global prototype.
|
||||
/// TODO cache the prototype per ObjectFile
|
||||
pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
const llvm_fn = llvm.AddFunction(
|
||||
ofile.module,
|
||||
@ -283,8 +283,8 @@ pub const Value = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef {
|
||||
const llvm_type = llvm.Int1TypeInContext(ofile.context);
|
||||
pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_type = llvm.Int1TypeInContext(ofile.context) orelse return error.OutOfMemory;
|
||||
if (self.x) {
|
||||
return llvm.ConstAllOnes(llvm_type);
|
||||
} else {
|
||||
@ -381,7 +381,7 @@ pub const Value = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
// TODO carefully port the logic from codegen.cpp:gen_const_val_ptr
|
||||
switch (self.special) {
|
||||
@ -391,7 +391,7 @@ pub const Value = struct {
|
||||
const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
|
||||
const ptr_bit_count = ofile.comp.target_ptr_bits;
|
||||
const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory;
|
||||
const indices = []llvm.ValueRef{
|
||||
const indices = []*llvm.Value{
|
||||
llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,
|
||||
llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,
|
||||
};
|
||||
@ -459,7 +459,7 @@ pub const Value = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?*llvm.Value {
|
||||
switch (self.special) {
|
||||
Special.Undefined => {
|
||||
const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
@ -534,7 +534,7 @@ pub const Value = struct {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?*llvm.Value {
|
||||
switch (self.base.typ.id) {
|
||||
Type.Id.Int => {
|
||||
const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "bigfloat.hpp"
|
||||
#include "target.hpp"
|
||||
#include "tokenizer.hpp"
|
||||
#include "libc_installation.hpp"
|
||||
|
||||
struct AstNode;
|
||||
struct ImportTableEntry;
|
||||
@ -630,24 +631,12 @@ struct AstNodeUnwrapOptional {
|
||||
AstNode *expr;
|
||||
};
|
||||
|
||||
enum CastOp {
|
||||
CastOpNoCast, // signifies the function call expression is not a cast
|
||||
CastOpNoop, // fn call expr is a cast, but does nothing
|
||||
CastOpIntToFloat,
|
||||
CastOpFloatToInt,
|
||||
CastOpBoolToInt,
|
||||
CastOpResizeSlice,
|
||||
CastOpNumLitToConcrete,
|
||||
CastOpErrSet,
|
||||
CastOpBitCast,
|
||||
CastOpPtrOfArrayToSlice,
|
||||
};
|
||||
|
||||
struct AstNodeFnCallExpr {
|
||||
AstNode *fn_ref_expr;
|
||||
ZigList<AstNode *> params;
|
||||
bool is_builtin;
|
||||
bool is_async;
|
||||
bool seen; // used by @compileLog
|
||||
AstNode *async_allocator;
|
||||
};
|
||||
|
||||
@ -691,15 +680,17 @@ struct AstNodePointerType {
|
||||
AstNode *align_expr;
|
||||
BigInt *bit_offset_start;
|
||||
BigInt *host_int_bytes;
|
||||
AstNode *op_expr;
|
||||
Token *allow_zero_token;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
AstNode *op_expr;
|
||||
};
|
||||
|
||||
struct AstNodeArrayType {
|
||||
AstNode *size;
|
||||
AstNode *child_type;
|
||||
AstNode *align_expr;
|
||||
Token *allow_zero_token;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
};
|
||||
@ -1038,6 +1029,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b);
|
||||
enum PtrLen {
|
||||
PtrLenUnknown,
|
||||
PtrLenSingle,
|
||||
PtrLenC,
|
||||
};
|
||||
|
||||
struct ZigTypePointer {
|
||||
@ -1049,6 +1041,7 @@ struct ZigTypePointer {
|
||||
uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
};
|
||||
|
||||
struct ZigTypeInt {
|
||||
@ -1247,6 +1240,12 @@ enum ZigTypeId {
|
||||
ZigTypeIdVector,
|
||||
};
|
||||
|
||||
enum OnePossibleValue {
|
||||
OnePossibleValueInvalid,
|
||||
OnePossibleValueNo,
|
||||
OnePossibleValueYes,
|
||||
};
|
||||
|
||||
struct ZigType {
|
||||
ZigTypeId id;
|
||||
Buf name;
|
||||
@ -1254,9 +1253,6 @@ struct ZigType {
|
||||
LLVMTypeRef type_ref;
|
||||
ZigLLVMDIType *di_type;
|
||||
|
||||
bool zero_bits; // this is denormalized data
|
||||
bool gen_h_loop_flag;
|
||||
|
||||
union {
|
||||
ZigTypePointer pointer;
|
||||
ZigTypeInt integral;
|
||||
@ -1282,6 +1278,11 @@ struct ZigType {
|
||||
// If we generate a constant name value for this type, we memoize it here.
|
||||
// The type of this is array
|
||||
ConstExprValue *cached_const_name_val;
|
||||
|
||||
OnePossibleValue one_possible_value;
|
||||
|
||||
bool zero_bits; // this is denormalized data
|
||||
bool gen_h_loop_flag;
|
||||
};
|
||||
|
||||
struct PackageTableEntry {
|
||||
@ -1340,15 +1341,11 @@ struct ZigFn {
|
||||
// in the case of async functions this is the implicit return type according to the
|
||||
// zig source code, not according to zig ir
|
||||
ZigType *src_implicit_return_type;
|
||||
bool is_test;
|
||||
FnInline fn_inline;
|
||||
FnAnalState anal_state;
|
||||
IrExecutable ir_executable;
|
||||
IrExecutable analyzed_executable;
|
||||
size_t prealloc_bbc;
|
||||
AstNode **param_source_nodes;
|
||||
Buf **param_names;
|
||||
uint32_t align_bytes;
|
||||
|
||||
AstNode *fn_no_inline_set_node;
|
||||
AstNode *fn_static_eval_set_node;
|
||||
@ -1358,13 +1355,22 @@ struct ZigFn {
|
||||
|
||||
Buf *section_name;
|
||||
AstNode *set_alignstack_node;
|
||||
uint32_t alignstack_value;
|
||||
|
||||
AstNode *set_cold_node;
|
||||
bool is_cold;
|
||||
|
||||
ZigList<FnExport> export_list;
|
||||
|
||||
LLVMValueRef valgrind_client_request_array;
|
||||
|
||||
FnInline fn_inline;
|
||||
FnAnalState anal_state;
|
||||
|
||||
uint32_t align_bytes;
|
||||
uint32_t alignstack_value;
|
||||
|
||||
bool calls_or_awaits_errorable_fn;
|
||||
bool is_cold;
|
||||
bool is_test;
|
||||
};
|
||||
|
||||
uint32_t fn_table_entry_hash(ZigFn*);
|
||||
@ -1484,6 +1490,7 @@ enum PanicMsgId {
|
||||
PanicMsgIdBadUnionField,
|
||||
PanicMsgIdBadEnumValue,
|
||||
PanicMsgIdFloatToInt,
|
||||
PanicMsgIdPtrCastNull,
|
||||
|
||||
PanicMsgIdCount,
|
||||
};
|
||||
@ -1498,11 +1505,12 @@ struct TypeId {
|
||||
struct {
|
||||
ZigType *child_type;
|
||||
PtrLen ptr_len;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
uint32_t alignment;
|
||||
uint32_t bit_offset_in_host;
|
||||
uint32_t host_int_bytes;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
} pointer;
|
||||
struct {
|
||||
ZigType *child_type;
|
||||
@ -1605,6 +1613,17 @@ struct LinkLib {
|
||||
bool provided_explicitly;
|
||||
};
|
||||
|
||||
enum ValgrindSupport {
|
||||
ValgrindSupportAuto,
|
||||
ValgrindSupportDisabled,
|
||||
ValgrindSupportEnabled,
|
||||
};
|
||||
|
||||
struct CFile {
|
||||
ZigList<const char *> args;
|
||||
const char *source_path;
|
||||
};
|
||||
|
||||
// When adding fields, check if they should be added to the hash computation in build_with_cache
|
||||
struct CodeGen {
|
||||
//////////////////////////// Runtime State
|
||||
@ -1660,7 +1679,7 @@ struct CodeGen {
|
||||
HashMap<GenericFnTypeId *, ZigFn *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
|
||||
HashMap<Scope *, ConstExprValue *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
|
||||
HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table;
|
||||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;
|
||||
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> exported_symbol_names;
|
||||
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
|
||||
HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
|
||||
HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
|
||||
@ -1732,12 +1751,16 @@ struct CodeGen {
|
||||
Buf triple_str;
|
||||
Buf global_asm;
|
||||
Buf *out_h_path;
|
||||
Buf *out_lib_path;
|
||||
Buf artifact_dir;
|
||||
Buf output_file_path;
|
||||
Buf o_file_output_path;
|
||||
Buf *wanted_output_file_path;
|
||||
Buf cache_dir;
|
||||
|
||||
Buf *zig_c_headers_dir; // Cannot be overridden; derived from zig_lib_dir.
|
||||
Buf *zig_std_special_dir; // Cannot be overridden; derived from zig_lib_dir.
|
||||
|
||||
IrInstruction *invalid_instruction;
|
||||
IrInstruction *unreach_instruction;
|
||||
|
||||
@ -1752,6 +1775,7 @@ struct CodeGen {
|
||||
ZigFn *cur_fn;
|
||||
ZigFn *main_fn;
|
||||
ZigFn *panic_fn;
|
||||
TldFn *panic_tld_fn;
|
||||
AstNode *root_export_decl;
|
||||
|
||||
CacheHash cache_hash;
|
||||
@ -1760,7 +1784,8 @@ struct CodeGen {
|
||||
unsigned pointer_size_bytes;
|
||||
uint32_t target_os_index;
|
||||
uint32_t target_arch_index;
|
||||
uint32_t target_environ_index;
|
||||
uint32_t target_sub_arch_index;
|
||||
uint32_t target_abi_index;
|
||||
uint32_t target_oformat_index;
|
||||
bool is_big_endian;
|
||||
bool have_pub_main;
|
||||
@ -1778,13 +1803,17 @@ struct CodeGen {
|
||||
bool verbose_ir;
|
||||
bool verbose_llvm_ir;
|
||||
bool verbose_cimport;
|
||||
bool verbose_cc;
|
||||
bool error_during_imports;
|
||||
bool generate_error_name_table;
|
||||
bool enable_cache;
|
||||
bool enable_time_report;
|
||||
bool system_linker_hack;
|
||||
bool reported_bad_link_libc_error;
|
||||
|
||||
//////////////////////////// Participates in Input Parameter Cache Hash
|
||||
/////// Note: there is a separate cache hash for builtin.zig, when adding fields,
|
||||
/////// consider if they need to go into both.
|
||||
ZigList<LinkLib *> link_libs_list;
|
||||
// add -framework [name] args to linker
|
||||
ZigList<Buf *> darwin_frameworks;
|
||||
@ -1793,8 +1822,11 @@ struct CodeGen {
|
||||
ZigList<Buf *> forbidden_libs;
|
||||
ZigList<Buf *> link_objects;
|
||||
ZigList<Buf *> assembly_files;
|
||||
ZigList<CFile *> c_source_files;
|
||||
ZigList<const char *> lib_dirs;
|
||||
|
||||
ZigLibCInstallation *libc;
|
||||
|
||||
size_t version_major;
|
||||
size_t version_minor;
|
||||
size_t version_patch;
|
||||
@ -1803,15 +1835,14 @@ struct CodeGen {
|
||||
EmitFileType emit_file_type;
|
||||
BuildMode build_mode;
|
||||
OutType out_type;
|
||||
ZigTarget zig_target;
|
||||
const ZigTarget *zig_target;
|
||||
TargetSubsystem subsystem;
|
||||
ValgrindSupport valgrind_support;
|
||||
bool is_static;
|
||||
bool strip_debug_symbols;
|
||||
bool is_test_build;
|
||||
bool is_single_threaded;
|
||||
bool is_native_target;
|
||||
bool linker_rdynamic;
|
||||
bool no_rosegment_workaround;
|
||||
bool each_lib_rpath;
|
||||
bool disable_pic;
|
||||
|
||||
@ -1821,31 +1852,21 @@ struct CodeGen {
|
||||
Buf *test_filter;
|
||||
Buf *test_name_prefix;
|
||||
PackageTableEntry *root_package;
|
||||
Buf *zig_lib_dir;
|
||||
Buf *zig_std_dir;
|
||||
|
||||
const char **llvm_argv;
|
||||
size_t llvm_argv_len;
|
||||
|
||||
const char **clang_argv;
|
||||
size_t clang_argv_len;
|
||||
|
||||
//////////////////////////// Unsorted
|
||||
|
||||
Buf *libc_lib_dir;
|
||||
Buf *libc_static_lib_dir;
|
||||
Buf *libc_include_dir;
|
||||
Buf *msvc_lib_dir;
|
||||
Buf *kernel32_lib_dir;
|
||||
Buf *zig_lib_dir;
|
||||
Buf *zig_std_dir;
|
||||
Buf *zig_c_headers_dir;
|
||||
Buf *zig_std_special_dir;
|
||||
Buf *dynamic_linker;
|
||||
ZigWindowsSDK *win_sdk;
|
||||
};
|
||||
|
||||
enum VarLinkage {
|
||||
VarLinkageInternal,
|
||||
VarLinkageExport,
|
||||
VarLinkageExportStrong,
|
||||
VarLinkageExportWeak,
|
||||
VarLinkageExportLinkOnce,
|
||||
VarLinkageExternal,
|
||||
};
|
||||
|
||||
@ -2084,6 +2105,11 @@ struct IrBasicBlock {
|
||||
IrInstruction *must_be_comptime_source_instr;
|
||||
};
|
||||
|
||||
enum LVal {
|
||||
LValNone,
|
||||
LValPtr,
|
||||
};
|
||||
|
||||
// These instructions are in transition to having "pass 1" instructions
|
||||
// and "pass 2" instructions. The pass 1 instructions are suffixed with Src
|
||||
// and pass 2 are suffixed with Gen.
|
||||
@ -2106,6 +2132,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdUnOp,
|
||||
IrInstructionIdBinOp,
|
||||
IrInstructionIdLoadPtr,
|
||||
IrInstructionIdLoadPtrGen,
|
||||
IrInstructionIdStorePtr,
|
||||
IrInstructionIdFieldPtr,
|
||||
IrInstructionIdStructFieldPtr,
|
||||
@ -2116,6 +2143,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdConst,
|
||||
IrInstructionIdReturn,
|
||||
IrInstructionIdCast,
|
||||
IrInstructionIdResizeSlice,
|
||||
IrInstructionIdContainerInitList,
|
||||
IrInstructionIdContainerInitFields,
|
||||
IrInstructionIdStructInit,
|
||||
@ -2183,6 +2211,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdPtrCastSrc,
|
||||
IrInstructionIdPtrCastGen,
|
||||
IrInstructionIdBitCast,
|
||||
IrInstructionIdBitCastGen,
|
||||
IrInstructionIdWidenOrShorten,
|
||||
IrInstructionIdIntToPtr,
|
||||
IrInstructionIdPtrToInt,
|
||||
@ -2347,6 +2376,7 @@ struct IrInstructionUnOp {
|
||||
|
||||
IrUnOp op_id;
|
||||
IrInstruction *value;
|
||||
LVal lval;
|
||||
};
|
||||
|
||||
enum IrBinOp {
|
||||
@ -2399,6 +2429,13 @@ struct IrInstructionLoadPtr {
|
||||
IrInstruction *ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionLoadPtrGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *ptr;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionStorePtr {
|
||||
IrInstruction base;
|
||||
|
||||
@ -2476,6 +2513,18 @@ struct IrInstructionReturn {
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
enum CastOp {
|
||||
CastOpNoCast, // signifies the function call expression is not a cast
|
||||
CastOpNoop, // fn call expr is a cast, but does nothing
|
||||
CastOpIntToFloat,
|
||||
CastOpFloatToInt,
|
||||
CastOpBoolToInt,
|
||||
CastOpNumLitToConcrete,
|
||||
CastOpErrSet,
|
||||
CastOpBitCast,
|
||||
CastOpPtrOfArrayToSlice,
|
||||
};
|
||||
|
||||
// TODO get rid of this instruction, replace with instructions for each op code
|
||||
struct IrInstructionCast {
|
||||
IrInstruction base;
|
||||
@ -2486,6 +2535,13 @@ struct IrInstructionCast {
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionResizeSlice {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *operand;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionContainerInitList {
|
||||
IrInstruction base;
|
||||
|
||||
@ -2591,6 +2647,7 @@ struct IrInstructionPtrType {
|
||||
PtrLen ptr_len;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
};
|
||||
|
||||
struct IrInstructionPromiseType {
|
||||
@ -2606,6 +2663,7 @@ struct IrInstructionSliceType {
|
||||
IrInstruction *child_type;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
};
|
||||
|
||||
struct IrInstructionAsm {
|
||||
@ -2994,12 +3052,14 @@ struct IrInstructionPtrCastSrc {
|
||||
|
||||
IrInstruction *dest_type;
|
||||
IrInstruction *ptr;
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
struct IrInstructionPtrCastGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *ptr;
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
struct IrInstructionBitCast {
|
||||
@ -3009,6 +3069,13 @@ struct IrInstructionBitCast {
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionBitCastGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *operand;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionWidenOrShorten {
|
||||
IrInstruction base;
|
||||
|
||||
@ -3079,11 +3146,6 @@ struct IrInstructionTypeName {
|
||||
IrInstruction *type_value;
|
||||
};
|
||||
|
||||
enum LVal {
|
||||
LValNone,
|
||||
LValPtr,
|
||||
};
|
||||
|
||||
struct IrInstructionDeclRef {
|
||||
IrInstruction base;
|
||||
|
||||
|
544
src/analyze.cpp
544
src/analyze.cpp
@ -356,7 +356,7 @@ uint64_t type_size(CodeGen *g, ZigType *type_entry) {
|
||||
}
|
||||
}
|
||||
|
||||
return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
|
||||
return LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref);
|
||||
}
|
||||
|
||||
uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) {
|
||||
@ -365,19 +365,19 @@ uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) {
|
||||
if (!type_has_bits(type_entry))
|
||||
return 0;
|
||||
|
||||
if (type_entry->id == ZigTypeIdStruct && type_entry->data.structure.layout == ContainerLayoutPacked) {
|
||||
uint64_t result = 0;
|
||||
for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
|
||||
result += type_size_bits(g, type_entry->data.structure.fields[i].type_entry);
|
||||
if (type_entry->id == ZigTypeIdStruct) {
|
||||
if (type_entry->data.structure.layout == ContainerLayoutPacked) {
|
||||
uint64_t result = 0;
|
||||
for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
|
||||
result += type_size_bits(g, type_entry->data.structure.fields[i].type_entry);
|
||||
}
|
||||
return result;
|
||||
} else if (type_entry->data.structure.layout == ContainerLayoutExtern) {
|
||||
return type_size(g, type_entry) * 8;
|
||||
}
|
||||
return result;
|
||||
} else if (type_entry->id == ZigTypeIdArray) {
|
||||
ZigType *child_type = type_entry->data.array.child_type;
|
||||
if (child_type->id == ZigTypeIdStruct &&
|
||||
child_type->data.structure.layout == ContainerLayoutPacked)
|
||||
{
|
||||
return type_entry->data.array.len * type_size_bits(g, child_type);
|
||||
}
|
||||
return type_entry->data.array.len * type_size_bits(g, child_type);
|
||||
}
|
||||
|
||||
return LLVMSizeOfTypeInBits(g->target_data_ref, type_entry->type_ref);
|
||||
@ -417,10 +417,25 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
static const char *ptr_len_to_star_str(PtrLen ptr_len) {
|
||||
switch (ptr_len) {
|
||||
case PtrLenSingle:
|
||||
return "*";
|
||||
case PtrLenUnknown:
|
||||
return "[*]";
|
||||
case PtrLenC:
|
||||
return "[*c]";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
|
||||
bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
|
||||
uint32_t bit_offset_in_host, uint32_t host_int_bytes)
|
||||
{
|
||||
// TODO when implementing https://github.com/ziglang/zig/issues/1953
|
||||
// move this to a parameter
|
||||
bool allow_zero = (ptr_len == PtrLenC);
|
||||
assert(!type_is_invalid(child_type));
|
||||
assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
|
||||
|
||||
@ -440,7 +455,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
|
||||
TypeId type_id = {};
|
||||
ZigType **parent_pointer = nullptr;
|
||||
if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) {
|
||||
if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || allow_zero) {
|
||||
type_id.id = ZigTypeIdPointer;
|
||||
type_id.data.pointer.child_type = child_type;
|
||||
type_id.data.pointer.is_const = is_const;
|
||||
@ -449,6 +464,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
type_id.data.pointer.bit_offset_in_host = bit_offset_in_host;
|
||||
type_id.data.pointer.host_int_bytes = host_int_bytes;
|
||||
type_id.data.pointer.ptr_len = ptr_len;
|
||||
type_id.data.pointer.allow_zero = allow_zero;
|
||||
|
||||
auto existing_entry = g->type_table.maybe_get(type_id);
|
||||
if (existing_entry)
|
||||
@ -466,21 +482,31 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdPointer);
|
||||
|
||||
const char *star_str = ptr_len == PtrLenSingle ? "*" : "[*]";
|
||||
const char *star_str = ptr_len_to_star_str(ptr_len);
|
||||
const char *const_str = is_const ? "const " : "";
|
||||
const char *volatile_str = is_volatile ? "volatile " : "";
|
||||
const char *allow_zero_str;
|
||||
if (ptr_len == PtrLenC) {
|
||||
assert(allow_zero);
|
||||
allow_zero_str = "";
|
||||
} else {
|
||||
allow_zero_str = allow_zero ? "allowzero " : "";
|
||||
}
|
||||
buf_resize(&entry->name, 0);
|
||||
if (host_int_bytes == 0 && byte_alignment == 0) {
|
||||
buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
buf_appendf(&entry->name, "%s%s%s%s%s",
|
||||
star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
|
||||
} else if (host_int_bytes == 0) {
|
||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment,
|
||||
const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
|
||||
const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
|
||||
} else if (byte_alignment == 0) {
|
||||
buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str,
|
||||
bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str,
|
||||
bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
|
||||
buf_ptr(&child_type->name));
|
||||
} else {
|
||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment,
|
||||
bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
|
||||
bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
|
||||
buf_ptr(&child_type->name));
|
||||
}
|
||||
|
||||
assert(child_type->id != ZigTypeIdInvalid);
|
||||
@ -488,7 +514,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
entry->zero_bits = !type_has_bits(child_type);
|
||||
|
||||
if (!entry->zero_bits) {
|
||||
if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || bit_offset_in_host != 0) {
|
||||
if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle ||
|
||||
bit_offset_in_host != 0 || allow_zero)
|
||||
{
|
||||
ZigType *peer_type = get_pointer_to_type_extra(g, child_type, false, false,
|
||||
PtrLenSingle, 0, 0, host_int_bytes);
|
||||
entry->type_ref = peer_type->type_ref;
|
||||
@ -522,6 +550,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
entry->data.pointer.explicit_alignment = byte_alignment;
|
||||
entry->data.pointer.bit_offset_in_host = bit_offset_in_host;
|
||||
entry->data.pointer.host_int_bytes = host_int_bytes;
|
||||
entry->data.pointer.allow_zero = allow_zero;
|
||||
|
||||
if (parent_pointer) {
|
||||
*parent_pointer = entry;
|
||||
@ -838,7 +867,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
|
||||
|
||||
ZigType *child_type = ptr_type->data.pointer.child_type;
|
||||
if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
|
||||
ptr_type->data.pointer.explicit_alignment != 0)
|
||||
ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero)
|
||||
{
|
||||
ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
@ -861,7 +890,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
|
||||
ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
assert(child_ptr_type->id == ZigTypeIdPointer);
|
||||
if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile ||
|
||||
child_ptr_type->data.pointer.explicit_alignment != 0)
|
||||
child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero)
|
||||
{
|
||||
ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
|
||||
ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false,
|
||||
@ -1073,10 +1102,10 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
if (type_is_c_abi_int(g, fn_type_id->return_type)) {
|
||||
return false;
|
||||
}
|
||||
if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
|
||||
if (g->zig_target->arch == ZigLLVM_x86_64) {
|
||||
X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);
|
||||
return abi_class == X64CABIClass_MEMORY;
|
||||
} else if (target_is_arm(&g->zig_target)) {
|
||||
} else if (target_is_arm(g->zig_target)) {
|
||||
return type_size(g, fn_type_id->return_type) > 16;
|
||||
}
|
||||
zig_panic("TODO implement C ABI for this architecture. See https://github.com/ziglang/zig/issues/1481");
|
||||
@ -1300,7 +1329,7 @@ static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *no
|
||||
size_t backward_branch_count = 0;
|
||||
return ir_eval_const_value(g, scope, node, type_entry,
|
||||
&backward_branch_count, default_backward_branch_quota,
|
||||
nullptr, nullptr, node, type_name, nullptr);
|
||||
nullptr, nullptr, node, type_name, nullptr, nullptr);
|
||||
}
|
||||
|
||||
ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
|
||||
@ -1415,7 +1444,10 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool type_allowed_in_packed_struct(ZigType *type_entry) {
|
||||
static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType *type_entry,
|
||||
AstNode *source_node)
|
||||
{
|
||||
Error err;
|
||||
switch (type_entry->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
@ -1432,32 +1464,79 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) {
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdPromise:
|
||||
return false;
|
||||
add_node_error(g, source_node,
|
||||
buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
|
||||
buf_ptr(&type_entry->name)));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
case ZigTypeIdVoid:
|
||||
case ZigTypeIdBool:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdPointer:
|
||||
case ZigTypeIdArray:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdVector:
|
||||
return true;
|
||||
return ErrorNone;
|
||||
case ZigTypeIdArray: {
|
||||
ZigType *elem_type = type_entry->data.array.child_type;
|
||||
if ((err = emit_error_unless_type_allowed_in_packed_struct(g, elem_type, source_node)))
|
||||
return err;
|
||||
if (type_size(g, type_entry) * 8 == type_size_bits(g, type_entry))
|
||||
return ErrorNone;
|
||||
add_node_error(g, source_node,
|
||||
buf_sprintf("array of '%s' not allowed in packed struct due to padding bits",
|
||||
buf_ptr(&elem_type->name)));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
case ZigTypeIdStruct:
|
||||
return type_entry->data.structure.layout == ContainerLayoutPacked;
|
||||
case ZigTypeIdUnion:
|
||||
return type_entry->data.unionation.layout == ContainerLayoutPacked;
|
||||
case ZigTypeIdOptional:
|
||||
{
|
||||
ZigType *child_type = type_entry->data.maybe.child_type;
|
||||
return type_is_codegen_pointer(child_type);
|
||||
switch (type_entry->data.structure.layout) {
|
||||
case ContainerLayoutPacked:
|
||||
case ContainerLayoutExtern:
|
||||
return ErrorNone;
|
||||
case ContainerLayoutAuto:
|
||||
add_node_error(g, source_node,
|
||||
buf_sprintf("non-packed, non-extern struct '%s' not allowed in packed struct; no guaranteed in-memory representation",
|
||||
buf_ptr(&type_entry->name)));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
case ZigTypeIdEnum:
|
||||
return type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;
|
||||
zig_unreachable();
|
||||
case ZigTypeIdUnion:
|
||||
switch (type_entry->data.unionation.layout) {
|
||||
case ContainerLayoutPacked:
|
||||
case ContainerLayoutExtern:
|
||||
return ErrorNone;
|
||||
case ContainerLayoutAuto:
|
||||
add_node_error(g, source_node,
|
||||
buf_sprintf("non-packed, non-extern union '%s' not allowed in packed struct; no guaranteed in-memory representation",
|
||||
buf_ptr(&type_entry->name)));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
zig_unreachable();
|
||||
case ZigTypeIdOptional:
|
||||
if (get_codegen_ptr_type(type_entry) != nullptr) {
|
||||
return ErrorNone;
|
||||
} else {
|
||||
add_node_error(g, source_node,
|
||||
buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
|
||||
buf_ptr(&type_entry->name)));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
case ZigTypeIdEnum: {
|
||||
AstNode *decl_node = type_entry->data.enumeration.decl_node;
|
||||
if (decl_node->data.container_decl.init_arg_expr != nullptr) {
|
||||
return ErrorNone;
|
||||
}
|
||||
ErrorMsg *msg = add_node_error(g, source_node,
|
||||
buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
|
||||
buf_ptr(&type_entry->name)));
|
||||
add_error_note(g, msg, decl_node,
|
||||
buf_sprintf("enum declaration does not specify an integer tag type"));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
|
||||
bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
@ -1583,7 +1662,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
|
||||
}
|
||||
} else if (param_node->data.param_decl.var_token != nullptr) {
|
||||
if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
|
||||
add_node_error(g, param_node->data.param_decl.type,
|
||||
add_node_error(g, param_node,
|
||||
buf_sprintf("parameter of type 'var' not allowed in function with calling convention '%s'",
|
||||
calling_convention_name(fn_type_id.cc)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
@ -2022,11 +2101,8 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
|
||||
type_struct_field->gen_index = gen_field_index;
|
||||
|
||||
if (packed) {
|
||||
if (!type_allowed_in_packed_struct(field_type)) {
|
||||
AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
|
||||
add_node_error(g, field_source_node,
|
||||
buf_sprintf("packed structs cannot contain fields of type '%s'",
|
||||
buf_ptr(&field_type->name)));
|
||||
AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
|
||||
if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_source_node))) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
break;
|
||||
}
|
||||
@ -2650,6 +2726,13 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
|
||||
buf_sprintf("enums, not structs, support field assignment"));
|
||||
}
|
||||
|
||||
if (field_type->id == ZigTypeIdOpaque) {
|
||||
add_node_error(g, field_node->data.struct_field.type,
|
||||
buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs"));
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type_requires_comptime(g, field_type)) {
|
||||
case ReqCompTimeYes:
|
||||
struct_type->data.structure.requires_comptime = true;
|
||||
@ -2828,7 +2911,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
||||
union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum ||
|
||||
enum_type_node != nullptr;
|
||||
bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
|
||||
bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr);
|
||||
bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr) && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease);
|
||||
ZigType *tag_type;
|
||||
bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
|
||||
bool *covered_enum_fields;
|
||||
@ -2934,6 +3017,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
||||
}
|
||||
union_field->type_entry = field_type;
|
||||
|
||||
if (field_type->id == ZigTypeIdOpaque) {
|
||||
add_node_error(g, field_node->data.struct_field.type,
|
||||
buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in unions"));
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type_requires_comptime(g, field_type)) {
|
||||
case ReqCompTimeInvalid:
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
@ -3182,36 +3272,19 @@ static bool scope_is_root_decls(Scope *scope) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, ZigType *fn_type) {
|
||||
add_node_error(g, proto_node,
|
||||
buf_sprintf("expected 'fn([]const u8, ?*builtin.StackTrace) noreturn', found '%s'",
|
||||
buf_ptr(&fn_type->name)));
|
||||
}
|
||||
void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) {
|
||||
ConstExprValue *panic_fn_type_val = get_builtin_value(g, "PanicFn");
|
||||
assert(panic_fn_type_val != nullptr);
|
||||
assert(panic_fn_type_val->type->id == ZigTypeIdMetaType);
|
||||
ZigType *panic_fn_type = panic_fn_type_val->data.x_type;
|
||||
|
||||
static void typecheck_panic_fn(CodeGen *g, ZigFn *panic_fn) {
|
||||
AstNode *proto_node = panic_fn->proto_node;
|
||||
assert(proto_node->type == NodeTypeFnProto);
|
||||
ZigType *fn_type = panic_fn->type_entry;
|
||||
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
|
||||
if (fn_type_id->param_count != 2) {
|
||||
return wrong_panic_prototype(g, proto_node, fn_type);
|
||||
}
|
||||
ZigType *const_u8_ptr = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
ZigType *const_u8_slice = get_slice_type(g, const_u8_ptr);
|
||||
if (fn_type_id->param_info[0].type != const_u8_slice) {
|
||||
return wrong_panic_prototype(g, proto_node, fn_type);
|
||||
}
|
||||
AstNode *fake_decl = allocate<AstNode>(1);
|
||||
*fake_decl = *panic_fn->proto_node;
|
||||
fake_decl->type = NodeTypeSymbol;
|
||||
fake_decl->data.symbol_expr.symbol = &panic_fn->symbol_name;
|
||||
|
||||
ZigType *optional_ptr_to_stack_trace_type = get_optional_type(g, get_ptr_to_stack_trace_type(g));
|
||||
if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) {
|
||||
return wrong_panic_prototype(g, proto_node, fn_type);
|
||||
}
|
||||
|
||||
ZigType *actual_return_type = fn_type_id->return_type;
|
||||
if (actual_return_type != g->builtin_types.entry_unreachable) {
|
||||
return wrong_panic_prototype(g, proto_node, fn_type);
|
||||
}
|
||||
// call this for the side effects of casting to panic_fn_type
|
||||
analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr);
|
||||
}
|
||||
|
||||
ZigType *get_test_fn_type(CodeGen *g) {
|
||||
@ -3231,16 +3304,16 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi
|
||||
g->have_c_main = true;
|
||||
g->subsystem = TargetSubsystemConsole;
|
||||
} else if (buf_eql_str(symbol_name, "WinMain") &&
|
||||
g->zig_target.os == OsWindows)
|
||||
g->zig_target->os == OsWindows)
|
||||
{
|
||||
g->have_winmain = true;
|
||||
g->subsystem = TargetSubsystemWindows;
|
||||
} else if (buf_eql_str(symbol_name, "WinMainCRTStartup") &&
|
||||
g->zig_target.os == OsWindows)
|
||||
g->zig_target->os == OsWindows)
|
||||
{
|
||||
g->have_winmain_crt_startup = true;
|
||||
} else if (buf_eql_str(symbol_name, "DllMainCRTStartup") &&
|
||||
g->zig_target.os == OsWindows)
|
||||
g->zig_target->os == OsWindows)
|
||||
{
|
||||
g->have_dllmain_crt_startup = true;
|
||||
}
|
||||
@ -3306,18 +3379,18 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
|
||||
if (!fn_table_entry->type_entry->data.fn.is_generic) {
|
||||
if (fn_def_node)
|
||||
g->fn_defs.append(fn_table_entry);
|
||||
}
|
||||
|
||||
if (scope_is_root_decls(tld_fn->base.parent_scope) &&
|
||||
(import == g->root_import || import->package == g->panic_package))
|
||||
if (scope_is_root_decls(tld_fn->base.parent_scope) &&
|
||||
(import == g->root_import || import->package == g->panic_package))
|
||||
{
|
||||
if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
|
||||
g->main_fn = fn_table_entry;
|
||||
} else if ((import->package == g->panic_package || g->have_pub_panic) &&
|
||||
buf_eql_str(&fn_table_entry->symbol_name, "panic"))
|
||||
{
|
||||
if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
|
||||
g->main_fn = fn_table_entry;
|
||||
} else if ((import->package == g->panic_package || g->have_pub_panic) &&
|
||||
buf_eql_str(&fn_table_entry->symbol_name, "panic"))
|
||||
{
|
||||
g->panic_fn = fn_table_entry;
|
||||
typecheck_panic_fn(g, fn_table_entry);
|
||||
}
|
||||
g->panic_fn = fn_table_entry;
|
||||
g->panic_tld_fn = tld_fn;
|
||||
}
|
||||
}
|
||||
} else if (source_node->type == NodeTypeTestDecl) {
|
||||
@ -3366,9 +3439,9 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
|
||||
if (is_export) {
|
||||
g->resolve_queue.append(tld);
|
||||
|
||||
auto entry = g->exported_symbol_names.put_unique(tld->name, tld->source_node);
|
||||
auto entry = g->exported_symbol_names.put_unique(tld->name, tld);
|
||||
if (entry) {
|
||||
AstNode *other_source_node = entry->value;
|
||||
AstNode *other_source_node = entry->value->source_node;
|
||||
ErrorMsg *msg = add_node_error(g, tld->source_node,
|
||||
buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name)));
|
||||
add_error_note(g, msg, other_source_node, buf_sprintf("other symbol here"));
|
||||
@ -3698,7 +3771,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
|
||||
|
||||
VarLinkage linkage;
|
||||
if (is_export) {
|
||||
linkage = VarLinkageExport;
|
||||
linkage = VarLinkageExportStrong;
|
||||
} else if (is_extern) {
|
||||
linkage = VarLinkageExternal;
|
||||
} else {
|
||||
@ -4041,7 +4114,9 @@ ZigType *get_src_ptr_type(ZigType *type) {
|
||||
if (type->id == ZigTypeIdFn) return type;
|
||||
if (type->id == ZigTypeIdPromise) return type;
|
||||
if (type->id == ZigTypeIdOptional) {
|
||||
if (type->data.maybe.child_type->id == ZigTypeIdPointer) return type->data.maybe.child_type;
|
||||
if (type->data.maybe.child_type->id == ZigTypeIdPointer) {
|
||||
return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type;
|
||||
}
|
||||
if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type;
|
||||
if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type;
|
||||
}
|
||||
@ -4055,6 +4130,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) {
|
||||
return ty;
|
||||
}
|
||||
|
||||
bool type_is_nonnull_ptr(ZigType *type) {
|
||||
return type_is_codegen_pointer(type) && !ptr_allows_addr_zero(type);
|
||||
}
|
||||
|
||||
bool type_is_codegen_pointer(ZigType *type) {
|
||||
return get_codegen_ptr_type(type) == type;
|
||||
}
|
||||
@ -4572,185 +4651,6 @@ bool handle_is_ptr(ZigType *type_entry) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
|
||||
if (g->win_sdk == nullptr) {
|
||||
if (zig_find_windows_sdk(&g->win_sdk)) {
|
||||
fprintf(stderr, "unable to determine windows sdk path\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
assert(g->win_sdk != nullptr);
|
||||
return g->win_sdk;
|
||||
}
|
||||
|
||||
|
||||
static Buf *get_linux_libc_lib_path(const char *o_file) {
|
||||
const char *cc_exe = getenv("CC");
|
||||
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
|
||||
ZigList<const char *> args = {};
|
||||
args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));
|
||||
Termination term;
|
||||
Buf *out_stderr = buf_alloc();
|
||||
Buf *out_stdout = buf_alloc();
|
||||
Error err;
|
||||
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
|
||||
zig_panic("unable to determine libc lib path: executing C compiler: %s", err_str(err));
|
||||
}
|
||||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
zig_panic("unable to determine libc lib path: executing C compiler command failed");
|
||||
}
|
||||
if (buf_ends_with_str(out_stdout, "\n")) {
|
||||
buf_resize(out_stdout, buf_len(out_stdout) - 1);
|
||||
}
|
||||
if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) {
|
||||
zig_panic("unable to determine libc lib path: C compiler could not find %s", o_file);
|
||||
}
|
||||
Buf *result = buf_alloc();
|
||||
os_path_dirname(out_stdout, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static Buf *get_posix_libc_include_path(void) {
|
||||
const char *cc_exe = getenv("CC");
|
||||
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
|
||||
ZigList<const char *> args = {};
|
||||
args.append("-E");
|
||||
args.append("-Wp,-v");
|
||||
args.append("-xc");
|
||||
args.append("/dev/null");
|
||||
Termination term;
|
||||
Buf *out_stderr = buf_alloc();
|
||||
Buf *out_stdout = buf_alloc();
|
||||
Error err;
|
||||
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
|
||||
zig_panic("unable to determine libc include path: executing C compiler: %s", err_str(err));
|
||||
}
|
||||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
zig_panic("unable to determine libc include path: executing C compiler command failed");
|
||||
}
|
||||
char *prev_newline = buf_ptr(out_stderr);
|
||||
ZigList<const char *> search_paths = {};
|
||||
for (;;) {
|
||||
char *newline = strchr(prev_newline, '\n');
|
||||
if (newline == nullptr) {
|
||||
break;
|
||||
}
|
||||
*newline = 0;
|
||||
if (prev_newline[0] == ' ') {
|
||||
search_paths.append(prev_newline);
|
||||
}
|
||||
prev_newline = newline + 1;
|
||||
}
|
||||
if (search_paths.length == 0) {
|
||||
zig_panic("unable to determine libc include path: even C compiler does not know where libc headers are");
|
||||
}
|
||||
for (size_t i = 0; i < search_paths.length; i += 1) {
|
||||
// search in reverse order
|
||||
const char *search_path = search_paths.items[search_paths.length - i - 1];
|
||||
// cut off spaces
|
||||
while (*search_path == ' ') {
|
||||
search_path += 1;
|
||||
}
|
||||
Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path);
|
||||
bool exists;
|
||||
if ((err = os_file_exists(stdlib_path, &exists))) {
|
||||
exists = false;
|
||||
}
|
||||
if (exists) {
|
||||
return buf_create_from_str(search_path);
|
||||
}
|
||||
}
|
||||
zig_panic("unable to determine libc include path: stdlib.h not found in C compiler search paths");
|
||||
}
|
||||
|
||||
void find_libc_include_path(CodeGen *g) {
|
||||
if (g->libc_include_dir == nullptr) {
|
||||
if (!g->is_native_target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g->zig_target.os == OsWindows) {
|
||||
ZigWindowsSDK *sdk = get_windows_sdk(g);
|
||||
g->libc_include_dir = buf_alloc();
|
||||
if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
|
||||
fprintf(stderr, "Unable to determine libc include path. --libc-include-dir");
|
||||
exit(1);
|
||||
}
|
||||
} else if (g->zig_target.os == OsLinux ||
|
||||
g->zig_target.os == OsMacOSX ||
|
||||
g->zig_target.os == OsFreeBSD)
|
||||
{
|
||||
g->libc_include_dir = get_posix_libc_include_path();
|
||||
} else {
|
||||
fprintf(stderr, "Unable to determine libc include path.\n"
|
||||
"TODO: implement finding libc at runtime for other operating systems.\n"
|
||||
"in the meantime, you can use as a workaround: --libc-include-dir\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
assert(buf_len(g->libc_include_dir) != 0);
|
||||
}
|
||||
|
||||
void find_libc_lib_path(CodeGen *g) {
|
||||
// later we can handle this better by reporting an error via the normal mechanism
|
||||
if (g->libc_lib_dir == nullptr ||
|
||||
(g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))
|
||||
{
|
||||
if (g->zig_target.os == OsWindows) {
|
||||
ZigWindowsSDK *sdk = get_windows_sdk(g);
|
||||
|
||||
if (g->msvc_lib_dir == nullptr) {
|
||||
if (sdk->msvc_lib_dir_ptr == nullptr) {
|
||||
fprintf(stderr, "Unable to determine vcruntime path. --msvc-lib-dir");
|
||||
exit(1);
|
||||
}
|
||||
g->msvc_lib_dir = buf_create_from_mem(sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
|
||||
}
|
||||
|
||||
if (g->libc_lib_dir == nullptr) {
|
||||
Buf* ucrt_lib_path = buf_alloc();
|
||||
if (os_get_win32_ucrt_lib_path(sdk, ucrt_lib_path, g->zig_target.arch.arch)) {
|
||||
fprintf(stderr, "Unable to determine ucrt path. --libc-lib-dir");
|
||||
exit(1);
|
||||
}
|
||||
g->libc_lib_dir = ucrt_lib_path;
|
||||
}
|
||||
|
||||
if (g->kernel32_lib_dir == nullptr) {
|
||||
Buf* kern_lib_path = buf_alloc();
|
||||
if (os_get_win32_kern32_path(sdk, kern_lib_path, g->zig_target.arch.arch)) {
|
||||
fprintf(stderr, "Unable to determine kernel32 path. --kernel32-lib-dir");
|
||||
exit(1);
|
||||
}
|
||||
g->kernel32_lib_dir = kern_lib_path;
|
||||
}
|
||||
|
||||
} else if (g->zig_target.os == OsLinux) {
|
||||
g->libc_lib_dir = get_linux_libc_lib_path("crt1.o");
|
||||
} else if (g->zig_target.os == OsFreeBSD) {
|
||||
g->libc_lib_dir = buf_create_from_str("/usr/lib");
|
||||
} else {
|
||||
zig_panic("Unable to determine libc lib path.");
|
||||
}
|
||||
} else {
|
||||
assert(buf_len(g->libc_lib_dir) != 0);
|
||||
}
|
||||
|
||||
if (g->libc_static_lib_dir == nullptr) {
|
||||
if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {
|
||||
return;
|
||||
} else if (g->zig_target.os == OsLinux) {
|
||||
g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o");
|
||||
} else if (g->zig_target.os == OsFreeBSD) {
|
||||
g->libc_static_lib_dir = buf_create_from_str("/usr/lib");
|
||||
} else {
|
||||
zig_panic("Unable to determine libc static lib path.");
|
||||
}
|
||||
} else {
|
||||
assert(buf_len(g->libc_static_lib_dir) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t hash_ptr(void *ptr) {
|
||||
return (uint32_t)(((uintptr_t)ptr) % UINT32_MAX);
|
||||
}
|
||||
@ -5229,6 +5129,10 @@ bool type_has_bits(ZigType *type_entry) {
|
||||
// Whether you can infer the value based solely on the type.
|
||||
OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
|
||||
assert(type_entry != nullptr);
|
||||
|
||||
if (type_entry->one_possible_value != OnePossibleValueInvalid)
|
||||
return type_entry->one_possible_value;
|
||||
|
||||
Error err;
|
||||
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
|
||||
return OnePossibleValueInvalid;
|
||||
@ -5276,8 +5180,14 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdVector:
|
||||
return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes;
|
||||
case ZigTypeIdPointer:
|
||||
return type_has_one_possible_value(g, type_entry->data.pointer.child_type);
|
||||
case ZigTypeIdPointer: {
|
||||
ZigType *elem_type = type_entry->data.pointer.child_type;
|
||||
// If the recursive function call asks, then we are not one possible value.
|
||||
type_entry->one_possible_value = OnePossibleValueNo;
|
||||
// Now update it to be the value of the recursive call.
|
||||
type_entry->one_possible_value = type_has_one_possible_value(g, elem_type);
|
||||
return type_entry->one_possible_value;
|
||||
}
|
||||
case ZigTypeIdUnion:
|
||||
if (type_entry->data.unionation.src_field_count > 1)
|
||||
return OnePossibleValueNo;
|
||||
@ -6010,16 +5920,20 @@ static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const
|
||||
}
|
||||
}
|
||||
|
||||
static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_val, size_t len) {
|
||||
switch (const_val->data.x_array.special) {
|
||||
static void render_const_val_array(CodeGen *g, Buf *buf, Buf *type_name, ConstExprValue *const_val, uint64_t start, uint64_t len) {
|
||||
ConstArrayValue *array = &const_val->data.x_array;
|
||||
switch (array->special) {
|
||||
case ConstArraySpecialUndef:
|
||||
buf_append_str(buf, "undefined");
|
||||
return;
|
||||
case ConstArraySpecialBuf: {
|
||||
Buf *array_buf = const_val->data.x_array.data.s_buf;
|
||||
Buf *array_buf = array->data.s_buf;
|
||||
const char *base = &buf_ptr(array_buf)[start];
|
||||
assert(start + len <= buf_len(array_buf));
|
||||
|
||||
buf_append_char(buf, '"');
|
||||
for (size_t i = 0; i < buf_len(array_buf); i += 1) {
|
||||
uint8_t c = buf_ptr(array_buf)[i];
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
uint8_t c = base[i];
|
||||
if (c == '"') {
|
||||
buf_append_str(buf, "\\\"");
|
||||
} else {
|
||||
@ -6030,12 +5944,13 @@ static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_v
|
||||
return;
|
||||
}
|
||||
case ConstArraySpecialNone: {
|
||||
buf_appendf(buf, "%s{", buf_ptr(&const_val->type->name));
|
||||
ConstExprValue *base = &array->data.s_none.elements[start];
|
||||
assert(start + len <= const_val->type->data.array.len);
|
||||
|
||||
buf_appendf(buf, "%s{", buf_ptr(type_name));
|
||||
for (uint64_t i = 0; i < len; i += 1) {
|
||||
if (i != 0)
|
||||
buf_appendf(buf, ",");
|
||||
ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i];
|
||||
render_const_value(g, buf, child_value);
|
||||
if (i != 0) buf_appendf(buf, ",");
|
||||
render_const_value(g, buf, &base[i]);
|
||||
}
|
||||
buf_appendf(buf, "}");
|
||||
return;
|
||||
@ -6124,10 +6039,16 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||
}
|
||||
case ZigTypeIdPointer:
|
||||
return render_const_val_ptr(g, buf, const_val, type_entry);
|
||||
case ZigTypeIdVector:
|
||||
return render_const_val_array(g, buf, const_val, type_entry->data.vector.len);
|
||||
case ZigTypeIdArray:
|
||||
return render_const_val_array(g, buf, const_val, type_entry->data.array.len);
|
||||
case ZigTypeIdArray: {
|
||||
uint64_t len = type_entry->data.array.len;
|
||||
render_const_val_array(g, buf, &type_entry->name, const_val, 0, len);
|
||||
return;
|
||||
}
|
||||
case ZigTypeIdVector: {
|
||||
uint32_t len = type_entry->data.vector.len;
|
||||
render_const_val_array(g, buf, &type_entry->name, const_val, 0, len);
|
||||
return;
|
||||
}
|
||||
case ZigTypeIdNull:
|
||||
{
|
||||
buf_appendf(buf, "null");
|
||||
@ -6169,7 +6090,24 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||
}
|
||||
case ZigTypeIdStruct:
|
||||
{
|
||||
buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name));
|
||||
if (is_slice(type_entry)) {
|
||||
ConstExprValue *len_val = &const_val->data.x_struct.fields[slice_len_index];
|
||||
size_t len = bigint_as_unsigned(&len_val->data.x_bigint);
|
||||
|
||||
ConstExprValue *ptr_val = &const_val->data.x_struct.fields[slice_ptr_index];
|
||||
if (ptr_val->special == ConstValSpecialUndef) {
|
||||
assert(len == 0);
|
||||
buf_appendf(buf, "((%s)(undefined))[0..0]", buf_ptr(&type_entry->name));
|
||||
return;
|
||||
}
|
||||
assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray);
|
||||
ConstExprValue *array = ptr_val->data.x_ptr.data.base_array.array_val;
|
||||
size_t start = ptr_val->data.x_ptr.data.base_array.elem_index;
|
||||
|
||||
render_const_val_array(g, buf, &type_entry->name, array, start, len);
|
||||
} else {
|
||||
buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case ZigTypeIdEnum:
|
||||
@ -6193,8 +6131,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||
}
|
||||
case ZigTypeIdUnion:
|
||||
{
|
||||
uint64_t tag = bigint_as_unsigned(&const_val->data.x_union.tag);
|
||||
TypeUnionField *field = &type_entry->data.unionation.fields[tag];
|
||||
const BigInt *tag = &const_val->data.x_union.tag;
|
||||
TypeUnionField *field = find_union_field_by_tag(type_entry, tag);
|
||||
buf_appendf(buf, "%s { .%s = ", buf_ptr(&type_entry->name), buf_ptr(field->name));
|
||||
render_const_value(g, buf, const_val->data.x_union.payload);
|
||||
buf_append_str(buf, "}");
|
||||
@ -6277,6 +6215,7 @@ uint32_t type_id_hash(TypeId x) {
|
||||
((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) +
|
||||
(x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +
|
||||
(x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) +
|
||||
(x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) +
|
||||
(((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) +
|
||||
(((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) +
|
||||
(((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881);
|
||||
@ -6327,6 +6266,7 @@ bool type_id_eql(TypeId a, TypeId b) {
|
||||
a.data.pointer.ptr_len == b.data.pointer.ptr_len &&
|
||||
a.data.pointer.is_const == b.data.pointer.is_const &&
|
||||
a.data.pointer.is_volatile == b.data.pointer.is_volatile &&
|
||||
a.data.pointer.allow_zero == b.data.pointer.allow_zero &&
|
||||
a.data.pointer.alignment == b.data.pointer.alignment &&
|
||||
a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host &&
|
||||
a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes;
|
||||
@ -6626,12 +6566,6 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
|
||||
if (is_libc && g->libc_link_lib != nullptr)
|
||||
return g->libc_link_lib;
|
||||
|
||||
if (g->enable_cache && is_libc && g->zig_target.os != OsMacOSX && g->zig_target.os != OsIOS && g->zig_target.os != OsFreeBSD) {
|
||||
fprintf(stderr, "TODO linking against libc is currently incompatible with `--cache on`.\n"
|
||||
"Zig is not yet capable of determining whether the libc installation has changed on subsequent builds.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
|
||||
LinkLib *existing_lib = g->link_libs_list.at(i);
|
||||
if (buf_eql_buf(existing_lib->name, name)) {
|
||||
@ -6860,3 +6794,21 @@ Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_no
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
const char *container_string(ContainerKind kind) {
|
||||
switch (kind) {
|
||||
case ContainerKindEnum: return "enum";
|
||||
case ContainerKindStruct: return "struct";
|
||||
case ContainerKindUnion: return "union";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool ptr_allows_addr_zero(ZigType *ptr_type) {
|
||||
if (ptr_type->id == ZigTypeIdPointer) {
|
||||
return ptr_type->data.pointer.allow_zero;
|
||||
} else if (ptr_type->id == ZigTypeIdOptional) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -40,11 +40,11 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type);
|
||||
ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type);
|
||||
ZigType *get_test_fn_type(CodeGen *g);
|
||||
bool handle_is_ptr(ZigType *type_entry);
|
||||
void find_libc_include_path(CodeGen *g);
|
||||
void find_libc_lib_path(CodeGen *g);
|
||||
|
||||
bool type_has_bits(ZigType *type_entry);
|
||||
|
||||
bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry);
|
||||
bool ptr_allows_addr_zero(ZigType *ptr_type);
|
||||
bool type_is_nonnull_ptr(ZigType *type);
|
||||
|
||||
ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);
|
||||
|
||||
@ -215,6 +215,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
|
||||
X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty);
|
||||
bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
|
||||
bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id);
|
||||
const char *container_string(ContainerKind kind);
|
||||
|
||||
uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field);
|
||||
|
||||
@ -225,14 +226,10 @@ enum ReqCompTime {
|
||||
};
|
||||
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry);
|
||||
|
||||
enum OnePossibleValue {
|
||||
OnePossibleValueInvalid,
|
||||
OnePossibleValueNo,
|
||||
OnePossibleValueYes,
|
||||
};
|
||||
OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry);
|
||||
|
||||
Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node,
|
||||
ConstExprValue *const_val, ZigType *wanted_type);
|
||||
|
||||
void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn);
|
||||
#endif
|
||||
|
@ -136,13 +136,19 @@ static const char *thread_local_string(Token *tok) {
|
||||
return (tok == nullptr) ? "" : "threadlocal ";
|
||||
}
|
||||
|
||||
const char *container_string(ContainerKind kind) {
|
||||
switch (kind) {
|
||||
case ContainerKindEnum: return "enum";
|
||||
case ContainerKindStruct: return "struct";
|
||||
case ContainerKindUnion: return "union";
|
||||
static const char *token_to_ptr_len_str(Token *tok) {
|
||||
assert(tok != nullptr);
|
||||
switch (tok->id) {
|
||||
case TokenIdStar:
|
||||
case TokenIdStarStar:
|
||||
return "*";
|
||||
case TokenIdBracketStarBracket:
|
||||
return "[*]";
|
||||
case TokenIdBracketStarCBracket:
|
||||
return "[*c]";
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static const char *node_type_str(NodeType node_type) {
|
||||
@ -644,13 +650,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
case NodeTypePointerType:
|
||||
{
|
||||
if (!grouped) fprintf(ar->f, "(");
|
||||
const char *star = "[*]";
|
||||
if (node->data.pointer_type.star_token != nullptr &&
|
||||
(node->data.pointer_type.star_token->id == TokenIdStar || node->data.pointer_type.star_token->id == TokenIdStarStar))
|
||||
{
|
||||
star = "*";
|
||||
}
|
||||
fprintf(ar->f, "%s", star);
|
||||
const char *ptr_len_str = token_to_ptr_len_str(node->data.pointer_type.star_token);
|
||||
fprintf(ar->f, "%s", ptr_len_str);
|
||||
if (node->data.pointer_type.align_expr != nullptr) {
|
||||
fprintf(ar->f, "align(");
|
||||
render_node_grouped(ar, node->data.pointer_type.align_expr);
|
||||
|
@ -17,7 +17,4 @@ void ast_print(FILE *f, AstNode *node, int indent);
|
||||
|
||||
void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size);
|
||||
|
||||
const char *container_string(ContainerKind kind);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1665,7 +1665,6 @@ int64_t bigint_as_signed(const BigInt *bigint) {
|
||||
return 0;
|
||||
} else if (bigint->digit_count == 1) {
|
||||
if (bigint->is_negative) {
|
||||
// TODO this code path is untested
|
||||
if (bigint->data.digit <= 9223372036854775808ULL) {
|
||||
return (-((int64_t)(bigint->data.digit - 1))) - 1;
|
||||
} else {
|
||||
|
@ -132,9 +132,7 @@ void buf_appendf(Buf *buf, const char *format, ...)
|
||||
|
||||
static inline bool buf_eql_mem(Buf *buf, const char *mem, size_t mem_len) {
|
||||
assert(buf->list.length);
|
||||
if (buf_len(buf) != mem_len)
|
||||
return false;
|
||||
return memcmp(buf_ptr(buf), mem, mem_len) == 0;
|
||||
return mem_eql_mem(buf_ptr(buf), buf_len(buf), mem, mem_len);
|
||||
}
|
||||
|
||||
static inline bool buf_eql_str(Buf *buf, const char *str) {
|
||||
|
@ -414,6 +414,39 @@ Error cache_add_file(CacheHash *ch, Buf *path) {
|
||||
return cache_add_file_fetch(ch, resolved_path, nullptr);
|
||||
}
|
||||
|
||||
Error cache_add_dep_file(CacheHash *ch, Buf *dep_file_path, bool verbose) {
|
||||
Error err;
|
||||
Buf *contents = buf_alloc();
|
||||
if ((err = os_fetch_file_path(dep_file_path, contents, false))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to read .d file: %s\n", err_str(err));
|
||||
}
|
||||
return ErrorReadingDepFile;
|
||||
}
|
||||
SplitIterator it = memSplit(buf_to_slice(contents), str("\n"));
|
||||
// skip first line
|
||||
SplitIterator_next(&it);
|
||||
for (;;) {
|
||||
Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it);
|
||||
if (!opt_line.is_some)
|
||||
break;
|
||||
if (opt_line.value.len == 0)
|
||||
continue;
|
||||
SplitIterator line_it = memSplit(opt_line.value, str(" \t"));
|
||||
Slice<uint8_t> filename;
|
||||
if (!SplitIterator_next(&line_it).unwrap(&filename))
|
||||
continue;
|
||||
Buf *filename_buf = buf_create_from_slice(filename);
|
||||
if ((err = cache_add_file(ch, filename_buf))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(filename_buf), err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static Error write_manifest_file(CacheHash *ch) {
|
||||
Error err;
|
||||
Buf contents = BUF_INIT;
|
||||
@ -464,3 +497,4 @@ void cache_release(CacheHash *ch) {
|
||||
|
||||
os_file_close(ch->manifest_file);
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,8 @@ Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest);
|
||||
// If you did not get a cache hit, call this function for every file
|
||||
// that is depended on, and then finish with cache_final.
|
||||
Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path);
|
||||
// This opens a file created by -MD -MF args to Clang
|
||||
Error ATTRIBUTE_MUST_USE cache_add_dep_file(CacheHash *ch, Buf *path, bool verbose);
|
||||
|
||||
// This variant of cache_add_file returns the file contents.
|
||||
// Also the file path argument must be already resolved.
|
||||
|
909
src/codegen.cpp
909
src/codegen.cpp
File diff suppressed because it is too large
Load Diff
@ -11,11 +11,12 @@
|
||||
#include "parser.hpp"
|
||||
#include "errmsg.hpp"
|
||||
#include "target.hpp"
|
||||
#include "libc_installation.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
|
||||
Buf *zig_lib_dir, Buf *override_std_dir);
|
||||
Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc);
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
@ -27,12 +28,6 @@ void codegen_set_is_static(CodeGen *codegen, bool is_static);
|
||||
void codegen_set_strip(CodeGen *codegen, bool strip);
|
||||
void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
|
||||
void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
|
||||
void codegen_set_libc_lib_dir(CodeGen *codegen, Buf *libc_lib_dir);
|
||||
void codegen_set_libc_static_lib_dir(CodeGen *g, Buf *libc_static_lib_dir);
|
||||
void codegen_set_libc_include_dir(CodeGen *codegen, Buf *libc_include_dir);
|
||||
void codegen_set_msvc_lib_dir(CodeGen *g, Buf *msvc_lib_dir);
|
||||
void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir);
|
||||
void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
|
||||
void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
|
||||
void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib);
|
||||
LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
|
||||
@ -46,6 +41,7 @@ void codegen_set_test_filter(CodeGen *g, Buf *filter);
|
||||
void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
|
||||
void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
|
||||
void codegen_set_output_h_path(CodeGen *g, Buf *h_path);
|
||||
void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path);
|
||||
void codegen_set_output_path(CodeGen *g, Buf *path);
|
||||
void codegen_add_time_event(CodeGen *g, const char *name);
|
||||
void codegen_print_timing_report(CodeGen *g, FILE *f);
|
||||
|
@ -34,6 +34,15 @@ const char *err_str(Error err) {
|
||||
case ErrorPipeBusy: return "pipe busy";
|
||||
case ErrorPrimitiveTypeNotFound: return "primitive type not found";
|
||||
case ErrorCacheUnavailable: return "cache unavailable";
|
||||
case ErrorPathTooLong: return "path too long";
|
||||
case ErrorCCompilerCannotFindFile: return "C compiler cannot find file";
|
||||
case ErrorReadingDepFile: return "failed to read .d file";
|
||||
case ErrorMissingArchitecture: return "missing architecture";
|
||||
case ErrorMissingOperatingSystem: return "missing operating system";
|
||||
case ErrorUnknownArchitecture: return "unrecognized architecture";
|
||||
case ErrorUnknownOperatingSystem: return "unrecognized operating system";
|
||||
case ErrorUnknownABI: return "unrecognized C ABI";
|
||||
case ErrorInvalidFilename: return "invalid filename";
|
||||
}
|
||||
return "(invalid error)";
|
||||
}
|
||||
|
@ -36,6 +36,15 @@ enum Error {
|
||||
ErrorPipeBusy,
|
||||
ErrorPrimitiveTypeNotFound,
|
||||
ErrorCacheUnavailable,
|
||||
ErrorPathTooLong,
|
||||
ErrorCCompilerCannotFindFile,
|
||||
ErrorReadingDepFile,
|
||||
ErrorMissingArchitecture,
|
||||
ErrorMissingOperatingSystem,
|
||||
ErrorUnknownArchitecture,
|
||||
ErrorUnknownOperatingSystem,
|
||||
ErrorUnknownABI,
|
||||
ErrorInvalidFilename,
|
||||
};
|
||||
|
||||
const char *err_str(Error err);
|
||||
|
1423
src/ir.cpp
1423
src/ir.cpp
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,7 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry);
|
||||
ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
|
||||
ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
|
||||
ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
|
||||
IrExecutable *parent_exec);
|
||||
IrExecutable *parent_exec, AstNode *expected_type_source_node);
|
||||
|
||||
ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
|
||||
ZigType *expected_type, AstNode *expected_type_source_node);
|
||||
|
@ -336,6 +336,11 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
|
||||
fprintf(irp->f, ".*");
|
||||
}
|
||||
|
||||
static void ir_print_load_ptr_gen(IrPrint *irp, IrInstructionLoadPtrGen *instruction) {
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, ".*");
|
||||
}
|
||||
|
||||
static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
|
||||
fprintf(irp->f, "*");
|
||||
ir_print_var_instruction(irp, instruction->ptr);
|
||||
@ -915,14 +920,18 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc
|
||||
|
||||
static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
|
||||
fprintf(irp->f, "@bitCast(");
|
||||
if (instruction->dest_type) {
|
||||
ir_print_other_instruction(irp, instruction->dest_type);
|
||||
}
|
||||
ir_print_other_instruction(irp, instruction->dest_type);
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_bit_cast_gen(IrPrint *irp, IrInstructionBitCastGen *instruction) {
|
||||
fprintf(irp->f, "@bitCast(");
|
||||
ir_print_other_instruction(irp, instruction->operand);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
|
||||
fprintf(irp->f, "WidenOrShorten(");
|
||||
ir_print_other_instruction(irp, instruction->target);
|
||||
@ -990,6 +999,12 @@ static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruct
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_resize_slice(IrPrint *irp, IrInstructionResizeSlice *instruction) {
|
||||
fprintf(irp->f, "@resizeSlice(");
|
||||
ir_print_other_instruction(irp, instruction->operand);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {
|
||||
fprintf(irp->f, "inttoerr ");
|
||||
ir_print_other_instruction(irp, instruction->target);
|
||||
@ -1462,6 +1477,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdLoadPtr:
|
||||
ir_print_load_ptr(irp, (IrInstructionLoadPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdLoadPtrGen:
|
||||
ir_print_load_ptr_gen(irp, (IrInstructionLoadPtrGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdStorePtr:
|
||||
ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction);
|
||||
break;
|
||||
@ -1678,6 +1696,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdBitCast:
|
||||
ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBitCastGen:
|
||||
ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdWidenOrShorten:
|
||||
ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction);
|
||||
break;
|
||||
@ -1852,6 +1873,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdAssertZero:
|
||||
ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction);
|
||||
break;
|
||||
case IrInstructionIdResizeSlice:
|
||||
ir_print_resize_slice(irp, (IrInstructionResizeSlice *)instruction);
|
||||
break;
|
||||
}
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
498
src/libc_installation.cpp
Normal file
498
src/libc_installation.cpp
Normal file
@ -0,0 +1,498 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "libc_installation.hpp"
|
||||
#include "os.hpp"
|
||||
#include "windows_sdk.h"
|
||||
#include "target.hpp"
|
||||
|
||||
static const char *zig_libc_keys[] = {
|
||||
"include_dir",
|
||||
"sys_include_dir",
|
||||
"crt_dir",
|
||||
"lib_dir",
|
||||
"static_lib_dir",
|
||||
"msvc_lib_dir",
|
||||
"kernel32_lib_dir",
|
||||
"dynamic_linker_path",
|
||||
};
|
||||
|
||||
static const size_t zig_libc_keys_len = array_length(zig_libc_keys);
|
||||
|
||||
static bool zig_libc_match_key(Slice<uint8_t> name, Slice<uint8_t> value, bool *found_keys,
|
||||
size_t index, Buf *field_ptr)
|
||||
{
|
||||
if (!memEql(name, str(zig_libc_keys[index]))) return false;
|
||||
buf_init_from_mem(field_ptr, (const char*)value.ptr, value.len);
|
||||
found_keys[index] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void zig_libc_init_empty(ZigLibCInstallation *libc) {
|
||||
*libc = {};
|
||||
buf_init_from_str(&libc->include_dir, "");
|
||||
buf_init_from_str(&libc->sys_include_dir, "");
|
||||
buf_init_from_str(&libc->crt_dir, "");
|
||||
buf_init_from_str(&libc->lib_dir, "");
|
||||
buf_init_from_str(&libc->static_lib_dir, "");
|
||||
buf_init_from_str(&libc->msvc_lib_dir, "");
|
||||
buf_init_from_str(&libc->kernel32_lib_dir, "");
|
||||
buf_init_from_str(&libc->dynamic_linker_path, "");
|
||||
}
|
||||
|
||||
Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget *target, bool verbose) {
|
||||
Error err;
|
||||
zig_libc_init_empty(libc);
|
||||
|
||||
bool found_keys[array_length(zig_libc_keys)] = {};
|
||||
|
||||
Buf *contents = buf_alloc();
|
||||
if ((err = os_fetch_file_path(libc_file, contents, false))) {
|
||||
if (err != ErrorFileNotFound && verbose) {
|
||||
fprintf(stderr, "Unable to read '%s': %s\n", buf_ptr(libc_file), err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
SplitIterator it = memSplit(buf_to_slice(contents), str("\n"));
|
||||
for (;;) {
|
||||
Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it);
|
||||
if (!opt_line.is_some)
|
||||
break;
|
||||
|
||||
if (opt_line.value.len == 0 || opt_line.value.ptr[0] == '#')
|
||||
continue;
|
||||
|
||||
SplitIterator line_it = memSplit(opt_line.value, str("="));
|
||||
Slice<uint8_t> name;
|
||||
if (!SplitIterator_next(&line_it).unwrap(&name)) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "missing equal sign after field name\n");
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
Slice<uint8_t> value = SplitIterator_rest(&line_it);
|
||||
bool match = false;
|
||||
match = match || zig_libc_match_key(name, value, found_keys, 0, &libc->include_dir);
|
||||
match = match || zig_libc_match_key(name, value, found_keys, 1, &libc->sys_include_dir);
|
||||
match = match || zig_libc_match_key(name, value, found_keys, 2, &libc->crt_dir);
|
||||
match = match || zig_libc_match_key(name, value, found_keys, 3, &libc->lib_dir);
|
||||
match = match || zig_libc_match_key(name, value, found_keys, 4, &libc->static_lib_dir);
|
||||
match = match || zig_libc_match_key(name, value, found_keys, 5, &libc->msvc_lib_dir);
|
||||
match = match || zig_libc_match_key(name, value, found_keys, 6, &libc->kernel32_lib_dir);
|
||||
match = match || zig_libc_match_key(name, value, found_keys, 7, &libc->dynamic_linker_path);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < zig_libc_keys_len; i += 1) {
|
||||
if (!found_keys[i]) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "missing field: %s\n", zig_libc_keys[i]);
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_len(&libc->include_dir) == 0) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "include_dir may not be empty\n");
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
if (buf_len(&libc->sys_include_dir) == 0) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "sys_include_dir may not be empty\n");
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
if (buf_len(&libc->crt_dir) == 0) {
|
||||
if (!target_is_darwin(target)) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "crt_dir may not be empty for %s\n", target_os_name(target->os));
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_len(&libc->lib_dir) == 0) {
|
||||
if (!target_is_darwin(target) && target->os != OsWindows) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "lib_dir may not be empty for %s\n", target_os_name(target->os));
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_len(&libc->static_lib_dir) == 0) {
|
||||
if (!target_is_darwin(target) && target->os != OsWindows) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "static_lib_dir may not be empty for %s\n", target_os_name(target->os));
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_len(&libc->msvc_lib_dir) == 0) {
|
||||
if (target->os == OsWindows) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "msvc_lib_dir may not be empty for %s\n", target_os_name(target->os));
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_len(&libc->kernel32_lib_dir) == 0) {
|
||||
if (target->os == OsWindows) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "kernel32_lib_dir may not be empty for %s\n", target_os_name(target->os));
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_len(&libc->dynamic_linker_path) == 0) {
|
||||
if (!target_is_darwin(target) && target->os != OsWindows) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "dynamic_linker_path may not be empty for %s\n", target_os_name(target->os));
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
static Error zig_libc_find_native_include_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) {
|
||||
Error err;
|
||||
if ((err = os_get_win32_ucrt_include_path(sdk, &self->include_dir))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unable to determine libc include path: %s\n", err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
static Error zig_libc_find_crt_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target,
|
||||
bool verbose)
|
||||
{
|
||||
Error err;
|
||||
if ((err = os_get_win32_ucrt_lib_path(sdk, &self->crt_dir, target->arch))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unable to determine ucrt path: %s\n", err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
static Error zig_libc_find_kernel32_lib_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target,
|
||||
bool verbose)
|
||||
{
|
||||
Error err;
|
||||
if ((err = os_get_win32_kern32_path(sdk, &self->kernel32_lib_dir, target->arch))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unable to determine kernel32 path: %s\n", err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
static Error zig_libc_find_native_msvc_lib_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) {
|
||||
if (sdk->msvc_lib_dir_ptr == nullptr) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unable to determine vcruntime.lib path\n");
|
||||
}
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
buf_init_from_mem(&self->msvc_lib_dir, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
|
||||
return ErrorNone;
|
||||
}
|
||||
static Error zig_libc_find_native_msvc_include_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) {
|
||||
Error err;
|
||||
if (sdk->msvc_lib_dir_ptr == nullptr) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unable to determine vcruntime.h path\n");
|
||||
}
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
Buf search_path = BUF_INIT;
|
||||
buf_init_from_mem(&search_path, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
|
||||
buf_append_str(&search_path, "\\..\\..\\include");
|
||||
|
||||
Buf *vcruntime_path = buf_sprintf("%s\\vcruntime.h", buf_ptr(&search_path));
|
||||
bool exists;
|
||||
if ((err = os_file_exists(vcruntime_path, &exists))) {
|
||||
exists = false;
|
||||
}
|
||||
if (exists) {
|
||||
self->sys_include_dir = search_path;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unable to determine vcruntime.h path\n");
|
||||
}
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
#else
|
||||
static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, bool verbose) {
|
||||
const char *cc_exe = getenv("CC");
|
||||
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
|
||||
ZigList<const char *> args = {};
|
||||
args.append("-E");
|
||||
args.append("-Wp,-v");
|
||||
args.append("-xc");
|
||||
args.append("/dev/null");
|
||||
Termination term;
|
||||
Buf *out_stderr = buf_alloc();
|
||||
Buf *out_stdout = buf_alloc();
|
||||
Error err;
|
||||
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to determine libc include path: executing '%s': %s\n", cc_exe, err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to determine libc include path: executing '%s' failed\n", cc_exe);
|
||||
}
|
||||
return ErrorCCompileErrors;
|
||||
}
|
||||
char *prev_newline = buf_ptr(out_stderr);
|
||||
ZigList<const char *> search_paths = {};
|
||||
for (;;) {
|
||||
char *newline = strchr(prev_newline, '\n');
|
||||
if (newline == nullptr) {
|
||||
break;
|
||||
}
|
||||
*newline = 0;
|
||||
if (prev_newline[0] == ' ') {
|
||||
search_paths.append(prev_newline);
|
||||
}
|
||||
prev_newline = newline + 1;
|
||||
}
|
||||
if (search_paths.length == 0) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to determine libc include path: '%s' cannot find libc headers\n", cc_exe);
|
||||
}
|
||||
return ErrorCCompileErrors;
|
||||
}
|
||||
for (size_t i = 0; i < search_paths.length; i += 1) {
|
||||
// search in reverse order
|
||||
const char *search_path = search_paths.items[search_paths.length - i - 1];
|
||||
// cut off spaces
|
||||
while (*search_path == ' ') {
|
||||
search_path += 1;
|
||||
}
|
||||
|
||||
if (buf_len(&self->include_dir) == 0) {
|
||||
Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path);
|
||||
bool exists;
|
||||
if ((err = os_file_exists(stdlib_path, &exists))) {
|
||||
exists = false;
|
||||
}
|
||||
if (exists) {
|
||||
buf_init_from_str(&self->include_dir, search_path);
|
||||
}
|
||||
}
|
||||
if (buf_len(&self->sys_include_dir) == 0) {
|
||||
Buf *stdlib_path = buf_sprintf("%s/sys/errno.h", search_path);
|
||||
bool exists;
|
||||
if ((err = os_file_exists(stdlib_path, &exists))) {
|
||||
exists = false;
|
||||
}
|
||||
if (exists) {
|
||||
buf_init_from_str(&self->sys_include_dir, search_path);
|
||||
}
|
||||
}
|
||||
if (buf_len(&self->include_dir) != 0 && buf_len(&self->sys_include_dir) != 0) {
|
||||
return ErrorNone;
|
||||
}
|
||||
}
|
||||
if (verbose) {
|
||||
if (buf_len(&self->include_dir) == 0) {
|
||||
fprintf(stderr, "unable to determine libc include path: stdlib.h not found in '%s' search paths\n", cc_exe);
|
||||
}
|
||||
if (buf_len(&self->sys_include_dir) == 0) {
|
||||
fprintf(stderr, "unable to determine libc include path: sys/errno.h not found in '%s' search paths\n", cc_exe);
|
||||
}
|
||||
}
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
#if !defined(ZIG_OS_DARWIN) && !defined(ZIG_OS_FREEBSD) && !defined(ZIG_OS_NETBSD)
|
||||
static Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose) {
|
||||
const char *cc_exe = getenv("CC");
|
||||
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
|
||||
ZigList<const char *> args = {};
|
||||
args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));
|
||||
Termination term;
|
||||
Buf *out_stderr = buf_alloc();
|
||||
Buf *out_stdout = buf_alloc();
|
||||
Error err;
|
||||
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to determine libc include path: executing '%s': %s\n", cc_exe, err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to determine libc include path: executing '%s' failed\n", cc_exe);
|
||||
}
|
||||
return ErrorCCompileErrors;
|
||||
}
|
||||
if (buf_ends_with_str(out_stdout, "\n")) {
|
||||
buf_resize(out_stdout, buf_len(out_stdout) - 1);
|
||||
}
|
||||
if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) {
|
||||
return ErrorCCompilerCannotFindFile;
|
||||
}
|
||||
if (want_dirname) {
|
||||
os_path_dirname(out_stdout, out);
|
||||
} else {
|
||||
buf_init_from_buf(out, out_stdout);
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
static Error zig_libc_find_native_crt_dir_posix(ZigLibCInstallation *self, bool verbose) {
|
||||
return zig_libc_cc_print_file_name("crt1.o", &self->crt_dir, true, verbose);
|
||||
}
|
||||
static Error zig_libc_find_native_lib_dir_posix(ZigLibCInstallation *self, bool verbose) {
|
||||
return zig_libc_cc_print_file_name("libgcc_s.so", &self->lib_dir, true, verbose);
|
||||
}
|
||||
|
||||
static Error zig_libc_find_native_static_lib_dir_posix(ZigLibCInstallation *self, bool verbose) {
|
||||
return zig_libc_cc_print_file_name("crtbegin.o", &self->static_lib_dir, true, verbose);
|
||||
}
|
||||
#endif
|
||||
|
||||
static Error zig_libc_find_native_dynamic_linker_posix(ZigLibCInstallation *self, bool verbose) {
|
||||
#if defined(ZIG_OS_LINUX)
|
||||
Error err;
|
||||
static const char *dyn_tests[] = {
|
||||
"ld-linux-x86-64.so.2",
|
||||
"ld-musl-x86_64.so.1",
|
||||
};
|
||||
for (size_t i = 0; i < array_length(dyn_tests); i += 1) {
|
||||
const char *lib_name = dyn_tests[i];
|
||||
if ((err = zig_libc_cc_print_file_name(lib_name, &self->dynamic_linker_path, false, true))) {
|
||||
if (err != ErrorCCompilerCannotFindFile)
|
||||
return err;
|
||||
continue;
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
#endif
|
||||
ZigTarget native_target;
|
||||
get_native_target(&native_target);
|
||||
const char *dynamic_linker_path = target_dynamic_linker(&native_target);
|
||||
if (dynamic_linker_path != nullptr) {
|
||||
buf_init_from_str(&self->dynamic_linker_path, dynamic_linker_path);
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
#endif
|
||||
|
||||
void zig_libc_render(ZigLibCInstallation *self, FILE *file) {
|
||||
fprintf(file,
|
||||
"# The directory that contains `stdlib.h`.\n"
|
||||
"# On POSIX, include directories be found with: `cc -E -Wp,-v -xc /dev/null`\n"
|
||||
"include_dir=%s\n"
|
||||
"# The system-specific include directory. May be the same as `include_dir`.\n"
|
||||
"# On Windows it's the directory that includes `vcruntime.h`.\n"
|
||||
"# On POSIX it's the directory that includes `sys/errno.h`.\n"
|
||||
"sys_include_dir=%s\n"
|
||||
"\n"
|
||||
"# The directory that contains `crt1.o`.\n"
|
||||
"# On POSIX, can be found with `cc -print-file-name=crt1.o`.\n"
|
||||
"# Not needed when targeting MacOS.\n"
|
||||
"crt_dir=%s\n"
|
||||
"\n"
|
||||
"# The directory that contains `libgcc_s.so`.\n"
|
||||
"# On POSIX, can be found with `cc -print-file-name=libgcc_s.so`.\n"
|
||||
"# Not needed when targeting MacOS or Windows.\n"
|
||||
"lib_dir=%s\n"
|
||||
"\n"
|
||||
"# The directory that contains `crtbegin.o`.\n"
|
||||
"# On POSIX, can be found with `cc -print-file-name=crtbegin.o`.\n"
|
||||
"# Not needed when targeting MacOS or Windows.\n"
|
||||
"static_lib_dir=%s\n"
|
||||
"\n"
|
||||
"# The directory that contains `vcruntime.lib`.\n"
|
||||
"# Only needed when targeting Windows.\n"
|
||||
"msvc_lib_dir=%s\n"
|
||||
"\n"
|
||||
"# The directory that contains `kernel32.lib`.\n"
|
||||
"# Only needed when targeting Windows.\n"
|
||||
"kernel32_lib_dir=%s\n"
|
||||
"\n"
|
||||
"# The full path to the dynamic linker, on the target system.\n"
|
||||
"# Not needed when targeting MacOS or Windows.\n"
|
||||
"dynamic_linker_path=%s\n"
|
||||
"\n"
|
||||
,
|
||||
buf_ptr(&self->include_dir),
|
||||
buf_ptr(&self->sys_include_dir),
|
||||
buf_ptr(&self->crt_dir),
|
||||
buf_ptr(&self->lib_dir),
|
||||
buf_ptr(&self->static_lib_dir),
|
||||
buf_ptr(&self->msvc_lib_dir),
|
||||
buf_ptr(&self->kernel32_lib_dir),
|
||||
buf_ptr(&self->dynamic_linker_path)
|
||||
);
|
||||
}
|
||||
|
||||
Error zig_libc_find_native(ZigLibCInstallation *self, bool verbose) {
|
||||
Error err;
|
||||
zig_libc_init_empty(self);
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
ZigTarget native_target;
|
||||
get_native_target(&native_target);
|
||||
ZigWindowsSDK *sdk;
|
||||
switch (zig_find_windows_sdk(&sdk)) {
|
||||
case ZigFindWindowsSdkErrorNone:
|
||||
if ((err = zig_libc_find_native_msvc_include_dir(self, sdk, verbose)))
|
||||
return err;
|
||||
if ((err = zig_libc_find_native_msvc_lib_dir(self, sdk, verbose)))
|
||||
return err;
|
||||
if ((err = zig_libc_find_kernel32_lib_dir(self, sdk, &native_target, verbose)))
|
||||
return err;
|
||||
if ((err = zig_libc_find_native_include_dir_windows(self, sdk, verbose)))
|
||||
return err;
|
||||
if ((err = zig_libc_find_crt_dir_windows(self, sdk, &native_target, verbose)))
|
||||
return err;
|
||||
return ErrorNone;
|
||||
case ZigFindWindowsSdkErrorOutOfMemory:
|
||||
return ErrorNoMem;
|
||||
case ZigFindWindowsSdkErrorNotFound:
|
||||
return ErrorFileNotFound;
|
||||
case ZigFindWindowsSdkErrorPathTooLong:
|
||||
return ErrorPathTooLong;
|
||||
}
|
||||
zig_unreachable();
|
||||
#else
|
||||
if ((err = zig_libc_find_native_include_dir_posix(self, verbose)))
|
||||
return err;
|
||||
#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
|
||||
buf_init_from_str(&self->crt_dir, "/usr/lib");
|
||||
buf_init_from_str(&self->lib_dir, "/usr/lib");
|
||||
buf_init_from_str(&self->static_lib_dir, "/usr/lib");
|
||||
#elif !defined(ZIG_OS_DARWIN)
|
||||
if ((err = zig_libc_find_native_crt_dir_posix(self, verbose)))
|
||||
return err;
|
||||
if ((err = zig_libc_find_native_lib_dir_posix(self, verbose)))
|
||||
return err;
|
||||
if ((err = zig_libc_find_native_static_lib_dir_posix(self, verbose)))
|
||||
return err;
|
||||
#endif
|
||||
if ((err = zig_libc_find_native_dynamic_linker_posix(self, verbose)))
|
||||
return err;
|
||||
return ErrorNone;
|
||||
#endif
|
||||
}
|
35
src/libc_installation.hpp
Normal file
35
src/libc_installation.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_LIBC_INSTALLATION_HPP
|
||||
#define ZIG_LIBC_INSTALLATION_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "buffer.hpp"
|
||||
#include "error.hpp"
|
||||
#include "target.hpp"
|
||||
|
||||
// Must be synchronized with zig_libc_keys
|
||||
struct ZigLibCInstallation {
|
||||
Buf include_dir;
|
||||
Buf sys_include_dir;
|
||||
Buf crt_dir;
|
||||
Buf lib_dir;
|
||||
Buf static_lib_dir;
|
||||
Buf msvc_lib_dir;
|
||||
Buf kernel32_lib_dir;
|
||||
Buf dynamic_linker_path;
|
||||
};
|
||||
|
||||
Error ATTRIBUTE_MUST_USE zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file,
|
||||
const ZigTarget *target, bool verbose);
|
||||
void zig_libc_render(ZigLibCInstallation *self, FILE *file);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE zig_libc_find_native(ZigLibCInstallation *self, bool verbose);
|
||||
|
||||
#endif
|
195
src/link.cpp
195
src/link.cpp
@ -17,32 +17,33 @@ struct LinkJob {
|
||||
HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table;
|
||||
};
|
||||
|
||||
static const char *get_libc_file(CodeGen *g, const char *file) {
|
||||
static const char *get_libc_crt_file(CodeGen *g, const char *file) {
|
||||
assert(g->libc != nullptr);
|
||||
Buf *out_buf = buf_alloc();
|
||||
os_path_join(g->libc_lib_dir, buf_create_from_str(file), out_buf);
|
||||
os_path_join(&g->libc->crt_dir, buf_create_from_str(file), out_buf);
|
||||
return buf_ptr(out_buf);
|
||||
}
|
||||
|
||||
static const char *get_libc_static_file(CodeGen *g, const char *file) {
|
||||
assert(g->libc != nullptr);
|
||||
Buf *out_buf = buf_alloc();
|
||||
os_path_join(g->libc_static_lib_dir, buf_create_from_str(file), out_buf);
|
||||
os_path_join(&g->libc->static_lib_dir, buf_create_from_str(file), out_buf);
|
||||
return buf_ptr(out_buf);
|
||||
}
|
||||
|
||||
static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) {
|
||||
ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target;
|
||||
|
||||
// The Mach-O LLD code is not well maintained, and trips an assertion
|
||||
// when we link compiler_rt and builtin as libraries rather than objects.
|
||||
// Here we workaround this by having compiler_rt and builtin be objects.
|
||||
// TODO write our own linker. https://github.com/ziglang/zig/issues/1535
|
||||
OutType child_out_type = OutTypeLib;
|
||||
if (parent_gen->zig_target.os == OsMacOSX) {
|
||||
if (parent_gen->zig_target->os == OsMacOSX) {
|
||||
child_out_type = OutTypeObj;
|
||||
}
|
||||
|
||||
CodeGen *child_gen = codegen_create(full_path, child_target, child_out_type,
|
||||
parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir);
|
||||
CodeGen *child_gen = codegen_create(full_path, parent_gen->zig_target, child_out_type,
|
||||
parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir,
|
||||
parent_gen->libc);
|
||||
|
||||
child_gen->out_h_path = nullptr;
|
||||
child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
|
||||
@ -55,6 +56,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path)
|
||||
codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
|
||||
codegen_set_is_static(child_gen, true);
|
||||
child_gen->disable_pic = parent_gen->disable_pic;
|
||||
child_gen->valgrind_support = ValgrindSupportDisabled;
|
||||
|
||||
codegen_set_out_name(child_gen, buf_create_from_str(aname));
|
||||
|
||||
@ -94,7 +96,7 @@ static Buf *build_compiler_rt(CodeGen *parent_gen) {
|
||||
}
|
||||
|
||||
static const char *get_darwin_arch_string(const ZigTarget *t) {
|
||||
switch (t->arch.arch) {
|
||||
switch (t->arch) {
|
||||
case ZigLLVM_aarch64:
|
||||
return "arm64";
|
||||
case ZigLLVM_thumb:
|
||||
@ -107,13 +109,13 @@ static const char *get_darwin_arch_string(const ZigTarget *t) {
|
||||
case ZigLLVM_ppc64le:
|
||||
return "ppc64le";
|
||||
default:
|
||||
return ZigLLVMGetArchTypeName(t->arch.arch);
|
||||
return ZigLLVMGetArchTypeName(t->arch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char *getLDMOption(const ZigTarget *t) {
|
||||
switch (t->arch.arch) {
|
||||
switch (t->arch) {
|
||||
case ZigLLVM_x86:
|
||||
return "elf_i386";
|
||||
case ZigLLVM_aarch64:
|
||||
@ -147,7 +149,7 @@ static const char *getLDMOption(const ZigTarget *t) {
|
||||
case ZigLLVM_systemz:
|
||||
return "elf64_s390";
|
||||
case ZigLLVM_x86_64:
|
||||
if (t->env_type == ZigLLVM_GNUX32) {
|
||||
if (t->abi == ZigLLVM_GNUX32) {
|
||||
return "elf32_x86_64";
|
||||
}
|
||||
// Any target elf will use the freebsd osabi if suffixed with "_fbsd".
|
||||
@ -170,78 +172,27 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {
|
||||
lj->rpath_table.put(rpath, true);
|
||||
}
|
||||
|
||||
static Buf *try_dynamic_linker_path(const char *ld_name) {
|
||||
const char *cc_exe = getenv("CC");
|
||||
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
|
||||
ZigList<const char *> args = {};
|
||||
args.append(buf_ptr(buf_sprintf("-print-file-name=%s", ld_name)));
|
||||
Termination term;
|
||||
Buf *out_stderr = buf_alloc();
|
||||
Buf *out_stdout = buf_alloc();
|
||||
int err;
|
||||
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
|
||||
return nullptr;
|
||||
}
|
||||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
if (buf_ends_with_str(out_stdout, "\n")) {
|
||||
buf_resize(out_stdout, buf_len(out_stdout) - 1);
|
||||
}
|
||||
if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, ld_name)) {
|
||||
return nullptr;
|
||||
}
|
||||
return out_stdout;
|
||||
}
|
||||
|
||||
static Buf *get_dynamic_linker_path(CodeGen *g) {
|
||||
if (g->zig_target.os == OsFreeBSD) {
|
||||
return buf_create_from_str("/libexec/ld-elf.so.1");
|
||||
}
|
||||
if (g->is_native_target && g->zig_target.arch.arch == ZigLLVM_x86_64) {
|
||||
static const char *ld_names[] = {
|
||||
"ld-linux-x86-64.so.2",
|
||||
"ld-musl-x86_64.so.1",
|
||||
};
|
||||
for (size_t i = 0; i < array_length(ld_names); i += 1) {
|
||||
const char *ld_name = ld_names[i];
|
||||
Buf *result = try_dynamic_linker_path(ld_name);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return target_dynamic_linker(&g->zig_target);
|
||||
}
|
||||
|
||||
static void construct_linker_job_elf(LinkJob *lj) {
|
||||
CodeGen *g = lj->codegen;
|
||||
|
||||
lj->args.append("-error-limit=0");
|
||||
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
find_libc_lib_path(g);
|
||||
}
|
||||
|
||||
if (g->linker_script) {
|
||||
lj->args.append("-T");
|
||||
lj->args.append(g->linker_script);
|
||||
}
|
||||
|
||||
if (g->no_rosegment_workaround) {
|
||||
lj->args.append("--no-rosegment");
|
||||
}
|
||||
lj->args.append("--gc-sections");
|
||||
|
||||
lj->args.append("-m");
|
||||
lj->args.append(getLDMOption(&g->zig_target));
|
||||
lj->args.append(getLDMOption(g->zig_target));
|
||||
|
||||
bool is_lib = g->out_type == OutTypeLib;
|
||||
bool shared = !g->is_static && is_lib;
|
||||
Buf *soname = nullptr;
|
||||
if (g->is_static) {
|
||||
if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb ||
|
||||
g->zig_target.arch.arch == ZigLLVM_thumb || g->zig_target.arch.arch == ZigLLVM_thumbeb)
|
||||
if (g->zig_target->arch == ZigLLVM_arm || g->zig_target->arch == ZigLLVM_armeb ||
|
||||
g->zig_target->arch == ZigLLVM_thumb || g->zig_target->arch == ZigLLVM_thumbeb)
|
||||
{
|
||||
lj->args.append("-Bstatic");
|
||||
} else {
|
||||
@ -263,15 +214,18 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
||||
if (lj->link_in_crt) {
|
||||
const char *crt1o;
|
||||
const char *crtbegino;
|
||||
if (g->is_static) {
|
||||
if (g->zig_target->os == OsNetBSD) {
|
||||
crt1o = "crt0.o";
|
||||
crtbegino = "crtbegin.o";
|
||||
} else if (g->is_static) {
|
||||
crt1o = "crt1.o";
|
||||
crtbegino = "crtbeginT.o";
|
||||
} else {
|
||||
crt1o = "Scrt1.o";
|
||||
crtbegino = "crtbegin.o";
|
||||
}
|
||||
lj->args.append(get_libc_file(g, crt1o));
|
||||
lj->args.append(get_libc_file(g, "crti.o"));
|
||||
lj->args.append(get_libc_crt_file(g, crt1o));
|
||||
lj->args.append(get_libc_crt_file(g, "crti.o"));
|
||||
lj->args.append(get_libc_static_file(g, crtbegino));
|
||||
}
|
||||
|
||||
@ -307,23 +261,24 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
||||
}
|
||||
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
assert(g->libc != nullptr);
|
||||
lj->args.append("-L");
|
||||
lj->args.append(buf_ptr(g->libc_lib_dir));
|
||||
lj->args.append(buf_ptr(&g->libc->crt_dir));
|
||||
|
||||
lj->args.append("-L");
|
||||
lj->args.append(buf_ptr(g->libc_static_lib_dir));
|
||||
}
|
||||
|
||||
if (!g->is_static) {
|
||||
if (g->dynamic_linker != nullptr) {
|
||||
assert(buf_len(g->dynamic_linker) != 0);
|
||||
lj->args.append("-dynamic-linker");
|
||||
lj->args.append(buf_ptr(g->dynamic_linker));
|
||||
} else {
|
||||
Buf *resolved_dynamic_linker = get_dynamic_linker_path(g);
|
||||
lj->args.append("-dynamic-linker");
|
||||
lj->args.append(buf_ptr(resolved_dynamic_linker));
|
||||
if (!buf_eql_buf(&g->libc->crt_dir, &g->libc->lib_dir)) {
|
||||
lj->args.append("-L");
|
||||
lj->args.append(buf_ptr(&g->libc->lib_dir));
|
||||
}
|
||||
|
||||
lj->args.append("-L");
|
||||
lj->args.append(buf_ptr(&g->libc->static_lib_dir));
|
||||
|
||||
if (!g->is_static) {
|
||||
assert(buf_len(&g->libc->dynamic_linker_path) != 0);
|
||||
lj->args.append("-dynamic-linker");
|
||||
lj->args.append(buf_ptr(&g->libc->dynamic_linker_path));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (shared) {
|
||||
@ -390,14 +345,14 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
||||
// crt end
|
||||
if (lj->link_in_crt) {
|
||||
lj->args.append(get_libc_static_file(g, "crtend.o"));
|
||||
lj->args.append(get_libc_file(g, "crtn.o"));
|
||||
lj->args.append(get_libc_crt_file(g, "crtn.o"));
|
||||
}
|
||||
|
||||
if (!g->is_native_target) {
|
||||
if (!g->zig_target->is_native) {
|
||||
lj->args.append("--allow-shlib-undefined");
|
||||
}
|
||||
|
||||
if (g->zig_target.os == OsZen) {
|
||||
if (g->zig_target->os == OsZen) {
|
||||
lj->args.append("-e");
|
||||
lj->args.append("_start");
|
||||
|
||||
@ -420,16 +375,16 @@ static void construct_linker_job_wasm(LinkJob *lj) {
|
||||
}
|
||||
|
||||
//static bool is_target_cyg_mingw(const ZigTarget *target) {
|
||||
// return (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_Cygnus) ||
|
||||
// (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_GNU);
|
||||
// return (target->os == ZigLLVM_Win32 && target->abi == ZigLLVM_Cygnus) ||
|
||||
// (target->os == ZigLLVM_Win32 && target->abi == ZigLLVM_GNU);
|
||||
//}
|
||||
|
||||
static void coff_append_machine_arg(CodeGen *g, ZigList<const char *> *list) {
|
||||
if (g->zig_target.arch.arch == ZigLLVM_x86) {
|
||||
if (g->zig_target->arch == ZigLLVM_x86) {
|
||||
list->append("-MACHINE:X86");
|
||||
} else if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
|
||||
} else if (g->zig_target->arch == ZigLLVM_x86_64) {
|
||||
list->append("-MACHINE:X64");
|
||||
} else if (g->zig_target.arch.arch == ZigLLVM_arm) {
|
||||
} else if (g->zig_target->arch == ZigLLVM_arm) {
|
||||
list->append("-MACHINE:ARM");
|
||||
}
|
||||
}
|
||||
@ -515,7 +470,7 @@ static void add_nt_link_args(LinkJob *lj, bool is_library) {
|
||||
// lj->args.append("-Bdynamic");
|
||||
// if (dll || shared) {
|
||||
// lj->args.append("-e");
|
||||
// if (g->zig_target.arch.arch == ZigLLVM_x86) {
|
||||
// if (g->zig_target.arch == ZigLLVM_x86) {
|
||||
// lj->args.append("_DllMainCRTStartup@12");
|
||||
// } else {
|
||||
// lj->args.append("DllMainCRTStartup");
|
||||
@ -541,7 +496,7 @@ static void add_nt_link_args(LinkJob *lj, bool is_library) {
|
||||
//lj->args.append("-lmingw32");
|
||||
|
||||
//lj->args.append("-lgcc");
|
||||
//bool is_android = (g->zig_target.env_type == ZigLLVM_Android);
|
||||
//bool is_android = (g->zig_target.abi == ZigLLVM_Android);
|
||||
//bool is_cyg_ming = is_target_cyg_mingw(&g->zig_target);
|
||||
//if (!g->is_static && !is_android) {
|
||||
// if (!is_cyg_ming) {
|
||||
@ -588,10 +543,6 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
|
||||
lj->args.append("/ERRORLIMIT:0");
|
||||
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
find_libc_lib_path(g);
|
||||
}
|
||||
|
||||
lj->args.append("/NOLOGO");
|
||||
|
||||
if (!g->strip_debug_symbols) {
|
||||
@ -608,6 +559,11 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
bool is_library = g->out_type == OutTypeLib;
|
||||
switch (g->subsystem) {
|
||||
case TargetSubsystemAuto:
|
||||
if (g->zig_target->os == OsUefi) {
|
||||
add_uefi_link_args(lj);
|
||||
} else {
|
||||
add_nt_link_args(lj, is_library);
|
||||
}
|
||||
break;
|
||||
case TargetSubsystemConsole:
|
||||
lj->args.append("/SUBSYSTEM:console");
|
||||
@ -646,13 +602,11 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
|
||||
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir))));
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
|
||||
assert(g->libc != nullptr);
|
||||
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
|
||||
if (g->libc_static_lib_dir != nullptr) {
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
|
||||
}
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir))));
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir))));
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir))));
|
||||
}
|
||||
|
||||
if (is_library && !g->is_static) {
|
||||
@ -687,7 +641,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
continue;
|
||||
}
|
||||
if (link_lib->provided_explicitly) {
|
||||
if (lj->codegen->zig_target.env_type == ZigLLVM_GNU) {
|
||||
if (lj->codegen->zig_target->abi == ZigLLVM_GNU) {
|
||||
Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
|
||||
lj->args.append(buf_ptr(arg));
|
||||
}
|
||||
@ -717,7 +671,8 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path))));
|
||||
gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path))));
|
||||
Buf diag = BUF_INIT;
|
||||
if (!zig_lld_link(g->zig_target.oformat, gen_lib_args.items, gen_lib_args.length, &diag)) {
|
||||
ZigLLVM_ObjectFormatType target_ofmt = target_object_format(g->zig_target);
|
||||
if (!zig_lld_link(target_ofmt, gen_lib_args.items, gen_lib_args.length, &diag)) {
|
||||
fprintf(stderr, "%s\n", buf_ptr(&diag));
|
||||
exit(1);
|
||||
}
|
||||
@ -786,7 +741,7 @@ static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
|
||||
platform->kind = MacOS;
|
||||
} else if (g->mios_version_min) {
|
||||
platform->kind = IPhoneOS;
|
||||
} else if (g->zig_target.os == OsMacOSX) {
|
||||
} else if (g->zig_target->os == OsMacOSX) {
|
||||
platform->kind = MacOS;
|
||||
g->mmacosx_version_min = buf_create_from_str("10.10");
|
||||
} else {
|
||||
@ -813,8 +768,8 @@ static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
|
||||
}
|
||||
|
||||
if (platform->kind == IPhoneOS &&
|
||||
(g->zig_target.arch.arch == ZigLLVM_x86 ||
|
||||
g->zig_target.arch.arch == ZigLLVM_x86_64))
|
||||
(g->zig_target->arch == ZigLLVM_x86 ||
|
||||
g->zig_target->arch == ZigLLVM_x86_64))
|
||||
{
|
||||
platform->kind = IPhoneOSSimulator;
|
||||
}
|
||||
@ -878,7 +833,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
}
|
||||
|
||||
lj->args.append("-arch");
|
||||
lj->args.append(get_darwin_arch_string(&g->zig_target));
|
||||
lj->args.append(get_darwin_arch_string(g->zig_target));
|
||||
|
||||
DarwinPlatform platform;
|
||||
get_darwin_platform(lj, &platform);
|
||||
@ -893,7 +848,11 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
lj->args.append("-ios_simulator_version_min");
|
||||
break;
|
||||
}
|
||||
lj->args.append(buf_ptr(buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro)));
|
||||
Buf *version_string = buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro);
|
||||
lj->args.append(buf_ptr(version_string));
|
||||
|
||||
lj->args.append("-sdk_version");
|
||||
lj->args.append(buf_ptr(version_string));
|
||||
|
||||
|
||||
if (g->out_type == OutTypeExe) {
|
||||
@ -914,7 +873,9 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
add_rpath(lj, &g->output_file_path);
|
||||
|
||||
if (shared) {
|
||||
lj->args.append("-headerpad_max_install_names");
|
||||
if (g->system_linker_hack) {
|
||||
lj->args.append("-headerpad_max_install_names");
|
||||
}
|
||||
} else if (g->is_static) {
|
||||
lj->args.append("-lcrt0.o");
|
||||
} else {
|
||||
@ -929,7 +890,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
}
|
||||
break;
|
||||
case IPhoneOS:
|
||||
if (g->zig_target.arch.arch == ZigLLVM_aarch64) {
|
||||
if (g->zig_target->arch == ZigLLVM_aarch64) {
|
||||
// iOS does not need any crt1 files for arm64
|
||||
} else if (darwin_version_lt(&platform, 3, 1)) {
|
||||
lj->args.append("-lcrt1.o");
|
||||
@ -959,7 +920,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
lj->args.append(buf_ptr(compiler_rt_o_path));
|
||||
}
|
||||
|
||||
if (g->is_native_target) {
|
||||
if (g->zig_target->is_native) {
|
||||
for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
|
||||
LinkLib *link_lib = g->link_libs_list.at(lib_i);
|
||||
if (buf_eql_str(link_lib->name, "c")) {
|
||||
@ -1000,7 +961,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
}
|
||||
|
||||
static void construct_linker_job(LinkJob *lj) {
|
||||
switch (lj->codegen->zig_target.oformat) {
|
||||
switch (target_object_format(lj->codegen->zig_target)) {
|
||||
case ZigLLVM_UnknownObjectFormat:
|
||||
zig_unreachable();
|
||||
|
||||
@ -1040,7 +1001,7 @@ void codegen_link(CodeGen *g) {
|
||||
for (size_t i = 0; i < g->link_objects.length; i += 1) {
|
||||
file_names.append((const char *)buf_ptr(g->link_objects.at(i)));
|
||||
}
|
||||
ZigLLVM_OSType os_type = get_llvm_os_type(g->zig_target.os);
|
||||
ZigLLVM_OSType os_type = get_llvm_os_type(g->zig_target->os);
|
||||
codegen_add_time_event(g, "LLVM Link");
|
||||
if (ZigLLVMWriteArchive(buf_ptr(&g->output_file_path), file_names.items, file_names.length, os_type)) {
|
||||
fprintf(stderr, "Unable to write archive '%s'\n", buf_ptr(&g->output_file_path));
|
||||
@ -1065,7 +1026,7 @@ void codegen_link(CodeGen *g) {
|
||||
Buf diag = BUF_INIT;
|
||||
|
||||
codegen_add_time_event(g, "LLVM Link");
|
||||
if (g->system_linker_hack && g->zig_target.os == OsMacOSX) {
|
||||
if (g->system_linker_hack && g->zig_target->os == OsMacOSX) {
|
||||
Termination term;
|
||||
ZigList<const char *> args = {};
|
||||
for (size_t i = 1; i < lj.args.length; i += 1) {
|
||||
@ -1075,7 +1036,7 @@ void codegen_link(CodeGen *g) {
|
||||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
exit(1);
|
||||
}
|
||||
} else if (!zig_lld_link(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) {
|
||||
} else if (!zig_lld_link(target_object_format(g->zig_target), lj.args.items, lj.args.length, &diag)) {
|
||||
fprintf(stderr, "%s\n", buf_ptr(&diag));
|
||||
exit(1);
|
||||
}
|
||||
|
345
src/main.cpp
345
src/main.cpp
@ -13,16 +13,17 @@
|
||||
#include "error.hpp"
|
||||
#include "os.hpp"
|
||||
#include "target.hpp"
|
||||
#include "libc_installation.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int print_error_usage(const char *arg0) {
|
||||
fprintf(stderr, "See `%s help` for detailed usage information\n", arg0);
|
||||
fprintf(stderr, "See `%s --help` for detailed usage information\n", arg0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static int print_full_usage(const char *arg0) {
|
||||
fprintf(stdout,
|
||||
static int print_full_usage(const char *arg0, FILE *file, int return_code) {
|
||||
fprintf(file,
|
||||
"Usage: %s [command] [options]\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
@ -31,10 +32,12 @@ static int print_full_usage(const char *arg0) {
|
||||
" build-lib [source] create library from source or object files\n"
|
||||
" build-obj [source] create object from source or assembly\n"
|
||||
" builtin show the source code of that @import(\"builtin\")\n"
|
||||
" help show this usage information\n"
|
||||
" cc C compiler\n"
|
||||
" fmt parse files and render in canonical zig format\n"
|
||||
" id print the base64-encoded compiler id\n"
|
||||
" init-exe initialize a `zig build` application in the cwd\n"
|
||||
" init-lib initialize a `zig build` library in the cwd\n"
|
||||
" libc [paths_file] Display native libc paths file or validate one\n"
|
||||
" run [source] create executable and run immediately\n"
|
||||
" translate-c [source] convert c code to zig code\n"
|
||||
" targets list available compilation targets\n"
|
||||
@ -44,16 +47,20 @@ static int print_full_usage(const char *arg0) {
|
||||
"\n"
|
||||
"Compile Options:\n"
|
||||
" --assembly [source] add assembly file to build\n"
|
||||
" --c-source [options] [file] compile C source code\n"
|
||||
" --cache-dir [path] override the cache directory\n"
|
||||
" --cache [auto|off|on] build in global cache, print out paths to stdout\n"
|
||||
" --color [auto|off|on] enable or disable colored error messages\n"
|
||||
" --disable-pic disable Position Independent Code for libraries\n"
|
||||
" --disable-valgrind omit valgrind client requests in debug builds\n"
|
||||
" --enable-valgrind include valgrind client requests release builds\n"
|
||||
" --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n"
|
||||
" -ftime-report print timing diagnostics\n"
|
||||
" --libc-include-dir [path] directory where libc stdlib.h resides\n"
|
||||
" --libc [file] Provide a file which specifies libc paths\n"
|
||||
" --name [name] override output name\n"
|
||||
" --output [file] override destination path\n"
|
||||
" --output-h [file] generate header file\n"
|
||||
" --output-lib [file] override import library path\n"
|
||||
" --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
|
||||
" --pkg-end pop current pkg\n"
|
||||
" --release-fast build with optimizations on and safety off\n"
|
||||
@ -62,15 +69,14 @@ static int print_full_usage(const char *arg0) {
|
||||
" --single-threaded source may assume it is only used single-threaded\n"
|
||||
" --static output will be statically linked\n"
|
||||
" --strip exclude debug symbols\n"
|
||||
" --target-arch [name] specify target architecture\n"
|
||||
" --target-environ [name] specify target environment\n"
|
||||
" --target-os [name] specify target operating system\n"
|
||||
" -target [name] <arch><sub>-<os>-<abi> see the targets command\n"
|
||||
" --verbose-tokenize enable compiler debug output for tokenization\n"
|
||||
" --verbose-ast enable compiler debug output for AST parsing\n"
|
||||
" --verbose-link enable compiler debug output for linking\n"
|
||||
" --verbose-ir enable compiler debug output for Zig IR\n"
|
||||
" --verbose-llvm-ir enable compiler debug output for LLVM IR\n"
|
||||
" --verbose-cimport enable compiler debug output for C imports\n"
|
||||
" --verbose-cc enable compiler debug output for C compilation\n"
|
||||
" -dirafter [dir] same as -isystem but do it last\n"
|
||||
" -isystem [dir] add additional search path for other .h files\n"
|
||||
" -mllvm [arg] forward an arg to LLVM's option processing\n"
|
||||
@ -79,10 +85,6 @@ static int print_full_usage(const char *arg0) {
|
||||
"Link Options:\n"
|
||||
" --dynamic-linker [path] set the path to ld.so\n"
|
||||
" --each-lib-rpath add rpath for each used dynamic library\n"
|
||||
" --libc-lib-dir [path] directory where libc crt1.o resides\n"
|
||||
" --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n"
|
||||
" --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n"
|
||||
" --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides\n"
|
||||
" --library [lib] link against lib\n"
|
||||
" --forbid-library [lib] make it an error to link against lib\n"
|
||||
" --library-path [dir] add a directory to the library search path\n"
|
||||
@ -91,7 +93,6 @@ static int print_full_usage(const char *arg0) {
|
||||
" -L[dir] alias for --library-path\n"
|
||||
" -rdynamic add all symbols to the dynamic symbol table\n"
|
||||
" -rpath [path] add directory to the runtime library search path\n"
|
||||
" --no-rosegment compromise security to workaround valgrind bug\n"
|
||||
" --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"
|
||||
" -framework [name] (darwin) link against framework\n"
|
||||
" -mios-version-min [ver] (darwin) set iOS deployment target\n"
|
||||
@ -106,7 +107,27 @@ static int print_full_usage(const char *arg0) {
|
||||
" --test-cmd [arg] specify test execution command one arg at a time\n"
|
||||
" --test-cmd-bin appends test binary path to test cmd args\n"
|
||||
, arg0);
|
||||
return EXIT_SUCCESS;
|
||||
return return_code;
|
||||
}
|
||||
|
||||
static int print_libc_usage(const char *arg0, FILE *file, int return_code) {
|
||||
fprintf(file,
|
||||
"Usage: %s libc\n"
|
||||
"\n"
|
||||
"Detect the native libc installation and print the resulting paths to stdout.\n"
|
||||
"You can save this into a file and then edit the paths to create a cross\n"
|
||||
"compilation libc kit. Then you can pass `--libc [file]` for Zig to use it.\n"
|
||||
"\n"
|
||||
"When compiling natively and no `--libc` argument provided, Zig automatically\n"
|
||||
"creates zig-cache/native_libc.txt so that it does not have to detect libc\n"
|
||||
"on every invocation. You can remove this file to have Zig re-detect the\n"
|
||||
"native libc.\n"
|
||||
"\n\n"
|
||||
"Usage: %s libc [file]\n"
|
||||
"\n"
|
||||
"Parse a libc installation text file and validate it.\n"
|
||||
, arg0, arg0);
|
||||
return return_code;
|
||||
}
|
||||
|
||||
static const char *ZIG_ZEN = "\n"
|
||||
@ -122,6 +143,14 @@ static const char *ZIG_ZEN = "\n"
|
||||
" * Minimize energy spent on coding style.\n"
|
||||
" * Together we serve end users.\n";
|
||||
|
||||
static bool arch_available_in_llvm(ZigLLVM_ArchType arch) {
|
||||
LLVMTargetRef target_ref;
|
||||
char *err_msg = nullptr;
|
||||
char triple_string[128];
|
||||
sprintf(triple_string, "%s-unknown-unknown-unknown", ZigLLVMGetArchTypeName(arch));
|
||||
return !LLVMGetTargetFromTriple(triple_string, &target_ref, &err_msg);
|
||||
}
|
||||
|
||||
static int print_target_list(FILE *f) {
|
||||
ZigTarget native;
|
||||
get_native_target(&native);
|
||||
@ -129,28 +158,36 @@ static int print_target_list(FILE *f) {
|
||||
fprintf(f, "Architectures:\n");
|
||||
size_t arch_count = target_arch_count();
|
||||
for (size_t arch_i = 0; arch_i < arch_count; arch_i += 1) {
|
||||
const ArchType *arch = get_target_arch(arch_i);
|
||||
char arch_name[50];
|
||||
get_arch_name(arch_name, arch);
|
||||
const char *native_str = (native.arch.arch == arch->arch && native.arch.sub_arch == arch->sub_arch) ?
|
||||
" (native)" : "";
|
||||
fprintf(f, " %s%s\n", arch_name, native_str);
|
||||
ZigLLVM_ArchType arch = target_arch_enum(arch_i);
|
||||
if (!arch_available_in_llvm(arch))
|
||||
continue;
|
||||
const char *arch_name = target_arch_name(arch);
|
||||
SubArchList sub_arch_list = target_subarch_list(arch);
|
||||
size_t sub_count = target_subarch_count(sub_arch_list);
|
||||
const char *arch_native_str = (native.arch == arch) ? " (native)" : "";
|
||||
fprintf(stderr, " %s%s\n", arch_name, arch_native_str);
|
||||
for (size_t sub_i = 0; sub_i < sub_count; sub_i += 1) {
|
||||
ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i);
|
||||
const char *sub_name = target_subarch_name(sub);
|
||||
const char *sub_native_str = (native.arch == arch && native.sub_arch == sub) ? " (native)" : "";
|
||||
fprintf(f, " %s%s\n", sub_name, sub_native_str);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "\nOperating Systems:\n");
|
||||
size_t os_count = target_os_count();
|
||||
for (size_t i = 0; i < os_count; i += 1) {
|
||||
Os os_type = get_target_os(i);
|
||||
Os os_type = target_os_enum(i);
|
||||
const char *native_str = (native.os == os_type) ? " (native)" : "";
|
||||
fprintf(f, " %s%s\n", get_target_os_name(os_type), native_str);
|
||||
fprintf(f, " %s%s\n", target_os_name(os_type), native_str);
|
||||
}
|
||||
|
||||
fprintf(f, "\nEnvironments:\n");
|
||||
size_t environ_count = target_environ_count();
|
||||
for (size_t i = 0; i < environ_count; i += 1) {
|
||||
ZigLLVM_EnvironmentType environ_type = get_target_environ(i);
|
||||
const char *native_str = (native.env_type == environ_type) ? " (native)" : "";
|
||||
fprintf(f, " %s%s\n", ZigLLVMGetEnvironmentTypeName(environ_type), native_str);
|
||||
fprintf(f, "\nC ABIs:\n");
|
||||
size_t abi_count = target_abi_count();
|
||||
for (size_t i = 0; i < abi_count; i += 1) {
|
||||
ZigLLVM_EnvironmentType abi = target_abi_enum(i);
|
||||
const char *native_str = (native.abi == abi) ? " (native)" : "";
|
||||
fprintf(f, " %s%s\n", target_abi_name(abi), native_str);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
@ -160,13 +197,13 @@ enum Cmd {
|
||||
CmdNone,
|
||||
CmdBuild,
|
||||
CmdBuiltin,
|
||||
CmdHelp,
|
||||
CmdRun,
|
||||
CmdTargets,
|
||||
CmdTest,
|
||||
CmdTranslateC,
|
||||
CmdVersion,
|
||||
CmdZen,
|
||||
CmdLibC,
|
||||
};
|
||||
|
||||
static const char *default_zig_cache_name = "zig-cache";
|
||||
@ -219,6 +256,8 @@ static bool get_cache_opt(CacheOpt opt, bool default_value) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
extern "C" int ZigClang_main(int argc, char **argv);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *arg0 = argv[0];
|
||||
Error err;
|
||||
@ -236,6 +275,12 @@ int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc >= 2 && (strcmp(argv[1], "cc") == 0 ||
|
||||
strcmp(argv[1], "-cc1") == 0 || strcmp(argv[1], "-cc1as") == 0))
|
||||
{
|
||||
return ZigClang_main(argc, argv);
|
||||
}
|
||||
|
||||
// Must be before all os.hpp function calls.
|
||||
os_init();
|
||||
|
||||
@ -345,6 +390,7 @@ int main(int argc, char **argv) {
|
||||
const char *in_file = nullptr;
|
||||
const char *out_file = nullptr;
|
||||
const char *out_file_h = nullptr;
|
||||
const char *out_file_lib = nullptr;
|
||||
bool strip = false;
|
||||
bool is_static = false;
|
||||
OutType out_type = OutTypeUnknown;
|
||||
@ -355,23 +401,17 @@ int main(int argc, char **argv) {
|
||||
bool verbose_ir = false;
|
||||
bool verbose_llvm_ir = false;
|
||||
bool verbose_cimport = false;
|
||||
bool verbose_cc = false;
|
||||
ErrColor color = ErrColorAuto;
|
||||
CacheOpt enable_cache = CacheOptAuto;
|
||||
const char *libc_lib_dir = nullptr;
|
||||
const char *libc_static_lib_dir = nullptr;
|
||||
const char *libc_include_dir = nullptr;
|
||||
const char *msvc_lib_dir = nullptr;
|
||||
const char *kernel32_lib_dir = nullptr;
|
||||
const char *dynamic_linker = nullptr;
|
||||
const char *libc_txt = nullptr;
|
||||
ZigList<const char *> clang_argv = {0};
|
||||
ZigList<const char *> llvm_argv = {0};
|
||||
ZigList<const char *> lib_dirs = {0};
|
||||
ZigList<const char *> link_libs = {0};
|
||||
ZigList<const char *> forbidden_link_libs = {0};
|
||||
ZigList<const char *> frameworks = {0};
|
||||
const char *target_arch = nullptr;
|
||||
const char *target_os = nullptr;
|
||||
const char *target_environ = nullptr;
|
||||
const char *target_string = nullptr;
|
||||
bool rdynamic = false;
|
||||
const char *mmacosx_version_min = nullptr;
|
||||
const char *mios_version_min = nullptr;
|
||||
@ -379,6 +419,7 @@ int main(int argc, char **argv) {
|
||||
ZigList<const char *> rpath_list = {0};
|
||||
bool each_lib_rpath = false;
|
||||
ZigList<const char *> objects = {0};
|
||||
ZigList<CFile *> c_source_files = {0};
|
||||
ZigList<const char *> asm_files = {0};
|
||||
const char *test_filter = nullptr;
|
||||
const char *test_name_prefix = nullptr;
|
||||
@ -392,11 +433,11 @@ int main(int argc, char **argv) {
|
||||
BuildMode build_mode = BuildModeDebug;
|
||||
ZigList<const char *> test_exec_args = {0};
|
||||
int runtime_args_start = -1;
|
||||
bool no_rosegment_workaround = false;
|
||||
bool system_linker_hack = false;
|
||||
TargetSubsystem subsystem = TargetSubsystemAuto;
|
||||
bool is_single_threaded = false;
|
||||
Buf *override_std_dir = nullptr;
|
||||
ValgrindSupport valgrind_support = ValgrindSupportAuto;
|
||||
|
||||
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
|
||||
Buf zig_exe_path_buf = BUF_INIT;
|
||||
@ -432,8 +473,11 @@ int main(int argc, char **argv) {
|
||||
Buf *build_runner_path = buf_alloc();
|
||||
os_path_join(get_zig_special_dir(), buf_create_from_str("build_runner.zig"), build_runner_path);
|
||||
|
||||
CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
|
||||
override_std_dir);
|
||||
ZigTarget target;
|
||||
get_native_target(&target);
|
||||
CodeGen *g = codegen_create(build_runner_path, &target, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
|
||||
override_std_dir, nullptr);
|
||||
g->valgrind_support = valgrind_support;
|
||||
g->enable_time_report = timing_info;
|
||||
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
|
||||
codegen_set_out_name(g, buf_create_from_str("build"));
|
||||
@ -484,6 +528,7 @@ int main(int argc, char **argv) {
|
||||
" --verbose-ir Enable compiler debug output for Zig IR\n"
|
||||
" --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"
|
||||
" --verbose-cimport Enable compiler debug output for C imports\n"
|
||||
" --verbose-cc Enable compiler debug output for C compilation\n"
|
||||
"\n"
|
||||
, zig_exe_path);
|
||||
return EXIT_SUCCESS;
|
||||
@ -493,7 +538,7 @@ int main(int argc, char **argv) {
|
||||
"No 'build.zig' file found.\n"
|
||||
"Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n"
|
||||
"or build an executable directly with `zig build-exe $FILENAME.zig`.\n"
|
||||
"See: `zig build --help` or `zig help` for more options.\n"
|
||||
"See: `zig build --help` or `zig --help` for more options.\n"
|
||||
);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@ -515,6 +560,37 @@ int main(int argc, char **argv) {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
return (term.how == TerminationIdClean) ? term.code : -1;
|
||||
} else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) {
|
||||
init_all_targets();
|
||||
ZigTarget target;
|
||||
get_native_target(&target);
|
||||
Buf *fmt_runner_path = buf_alloc();
|
||||
os_path_join(get_zig_special_dir(), buf_create_from_str("fmt_runner.zig"), fmt_runner_path);
|
||||
CodeGen *g = codegen_create(fmt_runner_path, &target, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
|
||||
nullptr, nullptr);
|
||||
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
|
||||
g->valgrind_support = valgrind_support;
|
||||
g->is_single_threaded = true;
|
||||
codegen_set_out_name(g, buf_create_from_str("fmt"));
|
||||
g->enable_cache = true;
|
||||
|
||||
codegen_build_and_link(g);
|
||||
|
||||
// TODO standardize os.cpp so that the args are supposed to have the exe
|
||||
ZigList<const char*> args_with_exe = {0};
|
||||
ZigList<const char*> args_without_exe = {0};
|
||||
const char *exec_path = buf_ptr(&g->output_file_path);
|
||||
args_with_exe.append(exec_path);
|
||||
for (int i = 2; i < argc; i += 1) {
|
||||
args_with_exe.append(argv[i]);
|
||||
args_without_exe.append(argv[i]);
|
||||
}
|
||||
args_with_exe.append(nullptr);
|
||||
os_execv(exec_path, args_with_exe.items);
|
||||
|
||||
Termination term;
|
||||
os_spawn_process(exec_path, args_without_exe, &term);
|
||||
return term.code;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
@ -527,6 +603,12 @@ int main(int argc, char **argv) {
|
||||
build_mode = BuildModeSafeRelease;
|
||||
} else if (strcmp(arg, "--release-small") == 0) {
|
||||
build_mode = BuildModeSmallRelease;
|
||||
} else if (strcmp(arg, "--help") == 0) {
|
||||
if (cmd == CmdLibC) {
|
||||
return print_libc_usage(arg0, stdout, EXIT_SUCCESS);
|
||||
} else {
|
||||
return print_full_usage(arg0, stdout, EXIT_SUCCESS);
|
||||
}
|
||||
} else if (strcmp(arg, "--strip") == 0) {
|
||||
strip = true;
|
||||
} else if (strcmp(arg, "--static") == 0) {
|
||||
@ -543,16 +625,20 @@ int main(int argc, char **argv) {
|
||||
verbose_llvm_ir = true;
|
||||
} else if (strcmp(arg, "--verbose-cimport") == 0) {
|
||||
verbose_cimport = true;
|
||||
} else if (strcmp(arg, "--verbose-cc") == 0) {
|
||||
verbose_cc = true;
|
||||
} else if (strcmp(arg, "-rdynamic") == 0) {
|
||||
rdynamic = true;
|
||||
} else if (strcmp(arg, "--no-rosegment") == 0) {
|
||||
no_rosegment_workaround = true;
|
||||
} else if (strcmp(arg, "--each-lib-rpath") == 0) {
|
||||
each_lib_rpath = true;
|
||||
} else if (strcmp(arg, "-ftime-report") == 0) {
|
||||
timing_info = true;
|
||||
} else if (strcmp(arg, "--disable-pic") == 0) {
|
||||
disable_pic = true;
|
||||
} else if (strcmp(arg, "--enable-valgrind") == 0) {
|
||||
valgrind_support = ValgrindSupportEnabled;
|
||||
} else if (strcmp(arg, "--disable-valgrind") == 0) {
|
||||
valgrind_support = ValgrindSupportDisabled;
|
||||
} else if (strcmp(arg, "--system-linker-hack") == 0) {
|
||||
system_linker_hack = true;
|
||||
} else if (strcmp(arg, "--single-threaded") == 0) {
|
||||
@ -590,6 +676,8 @@ int main(int argc, char **argv) {
|
||||
out_file = argv[i];
|
||||
} else if (strcmp(arg, "--output-h") == 0) {
|
||||
out_file_h = argv[i];
|
||||
} else if (strcmp(arg, "--output-lib") == 0) {
|
||||
out_file_lib = argv[i];
|
||||
} else if (strcmp(arg, "--color") == 0) {
|
||||
if (strcmp(argv[i], "auto") == 0) {
|
||||
color = ErrColorAuto;
|
||||
@ -625,18 +713,8 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
} else if (strcmp(arg, "--name") == 0) {
|
||||
out_name = argv[i];
|
||||
} else if (strcmp(arg, "--libc-lib-dir") == 0) {
|
||||
libc_lib_dir = argv[i];
|
||||
} else if (strcmp(arg, "--libc-static-lib-dir") == 0) {
|
||||
libc_static_lib_dir = argv[i];
|
||||
} else if (strcmp(arg, "--libc-include-dir") == 0) {
|
||||
libc_include_dir = argv[i];
|
||||
} else if (strcmp(arg, "--msvc-lib-dir") == 0) {
|
||||
msvc_lib_dir = argv[i];
|
||||
} else if (strcmp(arg, "--kernel32-lib-dir") == 0) {
|
||||
kernel32_lib_dir = argv[i];
|
||||
} else if (strcmp(arg, "--dynamic-linker") == 0) {
|
||||
dynamic_linker = argv[i];
|
||||
} else if (strcmp(arg, "--libc") == 0) {
|
||||
libc_txt = argv[i];
|
||||
} else if (strcmp(arg, "-isystem") == 0) {
|
||||
clang_argv.append("-isystem");
|
||||
clang_argv.append(argv[i]);
|
||||
@ -658,16 +736,25 @@ int main(int argc, char **argv) {
|
||||
forbidden_link_libs.append(argv[i]);
|
||||
} else if (strcmp(arg, "--object") == 0) {
|
||||
objects.append(argv[i]);
|
||||
} else if (strcmp(arg, "--c-source") == 0) {
|
||||
CFile *c_file = allocate<CFile>(1);
|
||||
for (;;) {
|
||||
if (argv[i][0] == '-') {
|
||||
c_file->args.append(argv[i]);
|
||||
i += 1;
|
||||
continue;
|
||||
} else {
|
||||
c_file->source_path = argv[i];
|
||||
c_source_files.append(c_file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(arg, "--assembly") == 0) {
|
||||
asm_files.append(argv[i]);
|
||||
} else if (strcmp(arg, "--cache-dir") == 0) {
|
||||
cache_dir = argv[i];
|
||||
} else if (strcmp(arg, "--target-arch") == 0) {
|
||||
target_arch = argv[i];
|
||||
} else if (strcmp(arg, "--target-os") == 0) {
|
||||
target_os = argv[i];
|
||||
} else if (strcmp(arg, "--target-environ") == 0) {
|
||||
target_environ = argv[i];
|
||||
} else if (strcmp(arg, "-target") == 0) {
|
||||
target_string = argv[i];
|
||||
} else if (strcmp(arg, "-mmacosx-version-min") == 0) {
|
||||
mmacosx_version_min = argv[i];
|
||||
} else if (strcmp(arg, "-mios-version-min") == 0) {
|
||||
@ -736,8 +823,6 @@ int main(int argc, char **argv) {
|
||||
} else if (strcmp(arg, "build-lib") == 0) {
|
||||
cmd = CmdBuild;
|
||||
out_type = OutTypeLib;
|
||||
} else if (strcmp(arg, "help") == 0) {
|
||||
cmd = CmdHelp;
|
||||
} else if (strcmp(arg, "run") == 0) {
|
||||
cmd = CmdRun;
|
||||
out_type = OutTypeExe;
|
||||
@ -745,6 +830,8 @@ int main(int argc, char **argv) {
|
||||
cmd = CmdVersion;
|
||||
} else if (strcmp(arg, "zen") == 0) {
|
||||
cmd = CmdZen;
|
||||
} else if (strcmp(arg, "libc") == 0) {
|
||||
cmd = CmdLibC;
|
||||
} else if (strcmp(arg, "translate-c") == 0) {
|
||||
cmd = CmdTranslateC;
|
||||
} else if (strcmp(arg, "test") == 0) {
|
||||
@ -764,6 +851,7 @@ int main(int argc, char **argv) {
|
||||
case CmdRun:
|
||||
case CmdTranslateC:
|
||||
case CmdTest:
|
||||
case CmdLibC:
|
||||
if (!in_file) {
|
||||
in_file = arg;
|
||||
if (cmd == CmdRun) {
|
||||
@ -776,7 +864,6 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
break;
|
||||
case CmdBuiltin:
|
||||
case CmdHelp:
|
||||
case CmdVersion:
|
||||
case CmdZen:
|
||||
case CmdTargets:
|
||||
@ -795,36 +882,34 @@ int main(int argc, char **argv) {
|
||||
|
||||
init_all_targets();
|
||||
|
||||
ZigTarget alloc_target;
|
||||
ZigTarget *target;
|
||||
if (!target_arch && !target_os && !target_environ) {
|
||||
target = nullptr;
|
||||
ZigTarget target;
|
||||
if (target_string == nullptr) {
|
||||
get_native_target(&target);
|
||||
} else {
|
||||
target = &alloc_target;
|
||||
get_unknown_target(target);
|
||||
if (target_arch) {
|
||||
if (parse_target_arch(target_arch, &target->arch)) {
|
||||
fprintf(stderr, "invalid --target-arch argument\n");
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
}
|
||||
if (target_os) {
|
||||
if (parse_target_os(target_os, &target->os)) {
|
||||
fprintf(stderr, "invalid --target-os argument\n");
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
}
|
||||
if (target_environ) {
|
||||
if (parse_target_environ(target_environ, &target->env_type)) {
|
||||
fprintf(stderr, "invalid --target-environ argument\n");
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
if ((err = target_parse_triple(&target, target_string))) {
|
||||
fprintf(stderr, "invalid target: %s\n", err_str(err));
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case CmdLibC: {
|
||||
if (in_file) {
|
||||
ZigLibCInstallation libc;
|
||||
if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true)))
|
||||
return EXIT_FAILURE;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
ZigLibCInstallation libc;
|
||||
if ((err = zig_libc_find_native(&libc, true)))
|
||||
return EXIT_FAILURE;
|
||||
zig_libc_render(&libc, stdout);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
case CmdBuiltin: {
|
||||
CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir(), override_std_dir);
|
||||
CodeGen *g = codegen_create(nullptr, &target, out_type, build_mode, get_zig_lib_dir(), override_std_dir,
|
||||
nullptr);
|
||||
g->valgrind_support = valgrind_support;
|
||||
g->is_single_threaded = is_single_threaded;
|
||||
Buf *builtin_source = codegen_generate_builtin_source(g);
|
||||
if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
|
||||
@ -838,15 +923,43 @@ int main(int argc, char **argv) {
|
||||
case CmdTranslateC:
|
||||
case CmdTest:
|
||||
{
|
||||
if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
|
||||
fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
|
||||
if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0 &&
|
||||
c_source_files.length == 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Expected at least one of these things:\n"
|
||||
" * Zig root source file argument\n"
|
||||
" * --object argument\n"
|
||||
" * --assembly argument\n"
|
||||
" * --c-source argument\n");
|
||||
return print_error_usage(arg0);
|
||||
} else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
|
||||
fprintf(stderr, "Expected source file argument.\n");
|
||||
return print_error_usage(arg0);
|
||||
} else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
|
||||
fprintf(stderr, "When building an object file, --object arguments are invalid.\n");
|
||||
return print_error_usage(arg0);
|
||||
} else if (cmd == CmdBuild && out_type == OutTypeObj) {
|
||||
if (objects.length != 0) {
|
||||
fprintf(stderr,
|
||||
"When building an object file, --object arguments are invalid.\n"
|
||||
"Consider building a static library instead.\n");
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
size_t zig_root_src_count = in_file ? 1 : 0;
|
||||
if (zig_root_src_count + c_source_files.length > 1) {
|
||||
fprintf(stderr,
|
||||
"When building an object file, only one of these allowed:\n"
|
||||
" * Zig root source file argument\n"
|
||||
" * --c-source argument\n"
|
||||
"Consider building a static library instead.\n");
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
if (c_source_files.length != 0 && asm_files.length != 0) {
|
||||
fprintf(stderr,
|
||||
"When building an object file, only one of these allowed:\n"
|
||||
" * --assembly argument\n"
|
||||
" * --c-source argument\n"
|
||||
"Consider building a static library instead.\n");
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
}
|
||||
|
||||
assert(cmd != CmdBuild || out_type != OutTypeUnknown);
|
||||
@ -873,6 +986,13 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (need_name && buf_out_name == nullptr && c_source_files.length == 1) {
|
||||
Buf basename = BUF_INIT;
|
||||
os_path_split(buf_create_from_str(c_source_files.at(0)->source_path), nullptr, &basename);
|
||||
buf_out_name = buf_alloc();
|
||||
os_path_extname(&basename, buf_out_name, nullptr);
|
||||
}
|
||||
|
||||
if (need_name && buf_out_name == nullptr) {
|
||||
fprintf(stderr, "--name [name] not provided and unable to infer\n\n");
|
||||
return print_error_usage(arg0);
|
||||
@ -883,8 +1003,17 @@ int main(int argc, char **argv) {
|
||||
if (cmd == CmdRun && buf_out_name == nullptr) {
|
||||
buf_out_name = buf_create_from_str("run");
|
||||
}
|
||||
CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir(),
|
||||
override_std_dir);
|
||||
ZigLibCInstallation *libc = nullptr;
|
||||
if (libc_txt != nullptr) {
|
||||
libc = allocate<ZigLibCInstallation>(1);
|
||||
if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) {
|
||||
fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
CodeGen *g = codegen_create(zig_root_source_file, &target, out_type, build_mode, get_zig_lib_dir(),
|
||||
override_std_dir, libc);
|
||||
g->valgrind_support = valgrind_support;
|
||||
g->subsystem = subsystem;
|
||||
|
||||
if (disable_pic) {
|
||||
@ -909,24 +1038,13 @@ int main(int argc, char **argv) {
|
||||
codegen_set_llvm_argv(g, llvm_argv.items, llvm_argv.length);
|
||||
codegen_set_strip(g, strip);
|
||||
codegen_set_is_static(g, is_static);
|
||||
if (libc_lib_dir)
|
||||
codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir));
|
||||
if (libc_static_lib_dir)
|
||||
codegen_set_libc_static_lib_dir(g, buf_create_from_str(libc_static_lib_dir));
|
||||
if (libc_include_dir)
|
||||
codegen_set_libc_include_dir(g, buf_create_from_str(libc_include_dir));
|
||||
if (msvc_lib_dir)
|
||||
codegen_set_msvc_lib_dir(g, buf_create_from_str(msvc_lib_dir));
|
||||
if (kernel32_lib_dir)
|
||||
codegen_set_kernel32_lib_dir(g, buf_create_from_str(kernel32_lib_dir));
|
||||
if (dynamic_linker)
|
||||
codegen_set_dynamic_linker(g, buf_create_from_str(dynamic_linker));
|
||||
g->verbose_tokenize = verbose_tokenize;
|
||||
g->verbose_ast = verbose_ast;
|
||||
g->verbose_link = verbose_link;
|
||||
g->verbose_ir = verbose_ir;
|
||||
g->verbose_llvm_ir = verbose_llvm_ir;
|
||||
g->verbose_cimport = verbose_cimport;
|
||||
g->verbose_cc = verbose_cc;
|
||||
codegen_set_errmsg_color(g, color);
|
||||
g->system_linker_hack = system_linker_hack;
|
||||
|
||||
@ -949,7 +1067,6 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
codegen_set_rdynamic(g, rdynamic);
|
||||
g->no_rosegment_workaround = no_rosegment_workaround;
|
||||
if (mmacosx_version_min && mios_version_min) {
|
||||
fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
|
||||
return EXIT_FAILURE;
|
||||
@ -975,11 +1092,14 @@ int main(int argc, char **argv) {
|
||||
codegen_set_output_path(g, buf_create_from_str(out_file));
|
||||
if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib))
|
||||
codegen_set_output_h_path(g, buf_create_from_str(out_file_h));
|
||||
if (out_file_lib != nullptr && out_type == OutTypeLib && !is_static)
|
||||
codegen_set_output_lib_path(g, buf_create_from_str(out_file_lib));
|
||||
|
||||
|
||||
add_package(g, cur_pkg, g->root_package);
|
||||
|
||||
if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
|
||||
g->c_source_files = c_source_files;
|
||||
for (size_t i = 0; i < objects.length; i += 1) {
|
||||
codegen_add_object(g, buf_create_from_str(objects.at(i)));
|
||||
}
|
||||
@ -1052,7 +1172,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!target_can_exec(&native, target)) {
|
||||
if (!target_can_exec(&native, &target)) {
|
||||
fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",
|
||||
buf_ptr(test_exe_path));
|
||||
return 0;
|
||||
@ -1079,8 +1199,6 @@ int main(int argc, char **argv) {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
case CmdHelp:
|
||||
return print_full_usage(arg0);
|
||||
case CmdVersion:
|
||||
printf("%s\n", ZIG_VERSION_STRING);
|
||||
return EXIT_SUCCESS;
|
||||
@ -1090,7 +1208,6 @@ int main(int argc, char **argv) {
|
||||
case CmdTargets:
|
||||
return print_target_list(stdout);
|
||||
case CmdNone:
|
||||
fprintf(stderr, "Zig programming language\n");
|
||||
return print_error_usage(arg0);
|
||||
return print_full_usage(arg0, stderr, EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
47
src/os.cpp
47
src/os.cpp
@ -50,11 +50,11 @@ typedef SSIZE_T ssize_t;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD)
|
||||
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
#if defined(ZIG_OS_FREEBSD)
|
||||
#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
@ -78,7 +78,7 @@ static clock_serv_t cclock;
|
||||
#if defined(__APPLE__) && !defined(environ)
|
||||
#include <crt_externs.h>
|
||||
#define environ (*_NSGetEnviron())
|
||||
#elif defined(ZIG_OS_FREEBSD)
|
||||
#elif defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
@ -1099,7 +1099,7 @@ Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
|
||||
case EINTR:
|
||||
return ErrorInterrupted;
|
||||
case EINVAL:
|
||||
zig_unreachable();
|
||||
return ErrorInvalidFilename;
|
||||
case ENFILE:
|
||||
case ENOMEM:
|
||||
return ErrorSystemResources;
|
||||
@ -1232,6 +1232,18 @@ static Error os_buf_to_tmp_file_posix(Buf *contents, Buf *suffix, Buf *out_tmp_p
|
||||
}
|
||||
#endif
|
||||
|
||||
Buf *os_tmp_filename(Buf *prefix, Buf *suffix) {
|
||||
Buf *result = buf_create_from_buf(prefix);
|
||||
|
||||
const char base64[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
|
||||
assert(array_length(base64) == 64 + 1);
|
||||
for (size_t i = 0; i < 12; i += 1) {
|
||||
buf_append_char(result, base64[rand() % 64]);
|
||||
}
|
||||
buf_append_buf(result, suffix);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
static Error os_buf_to_tmp_file_windows(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
|
||||
char tmp_dir[MAX_PATH + 1];
|
||||
@ -1458,6 +1470,15 @@ Error os_self_exe_path(Buf *out_path) {
|
||||
}
|
||||
buf_resize(out_path, cb - 1);
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_NETBSD)
|
||||
buf_resize(out_path, PATH_MAX);
|
||||
int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME };
|
||||
size_t cb = PATH_MAX;
|
||||
if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) {
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
buf_resize(out_path, cb - 1);
|
||||
return ErrorNone;
|
||||
#endif
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
@ -1541,7 +1562,7 @@ void os_stderr_set_color(TermColor color) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
|
||||
Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
buf_resize(output_buf, 0);
|
||||
buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr);
|
||||
@ -1562,7 +1583,7 @@ int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
|
||||
buf_init_from_buf(tmp_buf, output_buf);
|
||||
buf_append_str(tmp_buf, "ucrt.lib");
|
||||
if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
else {
|
||||
buf_resize(output_buf, 0);
|
||||
@ -1573,12 +1594,12 @@ int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
|
||||
#endif
|
||||
}
|
||||
|
||||
int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
|
||||
Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
buf_resize(output_buf, 0);
|
||||
buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr);
|
||||
if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
else {
|
||||
buf_resize(output_buf, 0);
|
||||
@ -1589,7 +1610,7 @@ int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
|
||||
Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
{
|
||||
buf_resize(output_buf, 0);
|
||||
@ -1611,7 +1632,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
|
||||
buf_init_from_buf(tmp_buf, output_buf);
|
||||
buf_append_str(tmp_buf, "kernel32.lib");
|
||||
if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -1634,7 +1655,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
|
||||
buf_init_from_buf(tmp_buf, output_buf);
|
||||
buf_append_str(tmp_buf, "kernel32.lib");
|
||||
if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
}
|
||||
return ErrorFileNotFound;
|
||||
@ -1776,7 +1797,7 @@ Error os_get_app_data_dir(Buf *out_path, const char *appname) {
|
||||
}
|
||||
|
||||
|
||||
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD)
|
||||
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
|
||||
static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, void *data) {
|
||||
ZigList<Buf *> *libs = reinterpret_cast< ZigList<Buf *> *>(data);
|
||||
if (info->dlpi_name[0] == '/') {
|
||||
@ -1787,7 +1808,7 @@ static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size,
|
||||
#endif
|
||||
|
||||
Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {
|
||||
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD)
|
||||
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
|
||||
paths.resize(0);
|
||||
dl_iterate_phdr(self_exe_shared_libs_callback, &paths);
|
||||
return ErrorNone;
|
||||
|
@ -25,6 +25,8 @@
|
||||
#define ZIG_OS_LINUX
|
||||
#elif defined(__FreeBSD__)
|
||||
#define ZIG_OS_FREEBSD
|
||||
#elif defined(__NetBSD__)
|
||||
#define ZIG_OS_NETBSD
|
||||
#else
|
||||
#define ZIG_OS_UNKNOWN
|
||||
#endif
|
||||
@ -119,6 +121,7 @@ Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd);
|
||||
bool os_stderr_tty(void);
|
||||
void os_stderr_set_color(TermColor color);
|
||||
|
||||
Buf *os_tmp_filename(Buf *prefix, Buf *suffix);
|
||||
Error os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
|
||||
Error os_delete_file(Buf *path);
|
||||
|
||||
@ -133,9 +136,9 @@ Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname);
|
||||
|
||||
int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
|
||||
int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
|
||||
Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);
|
||||
|
||||
|
@ -2739,6 +2739,7 @@ static AstNode *ast_parse_async_prefix(ParseContext *pc) {
|
||||
|
||||
AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async);
|
||||
res->data.fn_call_expr.is_async = true;
|
||||
res->data.fn_call_expr.seen = false;
|
||||
if (eat_token_if(pc, TokenIdCmpLessThan) != nullptr) {
|
||||
AstNode *prefix_expr = ast_expect(pc, ast_parse_prefix_expr);
|
||||
expect_token(pc, TokenIdCmpGreaterThan);
|
||||
@ -2759,6 +2760,7 @@ static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc) {
|
||||
|
||||
AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, paren);
|
||||
res->data.fn_call_expr.params = params;
|
||||
res->data.fn_call_expr.seen = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -2778,7 +2780,8 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) {
|
||||
// PtrTypeStart
|
||||
// <- ASTERISK
|
||||
// / ASTERISK2
|
||||
// / LBRACKET ASTERISK RBRACKET
|
||||
// / PTRUNKNOWN
|
||||
// / PTRC
|
||||
static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
|
||||
Token *asterisk = eat_token_if(pc, TokenIdStar);
|
||||
if (asterisk != nullptr) {
|
||||
@ -2804,6 +2807,13 @@ static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Token *cptr = eat_token_if(pc, TokenIdBracketStarCBracket);
|
||||
if (cptr != nullptr) {
|
||||
AstNode *res = ast_create_node(pc, NodeTypePointerType, cptr);
|
||||
res->data.pointer_type.star_token = cptr;
|
||||
return res;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
941
src/target.cpp
941
src/target.cpp
File diff suppressed because it is too large
Load Diff
@ -12,11 +12,6 @@
|
||||
|
||||
struct Buf;
|
||||
|
||||
struct ArchType {
|
||||
ZigLLVM_ArchType arch;
|
||||
ZigLLVM_SubArchType sub_arch;
|
||||
};
|
||||
|
||||
// Synchronize with target.cpp::os_list
|
||||
enum Os {
|
||||
OsFreestanding,
|
||||
@ -57,6 +52,15 @@ enum Os {
|
||||
OsUefi,
|
||||
};
|
||||
|
||||
// Synchronize with target.cpp::subarch_list_list
|
||||
enum SubArchList {
|
||||
SubArchListNone,
|
||||
SubArchListArm32,
|
||||
SubArchListArm64,
|
||||
SubArchListKalimba,
|
||||
SubArchListMips,
|
||||
};
|
||||
|
||||
enum TargetSubsystem {
|
||||
TargetSubsystemAuto, // Zig should infer the subsystem
|
||||
TargetSubsystemConsole,
|
||||
@ -70,11 +74,12 @@ enum TargetSubsystem {
|
||||
};
|
||||
|
||||
struct ZigTarget {
|
||||
ArchType arch;
|
||||
ZigLLVM_ArchType arch;
|
||||
ZigLLVM_SubArchType sub_arch;
|
||||
ZigLLVM_VendorType vendor;
|
||||
Os os;
|
||||
ZigLLVM_EnvironmentType env_type;
|
||||
ZigLLVM_ObjectFormatType oformat;
|
||||
ZigLLVM_EnvironmentType abi;
|
||||
bool is_native;
|
||||
};
|
||||
|
||||
enum CIntType {
|
||||
@ -90,53 +95,71 @@ enum CIntType {
|
||||
CIntTypeCount,
|
||||
};
|
||||
|
||||
size_t target_arch_count(void);
|
||||
const ArchType *get_target_arch(size_t index);
|
||||
void get_arch_name(char *out_str, const ArchType *arch);
|
||||
Error target_parse_triple(ZigTarget *target, const char *triple);
|
||||
Error target_parse_archsub(ZigLLVM_ArchType *arch, ZigLLVM_SubArchType *sub,
|
||||
const char *archsub_ptr, size_t archsub_len);
|
||||
Error target_parse_os(Os *os, const char *os_ptr, size_t os_len);
|
||||
Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len);
|
||||
|
||||
const char *arch_stack_pointer_register_name(const ArchType *arch);
|
||||
size_t target_arch_count(void);
|
||||
ZigLLVM_ArchType target_arch_enum(size_t index);
|
||||
const char *target_arch_name(ZigLLVM_ArchType arch);
|
||||
|
||||
SubArchList target_subarch_list(ZigLLVM_ArchType arch);
|
||||
size_t target_subarch_count(SubArchList sub_arch_list);
|
||||
ZigLLVM_SubArchType target_subarch_enum(SubArchList subarch_list, size_t index);
|
||||
const char *target_subarch_name(ZigLLVM_SubArchType subarch);
|
||||
|
||||
size_t target_subarch_list_count(void);
|
||||
SubArchList target_subarch_list_enum(size_t index);
|
||||
const char *target_subarch_list_name(SubArchList sub_arch_list);
|
||||
|
||||
const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch);
|
||||
|
||||
size_t target_vendor_count(void);
|
||||
ZigLLVM_VendorType get_target_vendor(size_t index);
|
||||
ZigLLVM_VendorType target_vendor_enum(size_t index);
|
||||
|
||||
size_t target_os_count(void);
|
||||
Os get_target_os(size_t index);
|
||||
const char *get_target_os_name(Os os_type);
|
||||
Os target_os_enum(size_t index);
|
||||
const char *target_os_name(Os os_type);
|
||||
|
||||
size_t target_environ_count(void);
|
||||
ZigLLVM_EnvironmentType get_target_environ(size_t index);
|
||||
size_t target_abi_count(void);
|
||||
ZigLLVM_EnvironmentType target_abi_enum(size_t index);
|
||||
const char *target_abi_name(ZigLLVM_EnvironmentType abi);
|
||||
ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os);
|
||||
|
||||
|
||||
size_t target_oformat_count(void);
|
||||
const ZigLLVM_ObjectFormatType get_target_oformat(size_t index);
|
||||
const char *get_target_oformat_name(ZigLLVM_ObjectFormatType oformat);
|
||||
ZigLLVM_ObjectFormatType target_oformat_enum(size_t index);
|
||||
const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat);
|
||||
ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target);
|
||||
|
||||
void get_native_target(ZigTarget *target);
|
||||
void get_unknown_target(ZigTarget *target);
|
||||
|
||||
int parse_target_arch(const char *str, ArchType *arch);
|
||||
int parse_target_os(const char *str, Os *os);
|
||||
int parse_target_environ(const char *str, ZigLLVM_EnvironmentType *env_type);
|
||||
void get_target_triple(Buf *triple, const ZigTarget *target);
|
||||
|
||||
void init_all_targets(void);
|
||||
|
||||
void get_target_triple(Buf *triple, const ZigTarget *target);
|
||||
|
||||
void resolve_target_object_format(ZigTarget *target);
|
||||
|
||||
uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id);
|
||||
|
||||
const char *target_o_file_ext(ZigTarget *target);
|
||||
const char *target_asm_file_ext(ZigTarget *target);
|
||||
const char *target_llvm_ir_file_ext(ZigTarget *target);
|
||||
const char *target_exe_file_ext(ZigTarget *target);
|
||||
const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch);
|
||||
const char *target_o_file_ext(const ZigTarget *target);
|
||||
const char *target_asm_file_ext(const ZigTarget *target);
|
||||
const char *target_llvm_ir_file_ext(const ZigTarget *target);
|
||||
const char *target_exe_file_ext(const ZigTarget *target);
|
||||
const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
|
||||
size_t version_major, size_t version_minor, size_t version_patch);
|
||||
|
||||
Buf *target_dynamic_linker(ZigTarget *target);
|
||||
const char *target_dynamic_linker(const ZigTarget *target);
|
||||
|
||||
bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);
|
||||
ZigLLVM_OSType get_llvm_os_type(Os os_type);
|
||||
|
||||
bool target_is_arm(const ZigTarget *target);
|
||||
bool target_allows_addr_zero(const ZigTarget *target);
|
||||
bool target_has_valgrind_support(const ZigTarget *target);
|
||||
bool target_is_darwin(const ZigTarget *target);
|
||||
bool target_requires_libc(const ZigTarget *target);
|
||||
bool target_supports_fpic(const ZigTarget *target);
|
||||
|
||||
#endif
|
||||
|
@ -221,6 +221,7 @@ enum TokenizeState {
|
||||
TokenizeStateError,
|
||||
TokenizeStateLBracket,
|
||||
TokenizeStateLBracketStar,
|
||||
TokenizeStateLBracketStarC,
|
||||
};
|
||||
|
||||
|
||||
@ -846,7 +847,6 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
switch (c) {
|
||||
case '*':
|
||||
t.state = TokenizeStateLBracketStar;
|
||||
set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
|
||||
break;
|
||||
default:
|
||||
// reinterpret as just an lbracket
|
||||
@ -857,6 +857,21 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
}
|
||||
break;
|
||||
case TokenizeStateLBracketStar:
|
||||
switch (c) {
|
||||
case 'c':
|
||||
t.state = TokenizeStateLBracketStarC;
|
||||
set_token_id(&t, t.cur_tok, TokenIdBracketStarCBracket);
|
||||
break;
|
||||
case ']':
|
||||
set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
invalid_char_error(&t, c);
|
||||
}
|
||||
break;
|
||||
case TokenizeStateLBracketStarC:
|
||||
switch (c) {
|
||||
case ']':
|
||||
end_token(&t);
|
||||
@ -1491,6 +1506,7 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
case TokenizeStateLineStringContinue:
|
||||
case TokenizeStateLineStringContinueC:
|
||||
case TokenizeStateLBracketStar:
|
||||
case TokenizeStateLBracketStarC:
|
||||
tokenize_error(&t, "unexpected EOF");
|
||||
break;
|
||||
case TokenizeStateLineComment:
|
||||
@ -1528,6 +1544,7 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdBitShiftRightEq: return ">>=";
|
||||
case TokenIdBitXorEq: return "^=";
|
||||
case TokenIdBracketStarBracket: return "[*]";
|
||||
case TokenIdBracketStarCBracket: return "[*c]";
|
||||
case TokenIdCharLiteral: return "CharLiteral";
|
||||
case TokenIdCmpEq: return "==";
|
||||
case TokenIdCmpGreaterOrEq: return ">=";
|
||||
|
@ -29,6 +29,7 @@ enum TokenId {
|
||||
TokenIdBitShiftRightEq,
|
||||
TokenIdBitXorEq,
|
||||
TokenIdBracketStarBracket,
|
||||
TokenIdBracketStarCBracket,
|
||||
TokenIdCharLiteral,
|
||||
TokenIdCmpEq,
|
||||
TokenIdCmpGreaterOrEq,
|
||||
|
2638
src/translate_c.cpp
2638
src/translate_c.cpp
File diff suppressed because it is too large
Load Diff
11
src/util.hpp
11
src/util.hpp
@ -147,11 +147,14 @@ static inline T clamp(T min_value, T value, T max_value) {
|
||||
return max(min(value, max_value), min_value);
|
||||
}
|
||||
|
||||
static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) {
|
||||
size_t str_len = strlen(str);
|
||||
if (str_len != mem_len)
|
||||
static inline bool mem_eql_mem(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) {
|
||||
if (a_len != b_len)
|
||||
return false;
|
||||
return memcmp(mem, str, mem_len) == 0;
|
||||
return memcmp(a_ptr, b_ptr, a_len) == 0;
|
||||
}
|
||||
|
||||
static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) {
|
||||
return mem_eql_mem(mem, mem_len, str, strlen(str));
|
||||
}
|
||||
|
||||
static inline bool is_power_of_2(uint64_t x) {
|
||||
|
214
src/zig_clang.cpp
Normal file
214
src/zig_clang.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The point of this file is to contain all the Clang C++ API interaction so that:
|
||||
* 1. The compile time of other files is kept under control.
|
||||
* 2. Provide a C interface to the Clang functions we need for self-hosting purposes.
|
||||
* 3. Prevent C++ from infecting the rest of the project.
|
||||
*/
|
||||
#include "zig_clang.h"
|
||||
|
||||
#if __GNUC__ >= 8
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||
#endif
|
||||
|
||||
#include <clang/Frontend/ASTUnit.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/AST/Expr.h>
|
||||
|
||||
#if __GNUC__ >= 8
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// Detect additions to the enum
|
||||
void zig2clang_BO(ZigClangBO op) {
|
||||
switch (op) {
|
||||
case ZigClangBO_PtrMemD:
|
||||
case ZigClangBO_PtrMemI:
|
||||
case ZigClangBO_Cmp:
|
||||
case ZigClangBO_Mul:
|
||||
case ZigClangBO_Div:
|
||||
case ZigClangBO_Rem:
|
||||
case ZigClangBO_Add:
|
||||
case ZigClangBO_Sub:
|
||||
case ZigClangBO_Shl:
|
||||
case ZigClangBO_Shr:
|
||||
case ZigClangBO_LT:
|
||||
case ZigClangBO_GT:
|
||||
case ZigClangBO_LE:
|
||||
case ZigClangBO_GE:
|
||||
case ZigClangBO_EQ:
|
||||
case ZigClangBO_NE:
|
||||
case ZigClangBO_And:
|
||||
case ZigClangBO_Xor:
|
||||
case ZigClangBO_Or:
|
||||
case ZigClangBO_LAnd:
|
||||
case ZigClangBO_LOr:
|
||||
case ZigClangBO_Assign:
|
||||
case ZigClangBO_Comma:
|
||||
case ZigClangBO_MulAssign:
|
||||
case ZigClangBO_DivAssign:
|
||||
case ZigClangBO_RemAssign:
|
||||
case ZigClangBO_AddAssign:
|
||||
case ZigClangBO_SubAssign:
|
||||
case ZigClangBO_ShlAssign:
|
||||
case ZigClangBO_ShrAssign:
|
||||
case ZigClangBO_AndAssign:
|
||||
case ZigClangBO_XorAssign:
|
||||
case ZigClangBO_OrAssign:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Add == clang::BO_Add, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_AddAssign == clang::BO_AddAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_And == clang::BO_And, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_AndAssign == clang::BO_AndAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Assign == clang::BO_Assign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Cmp == clang::BO_Cmp, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Comma == clang::BO_Comma, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Div == clang::BO_Div, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_DivAssign == clang::BO_DivAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_EQ == clang::BO_EQ, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_GE == clang::BO_GE, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_GT == clang::BO_GT, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_LAnd == clang::BO_LAnd, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_LE == clang::BO_LE, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_LOr == clang::BO_LOr, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_LT == clang::BO_LT, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Mul == clang::BO_Mul, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_MulAssign == clang::BO_MulAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_NE == clang::BO_NE, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Or == clang::BO_Or, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_OrAssign == clang::BO_OrAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_PtrMemD == clang::BO_PtrMemD, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_PtrMemI == clang::BO_PtrMemI, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Rem == clang::BO_Rem, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_RemAssign == clang::BO_RemAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Shl == clang::BO_Shl, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_ShlAssign == clang::BO_ShlAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Shr == clang::BO_Shr, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_ShrAssign == clang::BO_ShrAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Sub == clang::BO_Sub, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_SubAssign == clang::BO_SubAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Xor == clang::BO_Xor, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_XorAssign == clang::BO_XorAssign, "");
|
||||
|
||||
// This function detects additions to the enum
|
||||
void zig2clang_UO(ZigClangUO op) {
|
||||
switch (op) {
|
||||
case ZigClangUO_AddrOf:
|
||||
case ZigClangUO_Coawait:
|
||||
case ZigClangUO_Deref:
|
||||
case ZigClangUO_Extension:
|
||||
case ZigClangUO_Imag:
|
||||
case ZigClangUO_LNot:
|
||||
case ZigClangUO_Minus:
|
||||
case ZigClangUO_Not:
|
||||
case ZigClangUO_Plus:
|
||||
case ZigClangUO_PostDec:
|
||||
case ZigClangUO_PostInc:
|
||||
case ZigClangUO_PreDec:
|
||||
case ZigClangUO_PreInc:
|
||||
case ZigClangUO_Real:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_AddrOf == clang::UO_AddrOf, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Coawait == clang::UO_Coawait, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Deref == clang::UO_Deref, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Extension == clang::UO_Extension, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Imag == clang::UO_Imag, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_LNot == clang::UO_LNot, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Minus == clang::UO_Minus, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Not == clang::UO_Not, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Plus == clang::UO_Plus, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_PostDec == clang::UO_PostDec, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_PostInc == clang::UO_PostInc, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_PreDec == clang::UO_PreDec, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_PreInc == clang::UO_PreInc, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Real == clang::UO_Real, "");
|
||||
|
||||
static_assert(sizeof(ZigClangSourceLocation) == sizeof(clang::SourceLocation), "");
|
||||
static ZigClangSourceLocation bitcast(clang::SourceLocation src) {
|
||||
ZigClangSourceLocation dest;
|
||||
memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangSourceLocation));
|
||||
return dest;
|
||||
}
|
||||
static clang::SourceLocation bitcast(ZigClangSourceLocation src) {
|
||||
clang::SourceLocation dest;
|
||||
memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangSourceLocation));
|
||||
return dest;
|
||||
}
|
||||
|
||||
static_assert(sizeof(ZigClangQualType) == sizeof(clang::QualType), "");
|
||||
static ZigClangQualType bitcast(clang::QualType src) {
|
||||
ZigClangQualType dest;
|
||||
memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangQualType));
|
||||
return dest;
|
||||
}
|
||||
static clang::QualType bitcast(ZigClangQualType src) {
|
||||
clang::QualType dest;
|
||||
memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangQualType));
|
||||
return dest;
|
||||
}
|
||||
|
||||
ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *self,
|
||||
ZigClangSourceLocation Loc)
|
||||
{
|
||||
return bitcast(reinterpret_cast<const clang::SourceManager *>(self)->getSpellingLoc(bitcast(Loc)));
|
||||
}
|
||||
|
||||
const char *ZigClangSourceManager_getFilename(const ZigClangSourceManager *self,
|
||||
ZigClangSourceLocation SpellingLoc)
|
||||
{
|
||||
StringRef s = reinterpret_cast<const clang::SourceManager *>(self)->getFilename(bitcast(SpellingLoc));
|
||||
return (const char *)s.bytes_begin();
|
||||
}
|
||||
|
||||
unsigned ZigClangSourceManager_getSpellingLineNumber(const ZigClangSourceManager *self,
|
||||
ZigClangSourceLocation Loc)
|
||||
{
|
||||
return reinterpret_cast<const clang::SourceManager *>(self)->getSpellingLineNumber(bitcast(Loc));
|
||||
}
|
||||
|
||||
unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigClangSourceManager *self,
|
||||
ZigClangSourceLocation Loc)
|
||||
{
|
||||
return reinterpret_cast<const clang::SourceManager *>(self)->getSpellingColumnNumber(bitcast(Loc));
|
||||
}
|
||||
|
||||
const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *self,
|
||||
ZigClangSourceLocation SL)
|
||||
{
|
||||
return reinterpret_cast<const clang::SourceManager *>(self)->getCharacterData(bitcast(SL));
|
||||
}
|
||||
|
||||
ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext* self, ZigClangQualType T) {
|
||||
return bitcast(reinterpret_cast<const clang::ASTContext *>(self)->getPointerType(bitcast(T)));
|
||||
}
|
||||
|
||||
ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *self) {
|
||||
clang::ASTContext *result = &reinterpret_cast<clang::ASTUnit *>(self)->getASTContext();
|
||||
return reinterpret_cast<ZigClangASTContext *>(result);
|
||||
}
|
||||
|
||||
ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *self) {
|
||||
clang::SourceManager *result = &reinterpret_cast<clang::ASTUnit *>(self)->getSourceManager();
|
||||
return reinterpret_cast<ZigClangSourceManager *>(result);
|
||||
}
|
||||
|
||||
bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *self, void *context,
|
||||
bool (*Fn)(void *context, const ZigClangDecl *decl))
|
||||
{
|
||||
return reinterpret_cast<clang::ASTUnit *>(self)->visitLocalTopLevelDecls(context,
|
||||
reinterpret_cast<bool (*)(void *, const clang::Decl *)>(Fn));
|
||||
}
|
259
src/zig_clang.h
Normal file
259
src/zig_clang.h
Normal file
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_ZIG_CLANG_H
|
||||
#define ZIG_ZIG_CLANG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define ZIG_EXTERN_C extern "C"
|
||||
#else
|
||||
#define ZIG_EXTERN_C
|
||||
#endif
|
||||
|
||||
// ATTENTION: If you modify this file, be sure to update the corresponding
|
||||
// extern function declarations in the self-hosted compiler.
|
||||
|
||||
struct ZigClangSourceLocation {
|
||||
unsigned ID;
|
||||
};
|
||||
|
||||
struct ZigClangQualType {
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
struct ZigClangAPValue;
|
||||
struct ZigClangASTContext;
|
||||
struct ZigClangASTUnit;
|
||||
struct ZigClangArraySubscriptExpr;
|
||||
struct ZigClangArrayType;
|
||||
struct ZigClangAttributedType;
|
||||
struct ZigClangBinaryOperator;
|
||||
struct ZigClangBreakStmt;
|
||||
struct ZigClangBuiltinType;
|
||||
struct ZigClangCStyleCastExpr;
|
||||
struct ZigClangCallExpr;
|
||||
struct ZigClangCaseStmt;
|
||||
struct ZigClangCompoundAssignOperator;
|
||||
struct ZigClangCompoundStmt;
|
||||
struct ZigClangConditionalOperator;
|
||||
struct ZigClangConstantArrayType;
|
||||
struct ZigClangContinueStmt;
|
||||
struct ZigClangDecayedType;
|
||||
struct ZigClangDecl;
|
||||
struct ZigClangDeclRefExpr;
|
||||
struct ZigClangDeclStmt;
|
||||
struct ZigClangDefaultStmt;
|
||||
struct ZigClangDiagnosticOptions;
|
||||
struct ZigClangDiagnosticsEngine;
|
||||
struct ZigClangDoStmt;
|
||||
struct ZigClangElaboratedType;
|
||||
struct ZigClangEnumConstantDecl;
|
||||
struct ZigClangEnumDecl;
|
||||
struct ZigClangEnumType;
|
||||
struct ZigClangExpr;
|
||||
struct ZigClangFieldDecl;
|
||||
struct ZigClangFileID;
|
||||
struct ZigClangForStmt;
|
||||
struct ZigClangFullSourceLoc;
|
||||
struct ZigClangFunctionDecl;
|
||||
struct ZigClangFunctionProtoType;
|
||||
struct ZigClangIfStmt;
|
||||
struct ZigClangImplicitCastExpr;
|
||||
struct ZigClangIncompleteArrayType;
|
||||
struct ZigClangIntegerLiteral;
|
||||
struct ZigClangMacroDefinitionRecord;
|
||||
struct ZigClangMemberExpr;
|
||||
struct ZigClangNamedDecl;
|
||||
struct ZigClangNone;
|
||||
struct ZigClangPCHContainerOperations;
|
||||
struct ZigClangParenExpr;
|
||||
struct ZigClangParenType;
|
||||
struct ZigClangParmVarDecl;
|
||||
struct ZigClangPointerType;
|
||||
struct ZigClangPreprocessedEntity;
|
||||
struct ZigClangRecordDecl;
|
||||
struct ZigClangRecordType;
|
||||
struct ZigClangReturnStmt;
|
||||
struct ZigClangSkipFunctionBodiesScope;
|
||||
struct ZigClangSourceManager;
|
||||
struct ZigClangSourceRange;
|
||||
struct ZigClangStmt;
|
||||
struct ZigClangStorageClass;
|
||||
struct ZigClangStringLiteral;
|
||||
struct ZigClangStringRef;
|
||||
struct ZigClangSwitchStmt;
|
||||
struct ZigClangType;
|
||||
struct ZigClangTypedefNameDecl;
|
||||
struct ZigClangTypedefType;
|
||||
struct ZigClangUnaryExprOrTypeTraitExpr;
|
||||
struct ZigClangUnaryOperator;
|
||||
struct ZigClangValueDecl;
|
||||
struct ZigClangVarDecl;
|
||||
struct ZigClangWhileStmt;
|
||||
|
||||
enum ZigClangBO {
|
||||
ZigClangBO_PtrMemD,
|
||||
ZigClangBO_PtrMemI,
|
||||
ZigClangBO_Mul,
|
||||
ZigClangBO_Div,
|
||||
ZigClangBO_Rem,
|
||||
ZigClangBO_Add,
|
||||
ZigClangBO_Sub,
|
||||
ZigClangBO_Shl,
|
||||
ZigClangBO_Shr,
|
||||
ZigClangBO_Cmp,
|
||||
ZigClangBO_LT,
|
||||
ZigClangBO_GT,
|
||||
ZigClangBO_LE,
|
||||
ZigClangBO_GE,
|
||||
ZigClangBO_EQ,
|
||||
ZigClangBO_NE,
|
||||
ZigClangBO_And,
|
||||
ZigClangBO_Xor,
|
||||
ZigClangBO_Or,
|
||||
ZigClangBO_LAnd,
|
||||
ZigClangBO_LOr,
|
||||
ZigClangBO_Assign,
|
||||
ZigClangBO_MulAssign,
|
||||
ZigClangBO_DivAssign,
|
||||
ZigClangBO_RemAssign,
|
||||
ZigClangBO_AddAssign,
|
||||
ZigClangBO_SubAssign,
|
||||
ZigClangBO_ShlAssign,
|
||||
ZigClangBO_ShrAssign,
|
||||
ZigClangBO_AndAssign,
|
||||
ZigClangBO_XorAssign,
|
||||
ZigClangBO_OrAssign,
|
||||
ZigClangBO_Comma,
|
||||
};
|
||||
|
||||
enum ZigClangUO {
|
||||
ZigClangUO_PostInc,
|
||||
ZigClangUO_PostDec,
|
||||
ZigClangUO_PreInc,
|
||||
ZigClangUO_PreDec,
|
||||
ZigClangUO_AddrOf,
|
||||
ZigClangUO_Deref,
|
||||
ZigClangUO_Plus,
|
||||
ZigClangUO_Minus,
|
||||
ZigClangUO_Not,
|
||||
ZigClangUO_LNot,
|
||||
ZigClangUO_Real,
|
||||
ZigClangUO_Imag,
|
||||
ZigClangUO_Extension,
|
||||
ZigClangUO_Coawait,
|
||||
};
|
||||
|
||||
//struct ZigClangCC_AAPCS;
|
||||
//struct ZigClangCC_AAPCS_VFP;
|
||||
//struct ZigClangCC_C;
|
||||
//struct ZigClangCC_IntelOclBicc;
|
||||
//struct ZigClangCC_OpenCLKernel;
|
||||
//struct ZigClangCC_PreserveAll;
|
||||
//struct ZigClangCC_PreserveMost;
|
||||
//struct ZigClangCC_SpirFunction;
|
||||
//struct ZigClangCC_Swift;
|
||||
//struct ZigClangCC_Win64;
|
||||
//struct ZigClangCC_X86FastCall;
|
||||
//struct ZigClangCC_X86Pascal;
|
||||
//struct ZigClangCC_X86RegCall;
|
||||
//struct ZigClangCC_X86StdCall;
|
||||
//struct ZigClangCC_X86ThisCall;
|
||||
//struct ZigClangCC_X86VectorCall;
|
||||
//struct ZigClangCC_X86_64SysV;
|
||||
|
||||
//struct ZigClangCK_ARCConsumeObject;
|
||||
//struct ZigClangCK_ARCExtendBlockObject;
|
||||
//struct ZigClangCK_ARCProduceObject;
|
||||
//struct ZigClangCK_ARCReclaimReturnedObject;
|
||||
//struct ZigClangCK_AddressSpaceConversion;
|
||||
//struct ZigClangCK_AnyPointerToBlockPointerCast;
|
||||
//struct ZigClangCK_ArrayToPointerDecay;
|
||||
//struct ZigClangCK_AtomicToNonAtomic;
|
||||
//struct ZigClangCK_BaseToDerived;
|
||||
//struct ZigClangCK_BaseToDerivedMemberPointer;
|
||||
//struct ZigClangCK_BitCast;
|
||||
//struct ZigClangCK_BlockPointerToObjCPointerCast;
|
||||
//struct ZigClangCK_BooleanToSignedIntegral;
|
||||
//struct ZigClangCK_BuiltinFnToFnPtr;
|
||||
//struct ZigClangCK_CPointerToObjCPointerCast;
|
||||
//struct ZigClangCK_ConstructorConversion;
|
||||
//struct ZigClangCK_CopyAndAutoreleaseBlockObject;
|
||||
//struct ZigClangCK_Dependent;
|
||||
//struct ZigClangCK_DerivedToBase;
|
||||
//struct ZigClangCK_DerivedToBaseMemberPointer;
|
||||
//struct ZigClangCK_Dynamic;
|
||||
//struct ZigClangCK_FloatingCast;
|
||||
//struct ZigClangCK_FloatingComplexCast;
|
||||
//struct ZigClangCK_FloatingComplexToBoolean;
|
||||
//struct ZigClangCK_FloatingComplexToIntegralComplex;
|
||||
//struct ZigClangCK_FloatingComplexToReal;
|
||||
//struct ZigClangCK_FloatingRealToComplex;
|
||||
//struct ZigClangCK_FloatingToBoolean;
|
||||
//struct ZigClangCK_FloatingToIntegral;
|
||||
//struct ZigClangCK_FunctionToPointerDecay;
|
||||
//struct ZigClangCK_IntToOCLSampler;
|
||||
//struct ZigClangCK_IntegralCast;
|
||||
//struct ZigClangCK_IntegralComplexCast;
|
||||
//struct ZigClangCK_IntegralComplexToBoolean;
|
||||
//struct ZigClangCK_IntegralComplexToFloatingComplex;
|
||||
//struct ZigClangCK_IntegralComplexToReal;
|
||||
//struct ZigClangCK_IntegralRealToComplex;
|
||||
//struct ZigClangCK_IntegralToBoolean;
|
||||
//struct ZigClangCK_IntegralToFloating;
|
||||
//struct ZigClangCK_IntegralToPointer;
|
||||
//struct ZigClangCK_LValueBitCast;
|
||||
//struct ZigClangCK_LValueToRValue;
|
||||
//struct ZigClangCK_MemberPointerToBoolean;
|
||||
//struct ZigClangCK_NoOp;
|
||||
//struct ZigClangCK_NonAtomicToAtomic;
|
||||
//struct ZigClangCK_NullToMemberPointer;
|
||||
//struct ZigClangCK_NullToPointer;
|
||||
//struct ZigClangCK_ObjCObjectLValueCast;
|
||||
//struct ZigClangCK_PointerToBoolean;
|
||||
//struct ZigClangCK_PointerToIntegral;
|
||||
//struct ZigClangCK_ReinterpretMemberPointer;
|
||||
//struct ZigClangCK_ToUnion;
|
||||
//struct ZigClangCK_ToVoid;
|
||||
//struct ZigClangCK_UncheckedDerivedToBase;
|
||||
//struct ZigClangCK_UserDefinedConversion;
|
||||
//struct ZigClangCK_VectorSplat;
|
||||
//struct ZigClangCK_ZeroToOCLEvent;
|
||||
//struct ZigClangCK_ZeroToOCLQueue;
|
||||
|
||||
//struct ZigClangETK_Class;
|
||||
//struct ZigClangETK_Enum;
|
||||
//struct ZigClangETK_Interface;
|
||||
//struct ZigClangETK_None;
|
||||
//struct ZigClangETK_Struct;
|
||||
//struct ZigClangETK_Typename;
|
||||
//struct ZigClangETK_Union;
|
||||
|
||||
//struct ZigClangSC_None;
|
||||
//struct ZigClangSC_PrivateExtern;
|
||||
//struct ZigClangSC_Static;
|
||||
|
||||
//struct ZigClangTU_Complete;
|
||||
|
||||
ZIG_EXTERN_C ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *,
|
||||
ZigClangSourceLocation Loc);
|
||||
ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const ZigClangSourceManager *,
|
||||
ZigClangSourceLocation SpellingLoc);
|
||||
ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingLineNumber(const ZigClangSourceManager *,
|
||||
ZigClangSourceLocation Loc);
|
||||
ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigClangSourceManager *,
|
||||
ZigClangSourceLocation Loc);
|
||||
ZIG_EXTERN_C const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *,
|
||||
ZigClangSourceLocation SL);
|
||||
|
||||
ZIG_EXTERN_C ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext*, ZigClangQualType T);
|
||||
|
||||
ZIG_EXTERN_C ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *);
|
||||
ZIG_EXTERN_C ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *);
|
||||
ZIG_EXTERN_C bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *, void *context,
|
||||
bool (*Fn)(void *context, const ZigClangDecl *decl));
|
||||
#endif
|
226
src/zig_clang_cc1_main.cpp
Normal file
226
src/zig_clang_cc1_main.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
//===-- cc1_main.cpp - Clang CC1 Compiler Frontend ------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the entry point to the clang -cc1 functionality, which implements the
|
||||
// core compiler functionality along with a number of additional tools for
|
||||
// demonstration and testing purposes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Option/Arg.h"
|
||||
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
|
||||
#include "clang/Config/config.h"
|
||||
#include "clang/Basic/Stack.h"
|
||||
#include "clang/Driver/DriverDiagnostic.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "clang/Frontend/TextDiagnosticBuffer.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "clang/FrontendTool/Utils.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/LinkAllPasses.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Option/OptTable.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef CLANG_HAVE_RLIMITS
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
using namespace clang;
|
||||
using namespace llvm::opt;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Main driver
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void LLVMErrorHandler(void *UserData, const std::string &Message,
|
||||
bool GenCrashDiag) {
|
||||
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
|
||||
|
||||
Diags.Report(diag::err_fe_error_backend) << Message;
|
||||
|
||||
// Run the interrupt handlers to make sure any special cleanups get done, in
|
||||
// particular that we remove files registered with RemoveFileOnSignal.
|
||||
llvm::sys::RunInterruptHandlers();
|
||||
|
||||
// We cannot recover from llvm errors. When reporting a fatal error, exit
|
||||
// with status 70 to generate crash diagnostics. For BSD systems this is
|
||||
// defined as an internal software error. Otherwise, exit with status 1.
|
||||
exit(GenCrashDiag ? 70 : 1);
|
||||
}
|
||||
|
||||
#ifdef CLANG_HAVE_RLIMITS
|
||||
#if defined(__linux__) && defined(__PIE__)
|
||||
static size_t getCurrentStackAllocation() {
|
||||
// If we can't compute the current stack usage, allow for 512K of command
|
||||
// line arguments and environment.
|
||||
size_t Usage = 512 * 1024;
|
||||
if (FILE *StatFile = fopen("/proc/self/stat", "r")) {
|
||||
// We assume that the stack extends from its current address to the end of
|
||||
// the environment space. In reality, there is another string literal (the
|
||||
// program name) after the environment, but this is close enough (we only
|
||||
// need to be within 100K or so).
|
||||
unsigned long StackPtr, EnvEnd;
|
||||
// Disable silly GCC -Wformat warning that complains about length
|
||||
// modifiers on ignored format specifiers. We want to retain these
|
||||
// for documentation purposes even though they have no effect.
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat"
|
||||
#endif
|
||||
if (fscanf(StatFile,
|
||||
"%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu "
|
||||
"%*lu %*ld %*ld %*ld %*ld %*ld %*ld %*llu %*lu %*ld %*lu %*lu "
|
||||
"%*lu %*lu %lu %*lu %*lu %*lu %*lu %*lu %*llu %*lu %*lu %*d %*d "
|
||||
"%*u %*u %*llu %*lu %*ld %*lu %*lu %*lu %*lu %*lu %*lu %lu %*d",
|
||||
&StackPtr, &EnvEnd) == 2) {
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
Usage = StackPtr < EnvEnd ? EnvEnd - StackPtr : StackPtr - EnvEnd;
|
||||
}
|
||||
fclose(StatFile);
|
||||
}
|
||||
return Usage;
|
||||
}
|
||||
|
||||
#include <alloca.h>
|
||||
|
||||
LLVM_ATTRIBUTE_NOINLINE
|
||||
static void ensureStackAddressSpace() {
|
||||
// Linux kernels prior to 4.1 will sometimes locate the heap of a PIE binary
|
||||
// relatively close to the stack (they are only guaranteed to be 128MiB
|
||||
// apart). This results in crashes if we happen to heap-allocate more than
|
||||
// 128MiB before we reach our stack high-water mark.
|
||||
//
|
||||
// To avoid these crashes, ensure that we have sufficient virtual memory
|
||||
// pages allocated before we start running.
|
||||
size_t Curr = getCurrentStackAllocation();
|
||||
const int kTargetStack = DesiredStackSize - 256 * 1024;
|
||||
if (Curr < kTargetStack) {
|
||||
volatile char *volatile Alloc =
|
||||
static_cast<volatile char *>(alloca(kTargetStack - Curr));
|
||||
Alloc[0] = 0;
|
||||
Alloc[kTargetStack - Curr - 1] = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void ensureStackAddressSpace() {}
|
||||
#endif
|
||||
|
||||
/// Attempt to ensure that we have at least 8MiB of usable stack space.
|
||||
static void ensureSufficientStack() {
|
||||
struct rlimit rlim;
|
||||
if (getrlimit(RLIMIT_STACK, &rlim) != 0)
|
||||
return;
|
||||
|
||||
// Increase the soft stack limit to our desired level, if necessary and
|
||||
// possible.
|
||||
if (rlim.rlim_cur != RLIM_INFINITY &&
|
||||
rlim.rlim_cur < rlim_t(DesiredStackSize)) {
|
||||
// Try to allocate sufficient stack.
|
||||
if (rlim.rlim_max == RLIM_INFINITY ||
|
||||
rlim.rlim_max >= rlim_t(DesiredStackSize))
|
||||
rlim.rlim_cur = DesiredStackSize;
|
||||
else if (rlim.rlim_cur == rlim.rlim_max)
|
||||
return;
|
||||
else
|
||||
rlim.rlim_cur = rlim.rlim_max;
|
||||
|
||||
if (setrlimit(RLIMIT_STACK, &rlim) != 0 ||
|
||||
rlim.rlim_cur != DesiredStackSize)
|
||||
return;
|
||||
}
|
||||
|
||||
// We should now have a stack of size at least DesiredStackSize. Ensure
|
||||
// that we can actually use that much, if necessary.
|
||||
ensureStackAddressSpace();
|
||||
}
|
||||
#else
|
||||
static void ensureSufficientStack() {}
|
||||
#endif
|
||||
|
||||
int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
|
||||
ensureSufficientStack();
|
||||
|
||||
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
|
||||
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
|
||||
// Register the support for object-file-wrapped Clang modules.
|
||||
auto PCHOps = Clang->getPCHContainerOperations();
|
||||
PCHOps->registerWriter(llvm::make_unique<ObjectFilePCHContainerWriter>());
|
||||
PCHOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>());
|
||||
|
||||
// Initialize targets first, so that --version shows registered targets.
|
||||
llvm::InitializeAllTargets();
|
||||
llvm::InitializeAllTargetMCs();
|
||||
llvm::InitializeAllAsmPrinters();
|
||||
llvm::InitializeAllAsmParsers();
|
||||
|
||||
// Buffer diagnostics from argument parsing so that we can output them using a
|
||||
// well formed diagnostic object.
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
||||
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
|
||||
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
|
||||
bool Success = CompilerInvocation::CreateFromArgs(
|
||||
Clang->getInvocation(), Argv.begin(), Argv.end(), Diags);
|
||||
|
||||
// Infer the builtin include path if unspecified.
|
||||
if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
|
||||
Clang->getHeaderSearchOpts().ResourceDir.empty())
|
||||
Clang->getHeaderSearchOpts().ResourceDir =
|
||||
CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
|
||||
|
||||
// Create the actual diagnostics engine.
|
||||
Clang->createDiagnostics();
|
||||
if (!Clang->hasDiagnostics())
|
||||
return 1;
|
||||
|
||||
// Set an error handler, so that any LLVM backend diagnostics go through our
|
||||
// error handler.
|
||||
llvm::install_fatal_error_handler(LLVMErrorHandler,
|
||||
static_cast<void*>(&Clang->getDiagnostics()));
|
||||
|
||||
DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
|
||||
if (!Success)
|
||||
return 1;
|
||||
|
||||
// Execute the frontend actions.
|
||||
Success = ExecuteCompilerInvocation(Clang.get());
|
||||
|
||||
// If any timers were active but haven't been destroyed yet, print their
|
||||
// results now. This happens in -disable-free mode.
|
||||
llvm::TimerGroup::printAll(llvm::errs());
|
||||
|
||||
// Our error handler depends on the Diagnostics object, which we're
|
||||
// potentially about to delete. Uninstall the handler now so that any
|
||||
// later errors use the default handling behavior instead.
|
||||
llvm::remove_fatal_error_handler();
|
||||
|
||||
// When running with -disable-free, don't do any destruction or shutdown.
|
||||
if (Clang->getFrontendOpts().DisableFree) {
|
||||
BuryPointer(std::move(Clang));
|
||||
return !Success;
|
||||
}
|
||||
|
||||
return !Success;
|
||||
}
|
||||
|
573
src/zig_clang_cc1as_main.cpp
Normal file
573
src/zig_clang_cc1as_main.cpp
Normal file
@ -0,0 +1,573 @@
|
||||
//===-- cc1as_main.cpp - Clang Assembler ---------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the entry point to the clang -cc1as functionality, which implements
|
||||
// the direct interface to the LLVM MC based assembler.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Driver/DriverDiagnostic.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/MC/MCAsmBackend.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCCodeEmitter.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCObjectFileInfo.h"
|
||||
#include "llvm/MC/MCObjectWriter.h"
|
||||
#include "llvm/MC/MCParser/MCAsmParser.h"
|
||||
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCTargetOptions.h"
|
||||
#include "llvm/Option/Arg.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Option/OptTable.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
using namespace clang;
|
||||
using namespace clang::driver;
|
||||
using namespace clang::driver::options;
|
||||
using namespace llvm;
|
||||
using namespace llvm::opt;
|
||||
|
||||
namespace {
|
||||
|
||||
/// Helper class for representing a single invocation of the assembler.
|
||||
struct AssemblerInvocation {
|
||||
/// @name Target Options
|
||||
/// @{
|
||||
|
||||
/// The name of the target triple to assemble for.
|
||||
std::string Triple;
|
||||
|
||||
/// If given, the name of the target CPU to determine which instructions
|
||||
/// are legal.
|
||||
std::string CPU;
|
||||
|
||||
/// The list of target specific features to enable or disable -- this should
|
||||
/// be a list of strings starting with '+' or '-'.
|
||||
std::vector<std::string> Features;
|
||||
|
||||
/// The list of symbol definitions.
|
||||
std::vector<std::string> SymbolDefs;
|
||||
|
||||
/// @}
|
||||
/// @name Language Options
|
||||
/// @{
|
||||
|
||||
std::vector<std::string> IncludePaths;
|
||||
unsigned NoInitialTextSection : 1;
|
||||
unsigned SaveTemporaryLabels : 1;
|
||||
unsigned GenDwarfForAssembly : 1;
|
||||
unsigned RelaxELFRelocations : 1;
|
||||
unsigned DwarfVersion;
|
||||
std::string DwarfDebugFlags;
|
||||
std::string DwarfDebugProducer;
|
||||
std::string DebugCompilationDir;
|
||||
std::map<const std::string, const std::string> DebugPrefixMap;
|
||||
llvm::DebugCompressionType CompressDebugSections =
|
||||
llvm::DebugCompressionType::None;
|
||||
std::string MainFileName;
|
||||
std::string SplitDwarfFile;
|
||||
|
||||
/// @}
|
||||
/// @name Frontend Options
|
||||
/// @{
|
||||
|
||||
std::string InputFile;
|
||||
std::vector<std::string> LLVMArgs;
|
||||
std::string OutputPath;
|
||||
enum FileType {
|
||||
FT_Asm, ///< Assembly (.s) output, transliterate mode.
|
||||
FT_Null, ///< No output, for timing purposes.
|
||||
FT_Obj ///< Object file output.
|
||||
};
|
||||
FileType OutputType;
|
||||
unsigned ShowHelp : 1;
|
||||
unsigned ShowVersion : 1;
|
||||
|
||||
/// @}
|
||||
/// @name Transliterate Options
|
||||
/// @{
|
||||
|
||||
unsigned OutputAsmVariant;
|
||||
unsigned ShowEncoding : 1;
|
||||
unsigned ShowInst : 1;
|
||||
|
||||
/// @}
|
||||
/// @name Assembler Options
|
||||
/// @{
|
||||
|
||||
unsigned RelaxAll : 1;
|
||||
unsigned NoExecStack : 1;
|
||||
unsigned FatalWarnings : 1;
|
||||
unsigned IncrementalLinkerCompatible : 1;
|
||||
|
||||
/// The name of the relocation model to use.
|
||||
std::string RelocationModel;
|
||||
|
||||
/// @}
|
||||
|
||||
public:
|
||||
AssemblerInvocation() {
|
||||
Triple = "";
|
||||
NoInitialTextSection = 0;
|
||||
InputFile = "-";
|
||||
OutputPath = "-";
|
||||
OutputType = FT_Asm;
|
||||
OutputAsmVariant = 0;
|
||||
ShowInst = 0;
|
||||
ShowEncoding = 0;
|
||||
RelaxAll = 0;
|
||||
NoExecStack = 0;
|
||||
FatalWarnings = 0;
|
||||
IncrementalLinkerCompatible = 0;
|
||||
DwarfVersion = 0;
|
||||
}
|
||||
|
||||
static bool CreateFromArgs(AssemblerInvocation &Res,
|
||||
ArrayRef<const char *> Argv,
|
||||
DiagnosticsEngine &Diags);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
||||
ArrayRef<const char *> Argv,
|
||||
DiagnosticsEngine &Diags) {
|
||||
bool Success = true;
|
||||
|
||||
// Parse the arguments.
|
||||
std::unique_ptr<OptTable> OptTbl(createDriverOptTable());
|
||||
|
||||
const unsigned IncludedFlagsBitmask = options::CC1AsOption;
|
||||
unsigned MissingArgIndex, MissingArgCount;
|
||||
InputArgList Args = OptTbl->ParseArgs(Argv, MissingArgIndex, MissingArgCount,
|
||||
IncludedFlagsBitmask);
|
||||
|
||||
// Check for missing argument error.
|
||||
if (MissingArgCount) {
|
||||
Diags.Report(diag::err_drv_missing_argument)
|
||||
<< Args.getArgString(MissingArgIndex) << MissingArgCount;
|
||||
Success = false;
|
||||
}
|
||||
|
||||
// Issue errors on unknown arguments.
|
||||
for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
|
||||
auto ArgString = A->getAsString(Args);
|
||||
std::string Nearest;
|
||||
if (OptTbl->findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
|
||||
Diags.Report(diag::err_drv_unknown_argument) << ArgString;
|
||||
else
|
||||
Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
|
||||
<< ArgString << Nearest;
|
||||
Success = false;
|
||||
}
|
||||
|
||||
// Construct the invocation.
|
||||
|
||||
// Target Options
|
||||
Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
|
||||
Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
|
||||
Opts.Features = Args.getAllArgValues(OPT_target_feature);
|
||||
|
||||
// Use the default target triple if unspecified.
|
||||
if (Opts.Triple.empty())
|
||||
Opts.Triple = llvm::sys::getDefaultTargetTriple();
|
||||
|
||||
// Language Options
|
||||
Opts.IncludePaths = Args.getAllArgValues(OPT_I);
|
||||
Opts.NoInitialTextSection = Args.hasArg(OPT_n);
|
||||
Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels);
|
||||
// Any DebugInfoKind implies GenDwarfForAssembly.
|
||||
Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
|
||||
|
||||
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
|
||||
OPT_compress_debug_sections_EQ)) {
|
||||
if (A->getOption().getID() == OPT_compress_debug_sections) {
|
||||
// TODO: be more clever about the compression type auto-detection
|
||||
Opts.CompressDebugSections = llvm::DebugCompressionType::GNU;
|
||||
} else {
|
||||
Opts.CompressDebugSections =
|
||||
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
|
||||
.Case("none", llvm::DebugCompressionType::None)
|
||||
.Case("zlib", llvm::DebugCompressionType::Z)
|
||||
.Case("zlib-gnu", llvm::DebugCompressionType::GNU)
|
||||
.Default(llvm::DebugCompressionType::None);
|
||||
}
|
||||
}
|
||||
|
||||
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
|
||||
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
|
||||
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
|
||||
Opts.DwarfDebugProducer = Args.getLastArgValue(OPT_dwarf_debug_producer);
|
||||
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
|
||||
Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
|
||||
|
||||
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ))
|
||||
Opts.DebugPrefixMap.insert(StringRef(Arg).split('='));
|
||||
|
||||
// Frontend Options
|
||||
if (Args.hasArg(OPT_INPUT)) {
|
||||
bool First = true;
|
||||
for (const Arg *A : Args.filtered(OPT_INPUT)) {
|
||||
if (First) {
|
||||
Opts.InputFile = A->getValue();
|
||||
First = false;
|
||||
} else {
|
||||
Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
|
||||
Success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
|
||||
Opts.OutputPath = Args.getLastArgValue(OPT_o);
|
||||
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
|
||||
if (Arg *A = Args.getLastArg(OPT_filetype)) {
|
||||
StringRef Name = A->getValue();
|
||||
unsigned OutputType = StringSwitch<unsigned>(Name)
|
||||
.Case("asm", FT_Asm)
|
||||
.Case("null", FT_Null)
|
||||
.Case("obj", FT_Obj)
|
||||
.Default(~0U);
|
||||
if (OutputType == ~0U) {
|
||||
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
|
||||
Success = false;
|
||||
} else
|
||||
Opts.OutputType = FileType(OutputType);
|
||||
}
|
||||
Opts.ShowHelp = Args.hasArg(OPT_help);
|
||||
Opts.ShowVersion = Args.hasArg(OPT_version);
|
||||
|
||||
// Transliterate Options
|
||||
Opts.OutputAsmVariant =
|
||||
getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags);
|
||||
Opts.ShowEncoding = Args.hasArg(OPT_show_encoding);
|
||||
Opts.ShowInst = Args.hasArg(OPT_show_inst);
|
||||
|
||||
// Assemble Options
|
||||
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
|
||||
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
|
||||
Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
|
||||
Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
|
||||
Opts.IncrementalLinkerCompatible =
|
||||
Args.hasArg(OPT_mincremental_linker_compatible);
|
||||
Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym);
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
static std::unique_ptr<raw_fd_ostream>
|
||||
getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
|
||||
// Make sure that the Out file gets unlinked from the disk if we get a
|
||||
// SIGINT.
|
||||
if (Path != "-")
|
||||
sys::RemoveFileOnSignal(Path);
|
||||
|
||||
std::error_code EC;
|
||||
auto Out = llvm::make_unique<raw_fd_ostream>(
|
||||
Path, EC, (Binary ? sys::fs::F_None : sys::fs::F_Text));
|
||||
if (EC) {
|
||||
Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Out;
|
||||
}
|
||||
|
||||
static bool ExecuteAssembler(AssemblerInvocation &Opts,
|
||||
DiagnosticsEngine &Diags) {
|
||||
// Get the target specific parser.
|
||||
std::string Error;
|
||||
const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
|
||||
if (!TheTarget)
|
||||
return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
|
||||
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
|
||||
MemoryBuffer::getFileOrSTDIN(Opts.InputFile);
|
||||
|
||||
if (std::error_code EC = Buffer.getError()) {
|
||||
Error = EC.message();
|
||||
return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
|
||||
}
|
||||
|
||||
SourceMgr SrcMgr;
|
||||
|
||||
// Tell SrcMgr about this buffer, which is what the parser will pick up.
|
||||
SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc());
|
||||
|
||||
// Record the location of the include directories so that the lexer can find
|
||||
// it later.
|
||||
SrcMgr.setIncludeDirs(Opts.IncludePaths);
|
||||
|
||||
std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
|
||||
assert(MRI && "Unable to create target register info!");
|
||||
|
||||
std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, Opts.Triple));
|
||||
assert(MAI && "Unable to create target asm info!");
|
||||
|
||||
// Ensure MCAsmInfo initialization occurs before any use, otherwise sections
|
||||
// may be created with a combination of default and explicit settings.
|
||||
MAI->setCompressDebugSections(Opts.CompressDebugSections);
|
||||
|
||||
MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
|
||||
|
||||
bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
|
||||
if (Opts.OutputPath.empty())
|
||||
Opts.OutputPath = "-";
|
||||
std::unique_ptr<raw_fd_ostream> FDOS =
|
||||
getOutputStream(Opts.OutputPath, Diags, IsBinary);
|
||||
if (!FDOS)
|
||||
return true;
|
||||
std::unique_ptr<raw_fd_ostream> DwoOS;
|
||||
if (!Opts.SplitDwarfFile.empty())
|
||||
DwoOS = getOutputStream(Opts.SplitDwarfFile, Diags, IsBinary);
|
||||
|
||||
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
|
||||
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
|
||||
std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
|
||||
|
||||
MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr);
|
||||
|
||||
bool PIC = false;
|
||||
if (Opts.RelocationModel == "static") {
|
||||
PIC = false;
|
||||
} else if (Opts.RelocationModel == "pic") {
|
||||
PIC = true;
|
||||
} else {
|
||||
assert(Opts.RelocationModel == "dynamic-no-pic" &&
|
||||
"Invalid PIC model!");
|
||||
PIC = false;
|
||||
}
|
||||
|
||||
MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx);
|
||||
if (Opts.SaveTemporaryLabels)
|
||||
Ctx.setAllowTemporaryLabels(false);
|
||||
if (Opts.GenDwarfForAssembly)
|
||||
Ctx.setGenDwarfForAssembly(true);
|
||||
if (!Opts.DwarfDebugFlags.empty())
|
||||
Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
|
||||
if (!Opts.DwarfDebugProducer.empty())
|
||||
Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer));
|
||||
if (!Opts.DebugCompilationDir.empty())
|
||||
Ctx.setCompilationDir(Opts.DebugCompilationDir);
|
||||
if (!Opts.DebugPrefixMap.empty())
|
||||
for (const auto &KV : Opts.DebugPrefixMap)
|
||||
Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
|
||||
if (!Opts.MainFileName.empty())
|
||||
Ctx.setMainFileName(StringRef(Opts.MainFileName));
|
||||
Ctx.setDwarfVersion(Opts.DwarfVersion);
|
||||
|
||||
// Build up the feature string from the target feature list.
|
||||
std::string FS;
|
||||
if (!Opts.Features.empty()) {
|
||||
FS = Opts.Features[0];
|
||||
for (unsigned i = 1, e = Opts.Features.size(); i != e; ++i)
|
||||
FS += "," + Opts.Features[i];
|
||||
}
|
||||
|
||||
std::unique_ptr<MCStreamer> Str;
|
||||
|
||||
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
|
||||
std::unique_ptr<MCSubtargetInfo> STI(
|
||||
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
|
||||
|
||||
raw_pwrite_stream *Out = FDOS.get();
|
||||
std::unique_ptr<buffer_ostream> BOS;
|
||||
|
||||
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
|
||||
if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
|
||||
MCInstPrinter *IP = TheTarget->createMCInstPrinter(
|
||||
llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI);
|
||||
|
||||
std::unique_ptr<MCCodeEmitter> CE;
|
||||
if (Opts.ShowEncoding)
|
||||
CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
|
||||
MCTargetOptions MCOptions;
|
||||
std::unique_ptr<MCAsmBackend> MAB(
|
||||
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
|
||||
|
||||
auto FOut = llvm::make_unique<formatted_raw_ostream>(*Out);
|
||||
Str.reset(TheTarget->createAsmStreamer(
|
||||
Ctx, std::move(FOut), /*asmverbose*/ true,
|
||||
/*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB),
|
||||
Opts.ShowInst));
|
||||
} else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
|
||||
Str.reset(createNullStreamer(Ctx));
|
||||
} else {
|
||||
assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
|
||||
"Invalid file type!");
|
||||
if (!FDOS->supportsSeeking()) {
|
||||
BOS = make_unique<buffer_ostream>(*FDOS);
|
||||
Out = BOS.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<MCCodeEmitter> CE(
|
||||
TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
|
||||
MCTargetOptions MCOptions;
|
||||
std::unique_ptr<MCAsmBackend> MAB(
|
||||
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
|
||||
std::unique_ptr<MCObjectWriter> OW =
|
||||
DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
|
||||
: MAB->createObjectWriter(*Out);
|
||||
|
||||
Triple T(Opts.Triple);
|
||||
Str.reset(TheTarget->createMCObjectStreamer(
|
||||
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
|
||||
Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
|
||||
/*DWARFMustBeAtTheEnd*/ true));
|
||||
Str.get()->InitSections(Opts.NoExecStack);
|
||||
}
|
||||
|
||||
// Assembly to object compilation should leverage assembly info.
|
||||
Str->setUseAssemblerInfoForParsing(true);
|
||||
|
||||
bool Failed = false;
|
||||
|
||||
std::unique_ptr<MCAsmParser> Parser(
|
||||
createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
|
||||
|
||||
// FIXME: init MCTargetOptions from sanitizer flags here.
|
||||
MCTargetOptions Options;
|
||||
std::unique_ptr<MCTargetAsmParser> TAP(
|
||||
TheTarget->createMCAsmParser(*STI, *Parser, *MCII, Options));
|
||||
if (!TAP)
|
||||
Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
|
||||
|
||||
// Set values for symbols, if any.
|
||||
for (auto &S : Opts.SymbolDefs) {
|
||||
auto Pair = StringRef(S).split('=');
|
||||
auto Sym = Pair.first;
|
||||
auto Val = Pair.second;
|
||||
int64_t Value;
|
||||
// We have already error checked this in the driver.
|
||||
Val.getAsInteger(0, Value);
|
||||
Ctx.setSymbolValue(Parser->getStreamer(), Sym, Value);
|
||||
}
|
||||
|
||||
if (!Failed) {
|
||||
Parser->setTargetParser(*TAP.get());
|
||||
Failed = Parser->Run(Opts.NoInitialTextSection);
|
||||
}
|
||||
|
||||
// Close Streamer first.
|
||||
// It might have a reference to the output stream.
|
||||
Str.reset();
|
||||
// Close the output stream early.
|
||||
BOS.reset();
|
||||
FDOS.reset();
|
||||
|
||||
// Delete output file if there were errors.
|
||||
if (Failed) {
|
||||
if (Opts.OutputPath != "-")
|
||||
sys::fs::remove(Opts.OutputPath);
|
||||
if (!Opts.SplitDwarfFile.empty() && Opts.SplitDwarfFile != "-")
|
||||
sys::fs::remove(Opts.SplitDwarfFile);
|
||||
}
|
||||
|
||||
return Failed;
|
||||
}
|
||||
|
||||
static void LLVMErrorHandler(void *UserData, const std::string &Message,
|
||||
bool GenCrashDiag) {
|
||||
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
|
||||
|
||||
Diags.Report(diag::err_fe_error_backend) << Message;
|
||||
|
||||
// We cannot recover from llvm errors.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
|
||||
// Initialize targets and assembly printers/parsers.
|
||||
InitializeAllTargetInfos();
|
||||
InitializeAllTargetMCs();
|
||||
InitializeAllAsmParsers();
|
||||
|
||||
// Construct our diagnostic client.
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
||||
TextDiagnosticPrinter *DiagClient
|
||||
= new TextDiagnosticPrinter(errs(), &*DiagOpts);
|
||||
DiagClient->setPrefix("clang -cc1as");
|
||||
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
|
||||
|
||||
// Set an error handler, so that any LLVM backend diagnostics go through our
|
||||
// error handler.
|
||||
ScopedFatalErrorHandler FatalErrorHandler
|
||||
(LLVMErrorHandler, static_cast<void*>(&Diags));
|
||||
|
||||
// Parse the arguments.
|
||||
AssemblerInvocation Asm;
|
||||
if (!AssemblerInvocation::CreateFromArgs(Asm, Argv, Diags))
|
||||
return 1;
|
||||
|
||||
if (Asm.ShowHelp) {
|
||||
std::unique_ptr<OptTable> Opts(driver::createDriverOptTable());
|
||||
Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler",
|
||||
/*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
|
||||
/*ShowAllAliases=*/false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Honor -version.
|
||||
//
|
||||
// FIXME: Use a better -version message?
|
||||
if (Asm.ShowVersion) {
|
||||
llvm::cl::PrintVersionMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Honor -mllvm.
|
||||
//
|
||||
// FIXME: Remove this, one day.
|
||||
if (!Asm.LLVMArgs.empty()) {
|
||||
unsigned NumArgs = Asm.LLVMArgs.size();
|
||||
auto Args = llvm::make_unique<const char*[]>(NumArgs + 2);
|
||||
Args[0] = "clang (LLVM option parsing)";
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
Args[i + 1] = Asm.LLVMArgs[i].c_str();
|
||||
Args[NumArgs + 1] = nullptr;
|
||||
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
|
||||
}
|
||||
|
||||
// Execute the invocation, unless there were parsing errors.
|
||||
bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags);
|
||||
|
||||
// If any timers were active but haven't been destroyed yet, print their
|
||||
// results now.
|
||||
TimerGroup::printAll(errs());
|
||||
|
||||
return !!Failed;
|
||||
}
|
||||
|
513
src/zig_clang_driver.cpp
Normal file
513
src/zig_clang_driver.cpp
Normal file
@ -0,0 +1,513 @@
|
||||
//===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the entry point to the clang driver; it is a thin wrapper
|
||||
// for functionality in the Driver clang library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/DriverDiagnostic.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "clang/Driver/ToolChain.h"
|
||||
#include "clang/Frontend/ChainedDiagnosticConsumer.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/SerializedDiagnosticPrinter.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Option/OptTable.h"
|
||||
#include "llvm/Option/Option.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/StringSaver.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <system_error>
|
||||
using namespace clang;
|
||||
using namespace clang::driver;
|
||||
using namespace llvm::opt;
|
||||
|
||||
std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
|
||||
if (!CanonicalPrefixes) {
|
||||
SmallString<128> ExecutablePath(Argv0);
|
||||
// Do a PATH lookup if Argv0 isn't a valid path.
|
||||
if (!llvm::sys::fs::exists(ExecutablePath))
|
||||
if (llvm::ErrorOr<std::string> P =
|
||||
llvm::sys::findProgramByName(ExecutablePath))
|
||||
ExecutablePath = *P;
|
||||
return ExecutablePath.str();
|
||||
}
|
||||
|
||||
// This just needs to be some symbol in the binary; C++ doesn't
|
||||
// allow taking the address of ::main however.
|
||||
void *P = (void*) (intptr_t) GetExecutablePath;
|
||||
return llvm::sys::fs::getMainExecutable(Argv0, P);
|
||||
}
|
||||
|
||||
static const char *GetStableCStr(std::set<std::string> &SavedStrings,
|
||||
StringRef S) {
|
||||
return SavedStrings.insert(S).first->c_str();
|
||||
}
|
||||
|
||||
/// ApplyQAOverride - Apply a list of edits to the input argument lists.
|
||||
///
|
||||
/// The input string is a space separate list of edits to perform,
|
||||
/// they are applied in order to the input argument lists. Edits
|
||||
/// should be one of the following forms:
|
||||
///
|
||||
/// '#': Silence information about the changes to the command line arguments.
|
||||
///
|
||||
/// '^': Add FOO as a new argument at the beginning of the command line.
|
||||
///
|
||||
/// '+': Add FOO as a new argument at the end of the command line.
|
||||
///
|
||||
/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
|
||||
/// line.
|
||||
///
|
||||
/// 'xOPTION': Removes all instances of the literal argument OPTION.
|
||||
///
|
||||
/// 'XOPTION': Removes all instances of the literal argument OPTION,
|
||||
/// and the following argument.
|
||||
///
|
||||
/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
|
||||
/// at the end of the command line.
|
||||
///
|
||||
/// \param OS - The stream to write edit information to.
|
||||
/// \param Args - The vector of command line arguments.
|
||||
/// \param Edit - The override command to perform.
|
||||
/// \param SavedStrings - Set to use for storing string representations.
|
||||
static void ApplyOneQAOverride(raw_ostream &OS,
|
||||
SmallVectorImpl<const char*> &Args,
|
||||
StringRef Edit,
|
||||
std::set<std::string> &SavedStrings) {
|
||||
// This does not need to be efficient.
|
||||
|
||||
if (Edit[0] == '^') {
|
||||
const char *Str =
|
||||
GetStableCStr(SavedStrings, Edit.substr(1));
|
||||
OS << "### Adding argument " << Str << " at beginning\n";
|
||||
Args.insert(Args.begin() + 1, Str);
|
||||
} else if (Edit[0] == '+') {
|
||||
const char *Str =
|
||||
GetStableCStr(SavedStrings, Edit.substr(1));
|
||||
OS << "### Adding argument " << Str << " at end\n";
|
||||
Args.push_back(Str);
|
||||
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
|
||||
Edit.slice(2, Edit.size()-1).find('/') != StringRef::npos) {
|
||||
StringRef MatchPattern = Edit.substr(2).split('/').first;
|
||||
StringRef ReplPattern = Edit.substr(2).split('/').second;
|
||||
ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
|
||||
|
||||
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
|
||||
// Ignore end-of-line response file markers
|
||||
if (Args[i] == nullptr)
|
||||
continue;
|
||||
std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
|
||||
|
||||
if (Repl != Args[i]) {
|
||||
OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
|
||||
Args[i] = GetStableCStr(SavedStrings, Repl);
|
||||
}
|
||||
}
|
||||
} else if (Edit[0] == 'x' || Edit[0] == 'X') {
|
||||
auto Option = Edit.substr(1);
|
||||
for (unsigned i = 1; i < Args.size();) {
|
||||
if (Option == Args[i]) {
|
||||
OS << "### Deleting argument " << Args[i] << '\n';
|
||||
Args.erase(Args.begin() + i);
|
||||
if (Edit[0] == 'X') {
|
||||
if (i < Args.size()) {
|
||||
OS << "### Deleting argument " << Args[i] << '\n';
|
||||
Args.erase(Args.begin() + i);
|
||||
} else
|
||||
OS << "### Invalid X edit, end of command line!\n";
|
||||
}
|
||||
} else
|
||||
++i;
|
||||
}
|
||||
} else if (Edit[0] == 'O') {
|
||||
for (unsigned i = 1; i < Args.size();) {
|
||||
const char *A = Args[i];
|
||||
// Ignore end-of-line response file markers
|
||||
if (A == nullptr)
|
||||
continue;
|
||||
if (A[0] == '-' && A[1] == 'O' &&
|
||||
(A[2] == '\0' ||
|
||||
(A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
|
||||
('0' <= A[2] && A[2] <= '9'))))) {
|
||||
OS << "### Deleting argument " << Args[i] << '\n';
|
||||
Args.erase(Args.begin() + i);
|
||||
} else
|
||||
++i;
|
||||
}
|
||||
OS << "### Adding argument " << Edit << " at end\n";
|
||||
Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
|
||||
} else {
|
||||
OS << "### Unrecognized edit: " << Edit << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/// ApplyQAOverride - Apply a comma separate list of edits to the
|
||||
/// input argument lists. See ApplyOneQAOverride.
|
||||
static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
|
||||
const char *OverrideStr,
|
||||
std::set<std::string> &SavedStrings) {
|
||||
raw_ostream *OS = &llvm::errs();
|
||||
|
||||
if (OverrideStr[0] == '#') {
|
||||
++OverrideStr;
|
||||
OS = &llvm::nulls();
|
||||
}
|
||||
|
||||
*OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
|
||||
|
||||
// This does not need to be efficient.
|
||||
|
||||
const char *S = OverrideStr;
|
||||
while (*S) {
|
||||
const char *End = ::strchr(S, ' ');
|
||||
if (!End)
|
||||
End = S + strlen(S);
|
||||
if (End != S)
|
||||
ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
|
||||
S = End;
|
||||
if (*S != '\0')
|
||||
++S;
|
||||
}
|
||||
}
|
||||
|
||||
extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
|
||||
void *MainAddr);
|
||||
extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
|
||||
void *MainAddr);
|
||||
|
||||
static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
|
||||
SmallVectorImpl<const char *> &ArgVector,
|
||||
std::set<std::string> &SavedStrings) {
|
||||
// Put target and mode arguments at the start of argument list so that
|
||||
// arguments specified in command line could override them. Avoid putting
|
||||
// them at index 0, as an option like '-cc1' must remain the first.
|
||||
int InsertionPoint = 0;
|
||||
if (ArgVector.size() > 0)
|
||||
++InsertionPoint;
|
||||
|
||||
if (NameParts.DriverMode) {
|
||||
// Add the mode flag to the arguments.
|
||||
ArgVector.insert(ArgVector.begin() + InsertionPoint,
|
||||
GetStableCStr(SavedStrings, NameParts.DriverMode));
|
||||
}
|
||||
|
||||
if (NameParts.TargetIsValid) {
|
||||
const char *arr[] = {"-target", GetStableCStr(SavedStrings,
|
||||
NameParts.TargetPrefix)};
|
||||
ArgVector.insert(ArgVector.begin() + InsertionPoint,
|
||||
std::begin(arr), std::end(arr));
|
||||
}
|
||||
}
|
||||
|
||||
static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver,
|
||||
SmallVectorImpl<const char *> &Opts) {
|
||||
llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts);
|
||||
// The first instance of '#' should be replaced with '=' in each option.
|
||||
for (const char *Opt : Opts)
|
||||
if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#')))
|
||||
*NumberSignPtr = '=';
|
||||
}
|
||||
|
||||
static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
|
||||
// Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
|
||||
TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
|
||||
if (TheDriver.CCPrintOptions)
|
||||
TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
|
||||
|
||||
// Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE.
|
||||
TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS");
|
||||
if (TheDriver.CCPrintHeaders)
|
||||
TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
|
||||
|
||||
// Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
|
||||
TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
|
||||
if (TheDriver.CCLogDiagnostics)
|
||||
TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
|
||||
}
|
||||
|
||||
static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
|
||||
const std::string &Path) {
|
||||
// If the clang binary happens to be named cl.exe for compatibility reasons,
|
||||
// use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
|
||||
StringRef ExeBasename(llvm::sys::path::filename(Path));
|
||||
if (ExeBasename.equals_lower("cl.exe"))
|
||||
ExeBasename = "clang-cl.exe";
|
||||
DiagClient->setPrefix(ExeBasename);
|
||||
}
|
||||
|
||||
// This lets us create the DiagnosticsEngine with a properly-filled-out
|
||||
// DiagnosticOptions instance.
|
||||
static DiagnosticOptions *
|
||||
CreateAndPopulateDiagOpts(ArrayRef<const char *> argv) {
|
||||
auto *DiagOpts = new DiagnosticOptions;
|
||||
std::unique_ptr<OptTable> Opts(createDriverOptTable());
|
||||
unsigned MissingArgIndex, MissingArgCount;
|
||||
InputArgList Args =
|
||||
Opts->ParseArgs(argv.slice(1), MissingArgIndex, MissingArgCount);
|
||||
// We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
|
||||
// Any errors that would be diagnosed here will also be diagnosed later,
|
||||
// when the DiagnosticsEngine actually exists.
|
||||
(void)ParseDiagnosticArgs(*DiagOpts, Args);
|
||||
return DiagOpts;
|
||||
}
|
||||
|
||||
static void SetInstallDir(SmallVectorImpl<const char *> &argv,
|
||||
Driver &TheDriver, bool CanonicalPrefixes) {
|
||||
// Attempt to find the original path used to invoke the driver, to determine
|
||||
// the installed path. We do this manually, because we want to support that
|
||||
// path being a symlink.
|
||||
SmallString<128> InstalledPath(argv[0]);
|
||||
|
||||
// Do a PATH lookup, if there are no directory components.
|
||||
if (llvm::sys::path::filename(InstalledPath) == InstalledPath)
|
||||
if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName(
|
||||
llvm::sys::path::filename(InstalledPath.str())))
|
||||
InstalledPath = *Tmp;
|
||||
|
||||
// FIXME: We don't actually canonicalize this, we just make it absolute.
|
||||
if (CanonicalPrefixes)
|
||||
llvm::sys::fs::make_absolute(InstalledPath);
|
||||
|
||||
StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath));
|
||||
if (llvm::sys::fs::exists(InstalledPathParent))
|
||||
TheDriver.setInstalledDir(InstalledPathParent);
|
||||
}
|
||||
|
||||
static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
|
||||
void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath;
|
||||
if (Tool == "")
|
||||
return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP);
|
||||
if (Tool == "as")
|
||||
return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP);
|
||||
|
||||
// Reject unknown tools.
|
||||
llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
|
||||
<< "Valid tools include '-cc1' and '-cc1as'.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" int ZigClang_main(int argc_, const char **argv_);
|
||||
int ZigClang_main(int argc_, const char **argv_) {
|
||||
llvm::InitLLVM X(argc_, argv_);
|
||||
size_t argv_offset = (strcmp(argv_[1], "-cc1") == 0 || strcmp(argv_[1], "-cc1as") == 0) ? 0 : 1;
|
||||
SmallVector<const char *, 256> argv(argv_ + argv_offset, argv_ + argc_);
|
||||
|
||||
if (llvm::sys::Process::FixupStandardFileDescriptors())
|
||||
return 1;
|
||||
|
||||
llvm::InitializeAllTargets();
|
||||
auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]);
|
||||
|
||||
llvm::BumpPtrAllocator A;
|
||||
llvm::StringSaver Saver(A);
|
||||
|
||||
// Parse response files using the GNU syntax, unless we're in CL mode. There
|
||||
// are two ways to put clang in CL compatibility mode: argv[0] is either
|
||||
// clang-cl or cl, or --driver-mode=cl is on the command line. The normal
|
||||
// command line parsing can't happen until after response file parsing, so we
|
||||
// have to manually search for a --driver-mode=cl argument the hard way.
|
||||
// Finally, our -cc1 tools don't care which tokenization mode we use because
|
||||
// response files written by clang will tokenize the same way in either mode.
|
||||
bool ClangCLMode = false;
|
||||
if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") ||
|
||||
std::find_if(argv.begin(), argv.end(), [](const char *F) {
|
||||
return F && strcmp(F, "--driver-mode=cl") == 0;
|
||||
}) != argv.end()) {
|
||||
ClangCLMode = true;
|
||||
}
|
||||
enum { Default, POSIX, Windows } RSPQuoting = Default;
|
||||
for (const char *F : argv) {
|
||||
if (strcmp(F, "--rsp-quoting=posix") == 0)
|
||||
RSPQuoting = POSIX;
|
||||
else if (strcmp(F, "--rsp-quoting=windows") == 0)
|
||||
RSPQuoting = Windows;
|
||||
}
|
||||
|
||||
// Determines whether we want nullptr markers in argv to indicate response
|
||||
// files end-of-lines. We only use this for the /LINK driver argument with
|
||||
// clang-cl.exe on Windows.
|
||||
bool MarkEOLs = ClangCLMode;
|
||||
|
||||
llvm::cl::TokenizerCallback Tokenizer;
|
||||
if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode))
|
||||
Tokenizer = &llvm::cl::TokenizeWindowsCommandLine;
|
||||
else
|
||||
Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
|
||||
|
||||
if (MarkEOLs && argv.size() > 1 && StringRef(argv[1]).startswith("-cc1"))
|
||||
MarkEOLs = false;
|
||||
llvm::cl::ExpandResponseFiles(Saver, Tokenizer, argv, MarkEOLs);
|
||||
|
||||
// Handle -cc1 integrated tools, even if -cc1 was expanded from a response
|
||||
// file.
|
||||
auto FirstArg = std::find_if(argv.begin() + 1, argv.end(),
|
||||
[](const char *A) { return A != nullptr; });
|
||||
if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) {
|
||||
// If -cc1 came from a response file, remove the EOL sentinels.
|
||||
if (MarkEOLs) {
|
||||
auto newEnd = std::remove(argv.begin(), argv.end(), nullptr);
|
||||
argv.resize(newEnd - argv.begin());
|
||||
}
|
||||
return ExecuteCC1Tool(argv, argv[1] + 4);
|
||||
}
|
||||
|
||||
bool CanonicalPrefixes = true;
|
||||
for (int i = 1, size = argv.size(); i < size; ++i) {
|
||||
// Skip end-of-line response file markers
|
||||
if (argv[i] == nullptr)
|
||||
continue;
|
||||
if (StringRef(argv[i]) == "-no-canonical-prefixes") {
|
||||
CanonicalPrefixes = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle CL and _CL_ which permits additional command line options to be
|
||||
// prepended or appended.
|
||||
if (ClangCLMode) {
|
||||
// Arguments in "CL" are prepended.
|
||||
llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
|
||||
if (OptCL.hasValue()) {
|
||||
SmallVector<const char *, 8> PrependedOpts;
|
||||
getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts);
|
||||
|
||||
// Insert right after the program name to prepend to the argument list.
|
||||
argv.insert(argv.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
|
||||
}
|
||||
// Arguments in "_CL_" are appended.
|
||||
llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
|
||||
if (Opt_CL_.hasValue()) {
|
||||
SmallVector<const char *, 8> AppendedOpts;
|
||||
getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts);
|
||||
|
||||
// Insert at the end of the argument list to append.
|
||||
argv.append(AppendedOpts.begin(), AppendedOpts.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::set<std::string> SavedStrings;
|
||||
// Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
|
||||
// scenes.
|
||||
if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
|
||||
// FIXME: Driver shouldn't take extra initial argument.
|
||||
ApplyQAOverride(argv, OverrideStr, SavedStrings);
|
||||
}
|
||||
|
||||
std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes);
|
||||
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
|
||||
CreateAndPopulateDiagOpts(argv);
|
||||
|
||||
TextDiagnosticPrinter *DiagClient
|
||||
= new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
|
||||
FixupDiagPrefixExeName(DiagClient, Path);
|
||||
|
||||
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
|
||||
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
|
||||
|
||||
if (!DiagOpts->DiagnosticSerializationFile.empty()) {
|
||||
auto SerializedConsumer =
|
||||
clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
|
||||
&*DiagOpts, /*MergeChildRecords=*/true);
|
||||
Diags.setClient(new ChainedDiagnosticConsumer(
|
||||
Diags.takeClient(), std::move(SerializedConsumer)));
|
||||
}
|
||||
|
||||
ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
|
||||
|
||||
Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
|
||||
SetInstallDir(argv, TheDriver, CanonicalPrefixes);
|
||||
TheDriver.setTargetAndMode(TargetAndMode);
|
||||
|
||||
insertTargetAndModeArgs(TargetAndMode, argv, SavedStrings);
|
||||
|
||||
SetBackdoorDriverOutputsFromEnvVars(TheDriver);
|
||||
|
||||
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
|
||||
int Res = 1;
|
||||
if (C && !C->containsError()) {
|
||||
SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
|
||||
Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
|
||||
|
||||
// Force a crash to test the diagnostics.
|
||||
if (TheDriver.GenReproducer) {
|
||||
Diags.Report(diag::err_drv_force_crash)
|
||||
<< !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
|
||||
|
||||
// Pretend that every command failed.
|
||||
FailingCommands.clear();
|
||||
for (const auto &J : C->getJobs())
|
||||
if (const Command *C = dyn_cast<Command>(&J))
|
||||
FailingCommands.push_back(std::make_pair(-1, C));
|
||||
}
|
||||
|
||||
for (const auto &P : FailingCommands) {
|
||||
int CommandRes = P.first;
|
||||
const Command *FailingCommand = P.second;
|
||||
if (!Res)
|
||||
Res = CommandRes;
|
||||
|
||||
// If result status is < 0, then the driver command signalled an error.
|
||||
// If result status is 70, then the driver command reported a fatal error.
|
||||
// On Windows, abort will return an exit code of 3. In these cases,
|
||||
// generate additional diagnostic information if possible.
|
||||
bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
|
||||
#ifdef _WIN32
|
||||
DiagnoseCrash |= CommandRes == 3;
|
||||
#endif
|
||||
if (DiagnoseCrash) {
|
||||
TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Diags.getClient()->finish();
|
||||
|
||||
// If any timers were active but haven't been destroyed yet, print their
|
||||
// results now. This happens in -disable-free mode.
|
||||
llvm::TimerGroup::printAll(llvm::errs());
|
||||
|
||||
#ifdef _WIN32
|
||||
// Exit status should not be negative on Win32, unless abnormal termination.
|
||||
// Once abnormal termiation was caught, negative status should not be
|
||||
// propagated.
|
||||
if (Res < 0)
|
||||
Res = 1;
|
||||
#endif
|
||||
|
||||
// If we have multiple failing commands, we return the result of the first
|
||||
// failing command.
|
||||
return Res;
|
||||
}
|
||||
|
@ -732,7 +732,7 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *su
|
||||
const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) {
|
||||
switch (sub_arch) {
|
||||
case ZigLLVM_NoSubArch:
|
||||
return "(none)";
|
||||
return "";
|
||||
case ZigLLVM_ARMSubArch_v8_5a:
|
||||
return "v8_5a";
|
||||
case ZigLLVM_ARMSubArch_v8_4a:
|
||||
|
@ -215,7 +215,7 @@ ZIG_EXTERN_C void ZigLLVMParseCommandLineOptions(size_t argc, const char *const
|
||||
|
||||
|
||||
// copied from include/llvm/ADT/Triple.h
|
||||
|
||||
// synchronize with target.cpp::arch_list
|
||||
enum ZigLLVM_ArchType {
|
||||
ZigLLVM_UnknownArch,
|
||||
|
||||
@ -272,6 +272,7 @@ enum ZigLLVM_ArchType {
|
||||
ZigLLVM_LastArchType = ZigLLVM_renderscript64
|
||||
};
|
||||
|
||||
// synchronize with lists in target.cpp
|
||||
enum ZigLLVM_SubArchType {
|
||||
ZigLLVM_NoSubArch,
|
||||
|
||||
@ -409,7 +410,7 @@ ZIG_EXTERN_C const char *ZigLLVMGetArchTypeName(enum ZigLLVM_ArchType arch);
|
||||
ZIG_EXTERN_C const char *ZigLLVMGetSubArchTypeName(enum ZigLLVM_SubArchType sub_arch);
|
||||
ZIG_EXTERN_C const char *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor);
|
||||
ZIG_EXTERN_C const char *ZigLLVMGetOSTypeName(enum ZigLLVM_OSType os);
|
||||
ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentType env_type);
|
||||
ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentType abi);
|
||||
|
||||
ZIG_EXTERN_C bool ZigLLDLink(enum ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count,
|
||||
void (*append_diagnostic)(void *, const char *, size_t), void *context);
|
||||
|
@ -32,6 +32,10 @@ pub const BufSet = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exists(self: BufSet, key: []const u8) bool {
|
||||
return self.hash_map.get(key) != null;
|
||||
}
|
||||
|
||||
pub fn delete(self: *BufSet, key: []const u8) void {
|
||||
const entry = self.hash_map.remove(key) orelse return;
|
||||
self.free(entry.key);
|
||||
|
931
std/build.zig
931
std/build.zig
File diff suppressed because it is too large
Load Diff
35
std/build/fmt.zig
Normal file
35
std/build/fmt.zig
Normal file
@ -0,0 +1,35 @@
|
||||
const std = @import("../index.zig");
|
||||
const build = @import("../build.zig");
|
||||
const Step = build.Step;
|
||||
const Builder = build.Builder;
|
||||
const BufMap = std.BufMap;
|
||||
const mem = std.mem;
|
||||
|
||||
pub const FmtStep = struct {
|
||||
step: Step,
|
||||
builder: *Builder,
|
||||
argv: [][]const u8,
|
||||
|
||||
pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep {
|
||||
const self = builder.allocator.create(FmtStep) catch unreachable;
|
||||
const name = "zig fmt";
|
||||
self.* = FmtStep{
|
||||
.step = Step.init(name, builder.allocator, make),
|
||||
.builder = builder,
|
||||
.argv = builder.allocator.alloc([]u8, paths.len + 2) catch unreachable,
|
||||
};
|
||||
|
||||
self.argv[0] = builder.zig_exe;
|
||||
self.argv[1] = "fmt";
|
||||
for (paths) |path, i| {
|
||||
self.argv[2 + i] = builder.pathFromRoot(path);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
fn make(step: *Step) !void {
|
||||
const self = @fieldParentPtr(FmtStep, "step", step);
|
||||
|
||||
return self.builder.spawnChild(self.argv);
|
||||
}
|
||||
};
|
@ -36,11 +36,20 @@ pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usi
|
||||
pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int;
|
||||
pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int;
|
||||
|
||||
const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
|
||||
|
||||
/// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address
|
||||
/// of the mach header in a Mach-O executable file type. It does not appear in
|
||||
/// any file type other than a MH_EXECUTE file type. The type of the symbol is
|
||||
/// absolute as the header is not part of any section.
|
||||
pub extern "c" var _mh_execute_header: if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
|
||||
/// This symbol is populated when linking the system's libc, which is guaranteed
|
||||
/// on this operating system. However when building object files or libraries,
|
||||
/// the system libc won't be linked until the final executable. So we
|
||||
/// export a weak symbol here, to be overridden by the real one.
|
||||
pub extern "c" var _mh_execute_header: mach_hdr = undefined;
|
||||
comptime {
|
||||
@export("__mh_execute_header", _mh_execute_header, @import("builtin").GlobalLinkage.Weak);
|
||||
}
|
||||
|
||||
pub const mach_header_64 = macho.mach_header_64;
|
||||
pub const mach_header = macho.mach_header;
|
||||
|
@ -6,6 +6,7 @@ pub use switch (builtin.os) {
|
||||
Os.windows => @import("windows.zig"),
|
||||
Os.macosx, Os.ios => @import("darwin.zig"),
|
||||
Os.freebsd => @import("freebsd.zig"),
|
||||
Os.netbsd => @import("netbsd.zig"),
|
||||
else => empty_import,
|
||||
};
|
||||
const empty_import = @import("../empty.zig");
|
||||
|
116
std/c/netbsd.zig
Normal file
116
std/c/netbsd.zig
Normal file
@ -0,0 +1,116 @@
|
||||
extern "c" fn __errno() *c_int;
|
||||
pub const _errno = __errno;
|
||||
|
||||
pub extern "c" fn kqueue() c_int;
|
||||
pub extern "c" fn kevent(
|
||||
kq: c_int,
|
||||
changelist: [*]const Kevent,
|
||||
nchanges: c_int,
|
||||
eventlist: [*]Kevent,
|
||||
nevents: c_int,
|
||||
timeout: ?*const timespec,
|
||||
) c_int;
|
||||
pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
|
||||
pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
|
||||
pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
|
||||
pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize;
|
||||
pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
|
||||
pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int;
|
||||
pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
|
||||
pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
|
||||
pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int;
|
||||
pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;
|
||||
pub extern "c" fn setuid(uid: c_uint) c_int;
|
||||
pub extern "c" fn kill(pid: c_int, sig: c_int) c_int;
|
||||
pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
|
||||
pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
|
||||
|
||||
/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
|
||||
pub const Kevent = extern struct {
|
||||
ident: usize,
|
||||
filter: i32,
|
||||
flags: u32,
|
||||
fflags: u32,
|
||||
data: i64,
|
||||
udata: usize,
|
||||
};
|
||||
|
||||
pub const pthread_attr_t = extern struct {
|
||||
pta_magic: u32,
|
||||
pta_flags: c_int,
|
||||
pta_private: *c_void,
|
||||
};
|
||||
|
||||
pub const msghdr = extern struct {
|
||||
msg_name: *u8,
|
||||
msg_namelen: socklen_t,
|
||||
msg_iov: *iovec,
|
||||
msg_iovlen: i32,
|
||||
__pad1: i32,
|
||||
msg_control: *u8,
|
||||
msg_controllen: socklen_t,
|
||||
__pad2: socklen_t,
|
||||
msg_flags: i32,
|
||||
};
|
||||
|
||||
pub const Stat = extern struct {
|
||||
dev: u64,
|
||||
mode: u32,
|
||||
ino: u64,
|
||||
nlink: usize,
|
||||
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
rdev: u64,
|
||||
|
||||
atim: timespec,
|
||||
mtim: timespec,
|
||||
ctim: timespec,
|
||||
birthtim: timespec,
|
||||
|
||||
size: i64,
|
||||
blocks: i64,
|
||||
blksize: isize,
|
||||
flags: u32,
|
||||
gen: u32,
|
||||
__spare: [2]u32,
|
||||
};
|
||||
|
||||
pub const timespec = extern struct {
|
||||
tv_sec: i64,
|
||||
tv_nsec: isize,
|
||||
};
|
||||
|
||||
pub const dirent = extern struct {
|
||||
d_fileno: u64,
|
||||
d_reclen: u16,
|
||||
d_namlen: u16,
|
||||
d_type: u8,
|
||||
d_off: i64,
|
||||
d_name: [512]u8,
|
||||
};
|
||||
|
||||
pub const in_port_t = u16;
|
||||
pub const sa_family_t = u8;
|
||||
|
||||
pub const sockaddr = extern union {
|
||||
in: sockaddr_in,
|
||||
in6: sockaddr_in6,
|
||||
};
|
||||
|
||||
pub const sockaddr_in = extern struct {
|
||||
len: u8,
|
||||
family: sa_family_t,
|
||||
port: in_port_t,
|
||||
addr: u32,
|
||||
zero: [8]u8,
|
||||
};
|
||||
|
||||
pub const sockaddr_in6 = extern struct {
|
||||
len: u8,
|
||||
family: sa_family_t,
|
||||
port: in_port_t,
|
||||
flowinfo: u32,
|
||||
addr: [16]u8,
|
||||
scope_id: u32,
|
||||
};
|
@ -90,9 +90,60 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns a slice with the same pointer as addresses, with a potentially smaller len.
|
||||
/// On Windows, when first_address is not null, we ask for at least 32 stack frames,
|
||||
/// and then try to find the first address. If addresses.len is more than 32, we
|
||||
/// capture that many stack frames exactly, and then look for the first address,
|
||||
/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
|
||||
/// equals the passed in addresses pointer.
|
||||
pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.windows => {
|
||||
const addrs = stack_trace.instruction_addresses;
|
||||
const u32_addrs_len = @intCast(u32, addrs.len);
|
||||
const first_addr = first_address orelse {
|
||||
stack_trace.index = windows.RtlCaptureStackBackTrace(
|
||||
0,
|
||||
u32_addrs_len,
|
||||
@ptrCast(**c_void, addrs.ptr),
|
||||
null,
|
||||
);
|
||||
return;
|
||||
};
|
||||
var addr_buf_stack: [32]usize = undefined;
|
||||
const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
|
||||
const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
|
||||
const first_index = for (addr_buf[0..n]) |addr, i| {
|
||||
if (addr == first_addr) {
|
||||
break i;
|
||||
}
|
||||
} else {
|
||||
stack_trace.index = 0;
|
||||
return;
|
||||
};
|
||||
const slice = addr_buf[first_index..n];
|
||||
// We use a for loop here because slice and addrs may alias.
|
||||
for (slice) |addr, i| {
|
||||
addrs[i] = addr;
|
||||
}
|
||||
stack_trace.index = slice.len;
|
||||
},
|
||||
else => {
|
||||
var it = StackIterator.init(first_address);
|
||||
for (stack_trace.instruction_addresses) |*addr, i| {
|
||||
addr.* = it.next() orelse {
|
||||
stack_trace.index = i;
|
||||
return;
|
||||
};
|
||||
}
|
||||
stack_trace.index = stack_trace.instruction_addresses.len;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
|
||||
/// TODO multithreaded awareness
|
||||
pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void {
|
||||
pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
|
||||
const stderr = getStderrStream() catch return;
|
||||
const debug_info = getSelfDebugInfo() catch |err| {
|
||||
stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
|
||||
@ -141,7 +192,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
|
||||
const stderr = getStderrStream() catch os.abort();
|
||||
stderr.print(format ++ "\n", args) catch os.abort();
|
||||
if (trace) |t| {
|
||||
dumpStackTrace(t);
|
||||
dumpStackTrace(t.*);
|
||||
}
|
||||
dumpCurrentStackTrace(first_trace_addr);
|
||||
|
||||
@ -155,16 +206,15 @@ const WHITE = "\x1b[37;1m";
|
||||
const DIM = "\x1b[2m";
|
||||
const RESET = "\x1b[0m";
|
||||
|
||||
pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool) !void {
|
||||
var frame_index: usize = undefined;
|
||||
var frames_left: usize = undefined;
|
||||
if (stack_trace.index < stack_trace.instruction_addresses.len) {
|
||||
frame_index = 0;
|
||||
frames_left = stack_trace.index;
|
||||
} else {
|
||||
frame_index = (stack_trace.index + 1) % stack_trace.instruction_addresses.len;
|
||||
frames_left = stack_trace.instruction_addresses.len;
|
||||
}
|
||||
pub fn writeStackTrace(
|
||||
stack_trace: builtin.StackTrace,
|
||||
out_stream: var,
|
||||
allocator: *mem.Allocator,
|
||||
debug_info: *DebugInfo,
|
||||
tty_color: bool,
|
||||
) !void {
|
||||
var frame_index: usize = 0;
|
||||
var frames_left: usize = stack_trace.index;
|
||||
|
||||
while (frames_left != 0) : ({
|
||||
frames_left -= 1;
|
||||
@ -240,7 +290,7 @@ pub fn writeCurrentStackTraceWindows(
|
||||
pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
|
||||
builtin.Os.linux, builtin.Os.freebsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
|
||||
builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
|
||||
builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
|
||||
else => return error.UnsupportedOperatingSystem,
|
||||
}
|
||||
@ -574,7 +624,7 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach
|
||||
}
|
||||
|
||||
fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
|
||||
const base_addr = @ptrToInt(&std.c._mh_execute_header);
|
||||
const base_addr = std.os.getBaseAddress();
|
||||
const adjusted_addr = 0x100000000 + (address - base_addr);
|
||||
|
||||
const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
|
||||
@ -717,7 +767,7 @@ pub const OpenSelfDebugInfoError = error{
|
||||
|
||||
pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.linux, builtin.Os.freebsd => return openSelfDebugInfoLinux(allocator),
|
||||
builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return openSelfDebugInfoLinux(allocator),
|
||||
builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
|
||||
builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
|
||||
else => return error.UnsupportedOperatingSystem,
|
||||
@ -1141,7 +1191,7 @@ pub const DebugInfo = switch (builtin.os) {
|
||||
sect_contribs: []pdb.SectionContribEntry,
|
||||
modules: []Module,
|
||||
},
|
||||
builtin.Os.linux, builtin.Os.freebsd => DwarfInfo,
|
||||
builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => DwarfInfo,
|
||||
else => @compileError("Unsupported OS"),
|
||||
};
|
||||
|
||||
|
@ -85,6 +85,7 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.linux,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd,
|
||||
=> {
|
||||
const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len);
|
||||
defer loop.allocator.free(iovecs);
|
||||
@ -222,6 +223,7 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset:
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.linux,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd,
|
||||
=> {
|
||||
const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len);
|
||||
defer loop.allocator.free(iovecs);
|
||||
@ -402,7 +404,11 @@ pub async fn openPosix(
|
||||
|
||||
pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.linux,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd
|
||||
=> {
|
||||
const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC;
|
||||
return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
|
||||
},
|
||||
@ -431,6 +437,7 @@ pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.linux,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd,
|
||||
=> {
|
||||
const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC;
|
||||
return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
|
||||
@ -453,7 +460,7 @@ pub async fn openReadWrite(
|
||||
mode: os.File.Mode,
|
||||
) os.File.OpenError!os.FileHandle {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
const flags = posix.O_LARGEFILE | posix.O_RDWR | posix.O_CREAT | posix.O_CLOEXEC;
|
||||
return await (async openPosix(loop, path, flags, mode) catch unreachable);
|
||||
},
|
||||
@ -481,7 +488,7 @@ pub const CloseOperation = struct {
|
||||
os_data: OsData,
|
||||
|
||||
const OsData = switch (builtin.os) {
|
||||
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => OsDataPosix,
|
||||
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => OsDataPosix,
|
||||
|
||||
builtin.Os.windows => struct {
|
||||
handle: ?os.FileHandle,
|
||||
@ -500,7 +507,7 @@ pub const CloseOperation = struct {
|
||||
self.* = CloseOperation{
|
||||
.loop = loop,
|
||||
.os_data = switch (builtin.os) {
|
||||
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => initOsDataPosix(self),
|
||||
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => initOsDataPosix(self),
|
||||
builtin.Os.windows => OsData{ .handle = null },
|
||||
else => @compileError("Unsupported OS"),
|
||||
},
|
||||
@ -530,6 +537,7 @@ pub const CloseOperation = struct {
|
||||
builtin.Os.linux,
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd,
|
||||
=> {
|
||||
if (self.os_data.have_fd) {
|
||||
self.loop.posixFsRequest(&self.os_data.close_req_node);
|
||||
@ -552,6 +560,7 @@ pub const CloseOperation = struct {
|
||||
builtin.Os.linux,
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd,
|
||||
=> {
|
||||
self.os_data.close_req_node.data.msg.Close.fd = handle;
|
||||
self.os_data.have_fd = true;
|
||||
@ -569,6 +578,7 @@ pub const CloseOperation = struct {
|
||||
builtin.Os.linux,
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd,
|
||||
=> {
|
||||
self.os_data.have_fd = false;
|
||||
},
|
||||
@ -584,6 +594,7 @@ pub const CloseOperation = struct {
|
||||
builtin.Os.linux,
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd,
|
||||
=> {
|
||||
assert(self.os_data.have_fd);
|
||||
return self.os_data.close_req_node.data.msg.Close.fd;
|
||||
@ -608,6 +619,7 @@ pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8,
|
||||
builtin.Os.linux,
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd,
|
||||
=> return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),
|
||||
builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),
|
||||
else => @compileError("Unsupported OS"),
|
||||
@ -713,7 +725,7 @@ pub fn Watch(comptime V: type) type {
|
||||
os_data: OsData,
|
||||
|
||||
const OsData = switch (builtin.os) {
|
||||
builtin.Os.macosx, builtin.Os.freebsd => struct {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => struct {
|
||||
file_table: FileTable,
|
||||
table_lock: event.Lock,
|
||||
|
||||
@ -802,7 +814,7 @@ pub fn Watch(comptime V: type) type {
|
||||
return self;
|
||||
},
|
||||
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
const self = try loop.allocator.create(Self);
|
||||
errdefer loop.allocator.destroy(self);
|
||||
|
||||
@ -822,7 +834,7 @@ pub fn Watch(comptime V: type) type {
|
||||
/// All addFile calls and removeFile calls must have completed.
|
||||
pub fn destroy(self: *Self) void {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
// TODO we need to cancel the coroutines before destroying the lock
|
||||
self.os_data.table_lock.deinit();
|
||||
var it = self.os_data.file_table.iterator();
|
||||
@ -864,7 +876,10 @@ pub fn Watch(comptime V: type) type {
|
||||
|
||||
pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.macosx, builtin.Os.freebsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd
|
||||
=> return await (async addFileKEvent(self, file_path, value) catch unreachable),
|
||||
builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
|
||||
builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
|
||||
else => @compileError("Unsupported OS"),
|
||||
|
@ -50,7 +50,7 @@ pub const Loop = struct {
|
||||
};
|
||||
|
||||
pub const EventFd = switch (builtin.os) {
|
||||
builtin.Os.macosx, builtin.Os.freebsd => KEventFd,
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventFd,
|
||||
builtin.Os.linux => struct {
|
||||
base: ResumeNode,
|
||||
epoll_op: u32,
|
||||
@ -69,7 +69,7 @@ pub const Loop = struct {
|
||||
};
|
||||
|
||||
pub const Basic = switch (builtin.os) {
|
||||
builtin.Os.macosx, builtin.Os.freebsd => KEventBasic,
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventBasic,
|
||||
builtin.Os.linux => struct {
|
||||
base: ResumeNode,
|
||||
},
|
||||
@ -221,7 +221,7 @@ pub const Loop = struct {
|
||||
self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun);
|
||||
}
|
||||
},
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
self.os_data.kqfd = try os.bsdKQueue();
|
||||
errdefer os.close(self.os_data.kqfd);
|
||||
|
||||
@ -386,7 +386,7 @@ pub const Loop = struct {
|
||||
os.close(self.os_data.epollfd);
|
||||
self.allocator.free(self.eventfd_resume_nodes);
|
||||
},
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
os.close(self.os_data.kqfd);
|
||||
os.close(self.os_data.fs_kqfd);
|
||||
},
|
||||
@ -501,7 +501,7 @@ pub const Loop = struct {
|
||||
const eventfd_node = &resume_stack_node.data;
|
||||
eventfd_node.base.handle = next_tick_node.data;
|
||||
switch (builtin.os) {
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
const kevent_array = (*[1]posix.Kevent)(&eventfd_node.kevent);
|
||||
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
|
||||
_ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch {
|
||||
@ -564,6 +564,7 @@ pub const Loop = struct {
|
||||
builtin.Os.linux,
|
||||
builtin.Os.macosx,
|
||||
builtin.Os.freebsd,
|
||||
builtin.Os.netbsd,
|
||||
=> self.os_data.fs_thread.wait(),
|
||||
else => {},
|
||||
}
|
||||
@ -628,7 +629,7 @@ pub const Loop = struct {
|
||||
os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
|
||||
return;
|
||||
},
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
self.posixFsRequest(&self.os_data.fs_end_request);
|
||||
const final_kevent = (*[1]posix.Kevent)(&self.os_data.final_kevent);
|
||||
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
|
||||
@ -686,7 +687,7 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
},
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
var eventlist: [1]posix.Kevent = undefined;
|
||||
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
|
||||
const count = os.bsdKEvent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable;
|
||||
@ -749,7 +750,7 @@ pub const Loop = struct {
|
||||
self.beginOneEvent(); // finished in posixFsRun after processing the msg
|
||||
self.os_data.fs_queue.put(request_node);
|
||||
switch (builtin.os) {
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wake);
|
||||
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
|
||||
_ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
|
||||
@ -819,7 +820,7 @@ pub const Loop = struct {
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wait);
|
||||
var out_kevs: [1]posix.Kevent = undefined;
|
||||
_ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable;
|
||||
@ -831,7 +832,7 @@ pub const Loop = struct {
|
||||
|
||||
const OsData = switch (builtin.os) {
|
||||
builtin.Os.linux => LinuxOsData,
|
||||
builtin.Os.macosx, builtin.Os.freebsd => KEventData,
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventData,
|
||||
builtin.Os.windows => struct {
|
||||
io_port: windows.HANDLE,
|
||||
extra_thread_count: usize,
|
||||
|
@ -236,6 +236,9 @@ pub fn formatType(
|
||||
const casted_value = ([]const u8)(value);
|
||||
return output(context, casted_value);
|
||||
},
|
||||
builtin.TypeInfo.Pointer.Size.C => {
|
||||
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
|
||||
},
|
||||
},
|
||||
builtin.TypeId.Array => |info| {
|
||||
if (info.child == u8) {
|
||||
@ -828,7 +831,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
|
||||
return x;
|
||||
}
|
||||
|
||||
test "parseUnsigned" {
|
||||
test "fmt.parseUnsigned" {
|
||||
testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
|
||||
testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
|
||||
testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
|
||||
@ -855,6 +858,12 @@ test "parseUnsigned" {
|
||||
testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
|
||||
}
|
||||
|
||||
pub const parseFloat = @import("parse_float.zig").parseFloat;
|
||||
|
||||
test "fmt.parseFloat" {
|
||||
_ = @import("parse_float.zig");
|
||||
}
|
||||
|
||||
pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
|
||||
const value = switch (c) {
|
||||
'0'...'9' => c - '0',
|
||||
@ -1109,7 +1118,7 @@ test "fmt.format" {
|
||||
const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
|
||||
testing.expect(mem.eql(u8, result, "f64: nan\n"));
|
||||
}
|
||||
if (builtin.arch != builtin.Arch.armv8) {
|
||||
if (builtin.arch != builtin.Arch.arm) {
|
||||
// negative nan is not defined by IEE 754,
|
||||
// and ARM thus normalizes it to positive nan
|
||||
var buf1: [32]u8 = undefined;
|
||||
|
420
std/fmt/parse_float.zig
Normal file
420
std/fmt/parse_float.zig
Normal file
@ -0,0 +1,420 @@
|
||||
// Adapted from https://github.com/grzegorz-kraszewski/stringtofloat.
|
||||
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2016 Grzegorz Kraszewski
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Be aware that this implementation has the following limitations:
|
||||
//
|
||||
// - Is not round-trip accurate for all values
|
||||
// - Only supports round-to-zero
|
||||
// - Does not handle denormals
|
||||
|
||||
const std = @import("../index.zig");
|
||||
|
||||
const max_digits = 25;
|
||||
|
||||
const f64_plus_zero: u64 = 0x0000000000000000;
|
||||
const f64_minus_zero: u64 = 0x8000000000000000;
|
||||
const f64_plus_infinity: u64 = 0x7FF0000000000000;
|
||||
const f64_minus_infinity: u64 = 0xFFF0000000000000;
|
||||
|
||||
const Z96 = struct {
|
||||
d0: u32,
|
||||
d1: u32,
|
||||
d2: u32,
|
||||
|
||||
// d = s >> 1
|
||||
inline fn shiftRight1(d: *Z96, s: Z96) void {
|
||||
d.d0 = (s.d0 >> 1) | ((s.d1 & 1) << 31);
|
||||
d.d1 = (s.d1 >> 1) | ((s.d2 & 1) << 31);
|
||||
d.d2 = s.d2 >> 1;
|
||||
}
|
||||
|
||||
// d = s << 1
|
||||
inline fn shiftLeft1(d: *Z96, s: Z96) void {
|
||||
d.d2 = (s.d2 << 1) | ((s.d1 & (1 << 31)) >> 31);
|
||||
d.d1 = (s.d1 << 1) | ((s.d0 & (1 << 31)) >> 31);
|
||||
d.d0 = s.d0 << 1;
|
||||
}
|
||||
|
||||
// d += s
|
||||
inline fn add(d: *Z96, s: Z96) void {
|
||||
var w = u64(d.d0) + u64(s.d0);
|
||||
d.d0 = @truncate(u32, w);
|
||||
|
||||
w >>= 32;
|
||||
w += u64(d.d1) + u64(s.d1);
|
||||
d.d1 = @truncate(u32, w);
|
||||
|
||||
w >>= 32;
|
||||
w += u64(d.d2) + u64(s.d2);
|
||||
d.d2 = @truncate(u32, w);
|
||||
}
|
||||
|
||||
// d -= s
|
||||
inline fn sub(d: *Z96, s: Z96) void {
|
||||
var w = u64(d.d0) -% u64(s.d0);
|
||||
d.d0 = @truncate(u32, w);
|
||||
|
||||
w >>= 32;
|
||||
w += u64(d.d1) -% u64(s.d1);
|
||||
d.d1 = @truncate(u32, w);
|
||||
|
||||
w >>= 32;
|
||||
w += u64(d.d2) -% u64(s.d2);
|
||||
d.d2 = @truncate(u32, w);
|
||||
}
|
||||
};
|
||||
|
||||
const FloatRepr = struct {
|
||||
negative: bool,
|
||||
exponent: i32,
|
||||
mantissa: u64,
|
||||
};
|
||||
|
||||
fn convertRepr(comptime T: type, n: FloatRepr) T {
|
||||
const mask28: u32 = 0xf << 28;
|
||||
|
||||
var s: Z96 = undefined;
|
||||
var q: Z96 = undefined;
|
||||
var r: Z96 = undefined;
|
||||
|
||||
s.d0 = @truncate(u32, n.mantissa);
|
||||
s.d1 = @truncate(u32, n.mantissa >> 32);
|
||||
s.d2 = 0;
|
||||
|
||||
var binary_exponent: u64 = 92;
|
||||
var exp = n.exponent;
|
||||
|
||||
while (exp > 0) : (exp -= 1) {
|
||||
q.shiftLeft1(s); // q = p << 1
|
||||
r.shiftLeft1(q); // r = p << 2
|
||||
s.shiftLeft1(r); // p = p << 3
|
||||
q.add(s); // p = (p << 3) + (p << 1)
|
||||
|
||||
exp -= 1;
|
||||
|
||||
while (s.d2 & mask28 != 0) {
|
||||
q.shiftRight1(s);
|
||||
binary_exponent += 1;
|
||||
s = q;
|
||||
}
|
||||
}
|
||||
|
||||
while (exp < 0) {
|
||||
while (s.d2 & (1 << 31) == 0) {
|
||||
q.shiftLeft1(s);
|
||||
binary_exponent -= 1;
|
||||
s = q;
|
||||
}
|
||||
|
||||
q.d2 = s.d2 / 10;
|
||||
r.d1 = s.d2 % 10;
|
||||
r.d2 = (s.d1 >> 8) | (r.d1 << 24);
|
||||
q.d1 = r.d2 / 10;
|
||||
r.d1 = r.d2 % 10;
|
||||
r.d2 = ((s.d1 & 0xff) << 16) | (s.d0 >> 16) | (r.d1 << 24);
|
||||
r.d0 = r.d2 / 10;
|
||||
r.d1 = r.d2 % 10;
|
||||
q.d1 = (q.d1 << 8) | ((r.d0 & 0x00ff0000) >> 16);
|
||||
q.d0 = r.d0 << 16;
|
||||
r.d2 = (s.d0 *% 0xffff) | (r.d1 << 16);
|
||||
q.d0 |= r.d2 / 10;
|
||||
s = q;
|
||||
|
||||
exp += 1;
|
||||
}
|
||||
|
||||
if (s.d0 != 0 or s.d1 != 0 or s.d2 != 0) {
|
||||
while (s.d2 & mask28 == 0) {
|
||||
q.shiftLeft1(s);
|
||||
binary_exponent -= 1;
|
||||
s = q;
|
||||
}
|
||||
}
|
||||
|
||||
binary_exponent += 1023;
|
||||
|
||||
const repr: u64 = blk: {
|
||||
if (binary_exponent > 2046) {
|
||||
break :blk if (n.negative) f64_minus_infinity else f64_plus_infinity;
|
||||
} else if (binary_exponent < 1) {
|
||||
break :blk if (n.negative) f64_minus_zero else f64_plus_zero;
|
||||
} else if (s.d2 != 0) {
|
||||
const binexs2 = u64(binary_exponent) << 52;
|
||||
const rr = (u64(s.d2 & ~mask28) << 24) | ((u64(s.d1) + 128) >> 8) | binexs2;
|
||||
break :blk if (n.negative) rr | (1 << 63) else rr;
|
||||
} else {
|
||||
break :blk 0;
|
||||
}
|
||||
};
|
||||
|
||||
const f = @bitCast(f64, repr);
|
||||
return @floatCast(T, f);
|
||||
}
|
||||
|
||||
const State = enum {
|
||||
MaybeSign,
|
||||
LeadingMantissaZeros,
|
||||
LeadingFractionalZeros,
|
||||
MantissaIntegral,
|
||||
MantissaFractional,
|
||||
ExponentSign,
|
||||
LeadingExponentZeros,
|
||||
Exponent,
|
||||
};
|
||||
|
||||
const ParseResult = enum {
|
||||
Ok,
|
||||
PlusZero,
|
||||
MinusZero,
|
||||
PlusInf,
|
||||
MinusInf,
|
||||
};
|
||||
|
||||
inline fn isDigit(c: u8) bool {
|
||||
return c >= '0' and c <= '9';
|
||||
}
|
||||
|
||||
inline fn isSpace(c: u8) bool {
|
||||
return (c >= 0x09 and c <= 0x13) or c == 0x20;
|
||||
}
|
||||
|
||||
fn parseRepr(s: []const u8, n: *FloatRepr) !ParseResult {
|
||||
var digit_index: usize = 0;
|
||||
var negative = false;
|
||||
var negative_exp = false;
|
||||
var exponent: i32 = 0;
|
||||
|
||||
var state = State.MaybeSign;
|
||||
|
||||
var i: usize = 0;
|
||||
loop: while (i < s.len) {
|
||||
const c = s[i];
|
||||
|
||||
switch (state) {
|
||||
State.MaybeSign => {
|
||||
state = State.LeadingMantissaZeros;
|
||||
|
||||
if (c == '+') {
|
||||
i += 1;
|
||||
} else if (c == '-') {
|
||||
n.negative = true;
|
||||
i += 1;
|
||||
} else if (isDigit(c) or c == '.') {
|
||||
// continue
|
||||
} else {
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
},
|
||||
|
||||
State.LeadingMantissaZeros => {
|
||||
if (c == '0') {
|
||||
i += 1;
|
||||
} else if (c == '.') {
|
||||
i += 1;
|
||||
state = State.LeadingFractionalZeros;
|
||||
} else {
|
||||
state = State.MantissaIntegral;
|
||||
}
|
||||
},
|
||||
|
||||
State.LeadingFractionalZeros => {
|
||||
if (c == '0') {
|
||||
i += 1;
|
||||
if (n.exponent > std.math.minInt(i32)) {
|
||||
n.exponent -= 1;
|
||||
}
|
||||
} else {
|
||||
state = State.MantissaFractional;
|
||||
}
|
||||
},
|
||||
|
||||
State.MantissaIntegral => {
|
||||
if (isDigit(c)) {
|
||||
if (digit_index < max_digits) {
|
||||
n.mantissa *%= 10;
|
||||
n.mantissa += s[i] - '0';
|
||||
digit_index += 1;
|
||||
} else if (n.exponent < std.math.maxInt(i32)) {
|
||||
n.exponent += 1;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
} else if (c == '.') {
|
||||
i += 1;
|
||||
state = State.MantissaFractional;
|
||||
} else {
|
||||
state = State.MantissaFractional;
|
||||
}
|
||||
},
|
||||
|
||||
State.MantissaFractional => {
|
||||
if (isDigit(c)) {
|
||||
if (digit_index < max_digits) {
|
||||
n.mantissa *%= 10;
|
||||
n.mantissa += c - '0';
|
||||
n.exponent -%= 1;
|
||||
digit_index += 1;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
} else if (c == 'e' or c == 'E') {
|
||||
i += 1;
|
||||
state = State.ExponentSign;
|
||||
} else {
|
||||
state = State.ExponentSign;
|
||||
}
|
||||
},
|
||||
|
||||
State.ExponentSign => {
|
||||
if (c == '+') {
|
||||
i += 1;
|
||||
} else if (c == '-') {
|
||||
negative_exp = true;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
state = State.LeadingExponentZeros;
|
||||
},
|
||||
|
||||
State.LeadingExponentZeros => {
|
||||
if (c == '0') {
|
||||
i += 1;
|
||||
} else {
|
||||
state = State.Exponent;
|
||||
}
|
||||
},
|
||||
|
||||
State.Exponent => {
|
||||
if (isDigit(c)) {
|
||||
if (exponent < std.math.maxInt(i32)) {
|
||||
exponent *= 10;
|
||||
exponent += @intCast(i32, c - '0');
|
||||
}
|
||||
|
||||
i += 1;
|
||||
} else {
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (negative_exp) exponent = -exponent;
|
||||
n.exponent += exponent;
|
||||
|
||||
if (n.mantissa == 0) {
|
||||
return if (n.negative) ParseResult.MinusZero else ParseResult.PlusZero;
|
||||
} else if (n.exponent > 309) {
|
||||
return if (n.negative) ParseResult.MinusInf else ParseResult.PlusInf;
|
||||
} else if (n.exponent < -328) {
|
||||
return if (n.negative) ParseResult.MinusZero else ParseResult.PlusZero;
|
||||
}
|
||||
|
||||
return ParseResult.Ok;
|
||||
}
|
||||
|
||||
inline fn isLower(c: u8) bool {
|
||||
return c -% 'a' < 26;
|
||||
}
|
||||
|
||||
inline fn toUpper(c: u8) u8 {
|
||||
return if (isLower(c)) (c & 0x5f) else c;
|
||||
}
|
||||
|
||||
fn caseInEql(a: []const u8, b: []const u8) bool {
|
||||
if (a.len != b.len) return false;
|
||||
|
||||
for (a) |_, i| {
|
||||
if (toUpper(a[i]) != toUpper(b[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn parseFloat(comptime T: type, s: []const u8) !T {
|
||||
if (s.len == 0) {
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
|
||||
if (caseInEql(s, "nan")) {
|
||||
return std.math.nan(T);
|
||||
} else if (caseInEql(s, "inf") or caseInEql(s, "+inf")) {
|
||||
return std.math.inf(T);
|
||||
} else if (caseInEql(s, "-inf")) {
|
||||
return -std.math.inf(T);
|
||||
}
|
||||
|
||||
var r = FloatRepr{
|
||||
.negative = false,
|
||||
.exponent = 0,
|
||||
.mantissa = 0,
|
||||
};
|
||||
|
||||
return switch (try parseRepr(s, &r)) {
|
||||
ParseResult.Ok => convertRepr(T, r),
|
||||
ParseResult.PlusZero => 0.0,
|
||||
ParseResult.MinusZero => -T(0.0),
|
||||
ParseResult.PlusInf => std.math.inf(T),
|
||||
ParseResult.MinusInf => -std.math.inf(T),
|
||||
};
|
||||
}
|
||||
|
||||
test "fmt.parseFloat" {
|
||||
const testing = std.testing;
|
||||
const expect = testing.expect;
|
||||
const expectEqual = testing.expectEqual;
|
||||
const approxEq = std.math.approxEq;
|
||||
const epsilon = 1e-7;
|
||||
|
||||
inline for ([]type{ f16, f32, f64, f128 }) |T| {
|
||||
const Z = @IntType(false, T.bit_count);
|
||||
|
||||
testing.expectError(error.InvalidCharacter, parseFloat(T, ""));
|
||||
testing.expectError(error.InvalidCharacter, parseFloat(T, " 1"));
|
||||
testing.expectError(error.InvalidCharacter, parseFloat(T, "1abc"));
|
||||
|
||||
expectEqual(try parseFloat(T, "0"), 0.0);
|
||||
expectEqual((try parseFloat(T, "0")), 0.0);
|
||||
expectEqual((try parseFloat(T, "+0")), 0.0);
|
||||
expectEqual((try parseFloat(T, "-0")), 0.0);
|
||||
|
||||
expect(approxEq(T, try parseFloat(T, "3.141"), 3.141, epsilon));
|
||||
expect(approxEq(T, try parseFloat(T, "-3.141"), -3.141, epsilon));
|
||||
|
||||
expectEqual((try parseFloat(T, "1e-700")), 0);
|
||||
expectEqual((try parseFloat(T, "1e+700")), std.math.inf(T));
|
||||
|
||||
expectEqual(@bitCast(Z, try parseFloat(T, "nAn")), @bitCast(Z, std.math.nan(T)));
|
||||
expectEqual((try parseFloat(T, "inF")), std.math.inf(T));
|
||||
expectEqual((try parseFloat(T, "-INF")), -std.math.inf(T));
|
||||
|
||||
if (T != f16) {
|
||||
expect(approxEq(T, try parseFloat(T, "123142.1"), 123142.1, epsilon));
|
||||
expect(approxEq(T, try parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon));
|
||||
}
|
||||
}
|
||||
}
|
@ -496,6 +496,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
|
||||
builtin.TypeId.Pointer => |info| switch (info.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto hash C pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Slice => {
|
||||
const interval = std.math.max(1, key.len / 256);
|
||||
var i: usize = 0;
|
||||
@ -543,6 +544,7 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
|
||||
builtin.TypeId.Pointer => |info| switch (info.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto eql for C pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Slice => {
|
||||
if (a.len != b.len) return false;
|
||||
for (a) |a_item, i| {
|
||||
|
@ -71,7 +71,7 @@ pub const DirectAllocator = struct {
|
||||
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
|
||||
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
const p = os.posix;
|
||||
const alloc_size = if (alignment <= os.page_size) n else n + alignment;
|
||||
const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0);
|
||||
@ -120,7 +120,7 @@ pub const DirectAllocator = struct {
|
||||
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
|
||||
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
if (new_size <= old_mem.len) {
|
||||
const base_addr = @ptrToInt(old_mem.ptr);
|
||||
const old_addr_end = base_addr + old_mem.len;
|
||||
@ -164,7 +164,7 @@ pub const DirectAllocator = struct {
|
||||
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
|
||||
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
_ = os.posix.munmap(@ptrToInt(bytes.ptr), bytes.len);
|
||||
},
|
||||
Os.windows => {
|
||||
|
@ -9,6 +9,7 @@ pub const DynLib = @import("dynamic_library.zig").DynLib;
|
||||
pub const HashMap = @import("hash_map.zig").HashMap;
|
||||
pub const LinkedList = @import("linked_list.zig").LinkedList;
|
||||
pub const Mutex = @import("mutex.zig").Mutex;
|
||||
pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
|
||||
pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
|
||||
pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
|
||||
pub const SpinLock = @import("spinlock.zig").SpinLock;
|
||||
@ -59,7 +60,7 @@ test "std" {
|
||||
_ = @import("statically_initialized_mutex.zig");
|
||||
_ = @import("segmented_list.zig");
|
||||
_ = @import("spinlock.zig");
|
||||
|
||||
|
||||
_ = @import("base64.zig");
|
||||
_ = @import("build.zig");
|
||||
_ = @import("c/index.zig");
|
||||
@ -85,6 +86,7 @@ test "std" {
|
||||
_ = @import("net.zig");
|
||||
_ = @import("os/index.zig");
|
||||
_ = @import("pdb.zig");
|
||||
_ = @import("priority_queue.zig");
|
||||
_ = @import("rand/index.zig");
|
||||
_ = @import("sort.zig");
|
||||
_ = @import("testing.zig");
|
||||
|
83
std/io.zig
83
std/io.zig
@ -343,23 +343,24 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
|
||||
const amt_buffered = self.end_index - self.start_index;
|
||||
if (amt_buffered == 0) {
|
||||
assert(self.end_index <= buffer_size);
|
||||
if (self.end_index == buffer_size) {
|
||||
// we can read more data from the unbuffered stream
|
||||
if (dest_space < buffer_size) {
|
||||
self.start_index = 0;
|
||||
self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]);
|
||||
} else {
|
||||
// asking for so much data that buffering is actually less efficient.
|
||||
// forward the request directly to the unbuffered stream
|
||||
const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]);
|
||||
return dest_index + amt_read;
|
||||
}
|
||||
} else {
|
||||
// reading from the unbuffered stream returned less than we asked for
|
||||
// so we cannot read any more data.
|
||||
// Make sure the last read actually gave us some data
|
||||
if (self.end_index == 0) {
|
||||
// reading from the unbuffered stream returned nothing
|
||||
// so we have nothing left to read.
|
||||
return dest_index;
|
||||
}
|
||||
// we can read more data from the unbuffered stream
|
||||
if (dest_space < buffer_size) {
|
||||
self.start_index = 0;
|
||||
self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]);
|
||||
} else {
|
||||
// asking for so much data that buffering is actually less efficient.
|
||||
// forward the request directly to the unbuffered stream
|
||||
const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]);
|
||||
return dest_index + amt_read;
|
||||
}
|
||||
}
|
||||
|
||||
const copy_amount = math.min(dest_space, amt_buffered);
|
||||
const copy_end_index = self.start_index + copy_amount;
|
||||
mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]);
|
||||
@ -370,6 +371,46 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
|
||||
};
|
||||
}
|
||||
|
||||
test "io.BufferedInStream" {
|
||||
const OneByteReadInStream = struct {
|
||||
const Error = error{NoError};
|
||||
const Stream = InStream(Error);
|
||||
|
||||
stream: Stream,
|
||||
str: []const u8,
|
||||
curr: usize,
|
||||
|
||||
fn init(str: []const u8) @This() {
|
||||
return @This(){
|
||||
.stream = Stream{ .readFn = readFn },
|
||||
.str = str,
|
||||
.curr = 0,
|
||||
};
|
||||
}
|
||||
|
||||
fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
|
||||
const self = @fieldParentPtr(@This(), "stream", in_stream);
|
||||
if (self.str.len <= self.curr or dest.len == 0)
|
||||
return 0;
|
||||
|
||||
dest[0] = self.str[self.curr];
|
||||
self.curr += 1;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
var buf: [100]u8 = undefined;
|
||||
const allocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
|
||||
|
||||
const str = "This is a test";
|
||||
var one_byte_stream = OneByteReadInStream.init(str);
|
||||
var buf_in_stream = BufferedInStream(OneByteReadInStream.Error).init(&one_byte_stream.stream);
|
||||
const stream = &buf_in_stream.stream;
|
||||
|
||||
const res = try stream.readAllAlloc(allocator, str.len + 1);
|
||||
testing.expectEqualSlices(u8, str, res);
|
||||
}
|
||||
|
||||
/// Creates a stream which supports 'un-reading' data, so that it can be read again.
|
||||
/// This makes look-ahead style parsing much easier.
|
||||
pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type {
|
||||
@ -935,8 +976,6 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub const BufferedAtomicFile = struct {
|
||||
atomic_file: os.AtomicFile,
|
||||
file_stream: os.File.OutStream,
|
||||
@ -978,7 +1017,6 @@ pub const BufferedAtomicFile = struct {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
pub fn readLine(buf: *std.Buffer) ![]u8 {
|
||||
var stdin = try getStdIn();
|
||||
var stdin_stream = stdin.inStream();
|
||||
@ -1073,13 +1111,13 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
|
||||
else => in_stream,
|
||||
} };
|
||||
}
|
||||
|
||||
|
||||
pub fn alignToByte(self: *Self) void {
|
||||
if(!is_packed) return;
|
||||
if (!is_packed) return;
|
||||
self.in_stream.alignToByte();
|
||||
}
|
||||
|
||||
//@BUG: inferred error issue. See: #1386
|
||||
//@BUG: inferred error issue. See: #1386
|
||||
fn deserializeInt(self: *Self, comptime T: type) (Error || error{EndOfStream})!T {
|
||||
comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));
|
||||
|
||||
@ -1088,7 +1126,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
|
||||
|
||||
const U = @IntType(false, t_bit_count);
|
||||
const Log2U = math.Log2Int(U);
|
||||
const int_size = @sizeOf(U);
|
||||
const int_size = (U.bit_count + 7) / 8;
|
||||
|
||||
if (is_packed) {
|
||||
const result = try self.in_stream.readBitsNoEof(U, t_bit_count);
|
||||
@ -1301,7 +1339,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com
|
||||
|
||||
const U = @IntType(false, t_bit_count);
|
||||
const Log2U = math.Log2Int(U);
|
||||
const int_size = @sizeOf(U);
|
||||
const int_size = (U.bit_count + 7) / 8;
|
||||
|
||||
const u_value = @bitCast(U, value);
|
||||
|
||||
@ -1414,3 +1452,4 @@ test "import io tests" {
|
||||
_ = @import("io_test.zig");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,17 @@ test "write a file, read it, then delete it" {
|
||||
try st.print("end");
|
||||
try buf_stream.flush();
|
||||
}
|
||||
|
||||
{
|
||||
// make sure openWriteNoClobber doesn't harm the file
|
||||
if (os.File.openWriteNoClobber(tmp_file_name, os.File.default_mode)) |file| {
|
||||
unreachable;
|
||||
}
|
||||
else |err| {
|
||||
std.debug.assert(err == os.File.OpenError.PathAlreadyExists);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var file = try os.File.openRead(tmp_file_name);
|
||||
defer file.close();
|
||||
|
@ -1345,7 +1345,7 @@ pub const Parser = struct {
|
||||
return if (token.number_is_integer)
|
||||
Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
|
||||
else
|
||||
@panic("TODO: fmt.parseFloat not yet implemented");
|
||||
Value{ .Float = try std.fmt.parseFloat(f64, token.slice(input, i)) };
|
||||
}
|
||||
};
|
||||
|
||||
@ -1366,7 +1366,8 @@ test "json.parser.dynamic" {
|
||||
\\ },
|
||||
\\ "Animated" : false,
|
||||
\\ "IDs": [116, 943, 234, 38793],
|
||||
\\ "ArrayOfObject": [{"n": "m"}]
|
||||
\\ "ArrayOfObject": [{"n": "m"}],
|
||||
\\ "double": 1.3412
|
||||
\\ }
|
||||
\\}
|
||||
;
|
||||
@ -1395,4 +1396,7 @@ test "json.parser.dynamic" {
|
||||
|
||||
const obj0 = array_of_object.Array.at(0).Object.get("n").?.value;
|
||||
testing.expect(mem.eql(u8, obj0.String, "m"));
|
||||
|
||||
const double = image.Object.get("double").?.value;
|
||||
testing.expect(double.Float == 1.3412);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ pub fn fabs(x: var) @typeOf(x) {
|
||||
f16 => fabs16(x),
|
||||
f32 => fabs32(x),
|
||||
f64 => fabs64(x),
|
||||
f128 => fabs128(x),
|
||||
else => @compileError("fabs not implemented for " ++ @typeName(T)),
|
||||
};
|
||||
}
|
||||
@ -36,10 +37,17 @@ fn fabs64(x: f64) f64 {
|
||||
return @bitCast(f64, u);
|
||||
}
|
||||
|
||||
fn fabs128(x: f128) f128 {
|
||||
var u = @bitCast(u128, x);
|
||||
u &= maxInt(u128) >> 1;
|
||||
return @bitCast(f128, u);
|
||||
}
|
||||
|
||||
test "math.fabs" {
|
||||
expect(fabs(f16(1.0)) == fabs16(1.0));
|
||||
expect(fabs(f32(1.0)) == fabs32(1.0));
|
||||
expect(fabs(f64(1.0)) == fabs64(1.0));
|
||||
expect(fabs(f128(1.0)) == fabs128(1.0));
|
||||
}
|
||||
|
||||
test "math.fabs16" {
|
||||
@ -57,6 +65,11 @@ test "math.fabs64" {
|
||||
expect(fabs64(-1.0) == 1.0);
|
||||
}
|
||||
|
||||
test "math.fabs128" {
|
||||
expect(fabs128(1.0) == 1.0);
|
||||
expect(fabs128(-1.0) == 1.0);
|
||||
}
|
||||
|
||||
test "math.fabs16.special" {
|
||||
expect(math.isPositiveInf(fabs(math.inf(f16))));
|
||||
expect(math.isPositiveInf(fabs(-math.inf(f16))));
|
||||
@ -74,3 +87,9 @@ test "math.fabs64.special" {
|
||||
expect(math.isPositiveInf(fabs(-math.inf(f64))));
|
||||
expect(math.isNan(fabs(math.nan(f64))));
|
||||
}
|
||||
|
||||
test "math.fabs128.special" {
|
||||
expect(math.isPositiveInf(fabs(math.inf(f128))));
|
||||
expect(math.isPositiveInf(fabs(-math.inf(f128))));
|
||||
expect(math.isNan(fabs(math.nan(f128))));
|
||||
}
|
||||
|
@ -51,6 +51,12 @@ pub const nan_f64 = @bitCast(f64, nan_u64);
|
||||
pub const inf_u64 = u64(0x7FF << 52);
|
||||
pub const inf_f64 = @bitCast(f64, inf_u64);
|
||||
|
||||
pub const nan_u128 = u128(0x7fff0000000000000000000000000001);
|
||||
pub const nan_f128 = @bitCast(f128, nan_u128);
|
||||
|
||||
pub const inf_u128 = u128(0x7fff0000000000000000000000000000);
|
||||
pub const inf_f128 = @bitCast(f128, inf_u128);
|
||||
|
||||
pub const nan = @import("nan.zig").nan;
|
||||
pub const snan = @import("nan.zig").snan;
|
||||
pub const inf = @import("inf.zig").inf;
|
||||
@ -379,7 +385,7 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t
|
||||
return u0;
|
||||
}
|
||||
const is_signed = from < 0;
|
||||
const largest_positive_integer = max(if (from<0) (-from)-1 else from, to); // two's complement
|
||||
const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement
|
||||
const base = log2(largest_positive_integer);
|
||||
const upper = (1 << base) - 1;
|
||||
var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1;
|
||||
@ -752,6 +758,7 @@ test "minInt and maxInt" {
|
||||
testing.expect(maxInt(u16) == 65535);
|
||||
testing.expect(maxInt(u32) == 4294967295);
|
||||
testing.expect(maxInt(u64) == 18446744073709551615);
|
||||
testing.expect(maxInt(u128) == 340282366920938463463374607431768211455);
|
||||
|
||||
testing.expect(maxInt(i0) == 0);
|
||||
testing.expect(maxInt(i1) == 0);
|
||||
@ -760,6 +767,7 @@ test "minInt and maxInt" {
|
||||
testing.expect(maxInt(i32) == 2147483647);
|
||||
testing.expect(maxInt(i63) == 4611686018427387903);
|
||||
testing.expect(maxInt(i64) == 9223372036854775807);
|
||||
testing.expect(maxInt(i128) == 170141183460469231731687303715884105727);
|
||||
|
||||
testing.expect(minInt(u0) == 0);
|
||||
testing.expect(minInt(u1) == 0);
|
||||
@ -768,6 +776,7 @@ test "minInt and maxInt" {
|
||||
testing.expect(minInt(u32) == 0);
|
||||
testing.expect(minInt(u63) == 0);
|
||||
testing.expect(minInt(u64) == 0);
|
||||
testing.expect(minInt(u128) == 0);
|
||||
|
||||
testing.expect(minInt(i0) == 0);
|
||||
testing.expect(minInt(i1) == -1);
|
||||
@ -776,6 +785,7 @@ test "minInt and maxInt" {
|
||||
testing.expect(minInt(i32) == -2147483648);
|
||||
testing.expect(minInt(i63) == -4611686018427387904);
|
||||
testing.expect(minInt(i64) == -9223372036854775808);
|
||||
testing.expect(minInt(i128) == -170141183460469231731687303715884105728);
|
||||
}
|
||||
|
||||
test "max value type" {
|
||||
|
@ -3,9 +3,10 @@ const math = std.math;
|
||||
|
||||
pub fn inf(comptime T: type) T {
|
||||
return switch (T) {
|
||||
f16 => @bitCast(f16, math.inf_u16),
|
||||
f32 => @bitCast(f32, math.inf_u32),
|
||||
f64 => @bitCast(f64, math.inf_u64),
|
||||
f16 => math.inf_f16,
|
||||
f32 => math.inf_f32,
|
||||
f64 => math.inf_f64,
|
||||
f128 => math.inf_f128,
|
||||
else => @compileError("inf not implemented for " ++ @typeName(T)),
|
||||
};
|
||||
}
|
||||
|
@ -18,6 +18,10 @@ pub fn isInf(x: var) bool {
|
||||
const bits = @bitCast(u64, x);
|
||||
return bits & (maxInt(u64) >> 1) == (0x7FF << 52);
|
||||
},
|
||||
f128 => {
|
||||
const bits = @bitCast(u128, x);
|
||||
return bits & (maxInt(u128) >> 1) == (0x7FFF << 112);
|
||||
},
|
||||
else => {
|
||||
@compileError("isInf not implemented for " ++ @typeName(T));
|
||||
},
|
||||
@ -36,6 +40,9 @@ pub fn isPositiveInf(x: var) bool {
|
||||
f64 => {
|
||||
return @bitCast(u64, x) == 0x7FF << 52;
|
||||
},
|
||||
f128 => {
|
||||
return @bitCast(u128, x) == 0x7FFF << 112;
|
||||
},
|
||||
else => {
|
||||
@compileError("isPositiveInf not implemented for " ++ @typeName(T));
|
||||
},
|
||||
@ -54,6 +61,9 @@ pub fn isNegativeInf(x: var) bool {
|
||||
f64 => {
|
||||
return @bitCast(u64, x) == 0xFFF << 52;
|
||||
},
|
||||
f128 => {
|
||||
return @bitCast(u128, x) == 0xFFFF << 112;
|
||||
},
|
||||
else => {
|
||||
@compileError("isNegativeInf not implemented for " ++ @typeName(T));
|
||||
},
|
||||
@ -67,12 +77,16 @@ test "math.isInf" {
|
||||
expect(!isInf(f32(-0.0)));
|
||||
expect(!isInf(f64(0.0)));
|
||||
expect(!isInf(f64(-0.0)));
|
||||
expect(!isInf(f128(0.0)));
|
||||
expect(!isInf(f128(-0.0)));
|
||||
expect(isInf(math.inf(f16)));
|
||||
expect(isInf(-math.inf(f16)));
|
||||
expect(isInf(math.inf(f32)));
|
||||
expect(isInf(-math.inf(f32)));
|
||||
expect(isInf(math.inf(f64)));
|
||||
expect(isInf(-math.inf(f64)));
|
||||
expect(isInf(math.inf(f128)));
|
||||
expect(isInf(-math.inf(f128)));
|
||||
}
|
||||
|
||||
test "math.isPositiveInf" {
|
||||
@ -82,12 +96,16 @@ test "math.isPositiveInf" {
|
||||
expect(!isPositiveInf(f32(-0.0)));
|
||||
expect(!isPositiveInf(f64(0.0)));
|
||||
expect(!isPositiveInf(f64(-0.0)));
|
||||
expect(!isPositiveInf(f128(0.0)));
|
||||
expect(!isPositiveInf(f128(-0.0)));
|
||||
expect(isPositiveInf(math.inf(f16)));
|
||||
expect(!isPositiveInf(-math.inf(f16)));
|
||||
expect(isPositiveInf(math.inf(f32)));
|
||||
expect(!isPositiveInf(-math.inf(f32)));
|
||||
expect(isPositiveInf(math.inf(f64)));
|
||||
expect(!isPositiveInf(-math.inf(f64)));
|
||||
expect(isPositiveInf(math.inf(f128)));
|
||||
expect(!isPositiveInf(-math.inf(f128)));
|
||||
}
|
||||
|
||||
test "math.isNegativeInf" {
|
||||
@ -97,10 +115,14 @@ test "math.isNegativeInf" {
|
||||
expect(!isNegativeInf(f32(-0.0)));
|
||||
expect(!isNegativeInf(f64(0.0)));
|
||||
expect(!isNegativeInf(f64(-0.0)));
|
||||
expect(!isNegativeInf(f128(0.0)));
|
||||
expect(!isNegativeInf(f128(-0.0)));
|
||||
expect(!isNegativeInf(math.inf(f16)));
|
||||
expect(isNegativeInf(-math.inf(f16)));
|
||||
expect(!isNegativeInf(math.inf(f32)));
|
||||
expect(isNegativeInf(-math.inf(f32)));
|
||||
expect(!isNegativeInf(math.inf(f64)));
|
||||
expect(isNegativeInf(-math.inf(f64)));
|
||||
expect(!isNegativeInf(math.inf(f128)));
|
||||
expect(isNegativeInf(-math.inf(f128)));
|
||||
}
|
||||
|
@ -18,6 +18,10 @@ pub fn isNan(x: var) bool {
|
||||
const bits = @bitCast(u64, x);
|
||||
return (bits & (maxInt(u64) >> 1)) > (u64(0x7FF) << 52);
|
||||
},
|
||||
f128 => {
|
||||
const bits = @bitCast(u128, x);
|
||||
return (bits & (maxInt(u128) >> 1)) > (u128(0x7FFF) << 112);
|
||||
},
|
||||
else => {
|
||||
@compileError("isNan not implemented for " ++ @typeName(T));
|
||||
},
|
||||
@ -34,7 +38,9 @@ test "math.isNan" {
|
||||
expect(isNan(math.nan(f16)));
|
||||
expect(isNan(math.nan(f32)));
|
||||
expect(isNan(math.nan(f64)));
|
||||
expect(isNan(math.nan(f128)));
|
||||
expect(!isNan(f16(1.0)));
|
||||
expect(!isNan(f32(1.0)));
|
||||
expect(!isNan(f64(1.0)));
|
||||
expect(!isNan(f128(1.0)));
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ const math = @import("index.zig");
|
||||
|
||||
pub fn nan(comptime T: type) T {
|
||||
return switch (T) {
|
||||
f16 => @bitCast(f16, math.nan_u16),
|
||||
f32 => @bitCast(f32, math.nan_u32),
|
||||
f64 => @bitCast(f64, math.nan_u64),
|
||||
f16 => math.nan_f16,
|
||||
f32 => math.nan_f32,
|
||||
f64 => math.nan_f64,
|
||||
f128 => math.nan_f128,
|
||||
else => @compileError("nan not implemented for " ++ @typeName(T)),
|
||||
};
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ pub fn powi(comptime T: type, x: T, y: T) (error{
|
||||
|
||||
// powi(x, +-0) = 1 for any x
|
||||
if (y == 0 or y == -0) {
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (x) {
|
||||
@ -174,4 +174,11 @@ test "math.powi.special" {
|
||||
testing.expectError(error.Overflow, powi(u64, 2, 64));
|
||||
testing.expectError(error.Overflow, powi(u17, 2, 17));
|
||||
testing.expectError(error.Overflow, powi(u42, 2, 42));
|
||||
|
||||
testing.expect((try powi(u8, 6, 0)) == 1);
|
||||
testing.expect((try powi(u16, 5, 0)) == 1);
|
||||
testing.expect((try powi(u32, 12, 0)) == 1);
|
||||
testing.expect((try powi(u64, 34, 0)) == 1);
|
||||
testing.expect((try powi(u17, 16, 0)) == 1);
|
||||
testing.expect((try powi(u42, 34, 0)) == 1);
|
||||
}
|
||||
|
49
std/mem.zig
49
std/mem.zig
@ -423,8 +423,7 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.
|
||||
/// This function cannot fail and cannot cause undefined behavior.
|
||||
/// Assumes the endianness of memory is native. This means the function can
|
||||
/// simply pointer cast memory.
|
||||
pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T {
|
||||
comptime assert(T.bit_count % 8 == 0);
|
||||
pub fn readIntNative(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T {
|
||||
return @ptrCast(*align(1) const T, bytes).*;
|
||||
}
|
||||
|
||||
@ -432,7 +431,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T {
|
||||
/// The bit count of T must be evenly divisible by 8.
|
||||
/// This function cannot fail and cannot cause undefined behavior.
|
||||
/// Assumes the endianness of memory is foreign, so it must byte-swap.
|
||||
pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T {
|
||||
pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T {
|
||||
return @bswap(T, readIntNative(T, bytes));
|
||||
}
|
||||
|
||||
@ -446,22 +445,20 @@ pub const readIntBig = switch (builtin.endian) {
|
||||
builtin.Endian.Big => readIntNative,
|
||||
};
|
||||
|
||||
/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0
|
||||
/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0
|
||||
/// and ignores extra bytes.
|
||||
/// Note that @sizeOf(u24) is 3.
|
||||
/// The bit count of T must be evenly divisible by 8.
|
||||
/// Assumes the endianness of memory is native. This means the function can
|
||||
/// simply pointer cast memory.
|
||||
pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
|
||||
assert(@sizeOf(u24) == 3);
|
||||
assert(bytes.len >= @sizeOf(T));
|
||||
const n = @divExact(T.bit_count, 8);
|
||||
assert(bytes.len >= n);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr));
|
||||
return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr));
|
||||
}
|
||||
|
||||
/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0
|
||||
/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0
|
||||
/// and ignores extra bytes.
|
||||
/// Note that @sizeOf(u24) is 3.
|
||||
/// The bit count of T must be evenly divisible by 8.
|
||||
/// Assumes the endianness of memory is foreign, so it must byte-swap.
|
||||
pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T {
|
||||
@ -481,7 +478,7 @@ pub const readIntSliceBig = switch (builtin.endian) {
|
||||
/// Reads an integer from memory with bit count specified by T.
|
||||
/// The bit count of T must be evenly divisible by 8.
|
||||
/// This function cannot fail and cannot cause undefined behavior.
|
||||
pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T {
|
||||
pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, endian: builtin.Endian) T {
|
||||
if (endian == builtin.endian) {
|
||||
return readIntNative(T, bytes);
|
||||
} else {
|
||||
@ -489,15 +486,14 @@ pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.E
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0
|
||||
/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0
|
||||
/// and ignores extra bytes.
|
||||
/// Note that @sizeOf(u24) is 3.
|
||||
/// The bit count of T must be evenly divisible by 8.
|
||||
pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {
|
||||
assert(@sizeOf(u24) == 3);
|
||||
assert(bytes.len >= @sizeOf(T));
|
||||
const n = @divExact(T.bit_count, 8);
|
||||
assert(bytes.len >= n);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian);
|
||||
return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian);
|
||||
}
|
||||
|
||||
test "comptime read/write int" {
|
||||
@ -540,7 +536,7 @@ test "readIntBig and readIntLittle" {
|
||||
/// accepts any integer bit width.
|
||||
/// This function stores in native endian, which means it is implemented as a simple
|
||||
/// memory store.
|
||||
pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
|
||||
pub fn writeIntNative(comptime T: type, buf: *[(T.bit_count + 7) / 8]u8, value: T) void {
|
||||
@ptrCast(*align(1) T, buf).* = value;
|
||||
}
|
||||
|
||||
@ -548,7 +544,7 @@ pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
|
||||
/// This function always succeeds, has defined behavior for all inputs, but
|
||||
/// the integer bit width must be divisible by 8.
|
||||
/// This function stores in foreign endian, which means it does a @bswap first.
|
||||
pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
|
||||
pub fn writeIntForeign(comptime T: type, buf: *[@divExact(T.bit_count, 8)]u8, value: T) void {
|
||||
writeIntNative(T, buf, @bswap(T, value));
|
||||
}
|
||||
|
||||
@ -565,8 +561,7 @@ pub const writeIntBig = switch (builtin.endian) {
|
||||
/// Writes an integer to memory, storing it in twos-complement.
|
||||
/// This function always succeeds, has defined behavior for all inputs, but
|
||||
/// the integer bit width must be divisible by 8.
|
||||
pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void {
|
||||
comptime assert(T.bit_count % 8 == 0);
|
||||
pub fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value: T, endian: builtin.Endian) void {
|
||||
if (endian == builtin.endian) {
|
||||
return writeIntNative(T, buffer, value);
|
||||
} else {
|
||||
@ -575,15 +570,13 @@ pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: bui
|
||||
}
|
||||
|
||||
/// Writes a twos-complement little-endian integer to memory.
|
||||
/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3.
|
||||
/// Asserts that buf.len >= T.bit_count / 8.
|
||||
/// The bit count of T must be divisible by 8.
|
||||
/// Any extra bytes in buffer after writing the integer are set to zero. To
|
||||
/// avoid the branch to check for extra buffer bytes, use writeIntLittle
|
||||
/// instead.
|
||||
pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
|
||||
comptime assert(@sizeOf(u24) == 3);
|
||||
comptime assert(T.bit_count % 8 == 0);
|
||||
assert(buffer.len >= @sizeOf(T));
|
||||
assert(buffer.len >= @divExact(T.bit_count, 8));
|
||||
|
||||
// TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough
|
||||
const uint = @IntType(false, T.bit_count);
|
||||
@ -595,14 +588,12 @@ pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
|
||||
}
|
||||
|
||||
/// Writes a twos-complement big-endian integer to memory.
|
||||
/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3.
|
||||
/// Asserts that buffer.len >= T.bit_count / 8.
|
||||
/// The bit count of T must be divisible by 8.
|
||||
/// Any extra bytes in buffer before writing the integer are set to zero. To
|
||||
/// avoid the branch to check for extra buffer bytes, use writeIntBig instead.
|
||||
pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void {
|
||||
comptime assert(@sizeOf(u24) == 3);
|
||||
comptime assert(T.bit_count % 8 == 0);
|
||||
assert(buffer.len >= @sizeOf(T));
|
||||
assert(buffer.len >= @divExact(T.bit_count, 8));
|
||||
|
||||
// TODO I want to call writeIntBig here but comptime eval facilities aren't good enough
|
||||
const uint = @IntType(false, T.bit_count);
|
||||
@ -626,7 +617,7 @@ pub const writeIntSliceForeign = switch (builtin.endian) {
|
||||
};
|
||||
|
||||
/// Writes a twos-complement integer to memory, with the specified endianness.
|
||||
/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3.
|
||||
/// Asserts that buf.len >= T.bit_count / 8.
|
||||
/// The bit count of T must be evenly divisible by 8.
|
||||
/// Any extra bytes in buffer not part of the integer are set to zero, with
|
||||
/// respect to endianness. To avoid the branch to check for extra buffer bytes,
|
||||
|
@ -463,13 +463,16 @@ pub fn eql(a: var, b: @typeOf(a)) bool {
|
||||
builtin.TypeId.Pointer => {
|
||||
const info = @typeInfo(T).Pointer;
|
||||
switch (info.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One, builtin.TypeInfo.Pointer.Size.Many => return a == b,
|
||||
builtin.TypeInfo.Pointer.Size.One,
|
||||
builtin.TypeInfo.Pointer.Size.Many,
|
||||
builtin.TypeInfo.Pointer.Size.C,
|
||||
=> return a == b,
|
||||
builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len,
|
||||
}
|
||||
},
|
||||
builtin.TypeId.Optional => {
|
||||
if(a == null and b == null) return true;
|
||||
if(a == null or b == null) return false;
|
||||
if (a == null and b == null) return true;
|
||||
if (a == null or b == null) return false;
|
||||
return eql(a.?, b.?);
|
||||
},
|
||||
else => return a == b,
|
||||
|
@ -665,7 +665,7 @@ pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
|
||||
|
||||
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
|
||||
const ptr_result = c.mmap(
|
||||
@ptrCast(*c_void, address),
|
||||
@ptrCast(?*c_void, address),
|
||||
length,
|
||||
@bitCast(c_int, @intCast(c_uint, prot)),
|
||||
@bitCast(c_int, c_uint(flags)),
|
||||
|
@ -105,7 +105,7 @@ pub const File = struct {
|
||||
pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
|
||||
if (is_posix) {
|
||||
const path_c = try os.toPosixPath(path);
|
||||
return openWriteNoClobberC(path_c, file_mode);
|
||||
return openWriteNoClobberC(&path_c, file_mode);
|
||||
} else if (is_windows) {
|
||||
const path_w = try windows_util.sliceToPrefixedFileW(path);
|
||||
return openWriteNoClobberW(&path_w, file_mode);
|
||||
@ -237,7 +237,7 @@ pub const File = struct {
|
||||
|
||||
pub fn seekForward(self: File, amount: isize) SeekError!void {
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
|
||||
const err = posix.getErrno(result);
|
||||
if (err > 0) {
|
||||
@ -268,7 +268,7 @@ pub const File = struct {
|
||||
|
||||
pub fn seekTo(self: File, pos: usize) SeekError!void {
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
const ipos = try math.cast(isize, pos);
|
||||
const result = posix.lseek(self.handle, ipos, posix.SEEK_SET);
|
||||
const err = posix.getErrno(result);
|
||||
@ -309,7 +309,7 @@ pub const File = struct {
|
||||
|
||||
pub fn getPos(self: File) GetSeekPosError!usize {
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
|
||||
const err = posix.getErrno(result);
|
||||
if (err > 0) {
|
||||
|
@ -617,7 +617,7 @@ pub fn mkdir(path: [*]const u8, mode: u32) usize {
|
||||
|
||||
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
|
||||
const ptr_result = c.mmap(
|
||||
@ptrCast(*c_void, address),
|
||||
@ptrCast(?*c_void, address),
|
||||
length,
|
||||
@bitCast(c_int, @intCast(c_uint, prot)),
|
||||
@bitCast(c_int, c_uint(flags)),
|
||||
|
@ -43,7 +43,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
|
||||
};
|
||||
return os.path.join(allocator, [][]const u8{ home_dir, "Library", "Application Support", appname });
|
||||
},
|
||||
builtin.Os.linux, builtin.Os.freebsd => {
|
||||
builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
const home_dir = os.getEnvPosix("HOME") orelse {
|
||||
// TODO look in /etc/passwd
|
||||
return error.AppDataDirUnavailable;
|
||||
|
@ -11,7 +11,7 @@ pub const UserInfo = struct {
|
||||
/// POSIX function which gets a uid from username.
|
||||
pub fn getUserInfo(name: []const u8) !UserInfo {
|
||||
return switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => posixGetUserInfo(name),
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posixGetUserInfo(name),
|
||||
else => @compileError("Unsupported OS"),
|
||||
};
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ const builtin = @import("builtin");
|
||||
const Os = builtin.Os;
|
||||
const is_windows = builtin.os == Os.windows;
|
||||
const is_posix = switch (builtin.os) {
|
||||
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => true,
|
||||
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true,
|
||||
else => false,
|
||||
};
|
||||
const os = @This();
|
||||
@ -30,6 +30,7 @@ pub const windows = @import("windows/index.zig");
|
||||
pub const darwin = @import("darwin.zig");
|
||||
pub const linux = @import("linux/index.zig");
|
||||
pub const freebsd = @import("freebsd/index.zig");
|
||||
pub const netbsd = @import("netbsd/index.zig");
|
||||
pub const zen = @import("zen.zig");
|
||||
pub const uefi = @import("uefi.zig");
|
||||
|
||||
@ -37,6 +38,7 @@ pub const posix = switch (builtin.os) {
|
||||
Os.linux => linux,
|
||||
Os.macosx, Os.ios => darwin,
|
||||
Os.freebsd => freebsd,
|
||||
Os.netbsd => netbsd,
|
||||
Os.zen => zen,
|
||||
else => @compileError("Unsupported OS"),
|
||||
};
|
||||
@ -50,7 +52,7 @@ pub const time = @import("time.zig");
|
||||
|
||||
pub const page_size = 4 * 1024;
|
||||
pub const MAX_PATH_BYTES = switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => posix.PATH_MAX,
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX,
|
||||
// Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
|
||||
// If it would require 4 UTF-8 bytes, then there would be a surrogate
|
||||
// pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
|
||||
@ -125,7 +127,7 @@ pub fn getRandomBytes(buf: []u8) !void {
|
||||
else => return unexpectedErrorPosix(errno),
|
||||
}
|
||||
},
|
||||
Os.macosx, Os.ios, Os.freebsd => return getRandomBytesDevURandom(buf),
|
||||
Os.macosx, Os.ios, Os.freebsd, Os.netbsd => return getRandomBytesDevURandom(buf),
|
||||
Os.windows => {
|
||||
// Call RtlGenRandom() instead of CryptGetRandom() on Windows
|
||||
// https://github.com/rust-lang-nursery/rand/issues/111
|
||||
@ -185,7 +187,7 @@ pub fn abort() noreturn {
|
||||
c.abort();
|
||||
}
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
_ = posix.raise(posix.SIGABRT);
|
||||
_ = posix.raise(posix.SIGKILL);
|
||||
while (true) {}
|
||||
@ -211,7 +213,7 @@ pub fn exit(status: u8) noreturn {
|
||||
c.exit(status);
|
||||
}
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
posix.exit(status);
|
||||
},
|
||||
Os.windows => {
|
||||
@ -327,7 +329,7 @@ pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u6
|
||||
}
|
||||
}
|
||||
},
|
||||
builtin.Os.linux, builtin.Os.freebsd => while (true) {
|
||||
builtin.Os.linux, builtin.Os.freebsd, Os.netbsd => while (true) {
|
||||
const rc = posix.preadv(fd, iov, count, offset);
|
||||
const err = posix.getErrno(rc);
|
||||
switch (err) {
|
||||
@ -434,7 +436,7 @@ pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, off
|
||||
}
|
||||
}
|
||||
},
|
||||
builtin.Os.linux, builtin.Os.freebsd => while (true) {
|
||||
builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => while (true) {
|
||||
const rc = posix.pwritev(fd, iov, count, offset);
|
||||
const err = posix.getErrno(rc);
|
||||
switch (err) {
|
||||
@ -699,7 +701,9 @@ pub fn getBaseAddress() usize {
|
||||
const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
|
||||
return phdr - @sizeOf(std.elf.Ehdr);
|
||||
},
|
||||
builtin.Os.macosx, builtin.Os.freebsd => return @ptrToInt(&std.c._mh_execute_header),
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
return @ptrToInt(&std.c._mh_execute_header);
|
||||
},
|
||||
builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
|
||||
else => @compileError("Unsupported OS"),
|
||||
}
|
||||
@ -1339,7 +1343,7 @@ pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
|
||||
const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
|
||||
return deleteDirW(&dir_path_w);
|
||||
},
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
const err = posix.getErrno(posix.rmdir(dir_path));
|
||||
switch (err) {
|
||||
0 => return,
|
||||
@ -1382,7 +1386,7 @@ pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
|
||||
const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
|
||||
return deleteDirW(&dir_path_w);
|
||||
},
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
const dir_path_c = try toPosixPath(dir_path);
|
||||
return deleteDirC(&dir_path_c);
|
||||
},
|
||||
@ -1501,7 +1505,7 @@ pub const Dir = struct {
|
||||
allocator: *Allocator,
|
||||
|
||||
pub const Handle = switch (builtin.os) {
|
||||
Os.macosx, Os.ios, Os.freebsd => struct {
|
||||
Os.macosx, Os.ios, Os.freebsd, Os.netbsd => struct {
|
||||
fd: i32,
|
||||
seek: i64,
|
||||
buf: []u8,
|
||||
@ -1578,7 +1582,7 @@ pub const Dir = struct {
|
||||
.name_data = undefined,
|
||||
};
|
||||
},
|
||||
Os.macosx, Os.ios, Os.freebsd => Handle{
|
||||
Os.macosx, Os.ios, Os.freebsd, Os.netbsd => Handle{
|
||||
.fd = try posixOpen(
|
||||
dir_path,
|
||||
posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
|
||||
@ -1609,7 +1613,7 @@ pub const Dir = struct {
|
||||
Os.windows => {
|
||||
_ = windows.FindClose(self.handle.handle);
|
||||
},
|
||||
Os.macosx, Os.ios, Os.linux, Os.freebsd => {
|
||||
Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
|
||||
self.allocator.free(self.handle.buf);
|
||||
os.close(self.handle.fd);
|
||||
},
|
||||
@ -1625,6 +1629,7 @@ pub const Dir = struct {
|
||||
Os.macosx, Os.ios => return self.nextDarwin(),
|
||||
Os.windows => return self.nextWindows(),
|
||||
Os.freebsd => return self.nextFreebsd(),
|
||||
Os.netbsd => return self.nextFreebsd(),
|
||||
else => @compileError("unimplemented"),
|
||||
}
|
||||
}
|
||||
@ -2256,7 +2261,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
|
||||
pub fn openSelfExe() !os.File {
|
||||
switch (builtin.os) {
|
||||
Os.linux => return os.File.openReadC(c"/proc/self/exe"),
|
||||
Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
var buf: [MAX_PATH_BYTES]u8 = undefined;
|
||||
const self_exe_path = try selfExePath(&buf);
|
||||
buf[self_exe_path.len] = 0;
|
||||
@ -2317,6 +2322,19 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
||||
else => unexpectedErrorPosix(err),
|
||||
};
|
||||
},
|
||||
Os.netbsd => {
|
||||
var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC_ARGS, -1, posix.KERN_PROC_PATHNAME };
|
||||
var out_len: usize = out_buffer.len;
|
||||
const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
|
||||
|
||||
if (err == 0) return mem.toSlice(u8, out_buffer);
|
||||
|
||||
return switch (err) {
|
||||
posix.EFAULT => error.BadAdress,
|
||||
posix.EPERM => error.PermissionDenied,
|
||||
else => unexpectedErrorPosix(err),
|
||||
};
|
||||
},
|
||||
Os.windows => {
|
||||
var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
|
||||
const utf16le_slice = try selfExePathW(&utf16le_buf);
|
||||
@ -2355,7 +2373,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
|
||||
// will not return null.
|
||||
return path.dirname(full_exe_path).?;
|
||||
},
|
||||
Os.windows, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.windows, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
const self_exe_path = try selfExePath(out_buffer);
|
||||
// Assume that the OS APIs return absolute paths, and therefore dirname
|
||||
// will not return null.
|
||||
@ -3227,7 +3245,7 @@ pub const CpuCountError = error{
|
||||
|
||||
pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
|
||||
var count: c_int = undefined;
|
||||
var count_len: usize = @sizeOf(c_int);
|
||||
const rc = posix.sysctlbyname(switch (builtin.os) {
|
||||
|
@ -6,7 +6,7 @@ const vdso = @import("vdso.zig");
|
||||
pub use switch (builtin.arch) {
|
||||
builtin.Arch.x86_64 => @import("x86_64.zig"),
|
||||
builtin.Arch.i386 => @import("i386.zig"),
|
||||
builtin.Arch.aarch64v8 => @import("arm64.zig"),
|
||||
builtin.Arch.aarch64 => @import("arm64.zig"),
|
||||
else => @compileError("unsupported arch"),
|
||||
};
|
||||
pub use @import("errno.zig");
|
||||
|
134
std/os/netbsd/errno.zig
Normal file
134
std/os/netbsd/errno.zig
Normal file
@ -0,0 +1,134 @@
|
||||
pub const EPERM = 1; // Operation not permitted
|
||||
pub const ENOENT = 2; // No such file or directory
|
||||
pub const ESRCH = 3; // No such process
|
||||
pub const EINTR = 4; // Interrupted system call
|
||||
pub const EIO = 5; // Input/output error
|
||||
pub const ENXIO = 6; // Device not configured
|
||||
pub const E2BIG = 7; // Argument list too long
|
||||
pub const ENOEXEC = 8; // Exec format error
|
||||
pub const EBADF = 9; // Bad file descriptor
|
||||
pub const ECHILD = 10; // No child processes
|
||||
pub const EDEADLK = 11; // Resource deadlock avoided
|
||||
// 11 was EAGAIN
|
||||
pub const ENOMEM = 12; // Cannot allocate memory
|
||||
pub const EACCES = 13; // Permission denied
|
||||
pub const EFAULT = 14; // Bad address
|
||||
pub const ENOTBLK = 15; // Block device required
|
||||
pub const EBUSY = 16; // Device busy
|
||||
pub const EEXIST = 17; // File exists
|
||||
pub const EXDEV = 18; // Cross-device link
|
||||
pub const ENODEV = 19; // Operation not supported by device
|
||||
pub const ENOTDIR = 20; // Not a directory
|
||||
pub const EISDIR = 21; // Is a directory
|
||||
pub const EINVAL = 22; // Invalid argument
|
||||
pub const ENFILE = 23; // Too many open files in system
|
||||
pub const EMFILE = 24; // Too many open files
|
||||
pub const ENOTTY = 25; // Inappropriate ioctl for device
|
||||
pub const ETXTBSY = 26; // Text file busy
|
||||
pub const EFBIG = 27; // File too large
|
||||
pub const ENOSPC = 28; // No space left on device
|
||||
pub const ESPIPE = 29; // Illegal seek
|
||||
pub const EROFS = 30; // Read-only file system
|
||||
pub const EMLINK = 31; // Too many links
|
||||
pub const EPIPE = 32; // Broken pipe
|
||||
|
||||
// math software
|
||||
pub const EDOM = 33; // Numerical argument out of domain
|
||||
pub const ERANGE = 34; // Result too large or too small
|
||||
|
||||
// non-blocking and interrupt i/o
|
||||
pub const EAGAIN = 35; // Resource temporarily unavailable
|
||||
pub const EWOULDBLOCK = EAGAIN; // Operation would block
|
||||
pub const EINPROGRESS = 36; // Operation now in progress
|
||||
pub const EALREADY = 37; // Operation already in progress
|
||||
|
||||
// ipc/network software -- argument errors
|
||||
pub const ENOTSOCK = 38; // Socket operation on non-socket
|
||||
pub const EDESTADDRREQ = 39; // Destination address required
|
||||
pub const EMSGSIZE = 40; // Message too long
|
||||
pub const EPROTOTYPE = 41; // Protocol wrong type for socket
|
||||
pub const ENOPROTOOPT = 42; // Protocol option not available
|
||||
pub const EPROTONOSUPPORT = 43; // Protocol not supported
|
||||
pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
|
||||
pub const EOPNOTSUPP = 45; // Operation not supported
|
||||
pub const EPFNOSUPPORT = 46; // Protocol family not supported
|
||||
pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
|
||||
pub const EADDRINUSE = 48; // Address already in use
|
||||
pub const EADDRNOTAVAIL = 49; // Can't assign requested address
|
||||
|
||||
// ipc/network software -- operational errors
|
||||
pub const ENETDOWN = 50; // Network is down
|
||||
pub const ENETUNREACH = 51; // Network is unreachable
|
||||
pub const ENETRESET = 52; // Network dropped connection on reset
|
||||
pub const ECONNABORTED = 53; // Software caused connection abort
|
||||
pub const ECONNRESET = 54; // Connection reset by peer
|
||||
pub const ENOBUFS = 55; // No buffer space available
|
||||
pub const EISCONN = 56; // Socket is already connected
|
||||
pub const ENOTCONN = 57; // Socket is not connected
|
||||
pub const ESHUTDOWN = 58; // Can't send after socket shutdown
|
||||
pub const ETOOMANYREFS = 59; // Too many references: can't splice
|
||||
pub const ETIMEDOUT = 60; // Operation timed out
|
||||
pub const ECONNREFUSED = 61; // Connection refused
|
||||
|
||||
pub const ELOOP = 62; // Too many levels of symbolic links
|
||||
pub const ENAMETOOLONG = 63; // File name too long
|
||||
|
||||
// should be rearranged
|
||||
pub const EHOSTDOWN = 64; // Host is down
|
||||
pub const EHOSTUNREACH = 65; // No route to host
|
||||
pub const ENOTEMPTY = 66; // Directory not empty
|
||||
|
||||
// quotas & mush
|
||||
pub const EPROCLIM = 67; // Too many processes
|
||||
pub const EUSERS = 68; // Too many users
|
||||
pub const EDQUOT = 69; // Disc quota exceeded
|
||||
|
||||
// Network File System
|
||||
pub const ESTALE = 70; // Stale NFS file handle
|
||||
pub const EREMOTE = 71; // Too many levels of remote in path
|
||||
pub const EBADRPC = 72; // RPC struct is bad
|
||||
pub const ERPCMISMATCH = 73; // RPC version wrong
|
||||
pub const EPROGUNAVAIL = 74; // RPC prog. not avail
|
||||
pub const EPROGMISMATCH = 75; // Program version wrong
|
||||
pub const EPROCUNAVAIL = 76; // Bad procedure for program
|
||||
|
||||
pub const ENOLCK = 77; // No locks available
|
||||
pub const ENOSYS = 78; // Function not implemented
|
||||
|
||||
pub const EFTYPE = 79; // Inappropriate file type or format
|
||||
pub const EAUTH = 80; // Authentication error
|
||||
pub const ENEEDAUTH = 81; // Need authenticator
|
||||
|
||||
// SystemV IPC
|
||||
pub const EIDRM = 82; // Identifier removed
|
||||
pub const ENOMSG = 83; // No message of desired type
|
||||
pub const EOVERFLOW = 84; // Value too large to be stored in data type
|
||||
|
||||
// Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995
|
||||
pub const EILSEQ = 85; // Illegal byte sequence
|
||||
|
||||
// From IEEE Std 1003.1-2001
|
||||
// Base, Realtime, Threads or Thread Priority Scheduling option errors
|
||||
pub const ENOTSUP = 86; // Not supported
|
||||
|
||||
// Realtime option errors
|
||||
pub const ECANCELED = 87; // Operation canceled
|
||||
|
||||
// Realtime, XSI STREAMS option errors
|
||||
pub const EBADMSG = 88; // Bad or Corrupt message
|
||||
|
||||
// XSI STREAMS option errors
|
||||
pub const ENODATA = 89; // No message available
|
||||
pub const ENOSR = 90; // No STREAM resources
|
||||
pub const ENOSTR = 91; // Not a STREAM
|
||||
pub const ETIME = 92; // STREAM ioctl timeout
|
||||
|
||||
// File system extended attribute errors
|
||||
pub const ENOATTR = 93; // Attribute not found
|
||||
|
||||
// Realtime, XSI STREAMS option errors
|
||||
pub const EMULTIHOP = 94; // Multihop attempted
|
||||
pub const ENOLINK = 95; // Link has been severed
|
||||
pub const EPROTO = 96; // Protocol error
|
||||
|
||||
pub const ELAST = 96; // Must equal largest errno
|
725
std/os/netbsd/index.zig
Normal file
725
std/os/netbsd/index.zig
Normal file
@ -0,0 +1,725 @@
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub use @import("errno.zig");
|
||||
|
||||
const std = @import("../../index.zig");
|
||||
const c = std.c;
|
||||
|
||||
const assert = std.debug.assert;
|
||||
const maxInt = std.math.maxInt;
|
||||
pub const Kevent = c.Kevent;
|
||||
|
||||
pub const CTL_KERN = 1;
|
||||
pub const CTL_DEBUG = 5;
|
||||
|
||||
pub const KERN_PROC_ARGS = 48; // struct: process argv/env
|
||||
pub const KERN_PROC_PATHNAME = 5; // path to executable
|
||||
|
||||
pub const PATH_MAX = 1024;
|
||||
|
||||
pub const STDIN_FILENO = 0;
|
||||
pub const STDOUT_FILENO = 1;
|
||||
pub const STDERR_FILENO = 2;
|
||||
|
||||
pub const PROT_NONE = 0;
|
||||
pub const PROT_READ = 1;
|
||||
pub const PROT_WRITE = 2;
|
||||
pub const PROT_EXEC = 4;
|
||||
|
||||
pub const CLOCK_REALTIME = 0;
|
||||
pub const CLOCK_VIRTUAL = 1;
|
||||
pub const CLOCK_PROF = 2;
|
||||
pub const CLOCK_MONOTONIC = 3;
|
||||
pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000;
|
||||
pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000;
|
||||
|
||||
pub const MAP_FAILED = maxInt(usize);
|
||||
pub const MAP_SHARED = 0x0001;
|
||||
pub const MAP_PRIVATE = 0x0002;
|
||||
pub const MAP_REMAPDUP = 0x0004;
|
||||
pub const MAP_FIXED = 0x0010;
|
||||
pub const MAP_RENAME = 0x0020;
|
||||
pub const MAP_NORESERVE = 0x0040;
|
||||
pub const MAP_INHERIT = 0x0080;
|
||||
pub const MAP_HASSEMAPHORE = 0x0200;
|
||||
pub const MAP_TRYFIXED = 0x0400;
|
||||
pub const MAP_WIRED = 0x0800;
|
||||
|
||||
pub const MAP_FILE = 0x0000;
|
||||
pub const MAP_NOSYNC = 0x0800;
|
||||
pub const MAP_ANON = 0x1000;
|
||||
pub const MAP_ANONYMOUS = MAP_ANON;
|
||||
pub const MAP_STACK = 0x2000;
|
||||
|
||||
pub const WNOHANG = 0x00000001;
|
||||
pub const WUNTRACED = 0x00000002;
|
||||
pub const WSTOPPED = WUNTRACED;
|
||||
pub const WCONTINUED = 0x00000010;
|
||||
pub const WNOWAIT = 0x00010000;
|
||||
pub const WEXITED = 0x00000020;
|
||||
pub const WTRAPPED = 0x00000040;
|
||||
|
||||
pub const SA_ONSTACK = 0x0001;
|
||||
pub const SA_RESTART = 0x0002;
|
||||
pub const SA_RESETHAND = 0x0004;
|
||||
pub const SA_NOCLDSTOP = 0x0008;
|
||||
pub const SA_NODEFER = 0x0010;
|
||||
pub const SA_NOCLDWAIT = 0x0020;
|
||||
pub const SA_SIGINFO = 0x0040;
|
||||
|
||||
pub const SIGHUP = 1;
|
||||
pub const SIGINT = 2;
|
||||
pub const SIGQUIT = 3;
|
||||
pub const SIGILL = 4;
|
||||
pub const SIGTRAP = 5;
|
||||
pub const SIGABRT = 6;
|
||||
pub const SIGIOT = SIGABRT;
|
||||
pub const SIGEMT = 7;
|
||||
pub const SIGFPE = 8;
|
||||
pub const SIGKILL = 9;
|
||||
pub const SIGBUS = 10;
|
||||
pub const SIGSEGV = 11;
|
||||
pub const SIGSYS = 12;
|
||||
pub const SIGPIPE = 13;
|
||||
pub const SIGALRM = 14;
|
||||
pub const SIGTERM = 15;
|
||||
pub const SIGURG = 16;
|
||||
pub const SIGSTOP = 17;
|
||||
pub const SIGTSTP = 18;
|
||||
pub const SIGCONT = 19;
|
||||
pub const SIGCHLD = 20;
|
||||
pub const SIGTTIN = 21;
|
||||
pub const SIGTTOU = 22;
|
||||
pub const SIGIO = 23;
|
||||
pub const SIGXCPU = 24;
|
||||
pub const SIGXFSZ = 25;
|
||||
pub const SIGVTALRM = 26;
|
||||
pub const SIGPROF = 27;
|
||||
pub const SIGWINCH = 28;
|
||||
pub const SIGINFO = 29;
|
||||
pub const SIGUSR1 = 30;
|
||||
pub const SIGUSR2 = 31;
|
||||
pub const SIGPWR = 32;
|
||||
|
||||
pub const SIGRTMIN = 33;
|
||||
pub const SIGRTMAX = 63;
|
||||
|
||||
// access function
|
||||
pub const F_OK = 0; // test for existence of file
|
||||
pub const X_OK = 1; // test for execute or search permission
|
||||
pub const W_OK = 2; // test for write permission
|
||||
pub const R_OK = 4; // test for read permission
|
||||
|
||||
|
||||
pub const O_RDONLY = 0x0000;
|
||||
pub const O_WRONLY = 0x0001;
|
||||
pub const O_RDWR = 0x0002;
|
||||
pub const O_ACCMODE = 0x0003;
|
||||
|
||||
pub const O_CREAT = 0x0200;
|
||||
pub const O_EXCL = 0x0800;
|
||||
pub const O_NOCTTY = 0x8000;
|
||||
pub const O_TRUNC = 0x0400;
|
||||
pub const O_APPEND = 0x0008;
|
||||
pub const O_NONBLOCK = 0x0004;
|
||||
pub const O_DSYNC = 0x00010000;
|
||||
pub const O_SYNC = 0x0080;
|
||||
pub const O_RSYNC = 0x00020000;
|
||||
pub const O_DIRECTORY = 0x00080000;
|
||||
pub const O_NOFOLLOW = 0x00000100;
|
||||
pub const O_CLOEXEC = 0x00400000;
|
||||
|
||||
pub const O_ASYNC = 0x0040;
|
||||
pub const O_DIRECT = 0x00080000;
|
||||
pub const O_LARGEFILE = 0;
|
||||
pub const O_NOATIME = 0;
|
||||
pub const O_PATH = 0;
|
||||
pub const O_TMPFILE = 0;
|
||||
pub const O_NDELAY = O_NONBLOCK;
|
||||
|
||||
pub const F_DUPFD = 0;
|
||||
pub const F_GETFD = 1;
|
||||
pub const F_SETFD = 2;
|
||||
pub const F_GETFL = 3;
|
||||
pub const F_SETFL = 4;
|
||||
|
||||
pub const F_GETOWN = 5;
|
||||
pub const F_SETOWN = 6;
|
||||
|
||||
pub const F_GETLK = 7;
|
||||
pub const F_SETLK = 8;
|
||||
pub const F_SETLKW = 9;
|
||||
|
||||
pub const SEEK_SET = 0;
|
||||
pub const SEEK_CUR = 1;
|
||||
pub const SEEK_END = 2;
|
||||
|
||||
pub const SIG_BLOCK = 1;
|
||||
pub const SIG_UNBLOCK = 2;
|
||||
pub const SIG_SETMASK = 3;
|
||||
|
||||
pub const SOCK_STREAM = 1;
|
||||
pub const SOCK_DGRAM = 2;
|
||||
pub const SOCK_RAW = 3;
|
||||
pub const SOCK_RDM = 4;
|
||||
pub const SOCK_SEQPACKET = 5;
|
||||
|
||||
pub const SOCK_CLOEXEC = 0x10000000;
|
||||
pub const SOCK_NONBLOCK = 0x20000000;
|
||||
|
||||
pub const PROTO_ip = 0;
|
||||
pub const PROTO_icmp = 1;
|
||||
pub const PROTO_igmp = 2;
|
||||
pub const PROTO_ggp = 3;
|
||||
pub const PROTO_ipencap = 4;
|
||||
pub const PROTO_tcp = 6;
|
||||
pub const PROTO_egp = 8;
|
||||
pub const PROTO_pup = 12;
|
||||
pub const PROTO_udp = 17;
|
||||
pub const PROTO_xns_idp = 22;
|
||||
pub const PROTO_iso_tp4 = 29;
|
||||
pub const PROTO_ipv6 = 41;
|
||||
pub const PROTO_ipv6_route = 43;
|
||||
pub const PROTO_ipv6_frag = 44;
|
||||
pub const PROTO_rsvp = 46;
|
||||
pub const PROTO_gre = 47;
|
||||
pub const PROTO_esp = 50;
|
||||
pub const PROTO_ah = 51;
|
||||
pub const PROTO_ipv6_icmp = 58;
|
||||
pub const PROTO_ipv6_nonxt = 59;
|
||||
pub const PROTO_ipv6_opts = 60;
|
||||
pub const PROTO_encap = 98;
|
||||
pub const PROTO_pim = 103;
|
||||
pub const PROTO_raw = 255;
|
||||
|
||||
pub const PF_UNSPEC = 0;
|
||||
pub const PF_LOCAL = 1;
|
||||
pub const PF_UNIX = PF_LOCAL;
|
||||
pub const PF_FILE = PF_LOCAL;
|
||||
pub const PF_INET = 2;
|
||||
pub const PF_APPLETALK = 16;
|
||||
pub const PF_INET6 = 24;
|
||||
pub const PF_DECnet = 12;
|
||||
pub const PF_KEY = 29;
|
||||
pub const PF_ROUTE = 34;
|
||||
pub const PF_SNA = 11;
|
||||
pub const PF_MPLS = 33;
|
||||
pub const PF_CAN = 35;
|
||||
pub const PF_BLUETOOTH = 31;
|
||||
pub const PF_ISDN = 26;
|
||||
pub const PF_MAX = 37;
|
||||
|
||||
pub const AF_UNSPEC = PF_UNSPEC;
|
||||
pub const AF_LOCAL = PF_LOCAL;
|
||||
pub const AF_UNIX = AF_LOCAL;
|
||||
pub const AF_FILE = AF_LOCAL;
|
||||
pub const AF_INET = PF_INET;
|
||||
pub const AF_APPLETALK = PF_APPLETALK;
|
||||
pub const AF_INET6 = PF_INET6;
|
||||
pub const AF_KEY = PF_KEY;
|
||||
pub const AF_ROUTE = PF_ROUTE;
|
||||
pub const AF_SNA = PF_SNA;
|
||||
pub const AF_MPLS = PF_MPLS;
|
||||
pub const AF_CAN = PF_CAN;
|
||||
pub const AF_BLUETOOTH = PF_BLUETOOTH;
|
||||
pub const AF_ISDN = PF_ISDN;
|
||||
pub const AF_MAX = PF_MAX;
|
||||
|
||||
pub const DT_UNKNOWN = 0;
|
||||
pub const DT_FIFO = 1;
|
||||
pub const DT_CHR = 2;
|
||||
pub const DT_DIR = 4;
|
||||
pub const DT_BLK = 6;
|
||||
pub const DT_REG = 8;
|
||||
pub const DT_LNK = 10;
|
||||
pub const DT_SOCK = 12;
|
||||
pub const DT_WHT = 14;
|
||||
|
||||
/// add event to kq (implies enable)
|
||||
pub const EV_ADD = 0x0001;
|
||||
|
||||
/// delete event from kq
|
||||
pub const EV_DELETE = 0x0002;
|
||||
|
||||
/// enable event
|
||||
pub const EV_ENABLE = 0x0004;
|
||||
|
||||
/// disable event (not reported)
|
||||
pub const EV_DISABLE = 0x0008;
|
||||
|
||||
/// only report one occurrence
|
||||
pub const EV_ONESHOT = 0x0010;
|
||||
|
||||
/// clear event state after reporting
|
||||
pub const EV_CLEAR = 0x0020;
|
||||
|
||||
/// force immediate event output
|
||||
/// ... with or without EV_ERROR
|
||||
/// ... use KEVENT_FLAG_ERROR_EVENTS
|
||||
/// on syscalls supporting flags
|
||||
pub const EV_RECEIPT = 0x0040;
|
||||
|
||||
/// disable event after reporting
|
||||
pub const EV_DISPATCH = 0x0080;
|
||||
|
||||
pub const EVFILT_READ = 0;
|
||||
pub const EVFILT_WRITE = 1;
|
||||
|
||||
/// attached to aio requests
|
||||
pub const EVFILT_AIO = 2;
|
||||
|
||||
/// attached to vnodes
|
||||
pub const EVFILT_VNODE = 3;
|
||||
|
||||
/// attached to struct proc
|
||||
pub const EVFILT_PROC = 4;
|
||||
|
||||
/// attached to struct proc
|
||||
pub const EVFILT_SIGNAL = 5;
|
||||
|
||||
/// timers
|
||||
pub const EVFILT_TIMER = 6;
|
||||
|
||||
/// Filesystem events
|
||||
pub const EVFILT_FS = 7;
|
||||
|
||||
/// On input, NOTE_TRIGGER causes the event to be triggered for output.
|
||||
pub const NOTE_TRIGGER = 0x08000000;
|
||||
|
||||
/// low water mark
|
||||
pub const NOTE_LOWAT = 0x00000001;
|
||||
|
||||
/// vnode was removed
|
||||
pub const NOTE_DELETE = 0x00000001;
|
||||
|
||||
/// data contents changed
|
||||
pub const NOTE_WRITE = 0x00000002;
|
||||
|
||||
/// size increased
|
||||
pub const NOTE_EXTEND = 0x00000004;
|
||||
|
||||
/// attributes changed
|
||||
pub const NOTE_ATTRIB = 0x00000008;
|
||||
|
||||
/// link count changed
|
||||
pub const NOTE_LINK = 0x00000010;
|
||||
|
||||
/// vnode was renamed
|
||||
pub const NOTE_RENAME = 0x00000020;
|
||||
|
||||
/// vnode access was revoked
|
||||
pub const NOTE_REVOKE = 0x00000040;
|
||||
|
||||
/// process exited
|
||||
pub const NOTE_EXIT = 0x80000000;
|
||||
|
||||
/// process forked
|
||||
pub const NOTE_FORK = 0x40000000;
|
||||
|
||||
/// process exec'd
|
||||
pub const NOTE_EXEC = 0x20000000;
|
||||
|
||||
/// mask for signal & exit status
|
||||
pub const NOTE_PDATAMASK = 0x000fffff;
|
||||
pub const NOTE_PCTRLMASK = 0xf0000000;
|
||||
|
||||
pub const TIOCCBRK = 0x2000747a;
|
||||
pub const TIOCCDTR = 0x20007478;
|
||||
pub const TIOCCONS = 0x80047462;
|
||||
pub const TIOCDCDTIMESTAMP = 0x40107458;
|
||||
pub const TIOCDRAIN = 0x2000745e;
|
||||
pub const TIOCEXCL = 0x2000740d;
|
||||
pub const TIOCEXT = 0x80047460;
|
||||
pub const TIOCFLAG_CDTRCTS = 0x10;
|
||||
pub const TIOCFLAG_CLOCAL = 0x2;
|
||||
pub const TIOCFLAG_CRTSCTS = 0x4;
|
||||
pub const TIOCFLAG_MDMBUF = 0x8;
|
||||
pub const TIOCFLAG_SOFTCAR = 0x1;
|
||||
pub const TIOCFLUSH = 0x80047410;
|
||||
pub const TIOCGETA = 0x402c7413;
|
||||
pub const TIOCGETD = 0x4004741a;
|
||||
pub const TIOCGFLAGS = 0x4004745d;
|
||||
pub const TIOCGLINED = 0x40207442;
|
||||
pub const TIOCGPGRP = 0x40047477;
|
||||
pub const TIOCGQSIZE = 0x40047481;
|
||||
pub const TIOCGRANTPT = 0x20007447;
|
||||
pub const TIOCGSID = 0x40047463;
|
||||
pub const TIOCGSIZE = 0x40087468;
|
||||
pub const TIOCGWINSZ = 0x40087468;
|
||||
pub const TIOCMBIC = 0x8004746b;
|
||||
pub const TIOCMBIS = 0x8004746c;
|
||||
pub const TIOCMGET = 0x4004746a;
|
||||
pub const TIOCMSET = 0x8004746d;
|
||||
pub const TIOCM_CAR = 0x40;
|
||||
pub const TIOCM_CD = 0x40;
|
||||
pub const TIOCM_CTS = 0x20;
|
||||
pub const TIOCM_DSR = 0x100;
|
||||
pub const TIOCM_DTR = 0x2;
|
||||
pub const TIOCM_LE = 0x1;
|
||||
pub const TIOCM_RI = 0x80;
|
||||
pub const TIOCM_RNG = 0x80;
|
||||
pub const TIOCM_RTS = 0x4;
|
||||
pub const TIOCM_SR = 0x10;
|
||||
pub const TIOCM_ST = 0x8;
|
||||
pub const TIOCNOTTY = 0x20007471;
|
||||
pub const TIOCNXCL = 0x2000740e;
|
||||
pub const TIOCOUTQ = 0x40047473;
|
||||
pub const TIOCPKT = 0x80047470;
|
||||
pub const TIOCPKT_DATA = 0x0;
|
||||
pub const TIOCPKT_DOSTOP = 0x20;
|
||||
pub const TIOCPKT_FLUSHREAD = 0x1;
|
||||
pub const TIOCPKT_FLUSHWRITE = 0x2;
|
||||
pub const TIOCPKT_IOCTL = 0x40;
|
||||
pub const TIOCPKT_NOSTOP = 0x10;
|
||||
pub const TIOCPKT_START = 0x8;
|
||||
pub const TIOCPKT_STOP = 0x4;
|
||||
pub const TIOCPTMGET = 0x40287446;
|
||||
pub const TIOCPTSNAME = 0x40287448;
|
||||
pub const TIOCRCVFRAME = 0x80087445;
|
||||
pub const TIOCREMOTE = 0x80047469;
|
||||
pub const TIOCSBRK = 0x2000747b;
|
||||
pub const TIOCSCTTY = 0x20007461;
|
||||
pub const TIOCSDTR = 0x20007479;
|
||||
pub const TIOCSETA = 0x802c7414;
|
||||
pub const TIOCSETAF = 0x802c7416;
|
||||
pub const TIOCSETAW = 0x802c7415;
|
||||
pub const TIOCSETD = 0x8004741b;
|
||||
pub const TIOCSFLAGS = 0x8004745c;
|
||||
pub const TIOCSIG = 0x2000745f;
|
||||
pub const TIOCSLINED = 0x80207443;
|
||||
pub const TIOCSPGRP = 0x80047476;
|
||||
pub const TIOCSQSIZE = 0x80047480;
|
||||
pub const TIOCSSIZE = 0x80087467;
|
||||
pub const TIOCSTART = 0x2000746e;
|
||||
pub const TIOCSTAT = 0x80047465;
|
||||
pub const TIOCSTI = 0x80017472;
|
||||
pub const TIOCSTOP = 0x2000746f;
|
||||
pub const TIOCSWINSZ = 0x80087467;
|
||||
pub const TIOCUCNTL = 0x80047466;
|
||||
pub const TIOCXMTFRAME = 0x80087444;
|
||||
|
||||
pub const sockaddr = c.sockaddr;
|
||||
pub const sockaddr_in = c.sockaddr_in;
|
||||
pub const sockaddr_in6 = c.sockaddr_in6;
|
||||
|
||||
fn unsigned(s: i32) u32 {
|
||||
return @bitCast(u32, s);
|
||||
}
|
||||
fn signed(s: u32) i32 {
|
||||
return @bitCast(i32, s);
|
||||
}
|
||||
pub fn WEXITSTATUS(s: i32) i32 {
|
||||
return signed((unsigned(s) >> 8) & 0xff);
|
||||
}
|
||||
pub fn WTERMSIG(s: i32) i32 {
|
||||
return signed(unsigned(s) & 0x7f);
|
||||
}
|
||||
pub fn WSTOPSIG(s: i32) i32 {
|
||||
return WEXITSTATUS(s);
|
||||
}
|
||||
pub fn WIFEXITED(s: i32) bool {
|
||||
return WTERMSIG(s) == 0;
|
||||
}
|
||||
|
||||
pub fn WIFCONTINUED(s: i32) bool {
|
||||
return ((s & 0x7f) == 0xffff);
|
||||
}
|
||||
|
||||
pub fn WIFSTOPPED(s: i32) bool {
|
||||
return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s));
|
||||
}
|
||||
|
||||
pub fn WIFSIGNALED(s: i32) bool {
|
||||
return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s);
|
||||
}
|
||||
|
||||
pub const winsize = extern struct {
|
||||
ws_row: u16,
|
||||
ws_col: u16,
|
||||
ws_xpixel: u16,
|
||||
ws_ypixel: u16,
|
||||
};
|
||||
|
||||
/// Get the errno from a syscall return value, or 0 for no error.
|
||||
pub fn getErrno(r: usize) usize {
|
||||
const signed_r = @bitCast(isize, r);
|
||||
return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
|
||||
}
|
||||
|
||||
pub fn dup2(old: i32, new: i32) usize {
|
||||
return errnoWrap(c.dup2(old, new));
|
||||
}
|
||||
|
||||
pub fn chdir(path: [*]const u8) usize {
|
||||
return errnoWrap(c.chdir(path));
|
||||
}
|
||||
|
||||
pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
|
||||
return errnoWrap(c.execve(path, argv, envp));
|
||||
}
|
||||
|
||||
pub fn fork() usize {
|
||||
return errnoWrap(c.fork());
|
||||
}
|
||||
|
||||
pub fn access(path: [*]const u8, mode: u32) usize {
|
||||
return errnoWrap(c.access(path, mode));
|
||||
}
|
||||
|
||||
pub fn getcwd(buf: [*]u8, size: usize) usize {
|
||||
return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
|
||||
}
|
||||
|
||||
pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
|
||||
return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
|
||||
}
|
||||
|
||||
pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
|
||||
return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
|
||||
}
|
||||
|
||||
pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
|
||||
return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
|
||||
}
|
||||
|
||||
pub fn isatty(fd: i32) bool {
|
||||
return c.isatty(fd) != 0;
|
||||
}
|
||||
|
||||
pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
|
||||
return errnoWrap(c.readlink(path, buf_ptr, buf_len));
|
||||
}
|
||||
|
||||
pub fn mkdir(path: [*]const u8, mode: u32) usize {
|
||||
return errnoWrap(c.mkdir(path, mode));
|
||||
}
|
||||
|
||||
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
|
||||
const ptr_result = c.mmap(
|
||||
@ptrCast(?*c_void, address),
|
||||
length,
|
||||
@bitCast(c_int, @intCast(c_uint, prot)),
|
||||
@bitCast(c_int, c_uint(flags)),
|
||||
fd,
|
||||
offset,
|
||||
);
|
||||
const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
|
||||
return errnoWrap(isize_result);
|
||||
}
|
||||
|
||||
pub fn munmap(address: usize, length: usize) usize {
|
||||
return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
|
||||
}
|
||||
|
||||
pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
|
||||
return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
|
||||
}
|
||||
|
||||
pub fn rmdir(path: [*]const u8) usize {
|
||||
return errnoWrap(c.rmdir(path));
|
||||
}
|
||||
|
||||
pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
|
||||
return errnoWrap(c.symlink(existing, new));
|
||||
}
|
||||
|
||||
pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
|
||||
return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
|
||||
}
|
||||
|
||||
pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
|
||||
return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
|
||||
}
|
||||
|
||||
pub fn pipe(fd: *[2]i32) usize {
|
||||
return pipe2(fd, 0);
|
||||
}
|
||||
|
||||
pub fn pipe2(fd: *[2]i32, flags: u32) usize {
|
||||
comptime assert(i32.bit_count == c_int.bit_count);
|
||||
return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
|
||||
}
|
||||
|
||||
pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
|
||||
return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
|
||||
}
|
||||
|
||||
pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
|
||||
return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
|
||||
}
|
||||
|
||||
pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
|
||||
return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
|
||||
}
|
||||
|
||||
pub fn rename(old: [*]const u8, new: [*]const u8) usize {
|
||||
return errnoWrap(c.rename(old, new));
|
||||
}
|
||||
|
||||
pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
|
||||
return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
|
||||
}
|
||||
|
||||
pub fn create(path: [*]const u8, perm: usize) usize {
|
||||
return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
|
||||
}
|
||||
|
||||
pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
|
||||
return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
|
||||
}
|
||||
|
||||
pub fn close(fd: i32) usize {
|
||||
return errnoWrap(c.close(fd));
|
||||
}
|
||||
|
||||
pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
|
||||
return errnoWrap(c.lseek(fd, offset, whence));
|
||||
}
|
||||
|
||||
pub fn exit(code: i32) noreturn {
|
||||
c.exit(code);
|
||||
}
|
||||
|
||||
pub fn kill(pid: i32, sig: i32) usize {
|
||||
return errnoWrap(c.kill(pid, sig));
|
||||
}
|
||||
|
||||
pub fn unlink(path: [*]const u8) usize {
|
||||
return errnoWrap(c.unlink(path));
|
||||
}
|
||||
|
||||
pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
|
||||
comptime assert(i32.bit_count == c_int.bit_count);
|
||||
return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
|
||||
}
|
||||
|
||||
pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
|
||||
return errnoWrap(c.nanosleep(req, rem));
|
||||
}
|
||||
|
||||
pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
|
||||
return errnoWrap(c.clock_gettime(clk_id, tp));
|
||||
}
|
||||
|
||||
pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
|
||||
return errnoWrap(c.clock_getres(clk_id, tp));
|
||||
}
|
||||
|
||||
pub fn setuid(uid: u32) usize {
|
||||
return errnoWrap(c.setuid(uid));
|
||||
}
|
||||
|
||||
pub fn setgid(gid: u32) usize {
|
||||
return errnoWrap(c.setgid(gid));
|
||||
}
|
||||
|
||||
pub fn setreuid(ruid: u32, euid: u32) usize {
|
||||
return errnoWrap(c.setreuid(ruid, euid));
|
||||
}
|
||||
|
||||
pub fn setregid(rgid: u32, egid: u32) usize {
|
||||
return errnoWrap(c.setregid(rgid, egid));
|
||||
}
|
||||
|
||||
const NSIG = 32;
|
||||
|
||||
pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
|
||||
pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
|
||||
pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
|
||||
|
||||
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
|
||||
pub const Sigaction = extern struct {
|
||||
/// signal handler
|
||||
__sigaction_u: extern union {
|
||||
__sa_handler: extern fn (i32) void,
|
||||
__sa_sigaction: extern fn (i32, *__siginfo, usize) void,
|
||||
},
|
||||
|
||||
/// see signal options
|
||||
sa_flags: u32,
|
||||
|
||||
/// signal mask to apply
|
||||
sa_mask: sigset_t,
|
||||
};
|
||||
|
||||
pub const _SIG_WORDS = 4;
|
||||
pub const _SIG_MAXSIG = 128;
|
||||
|
||||
pub inline fn _SIG_IDX(sig: usize) usize {
|
||||
return sig - 1;
|
||||
}
|
||||
pub inline fn _SIG_WORD(sig: usize) usize {
|
||||
return_SIG_IDX(sig) >> 5;
|
||||
}
|
||||
pub inline fn _SIG_BIT(sig: usize) usize {
|
||||
return 1 << (_SIG_IDX(sig) & 31);
|
||||
}
|
||||
pub inline fn _SIG_VALID(sig: usize) usize {
|
||||
return sig <= _SIG_MAXSIG and sig > 0;
|
||||
}
|
||||
|
||||
pub const sigset_t = extern struct {
|
||||
__bits: [_SIG_WORDS]u32,
|
||||
};
|
||||
|
||||
pub fn raise(sig: i32) usize {
|
||||
return errnoWrap(c.raise(sig));
|
||||
}
|
||||
|
||||
pub const Stat = c.Stat;
|
||||
pub const dirent = c.dirent;
|
||||
pub const timespec = c.timespec;
|
||||
|
||||
pub fn fstat(fd: i32, buf: *c.Stat) usize {
|
||||
return errnoWrap(c.fstat(fd, buf));
|
||||
}
|
||||
pub const iovec = extern struct {
|
||||
iov_base: [*]u8,
|
||||
iov_len: usize,
|
||||
};
|
||||
|
||||
pub const iovec_const = extern struct {
|
||||
iov_base: [*]const u8,
|
||||
iov_len: usize,
|
||||
};
|
||||
|
||||
// TODO avoid libc dependency
|
||||
pub fn kqueue() usize {
|
||||
return errnoWrap(c.kqueue());
|
||||
}
|
||||
|
||||
// TODO avoid libc dependency
|
||||
pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
|
||||
return errnoWrap(c.kevent(
|
||||
kq,
|
||||
changelist.ptr,
|
||||
@intCast(c_int, changelist.len),
|
||||
eventlist.ptr,
|
||||
@intCast(c_int, eventlist.len),
|
||||
timeout,
|
||||
));
|
||||
}
|
||||
|
||||
// TODO avoid libc dependency
|
||||
pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
|
||||
return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
// TODO avoid libc dependency
|
||||
pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
|
||||
return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
// TODO avoid libc dependency
|
||||
pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
|
||||
return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
|
||||
}
|
||||
|
||||
// TODO avoid libc dependency
|
||||
|
||||
/// Takes the return value from a syscall and formats it back in the way
|
||||
/// that the kernel represents it to libc. Errno was a mistake, let's make
|
||||
/// it go away forever.
|
||||
fn errnoWrap(value: isize) usize {
|
||||
return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
|
||||
}
|
@ -1226,7 +1226,7 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro
|
||||
const pathname_w = try windows_util.cStrToPrefixedFileW(pathname);
|
||||
return realW(out_buffer, pathname_w);
|
||||
},
|
||||
Os.freebsd, Os.macosx, Os.ios => {
|
||||
Os.freebsd, Os.netbsd, Os.macosx, Os.ios => {
|
||||
// TODO instead of calling the libc function here, port the implementation to Zig
|
||||
const err = posix.getErrno(posix.realpath(pathname, out_buffer));
|
||||
switch (err) {
|
||||
@ -1267,7 +1267,7 @@ pub fn real(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: []const u8) RealError!
|
||||
const pathname_w = try windows_util.sliceToPrefixedFileW(pathname);
|
||||
return realW(out_buffer, &pathname_w);
|
||||
},
|
||||
Os.macosx, Os.ios, Os.linux, Os.freebsd => {
|
||||
Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
|
||||
const pathname_c = try os.toPosixPath(pathname);
|
||||
return realC(out_buffer, &pathname_c);
|
||||
},
|
||||
|
@ -14,7 +14,7 @@ pub const epoch = @import("epoch.zig");
|
||||
/// Sleep for the specified duration
|
||||
pub fn sleep(nanoseconds: u64) void {
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
|
||||
const s = nanoseconds / ns_per_s;
|
||||
const ns = nanoseconds % ns_per_s;
|
||||
posixSleep(@intCast(u63, s), @intCast(u63, ns));
|
||||
@ -62,7 +62,7 @@ pub fn timestamp() u64 {
|
||||
/// Get the posix timestamp, UTC, in milliseconds
|
||||
pub const milliTimestamp = switch (builtin.os) {
|
||||
Os.windows => milliTimestampWindows,
|
||||
Os.linux, Os.freebsd => milliTimestampPosix,
|
||||
Os.linux, Os.freebsd, Os.netbsd => milliTimestampPosix,
|
||||
Os.macosx, Os.ios => milliTimestampDarwin,
|
||||
else => @compileError("Unsupported OS"),
|
||||
};
|
||||
@ -178,7 +178,7 @@ pub const Timer = struct {
|
||||
debug.assert(err != windows.FALSE);
|
||||
self.start_time = @intCast(u64, start_time);
|
||||
},
|
||||
Os.linux, Os.freebsd => {
|
||||
Os.linux, Os.freebsd, Os.netbsd => {
|
||||
//On Linux, seccomp can do arbitrary things to our ability to call
|
||||
// syscalls, including return any errno value it wants and
|
||||
// inconsistently throwing errors. Since we can't account for
|
||||
@ -214,7 +214,7 @@ pub const Timer = struct {
|
||||
var clock = clockNative() - self.start_time;
|
||||
return switch (builtin.os) {
|
||||
Os.windows => @divFloor(clock * ns_per_s, self.frequency),
|
||||
Os.linux, Os.freebsd => clock,
|
||||
Os.linux, Os.freebsd, Os.netbsd => clock,
|
||||
Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom),
|
||||
else => @compileError("Unsupported OS"),
|
||||
};
|
||||
@ -235,7 +235,7 @@ pub const Timer = struct {
|
||||
|
||||
const clockNative = switch (builtin.os) {
|
||||
Os.windows => clockWindows,
|
||||
Os.linux, Os.freebsd => clockLinux,
|
||||
Os.linux, Os.freebsd, Os.netbsd => clockLinux,
|
||||
Os.macosx, Os.ios => clockDarwin,
|
||||
else => @compileError("Unsupported OS"),
|
||||
};
|
||||
|
331
std/priority_queue.zig
Normal file
331
std/priority_queue.zig
Normal file
@ -0,0 +1,331 @@
|
||||
const std = @import("index.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const debug = std.debug;
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
pub fn PriorityQueue(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
items: []T,
|
||||
len: usize,
|
||||
allocator: *Allocator,
|
||||
compareFn: fn (a: T, b: T) bool,
|
||||
|
||||
pub fn init(allocator: *Allocator, compareFn: fn (a: T, b: T) bool) Self {
|
||||
return Self{
|
||||
.items = []T{},
|
||||
.len = 0,
|
||||
.allocator = allocator,
|
||||
.compareFn = compareFn,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Self) void {
|
||||
self.allocator.free(self.items);
|
||||
}
|
||||
|
||||
pub fn add(self: *Self, elem: T) !void {
|
||||
try ensureCapacity(self, self.len + 1);
|
||||
|
||||
self.items[self.len] = elem;
|
||||
var child_index = self.len;
|
||||
while (child_index > 0) {
|
||||
var parent_index = ((child_index - 1) >> 1);
|
||||
const child = self.items[child_index];
|
||||
const parent = self.items[parent_index];
|
||||
|
||||
if (!self.compareFn(child, parent)) break;
|
||||
|
||||
self.items[parent_index] = child;
|
||||
self.items[child_index] = parent;
|
||||
child_index = parent_index;
|
||||
}
|
||||
self.len += 1;
|
||||
}
|
||||
|
||||
pub fn peek(self: *Self) ?T {
|
||||
return if (self.len > 0) self.items[0] else null;
|
||||
}
|
||||
|
||||
pub fn removeOrNull(self: *Self) ?T {
|
||||
return if (self.len > 0) self.remove() else null;
|
||||
}
|
||||
|
||||
pub fn remove(self: *Self) T {
|
||||
const first = self.items[0];
|
||||
const last = self.items[self.len - 1];
|
||||
self.items[0] = last;
|
||||
self.len -= 1;
|
||||
siftDown(self);
|
||||
return first;
|
||||
}
|
||||
|
||||
pub fn count(self: Self) usize {
|
||||
return self.len;
|
||||
}
|
||||
|
||||
pub fn capacity(self: Self) usize {
|
||||
return self.items.len;
|
||||
}
|
||||
|
||||
fn siftDown(self: *Self) void {
|
||||
var index: usize = 0;
|
||||
const half = self.len >> 1;
|
||||
while (true) {
|
||||
var left_index = (index << 1) + 1;
|
||||
var right_index = left_index + 1;
|
||||
var left = if (left_index < self.len) self.items[left_index] else null;
|
||||
var right = if (right_index < self.len) self.items[right_index] else null;
|
||||
|
||||
var smallest_index = index;
|
||||
var smallest = self.items[index];
|
||||
|
||||
if (left) |e| {
|
||||
if (self.compareFn(e, smallest)) {
|
||||
smallest_index = left_index;
|
||||
smallest = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (right) |e| {
|
||||
if (self.compareFn(e, smallest)) {
|
||||
smallest_index = right_index;
|
||||
smallest = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (smallest_index == index) return;
|
||||
|
||||
self.items[smallest_index] = self.items[index];
|
||||
self.items[index] = smallest;
|
||||
index = smallest_index;
|
||||
|
||||
if (index >= half) return;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {
|
||||
var better_capacity = self.capacity();
|
||||
if (better_capacity >= new_capacity) return;
|
||||
while (true) {
|
||||
better_capacity += better_capacity / 2 + 8;
|
||||
if (better_capacity >= new_capacity) break;
|
||||
}
|
||||
self.items = try self.allocator.realloc(T, self.items, better_capacity);
|
||||
}
|
||||
|
||||
pub fn resize(self: *Self, new_len: usize) !void {
|
||||
try self.ensureCapacity(new_len);
|
||||
self.len = new_len;
|
||||
}
|
||||
|
||||
pub fn shrink(self: *Self, new_len: usize) void {
|
||||
assert(new_len <= self.len);
|
||||
self.len = new_len;
|
||||
}
|
||||
|
||||
const Iterator = struct {
|
||||
queue: *PriorityQueue(T),
|
||||
count: usize,
|
||||
|
||||
fn next(it: *Iterator) ?T {
|
||||
if (it.count > it.queue.len - 1) return null;
|
||||
const out = it.count;
|
||||
it.count += 1;
|
||||
return it.queue.items[out];
|
||||
}
|
||||
|
||||
fn reset(it: *Iterator) void {
|
||||
it.count = 0;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn iterator(self: *Self) Iterator {
|
||||
return Iterator{
|
||||
.queue = self,
|
||||
.count = 0,
|
||||
};
|
||||
}
|
||||
|
||||
fn dump(self: *Self) void {
|
||||
warn("{{ ");
|
||||
warn("items: ");
|
||||
for (self.items) |e, i| {
|
||||
if (i >= self.len) break;
|
||||
warn("{}, ", e);
|
||||
}
|
||||
warn("array: ");
|
||||
for (self.items) |e, i| {
|
||||
warn("{}, ", e);
|
||||
}
|
||||
warn("len: {} ", self.len);
|
||||
warn("capacity: {}", self.capacity());
|
||||
warn(" }}\n");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn lessThan(a: u32, b: u32) bool {
|
||||
return a < b;
|
||||
}
|
||||
|
||||
fn greaterThan(a: u32, b: u32) bool {
|
||||
return a > b;
|
||||
}
|
||||
|
||||
const PQ = PriorityQueue(u32);
|
||||
|
||||
test "std.PriorityQueue: add and remove min heap" {
|
||||
var queue = PQ.init(debug.global_allocator, lessThan);
|
||||
defer queue.deinit();
|
||||
|
||||
try queue.add(54);
|
||||
try queue.add(12);
|
||||
try queue.add(7);
|
||||
try queue.add(23);
|
||||
try queue.add(25);
|
||||
try queue.add(13);
|
||||
expectEqual(u32(7), queue.remove());
|
||||
expectEqual(u32(12), queue.remove());
|
||||
expectEqual(u32(13), queue.remove());
|
||||
expectEqual(u32(23), queue.remove());
|
||||
expectEqual(u32(25), queue.remove());
|
||||
expectEqual(u32(54), queue.remove());
|
||||
}
|
||||
|
||||
test "std.PriorityQueue: add and remove same min heap" {
|
||||
var queue = PQ.init(debug.global_allocator, lessThan);
|
||||
defer queue.deinit();
|
||||
|
||||
try queue.add(1);
|
||||
try queue.add(1);
|
||||
try queue.add(2);
|
||||
try queue.add(2);
|
||||
try queue.add(1);
|
||||
try queue.add(1);
|
||||
expectEqual(u32(1), queue.remove());
|
||||
expectEqual(u32(1), queue.remove());
|
||||
expectEqual(u32(1), queue.remove());
|
||||
expectEqual(u32(1), queue.remove());
|
||||
expectEqual(u32(2), queue.remove());
|
||||
expectEqual(u32(2), queue.remove());
|
||||
}
|
||||
|
||||
test "std.PriorityQueue: removeOrNull on empty" {
|
||||
var queue = PQ.init(debug.global_allocator, lessThan);
|
||||
defer queue.deinit();
|
||||
|
||||
expect(queue.removeOrNull() == null);
|
||||
}
|
||||
|
||||
test "std.PriorityQueue: edge case 3 elements" {
|
||||
var queue = PQ.init(debug.global_allocator, lessThan);
|
||||
defer queue.deinit();
|
||||
|
||||
try queue.add(9);
|
||||
try queue.add(3);
|
||||
try queue.add(2);
|
||||
expectEqual(u32(2), queue.remove());
|
||||
expectEqual(u32(3), queue.remove());
|
||||
expectEqual(u32(9), queue.remove());
|
||||
}
|
||||
|
||||
test "std.PriorityQueue: peek" {
|
||||
var queue = PQ.init(debug.global_allocator, lessThan);
|
||||
defer queue.deinit();
|
||||
|
||||
expect(queue.peek() == null);
|
||||
try queue.add(9);
|
||||
try queue.add(3);
|
||||
try queue.add(2);
|
||||
expectEqual(u32(2), queue.peek().?);
|
||||
expectEqual(u32(2), queue.peek().?);
|
||||
}
|
||||
|
||||
test "std.PriorityQueue: sift up with odd indices" {
|
||||
var queue = PQ.init(debug.global_allocator, lessThan);
|
||||
defer queue.deinit();
|
||||
const items = []u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
|
||||
for (items) |e| {
|
||||
try queue.add(e);
|
||||
}
|
||||
|
||||
expectEqual(u32(1), queue.remove());
|
||||
expectEqual(u32(2), queue.remove());
|
||||
expectEqual(u32(5), queue.remove());
|
||||
expectEqual(u32(6), queue.remove());
|
||||
expectEqual(u32(7), queue.remove());
|
||||
expectEqual(u32(7), queue.remove());
|
||||
expectEqual(u32(11), queue.remove());
|
||||
expectEqual(u32(12), queue.remove());
|
||||
expectEqual(u32(13), queue.remove());
|
||||
expectEqual(u32(14), queue.remove());
|
||||
expectEqual(u32(15), queue.remove());
|
||||
expectEqual(u32(15), queue.remove());
|
||||
expectEqual(u32(16), queue.remove());
|
||||
expectEqual(u32(21), queue.remove());
|
||||
expectEqual(u32(22), queue.remove());
|
||||
expectEqual(u32(24), queue.remove());
|
||||
expectEqual(u32(24), queue.remove());
|
||||
expectEqual(u32(25), queue.remove());
|
||||
}
|
||||
|
||||
test "std.PriorityQueue: add and remove max heap" {
|
||||
var queue = PQ.init(debug.global_allocator, greaterThan);
|
||||
defer queue.deinit();
|
||||
|
||||
try queue.add(54);
|
||||
try queue.add(12);
|
||||
try queue.add(7);
|
||||
try queue.add(23);
|
||||
try queue.add(25);
|
||||
try queue.add(13);
|
||||
expectEqual(u32(54), queue.remove());
|
||||
expectEqual(u32(25), queue.remove());
|
||||
expectEqual(u32(23), queue.remove());
|
||||
expectEqual(u32(13), queue.remove());
|
||||
expectEqual(u32(12), queue.remove());
|
||||
expectEqual(u32(7), queue.remove());
|
||||
}
|
||||
|
||||
test "std.PriorityQueue: add and remove same max heap" {
|
||||
var queue = PQ.init(debug.global_allocator, greaterThan);
|
||||
defer queue.deinit();
|
||||
|
||||
try queue.add(1);
|
||||
try queue.add(1);
|
||||
try queue.add(2);
|
||||
try queue.add(2);
|
||||
try queue.add(1);
|
||||
try queue.add(1);
|
||||
expectEqual(u32(2), queue.remove());
|
||||
expectEqual(u32(2), queue.remove());
|
||||
expectEqual(u32(1), queue.remove());
|
||||
expectEqual(u32(1), queue.remove());
|
||||
expectEqual(u32(1), queue.remove());
|
||||
expectEqual(u32(1), queue.remove());
|
||||
}
|
||||
|
||||
test "std.PriorityQueue: iterator" {
|
||||
var queue = PQ.init(debug.global_allocator, lessThan);
|
||||
var map = std.AutoHashMap(u32, void).init(debug.global_allocator);
|
||||
defer {
|
||||
queue.deinit();
|
||||
map.deinit();
|
||||
}
|
||||
|
||||
const items = []u32{ 54, 12, 7, 23, 25, 13 };
|
||||
for (items) |e| {
|
||||
_ = try queue.add(e);
|
||||
_ = try map.put(e, {});
|
||||
}
|
||||
|
||||
var it = queue.iterator();
|
||||
while (it.next()) |e| {
|
||||
_ = map.remove(e);
|
||||
}
|
||||
|
||||
expectEqual(usize(0), map.count());
|
||||
}
|
@ -23,15 +23,15 @@ nakedcc fn _start() noreturn {
|
||||
switch (builtin.arch) {
|
||||
builtin.Arch.x86_64 => {
|
||||
argc_ptr = asm ("lea (%%rsp), %[argc]"
|
||||
: [argc] "=r" (-> [*]usize)
|
||||
);
|
||||
: [argc] "=r" (-> [*]usize)
|
||||
);
|
||||
},
|
||||
builtin.Arch.i386 => {
|
||||
argc_ptr = asm ("lea (%%esp), %[argc]"
|
||||
: [argc] "=r" (-> [*]usize)
|
||||
);
|
||||
},
|
||||
builtin.Arch.aarch64v8 => {
|
||||
builtin.Arch.aarch64, builtin.Arch.aarch64_be => {
|
||||
argc_ptr = asm ("mov %[argc], sp"
|
||||
: [argc] "=r" (-> [*]usize)
|
||||
);
|
||||
@ -123,7 +123,7 @@ inline fn callMain() u8 {
|
||||
std.debug.warn("error: {}\n", @errorName(err));
|
||||
if (builtin.os != builtin.Os.zen) {
|
||||
if (@errorReturnTrace()) |trace| {
|
||||
std.debug.dumpStackTrace(trace);
|
||||
std.debug.dumpStackTrace(trace.*);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
@ -142,7 +142,10 @@ fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent:
|
||||
var phdr_addr = at_phdr;
|
||||
var n = at_phnum;
|
||||
var base: usize = 0;
|
||||
while (n != 0) : ({n -= 1; phdr_addr += at_phent;}) {
|
||||
while (n != 0) : ({
|
||||
n -= 1;
|
||||
phdr_addr += at_phent;
|
||||
}) {
|
||||
const phdr = @intToPtr(*std.elf.Phdr, phdr_addr);
|
||||
// TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917
|
||||
switch (phdr.p_type) {
|
||||
|
191
std/special/compiler_rt/addXf3.zig
Normal file
191
std/special/compiler_rt/addXf3.zig
Normal file
@ -0,0 +1,191 @@
|
||||
// Ported from:
|
||||
//
|
||||
// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const compiler_rt = @import("index.zig");
|
||||
|
||||
pub extern fn __addtf3(a: f128, b: f128) f128 {
|
||||
return addXf3(f128, a, b);
|
||||
}
|
||||
|
||||
pub extern fn __subtf3(a: f128, b: f128) f128 {
|
||||
const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (u128(1) << 127));
|
||||
return addXf3(f128, a, neg_b);
|
||||
}
|
||||
|
||||
inline fn normalize(comptime T: type, significand: *@IntType(false, T.bit_count)) i32 {
|
||||
const Z = @IntType(false, T.bit_count);
|
||||
const significandBits = std.math.floatMantissaBits(T);
|
||||
const implicitBit = Z(1) << significandBits;
|
||||
|
||||
const shift = @clz(significand.*) - @clz(implicitBit);
|
||||
significand.* <<= @intCast(u7, shift);
|
||||
return 1 - shift;
|
||||
}
|
||||
|
||||
inline fn addXf3(comptime T: type, a: T, b: T) T {
|
||||
const Z = @IntType(false, T.bit_count);
|
||||
|
||||
const typeWidth = T.bit_count;
|
||||
const significandBits = std.math.floatMantissaBits(T);
|
||||
const exponentBits = std.math.floatExponentBits(T);
|
||||
|
||||
const signBit = (Z(1) << (significandBits + exponentBits));
|
||||
const maxExponent = ((1 << exponentBits) - 1);
|
||||
const exponentBias = (maxExponent >> 1);
|
||||
|
||||
const implicitBit = (Z(1) << significandBits);
|
||||
const quietBit = implicitBit >> 1;
|
||||
const significandMask = implicitBit - 1;
|
||||
|
||||
const absMask = signBit - 1;
|
||||
const exponentMask = absMask ^ significandMask;
|
||||
const qnanRep = exponentMask | quietBit;
|
||||
|
||||
var aRep = @bitCast(Z, a);
|
||||
var bRep = @bitCast(Z, b);
|
||||
const aAbs = aRep & absMask;
|
||||
const bAbs = bRep & absMask;
|
||||
|
||||
const negative = (aRep & signBit) != 0;
|
||||
const exponent = @intCast(i32, aAbs >> significandBits) - exponentBias;
|
||||
const significand = (aAbs & significandMask) | implicitBit;
|
||||
|
||||
const infRep = @bitCast(Z, std.math.inf(T));
|
||||
|
||||
// Detect if a or b is zero, infinity, or NaN.
|
||||
if (aAbs - Z(1) >= infRep - Z(1) or
|
||||
bAbs - Z(1) >= infRep - Z(1))
|
||||
{
|
||||
// NaN + anything = qNaN
|
||||
if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit);
|
||||
// anything + NaN = qNaN
|
||||
if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit);
|
||||
|
||||
if (aAbs == infRep) {
|
||||
// +/-infinity + -/+infinity = qNaN
|
||||
if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) {
|
||||
return @bitCast(T, qnanRep);
|
||||
}
|
||||
// +/-infinity + anything remaining = +/- infinity
|
||||
else {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
// anything remaining + +/-infinity = +/-infinity
|
||||
if (bAbs == infRep) return b;
|
||||
|
||||
// zero + anything = anything
|
||||
if (aAbs == 0) {
|
||||
// but we need to get the sign right for zero + zero
|
||||
if (bAbs == 0) {
|
||||
return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b));
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
// anything + zero = anything
|
||||
if (bAbs == 0) return a;
|
||||
}
|
||||
|
||||
// Swap a and b if necessary so that a has the larger absolute value.
|
||||
if (bAbs > aAbs) {
|
||||
const temp = aRep;
|
||||
aRep = bRep;
|
||||
bRep = temp;
|
||||
}
|
||||
|
||||
// Extract the exponent and significand from the (possibly swapped) a and b.
|
||||
var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent);
|
||||
var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent);
|
||||
var aSignificand = aRep & significandMask;
|
||||
var bSignificand = bRep & significandMask;
|
||||
|
||||
// Normalize any denormals, and adjust the exponent accordingly.
|
||||
if (aExponent == 0) aExponent = normalize(T, &aSignificand);
|
||||
if (bExponent == 0) bExponent = normalize(T, &bSignificand);
|
||||
|
||||
// The sign of the result is the sign of the larger operand, a. If they
|
||||
// have opposite signs, we are performing a subtraction; otherwise addition.
|
||||
const resultSign = aRep & signBit;
|
||||
const subtraction = (aRep ^ bRep) & signBit != 0;
|
||||
|
||||
// Shift the significands to give us round, guard and sticky, and or in the
|
||||
// implicit significand bit. (If we fell through from the denormal path it
|
||||
// was already set by normalize( ), but setting it twice won't hurt
|
||||
// anything.)
|
||||
aSignificand = (aSignificand | implicitBit) << 3;
|
||||
bSignificand = (bSignificand | implicitBit) << 3;
|
||||
|
||||
// Shift the significand of b by the difference in exponents, with a sticky
|
||||
// bottom bit to get rounding correct.
|
||||
const @"align" = @intCast(Z, aExponent - bExponent);
|
||||
if (@"align" != 0) {
|
||||
if (@"align" < typeWidth) {
|
||||
const sticky = if (bSignificand << @intCast(u7, typeWidth - @"align") != 0) Z(1) else 0;
|
||||
bSignificand = (bSignificand >> @truncate(u7, @"align")) | sticky;
|
||||
} else {
|
||||
bSignificand = 1; // sticky; b is known to be non-zero.
|
||||
}
|
||||
}
|
||||
if (subtraction) {
|
||||
aSignificand -= bSignificand;
|
||||
// If a == -b, return +zero.
|
||||
if (aSignificand == 0) return @bitCast(T, Z(0));
|
||||
|
||||
// If partial cancellation occured, we need to left-shift the result
|
||||
// and adjust the exponent:
|
||||
if (aSignificand < implicitBit << 3) {
|
||||
const shift = @intCast(i32, @clz(aSignificand)) - @intCast(i32, @clz(implicitBit << 3));
|
||||
aSignificand <<= @intCast(u7, shift);
|
||||
aExponent -= shift;
|
||||
}
|
||||
} else { // addition
|
||||
aSignificand += bSignificand;
|
||||
|
||||
// If the addition carried up, we need to right-shift the result and
|
||||
// adjust the exponent:
|
||||
if (aSignificand & (implicitBit << 4) != 0) {
|
||||
const sticky = aSignificand & 1;
|
||||
aSignificand = aSignificand >> 1 | sticky;
|
||||
aExponent += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have overflowed the type, return +/- infinity:
|
||||
if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign);
|
||||
|
||||
if (aExponent <= 0) {
|
||||
// Result is denormal before rounding; the exponent is zero and we
|
||||
// need to shift the significand.
|
||||
const shift = @intCast(Z, 1 - aExponent);
|
||||
const sticky = if (aSignificand << @intCast(u7, typeWidth - shift) != 0) Z(1) else 0;
|
||||
aSignificand = aSignificand >> @intCast(u7, shift | sticky);
|
||||
aExponent = 0;
|
||||
}
|
||||
|
||||
// Low three bits are round, guard, and sticky.
|
||||
const roundGuardSticky = aSignificand & 0x7;
|
||||
|
||||
// Shift the significand into place, and mask off the implicit bit.
|
||||
var result = (aSignificand >> 3) & significandMask;
|
||||
|
||||
// Insert the exponent and sign.
|
||||
result |= @intCast(Z, aExponent) << significandBits;
|
||||
result |= resultSign;
|
||||
|
||||
// Final rounding. The result may overflow to infinity, but that is the
|
||||
// correct result in that case.
|
||||
if (roundGuardSticky > 0x4) result += 1;
|
||||
if (roundGuardSticky == 0x4) result += result & 1;
|
||||
|
||||
return @bitCast(T, result);
|
||||
}
|
||||
|
||||
test "import addXf3" {
|
||||
_ = @import("addXf3_test.zig");
|
||||
}
|
85
std/special/compiler_rt/addXf3_test.zig
Normal file
85
std/special/compiler_rt/addXf3_test.zig
Normal file
@ -0,0 +1,85 @@
|
||||
// Ported from:
|
||||
//
|
||||
// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c
|
||||
// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/subtf3_test.c
|
||||
|
||||
const qnan128 = @bitCast(f128, u128(0x7fff800000000000) << 64);
|
||||
const inf128 = @bitCast(f128, u128(0x7fff000000000000) << 64);
|
||||
|
||||
const __addtf3 = @import("addXf3.zig").__addtf3;
|
||||
|
||||
fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void {
|
||||
const x = __addtf3(a, b);
|
||||
|
||||
const rep = @bitCast(u128, x);
|
||||
const hi = @intCast(u64, rep >> 64);
|
||||
const lo = @truncate(u64, rep);
|
||||
|
||||
if (hi == expected_hi and lo == expected_lo) {
|
||||
return;
|
||||
}
|
||||
// test other possible NaN representation (signal NaN)
|
||||
else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
|
||||
if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and
|
||||
((hi & 0xffffffffffff) > 0 or lo > 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@panic("__addtf3 test failure");
|
||||
}
|
||||
|
||||
test "addtf3" {
|
||||
test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
|
||||
|
||||
// NaN + any = NaN
|
||||
test__addtf3(@bitCast(f128, (u128(0x7fff000000000000) << 64) | u128(0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
|
||||
|
||||
// inf + inf = inf
|
||||
test__addtf3(inf128, inf128, 0x7fff000000000000, 0x0);
|
||||
|
||||
// inf + any = inf
|
||||
test__addtf3(inf128, 0x1.2335653452436234723489432abcdefp+5, 0x7fff000000000000, 0x0);
|
||||
|
||||
// any + any
|
||||
test__addtf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x40042afc95c8b579, 0x61e58dd6c51eb77c);
|
||||
}
|
||||
|
||||
const __subtf3 = @import("addXf3.zig").__subtf3;
|
||||
|
||||
fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void {
|
||||
const x = __subtf3(a, b);
|
||||
|
||||
const rep = @bitCast(u128, x);
|
||||
const hi = @intCast(u64, rep >> 64);
|
||||
const lo = @truncate(u64, rep);
|
||||
|
||||
if (hi == expected_hi and lo == expected_lo) {
|
||||
return;
|
||||
}
|
||||
// test other possible NaN representation (signal NaN)
|
||||
else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
|
||||
if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and
|
||||
((hi & 0xffffffffffff) > 0 or lo > 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@panic("__subtf3 test failure");
|
||||
}
|
||||
|
||||
test "subtf3" {
|
||||
// qNaN - any = qNaN
|
||||
test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
|
||||
|
||||
// NaN + any = NaN
|
||||
test__subtf3(@bitCast(f128, (u128(0x7fff000000000000) << 64) | u128(0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
|
||||
|
||||
// inf - any = inf
|
||||
test__subtf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0);
|
||||
|
||||
// any + any
|
||||
test__subtf3(0x1.234567829a3bcdef5678ade36734p+5, 0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x40041b8af1915166, 0xa44a7bca780a166c);
|
||||
}
|
@ -21,6 +21,9 @@ comptime {
|
||||
|
||||
@export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage);
|
||||
|
||||
@export("__addtf3", @import("addXf3.zig").__addtf3, linkage);
|
||||
@export("__subtf3", @import("addXf3.zig").__subtf3, linkage);
|
||||
|
||||
@export("__floattitf", @import("floattitf.zig").__floattitf, linkage);
|
||||
@export("__floattidf", @import("floattidf.zig").__floattidf, linkage);
|
||||
@export("__floattisf", @import("floattisf.zig").__floattisf, linkage);
|
||||
@ -37,6 +40,7 @@ comptime {
|
||||
@export("__extendhfsf2", @import("extendXfYf2.zig").__extendhfsf2, linkage);
|
||||
|
||||
@export("__truncsfhf2", @import("truncXfYf2.zig").__truncsfhf2, linkage);
|
||||
@export("__truncdfhf2", @import("truncXfYf2.zig").__truncdfhf2, linkage);
|
||||
@export("__trunctfdf2", @import("truncXfYf2.zig").__trunctfdf2, linkage);
|
||||
@export("__trunctfsf2", @import("truncXfYf2.zig").__trunctfsf2, linkage);
|
||||
|
||||
@ -180,60 +184,10 @@ const is_arm_64 = switch (builtin.arch) {
|
||||
};
|
||||
|
||||
const is_arm_arch = switch (builtin.arch) {
|
||||
builtin.Arch.armv8_3a,
|
||||
builtin.Arch.armv8_2a,
|
||||
builtin.Arch.armv8_1a,
|
||||
builtin.Arch.armv8,
|
||||
builtin.Arch.armv8r,
|
||||
builtin.Arch.armv8m_baseline,
|
||||
builtin.Arch.armv8m_mainline,
|
||||
builtin.Arch.armv7,
|
||||
builtin.Arch.armv7em,
|
||||
builtin.Arch.armv7m,
|
||||
builtin.Arch.armv7s,
|
||||
builtin.Arch.armv7k,
|
||||
builtin.Arch.armv7ve,
|
||||
builtin.Arch.armv6,
|
||||
builtin.Arch.armv6m,
|
||||
builtin.Arch.armv6k,
|
||||
builtin.Arch.armv6t2,
|
||||
builtin.Arch.armv5,
|
||||
builtin.Arch.armv5te,
|
||||
builtin.Arch.armv4t,
|
||||
builtin.Arch.armebv8_3a,
|
||||
builtin.Arch.armebv8_2a,
|
||||
builtin.Arch.armebv8_1a,
|
||||
builtin.Arch.armebv8,
|
||||
builtin.Arch.armebv8r,
|
||||
builtin.Arch.armebv8m_baseline,
|
||||
builtin.Arch.armebv8m_mainline,
|
||||
builtin.Arch.armebv7,
|
||||
builtin.Arch.armebv7em,
|
||||
builtin.Arch.armebv7m,
|
||||
builtin.Arch.armebv7s,
|
||||
builtin.Arch.armebv7k,
|
||||
builtin.Arch.armebv7ve,
|
||||
builtin.Arch.armebv6,
|
||||
builtin.Arch.armebv6m,
|
||||
builtin.Arch.armebv6k,
|
||||
builtin.Arch.armebv6t2,
|
||||
builtin.Arch.armebv5,
|
||||
builtin.Arch.armebv5te,
|
||||
builtin.Arch.armebv4t,
|
||||
builtin.Arch.aarch64v8_3a,
|
||||
builtin.Arch.aarch64v8_2a,
|
||||
builtin.Arch.aarch64v8_1a,
|
||||
builtin.Arch.aarch64v8,
|
||||
builtin.Arch.aarch64v8r,
|
||||
builtin.Arch.aarch64v8m_baseline,
|
||||
builtin.Arch.aarch64v8m_mainline,
|
||||
builtin.Arch.aarch64_bev8_3a,
|
||||
builtin.Arch.aarch64_bev8_2a,
|
||||
builtin.Arch.aarch64_bev8_1a,
|
||||
builtin.Arch.aarch64_bev8,
|
||||
builtin.Arch.aarch64_bev8r,
|
||||
builtin.Arch.aarch64_bev8m_baseline,
|
||||
builtin.Arch.aarch64_bev8m_mainline,
|
||||
builtin.Arch.arm,
|
||||
builtin.Arch.armeb,
|
||||
builtin.Arch.aarch64,
|
||||
builtin.Arch.aarch64_be,
|
||||
builtin.Arch.thumb,
|
||||
builtin.Arch.thumbeb,
|
||||
=> true,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user