mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 19:23:08 +00:00
stage2: linking with LLD and building glibc static CRT files
* implement --debug-cc and --debug-link
* implement C source files having extra flags
- TODO a way to pass them on the CLI
* introduce the Directory abstraction which contains both an open file
descriptor and a file path name. The former is preferred but the
latter is needed when communicating paths over a command line (e.g.
to Clang or LLD).
* use the cache hash to choose an artifact directory
- TODO: use separate cache hash instances for the zig module and
each C object
* Module: introduce the crt_files table for keeping track of built libc
artifacts for linking.
* Add the ability to build 4/6 of the glibc static CRT lib files.
* The zig-cache directory is now passed as a parameter to Module.
* Implement the CLI logic of -femit-bin and -femit-h
- TODO: respect -fno-emit-bin
- TODO: the emit .h feature
* Add the -fvalgrind, -fstack-check, and --single-threaded CLI options.
* Implement the logic for auto detecting whether to enable PIC,
sanitize-C, stack-check, valgrind, and single-threaded.
* Properly add PIC args (or not) to clang argv.
* Implement renaming clang-compiled object files into their proper
place within the cache artifact directory.
- TODO: std lib needs a proper higher level abstraction for
std.os.renameat.
* Package is cleaned up to use the "Unmanaged" StringHashMap and use the
new Directory abstraction.
* Clean up zig lib directory detection to make proper use of directory
handles.
* Linker code invokes LLD.
- TODO properly deal with the stdout and stderr that we get from it
and expose diagnostics from the Module API that match the expected
error message format.
* Delete the bitrotted LLVM C ABI bindings. We'll resurrect just the
functions we need as we introduce dependencies on them. So far it
only has ZigLLDLink in it.
* Remove dead timer code.
* `zig env` now prints the path to the zig executable as well.
This commit is contained in:
parent
8374be1a1c
commit
03a23418ff
@ -25,6 +25,8 @@ const astgen = @import("astgen.zig");
|
||||
const zir_sema = @import("zir_sema.zig");
|
||||
const build_options = @import("build_options");
|
||||
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||
const glibc = @import("glibc.zig");
|
||||
const fatal = @import("main.zig").fatal;
|
||||
|
||||
/// General-purpose allocator. Used for both temporary and long-term storage.
|
||||
gpa: *Allocator,
|
||||
@ -91,17 +93,20 @@ sanitize_c: bool,
|
||||
/// Otherwise we attempt to parse the error messages and expose them via the Module API.
|
||||
/// This is `true` for `zig cc`, `zig c++`, and `zig translate-c`.
|
||||
clang_passthrough_mode: bool,
|
||||
/// Whether to print clang argvs to stdout.
|
||||
debug_cc: bool,
|
||||
|
||||
/// Error tags and their values, tag names are duped with mod.gpa.
|
||||
global_error_set: std.StringHashMapUnmanaged(u16) = .{},
|
||||
|
||||
c_source_files: []const []const u8,
|
||||
c_source_files: []const CSourceFile,
|
||||
clang_argv: []const []const u8,
|
||||
cache: std.cache_hash.CacheHash,
|
||||
/// Path to own executable for invoking `zig clang`.
|
||||
self_exe_path: ?[]const u8,
|
||||
zig_lib_dir: []const u8,
|
||||
zig_cache_dir_path: []const u8,
|
||||
zig_lib_directory: Directory,
|
||||
zig_cache_directory: Directory,
|
||||
zig_cache_artifact_directory: Directory,
|
||||
libc_include_dir_list: []const []const u8,
|
||||
rand: *std.rand.Random,
|
||||
|
||||
@ -118,8 +123,19 @@ libunwind_static_lib: ?[]const u8 = null,
|
||||
/// and resolved before calling linker.flush().
|
||||
libc_static_lib: ?[]const u8 = null,
|
||||
|
||||
/// For example `Scrt1.o` and `libc.so.6`. These are populated after building libc from source,
|
||||
/// The set of needed CRT (C runtime) files differs depending on the target and compilation settings.
|
||||
/// The key is the basename, and the value is the absolute path to the completed build artifact.
|
||||
crt_files: std.StringHashMapUnmanaged([]const u8) = .{},
|
||||
|
||||
pub const InnerError = error{ OutOfMemory, AnalysisFail };
|
||||
|
||||
/// For passing to a C compiler.
|
||||
pub const CSourceFile = struct {
|
||||
src_path: []const u8,
|
||||
extra_flags: []const []const u8 = &[0][]const u8{},
|
||||
};
|
||||
|
||||
const WorkItem = union(enum) {
|
||||
/// Write the machine code for a Decl to the output file.
|
||||
codegen_decl: *Decl,
|
||||
@ -133,6 +149,11 @@ const WorkItem = union(enum) {
|
||||
/// Invoke the Clang compiler to create an object file, which gets linked
|
||||
/// with the Module.
|
||||
c_object: *CObject,
|
||||
|
||||
/// one of the glibc static objects
|
||||
glibc_crt_file: glibc.CRTFile,
|
||||
/// one of the glibc shared objects
|
||||
glibc_so: *const glibc.Lib,
|
||||
};
|
||||
|
||||
pub const Export = struct {
|
||||
@ -701,7 +722,7 @@ pub const Scope = struct {
|
||||
pub fn getSource(self: *File, module: *Module) ![:0]const u8 {
|
||||
switch (self.source) {
|
||||
.unloaded => {
|
||||
const source = try module.root_pkg.?.root_src_dir.readFileAllocOptions(
|
||||
const source = try module.root_pkg.?.root_src_directory.handle.readFileAllocOptions(
|
||||
module.gpa,
|
||||
self.sub_file_path,
|
||||
std.math.maxInt(u32),
|
||||
@ -805,7 +826,7 @@ pub const Scope = struct {
|
||||
pub fn getSource(self: *ZIRModule, module: *Module) ![:0]const u8 {
|
||||
switch (self.source) {
|
||||
.unloaded => {
|
||||
const source = try module.root_pkg.?.root_src_dir.readFileAllocOptions(
|
||||
const source = try module.root_pkg.?.root_src_directory.handle.readFileAllocOptions(
|
||||
module.gpa,
|
||||
self.sub_file_path,
|
||||
std.math.maxInt(u32),
|
||||
@ -937,18 +958,35 @@ pub const AllErrors = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Directory = struct {
|
||||
/// This field is redundant for operations that can act on the open directory handle
|
||||
/// directly, but it is needed when passing the directory to a child process.
|
||||
/// `null` means cwd.
|
||||
path: ?[]const u8,
|
||||
handle: std.fs.Dir,
|
||||
};
|
||||
|
||||
pub const EmitLoc = struct {
|
||||
/// If this is `null` it means the file will be output to the cache directory.
|
||||
/// When provided, both the open file handle and the path name must outlive the `Module`.
|
||||
directory: ?Module.Directory,
|
||||
/// This may not have sub-directories in it.
|
||||
basename: []const u8,
|
||||
};
|
||||
|
||||
pub const InitOptions = struct {
|
||||
zig_lib_dir: []const u8,
|
||||
zig_lib_directory: Directory,
|
||||
zig_cache_directory: Directory,
|
||||
target: Target,
|
||||
root_name: []const u8,
|
||||
root_pkg: ?*Package,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
rand: *std.rand.Random,
|
||||
dynamic_linker: ?[]const u8 = null,
|
||||
bin_file_dir_path: ?[]const u8 = null,
|
||||
bin_file_dir: ?std.fs.Dir = null,
|
||||
bin_file_path: []const u8,
|
||||
emit_h: ?[]const u8 = null,
|
||||
/// `null` means to not emit a binary file.
|
||||
emit_bin: ?EmitLoc,
|
||||
/// `null` means to not emit a C header file.
|
||||
emit_h: ?EmitLoc = null,
|
||||
link_mode: ?std.builtin.LinkMode = null,
|
||||
object_format: ?std.builtin.ObjectFormat = null,
|
||||
optimize_mode: std.builtin.Mode = .Debug,
|
||||
@ -957,7 +995,7 @@ pub const InitOptions = struct {
|
||||
lld_argv: []const []const u8 = &[0][]const u8{},
|
||||
lib_dirs: []const []const u8 = &[0][]const u8{},
|
||||
rpath_list: []const []const u8 = &[0][]const u8{},
|
||||
c_source_files: []const []const u8 = &[0][]const u8{},
|
||||
c_source_files: []const CSourceFile = &[0]CSourceFile{},
|
||||
link_objects: []const []const u8 = &[0][]const u8{},
|
||||
framework_dirs: []const []const u8 = &[0][]const u8{},
|
||||
frameworks: []const []const u8 = &[0][]const u8{},
|
||||
@ -966,11 +1004,14 @@ pub const InitOptions = struct {
|
||||
link_libcpp: bool = false,
|
||||
want_pic: ?bool = null,
|
||||
want_sanitize_c: ?bool = null,
|
||||
want_stack_check: ?bool = null,
|
||||
want_valgrind: ?bool = null,
|
||||
use_llvm: ?bool = null,
|
||||
use_lld: ?bool = null,
|
||||
use_clang: ?bool = null,
|
||||
rdynamic: bool = false,
|
||||
strip: bool = false,
|
||||
single_threaded: bool = false,
|
||||
is_native_os: bool,
|
||||
link_eh_frame_hdr: bool = false,
|
||||
linker_script: ?[]const u8 = null,
|
||||
@ -984,6 +1025,8 @@ pub const InitOptions = struct {
|
||||
linker_z_nodelete: bool = false,
|
||||
linker_z_defs: bool = false,
|
||||
clang_passthrough_mode: bool = false,
|
||||
debug_cc: bool = false,
|
||||
debug_link: bool = false,
|
||||
stack_size_override: ?u64 = null,
|
||||
self_exe_path: ?[]const u8 = null,
|
||||
version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 },
|
||||
@ -1057,17 +1100,126 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
|
||||
const libc_dirs = try detectLibCIncludeDirs(
|
||||
arena,
|
||||
options.zig_lib_dir,
|
||||
options.zig_lib_directory.path.?,
|
||||
options.target,
|
||||
options.is_native_os,
|
||||
options.link_libc,
|
||||
options.libc_installation,
|
||||
);
|
||||
|
||||
const must_pic: bool = b: {
|
||||
if (target_util.requiresPIC(options.target, options.link_libc))
|
||||
break :b true;
|
||||
break :b link_mode == .Dynamic;
|
||||
};
|
||||
const pic = options.want_pic orelse must_pic;
|
||||
|
||||
if (options.emit_h != null) fatal("-femit-h not supported yet", .{}); // TODO
|
||||
|
||||
const emit_bin = options.emit_bin orelse fatal("-fno-emit-bin not supported yet", .{}); // TODO
|
||||
|
||||
// Make a decision on whether to use Clang for translate-c and compiling C files.
|
||||
const use_clang = if (options.use_clang) |explicit| explicit else blk: {
|
||||
if (build_options.have_llvm) {
|
||||
// Can't use it if we don't have it!
|
||||
break :blk false;
|
||||
}
|
||||
// It's not planned to do our own translate-c or C compilation.
|
||||
break :blk true;
|
||||
};
|
||||
|
||||
const is_safe_mode = switch (options.optimize_mode) {
|
||||
.Debug, .ReleaseSafe => true,
|
||||
.ReleaseFast, .ReleaseSmall => false,
|
||||
};
|
||||
|
||||
const sanitize_c = options.want_sanitize_c orelse is_safe_mode;
|
||||
|
||||
const stack_check: bool = b: {
|
||||
if (!target_util.supportsStackProbing(options.target))
|
||||
break :b false;
|
||||
break :b options.want_stack_check orelse is_safe_mode;
|
||||
};
|
||||
|
||||
const valgrind: bool = b: {
|
||||
if (!target_util.hasValgrindSupport(options.target))
|
||||
break :b false;
|
||||
break :b options.want_valgrind orelse (options.optimize_mode == .Debug);
|
||||
};
|
||||
|
||||
const single_threaded = options.single_threaded or target_util.isSingleThreaded(options.target);
|
||||
|
||||
// We put everything into the cache hash that *cannot be modified during an incremental update*.
|
||||
// For example, one cannot change the target between updates, but one can change source files,
|
||||
// so the target goes into the cache hash, but source files do not. This is so that we can
|
||||
// find the same binary and incrementally update it even if there are modified source files.
|
||||
// We do this even if outputting to the current directory because (1) this cache_hash instance
|
||||
// will be the "parent" of other cache_hash instances such as for C objects, (2) we need
|
||||
// a place for intermediate build artifacts, such as a .o file to be linked with LLD, and (3)
|
||||
// we need somewhere to store serialization of incremental compilation metadata.
|
||||
var cache = try std.cache_hash.CacheHash.init(gpa, options.zig_cache_directory.handle, "h");
|
||||
errdefer cache.release();
|
||||
|
||||
// Now we will prepare hash state initializations to avoid redundantly computing hashes.
|
||||
// First we add common things between things that apply to zig source and all c source files.
|
||||
cache.addBytes(build_options.version);
|
||||
cache.add(options.optimize_mode);
|
||||
cache.add(options.target.cpu.arch);
|
||||
cache.addBytes(options.target.cpu.model.name);
|
||||
cache.add(options.target.cpu.features.ints);
|
||||
cache.add(options.target.os.tag);
|
||||
switch (options.target.os.tag) {
|
||||
.linux => {
|
||||
cache.add(options.target.os.version_range.linux.range.min);
|
||||
cache.add(options.target.os.version_range.linux.range.max);
|
||||
cache.add(options.target.os.version_range.linux.glibc);
|
||||
},
|
||||
.windows => {
|
||||
cache.add(options.target.os.version_range.windows.min);
|
||||
cache.add(options.target.os.version_range.windows.max);
|
||||
},
|
||||
.freebsd,
|
||||
.macosx,
|
||||
.ios,
|
||||
.tvos,
|
||||
.watchos,
|
||||
.netbsd,
|
||||
.openbsd,
|
||||
.dragonfly,
|
||||
=> {
|
||||
cache.add(options.target.os.version_range.semver.min);
|
||||
cache.add(options.target.os.version_range.semver.max);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
cache.add(options.target.abi);
|
||||
cache.add(ofmt);
|
||||
cache.add(pic);
|
||||
cache.add(stack_check);
|
||||
cache.add(sanitize_c);
|
||||
cache.add(valgrind);
|
||||
cache.add(link_mode);
|
||||
cache.add(options.strip);
|
||||
cache.add(single_threaded);
|
||||
// TODO audit this and make sure everything is in it
|
||||
|
||||
// We don't care whether we find something there, just show us the digest.
|
||||
const digest = (try cache.hit()) orelse cache.final();
|
||||
|
||||
const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
|
||||
var artifact_dir = try options.zig_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
|
||||
errdefer artifact_dir.close();
|
||||
const zig_cache_artifact_directory: Directory = .{
|
||||
.handle = artifact_dir,
|
||||
.path = if (options.zig_cache_directory.path) |p|
|
||||
try std.fs.path.join(arena, &[_][]const u8{ p, artifact_sub_dir })
|
||||
else
|
||||
artifact_sub_dir,
|
||||
};
|
||||
|
||||
const bin_file = try link.File.openPath(gpa, .{
|
||||
.dir = options.bin_file_dir orelse std.fs.cwd(),
|
||||
.dir_path = options.bin_file_dir_path,
|
||||
.sub_path = options.bin_file_path,
|
||||
.directory = emit_bin.directory orelse zig_cache_artifact_directory,
|
||||
.sub_path = emit_bin.basename,
|
||||
.root_name = root_name,
|
||||
.root_pkg = options.root_pkg,
|
||||
.target = options.target,
|
||||
@ -1103,6 +1255,11 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
.override_soname = options.override_soname,
|
||||
.version = options.version,
|
||||
.libc_installation = libc_dirs.libc_installation,
|
||||
.pic = pic,
|
||||
.valgrind = valgrind,
|
||||
.stack_check = stack_check,
|
||||
.single_threaded = single_threaded,
|
||||
.debug_link = options.debug_link,
|
||||
});
|
||||
errdefer bin_file.destroy();
|
||||
|
||||
@ -1142,83 +1299,12 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
}
|
||||
};
|
||||
|
||||
// We put everything into the cache hash except for the root source file, because we want to
|
||||
// find the same binary and incrementally update it even if the file contents changed.
|
||||
// TODO Look into storing this information in memory rather than on disk and solving
|
||||
// serialization/deserialization of *all* incremental compilation state in a more generic way.
|
||||
const cache_parent_dir = if (options.root_pkg) |root_pkg| root_pkg.root_src_dir else std.fs.cwd();
|
||||
var cache_dir = try cache_parent_dir.makeOpenPath("zig-cache", .{});
|
||||
defer cache_dir.close();
|
||||
|
||||
try cache_dir.makePath("tmp");
|
||||
try cache_dir.makePath("o");
|
||||
// We need this string because of sending paths to clang as a child process.
|
||||
const zig_cache_dir_path = if (options.root_pkg) |root_pkg|
|
||||
try std.fmt.allocPrint(arena, "{}" ++ std.fs.path.sep_str ++ "zig-cache", .{root_pkg.root_src_dir_path})
|
||||
else
|
||||
"zig-cache";
|
||||
|
||||
var cache = try std.cache_hash.CacheHash.init(gpa, cache_dir, "h");
|
||||
errdefer cache.release();
|
||||
|
||||
// Now we will prepare hash state initializations to avoid redundantly computing hashes.
|
||||
// First we add common things between things that apply to zig source and all c source files.
|
||||
cache.addBytes(build_options.version);
|
||||
cache.add(options.optimize_mode);
|
||||
cache.add(options.target.cpu.arch);
|
||||
cache.addBytes(options.target.cpu.model.name);
|
||||
cache.add(options.target.cpu.features.ints);
|
||||
cache.add(options.target.os.tag);
|
||||
switch (options.target.os.tag) {
|
||||
.linux => {
|
||||
cache.add(options.target.os.version_range.linux.range.min);
|
||||
cache.add(options.target.os.version_range.linux.range.max);
|
||||
cache.add(options.target.os.version_range.linux.glibc);
|
||||
},
|
||||
.windows => {
|
||||
cache.add(options.target.os.version_range.windows.min);
|
||||
cache.add(options.target.os.version_range.windows.max);
|
||||
},
|
||||
.freebsd,
|
||||
.macosx,
|
||||
.ios,
|
||||
.tvos,
|
||||
.watchos,
|
||||
.netbsd,
|
||||
.openbsd,
|
||||
.dragonfly,
|
||||
=> {
|
||||
cache.add(options.target.os.version_range.semver.min);
|
||||
cache.add(options.target.os.version_range.semver.max);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
cache.add(options.target.abi);
|
||||
cache.add(ofmt);
|
||||
// TODO PIC (see detect_pic from codegen.cpp)
|
||||
cache.add(bin_file.options.link_mode);
|
||||
cache.add(options.strip);
|
||||
|
||||
// Make a decision on whether to use Clang for translate-c and compiling C files.
|
||||
const use_clang = if (options.use_clang) |explicit| explicit else blk: {
|
||||
if (build_options.have_llvm) {
|
||||
// Can't use it if we don't have it!
|
||||
break :blk false;
|
||||
}
|
||||
// It's not planned to do our own translate-c or C compilation.
|
||||
break :blk true;
|
||||
};
|
||||
|
||||
const sanitize_c: bool = options.want_sanitize_c orelse switch (options.optimize_mode) {
|
||||
.Debug, .ReleaseSafe => true,
|
||||
.ReleaseSmall, .ReleaseFast => false,
|
||||
};
|
||||
|
||||
mod.* = .{
|
||||
.gpa = gpa,
|
||||
.arena_state = arena_allocator.state,
|
||||
.zig_lib_dir = options.zig_lib_dir,
|
||||
.zig_cache_dir_path = zig_cache_dir_path,
|
||||
.zig_lib_directory = options.zig_lib_directory,
|
||||
.zig_cache_directory = options.zig_cache_directory,
|
||||
.zig_cache_artifact_directory = zig_cache_artifact_directory,
|
||||
.root_pkg = options.root_pkg,
|
||||
.root_scope = root_scope,
|
||||
.bin_file = bin_file,
|
||||
@ -1233,6 +1319,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
.sanitize_c = sanitize_c,
|
||||
.rand = options.rand,
|
||||
.clang_passthrough_mode = options.clang_passthrough_mode,
|
||||
.debug_cc = options.debug_cc,
|
||||
};
|
||||
break :mod mod;
|
||||
};
|
||||
@ -1245,22 +1332,21 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
errdefer local_arena.deinit();
|
||||
|
||||
const c_object = try local_arena.allocator.create(CObject);
|
||||
const src_path = try local_arena.allocator.dupe(u8, c_source_file);
|
||||
|
||||
c_object.* = .{
|
||||
.status = .{ .new = {} },
|
||||
.src_path = src_path,
|
||||
.extra_flags = &[0][]const u8{},
|
||||
// TODO why are we duplicating this memory? do we need to?
|
||||
// look into refactoring to turn these 2 fields simply into a CSourceFile
|
||||
.src_path = try local_arena.allocator.dupe(u8, c_source_file.src_path),
|
||||
.extra_flags = try local_arena.allocator.dupe([]const u8, c_source_file.extra_flags),
|
||||
.arena = local_arena.state,
|
||||
};
|
||||
mod.c_object_table.putAssumeCapacityNoClobber(c_object, {});
|
||||
}
|
||||
|
||||
// If we need to build glibc for the target, add work items for it.
|
||||
if (mod.bin_file.options.link_libc and
|
||||
mod.bin_file.options.libc_installation == null and
|
||||
mod.bin_file.options.target.isGnuLibC())
|
||||
{
|
||||
// We go through the work queue so that building can be done in parallel.
|
||||
if (mod.wantBuildGLibCFromSource()) {
|
||||
try mod.addBuildingGLibCWorkItems();
|
||||
}
|
||||
|
||||
@ -1273,6 +1359,15 @@ pub fn destroy(self: *Module) void {
|
||||
self.deletion_set.deinit(gpa);
|
||||
self.work_queue.deinit();
|
||||
|
||||
{
|
||||
var it = self.crt_files.iterator();
|
||||
while (it.next()) |entry| {
|
||||
gpa.free(entry.key);
|
||||
gpa.free(entry.value);
|
||||
}
|
||||
self.crt_files.deinit(gpa);
|
||||
}
|
||||
|
||||
for (self.decl_table.items()) |entry| {
|
||||
entry.value.destroy(gpa);
|
||||
}
|
||||
@ -1322,6 +1417,8 @@ pub fn destroy(self: *Module) void {
|
||||
gpa.free(entry.key);
|
||||
}
|
||||
self.global_error_set.deinit(gpa);
|
||||
|
||||
self.zig_cache_artifact_directory.handle.close();
|
||||
self.cache.release();
|
||||
|
||||
// This destroys `self`.
|
||||
@ -1458,7 +1555,7 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
|
||||
if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {
|
||||
const global_err_src_path = blk: {
|
||||
if (self.root_pkg) |root_pkg| break :blk root_pkg.root_src_path;
|
||||
if (self.c_source_files.len != 0) break :blk self.c_source_files[0];
|
||||
if (self.c_source_files.len != 0) break :blk self.c_source_files[0].src_path;
|
||||
if (self.bin_file.options.objects.len != 0) break :blk self.bin_file.options.objects[0];
|
||||
break :blk "(no file)";
|
||||
};
|
||||
@ -1581,6 +1678,17 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
|
||||
},
|
||||
};
|
||||
},
|
||||
.glibc_crt_file => |crt_file| {
|
||||
glibc.buildCRTFile(self, crt_file) catch |err| {
|
||||
// This is a problem with the Zig installation. It's mostly OK to crash here,
|
||||
// but TODO because it would be even better if we could recover gracefully
|
||||
// from temporary problems such as out-of-disk-space.
|
||||
fatal("unable to build glibc CRT file: {}", .{@errorName(err)});
|
||||
};
|
||||
},
|
||||
.glibc_so => |glibc_lib| {
|
||||
fatal("TODO build glibc shared object '{}.so.{}'", .{ glibc_lib.name, glibc_lib.sover });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -1588,6 +1696,8 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
// TODO this C source file needs its own cache hash instance
|
||||
|
||||
if (!build_options.have_llvm) {
|
||||
return mod.failCObj(c_object, "clang not available: compiler not built with LLVM extensions enabled", .{});
|
||||
}
|
||||
@ -1616,6 +1726,9 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {
|
||||
// We can't know the digest until we do the C compiler invocation, so we need a temporary filename.
|
||||
const out_obj_path = try mod.tmpFilePath(arena, o_basename);
|
||||
|
||||
var zig_cache_tmp_dir = try mod.zig_cache_directory.handle.makeOpenPath("tmp", .{});
|
||||
defer zig_cache_tmp_dir.close();
|
||||
|
||||
try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang", "-c" });
|
||||
|
||||
const ext = classifyFileExt(c_object.src_path);
|
||||
@ -1628,9 +1741,12 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {
|
||||
try argv.append(c_object.src_path);
|
||||
try argv.appendSlice(c_object.extra_flags);
|
||||
|
||||
//for (argv.items) |arg| {
|
||||
// std.debug.print("{} ", .{arg});
|
||||
//}
|
||||
if (mod.debug_cc) {
|
||||
for (argv.items[0 .. argv.items.len - 1]) |arg| {
|
||||
std.debug.print("{} ", .{arg});
|
||||
}
|
||||
std.debug.print("{}\n", .{argv.items[argv.items.len - 1]});
|
||||
}
|
||||
|
||||
const child = try std.ChildProcess.init(argv.items, arena);
|
||||
defer child.deinit();
|
||||
@ -1689,11 +1805,13 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {
|
||||
|
||||
// TODO handle .d files
|
||||
|
||||
// TODO rename into place
|
||||
std.debug.print("TODO rename {} into cache dir\n", .{out_obj_path});
|
||||
// TODO Add renameat capabilities to the std lib in a higher layer than the posix layer.
|
||||
const tmp_basename = std.fs.path.basename(out_obj_path);
|
||||
try std.os.renameat(zig_cache_tmp_dir.fd, tmp_basename, mod.zig_cache_artifact_directory.handle.fd, o_basename);
|
||||
|
||||
// TODO use the cache file name instead of tmp file name
|
||||
const success_file_path = try mod.gpa.dupe(u8, out_obj_path);
|
||||
const success_file_path = try std.fs.path.join(mod.gpa, &[_][]const u8{
|
||||
mod.zig_cache_artifact_directory.path.?, o_basename,
|
||||
});
|
||||
c_object.status = .{ .success = success_file_path };
|
||||
}
|
||||
|
||||
@ -1702,7 +1820,7 @@ fn tmpFilePath(mod: *Module, arena: *Allocator, suffix: []const u8) error{OutOfM
|
||||
return std.fmt.allocPrint(
|
||||
arena,
|
||||
"{}" ++ s ++ "tmp" ++ s ++ "{x}-{}",
|
||||
.{ mod.zig_cache_dir_path, mod.rand.int(u64), suffix },
|
||||
.{ mod.zig_cache_directory.path.?, mod.rand.int(u64), suffix },
|
||||
);
|
||||
}
|
||||
|
||||
@ -1749,10 +1867,10 @@ fn addCCArgs(
|
||||
|
||||
if (mod.bin_file.options.link_libcpp) {
|
||||
const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{
|
||||
mod.zig_lib_dir, "libcxx", "include",
|
||||
mod.zig_lib_directory.path.?, "libcxx", "include",
|
||||
});
|
||||
const libcxxabi_include_path = try std.fs.path.join(arena, &[_][]const u8{
|
||||
mod.zig_lib_dir, "libcxxabi", "include",
|
||||
mod.zig_lib_directory.path.?, "libcxxabi", "include",
|
||||
});
|
||||
|
||||
try argv.append("-isystem");
|
||||
@ -1776,7 +1894,7 @@ fn addCCArgs(
|
||||
// According to Rich Felker libc headers are supposed to go before C language headers.
|
||||
// However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics
|
||||
// and other compiler specific items.
|
||||
const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ mod.zig_lib_dir, "include" });
|
||||
const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ mod.zig_lib_directory.path.?, "include" });
|
||||
try argv.append("-isystem");
|
||||
try argv.append(c_headers_dir);
|
||||
|
||||
@ -1891,10 +2009,9 @@ fn addCCArgs(
|
||||
},
|
||||
}
|
||||
|
||||
// TODO add CLI args for PIC
|
||||
//if (target_supports_fpic(g->zig_target) and g->have_pic) {
|
||||
// try argv.append("-fPIC");
|
||||
//}
|
||||
if (target_util.supports_fpic(target) and mod.bin_file.options.pic) {
|
||||
try argv.append("-fPIC");
|
||||
}
|
||||
|
||||
try argv.appendSlice(mod.clang_argv);
|
||||
}
|
||||
@ -4497,7 +4614,9 @@ fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const
|
||||
}
|
||||
|
||||
pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8) ![]const u8 {
|
||||
// TODO port support for building crt files from stage1
|
||||
if (mod.wantBuildGLibCFromSource()) {
|
||||
return mod.crt_files.get(basename).?;
|
||||
}
|
||||
const lci = mod.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable;
|
||||
const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
|
||||
const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
|
||||
@ -4505,6 +4624,23 @@ pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8)
|
||||
}
|
||||
|
||||
fn addBuildingGLibCWorkItems(mod: *Module) !void {
|
||||
// crti.o, crtn.o, start.os, abi-note.o, Scrt1.o, libc_nonshared.a
|
||||
try mod.work_queue.ensureUnusedCapacity(6);
|
||||
const static_file_work_items = [_]WorkItem{
|
||||
.{ .glibc_crt_file = .crti_o },
|
||||
.{ .glibc_crt_file = .crtn_o },
|
||||
.{ .glibc_crt_file = .start_os },
|
||||
.{ .glibc_crt_file = .abi_note_o },
|
||||
.{ .glibc_crt_file = .scrt1_o },
|
||||
.{ .glibc_crt_file = .libc_nonshared_a },
|
||||
};
|
||||
try mod.work_queue.ensureUnusedCapacity(static_file_work_items.len + glibc.libs.len);
|
||||
mod.work_queue.writeAssumeCapacity(&static_file_work_items);
|
||||
for (glibc.libs) |*glibc_so| {
|
||||
mod.work_queue.writeItemAssumeCapacity(.{ .glibc_so = glibc_so });
|
||||
}
|
||||
}
|
||||
|
||||
fn wantBuildGLibCFromSource(mod: *Module) bool {
|
||||
return mod.bin_file.options.link_libc and
|
||||
mod.bin_file.options.libc_installation == null and
|
||||
mod.bin_file.options.target.isGnuLibC();
|
||||
}
|
||||
|
||||
@ -1,59 +1,59 @@
|
||||
pub const Table = std.StringHashMap(*Package);
|
||||
pub const Table = std.StringHashMapUnmanaged(*Package);
|
||||
|
||||
/// This should be used for file operations.
|
||||
root_src_dir: std.fs.Dir,
|
||||
/// This is for metadata purposes, for example putting into debug information.
|
||||
root_src_dir_path: []u8,
|
||||
/// Relative to `root_src_dir` and `root_src_dir_path`.
|
||||
root_src_directory: Module.Directory,
|
||||
/// Relative to `root_src_directory`.
|
||||
root_src_path: []u8,
|
||||
table: Table,
|
||||
|
||||
/// No references to `root_src_dir` and `root_src_path` are kept.
|
||||
pub fn create(
|
||||
allocator: *mem.Allocator,
|
||||
gpa: *Allocator,
|
||||
base_dir: std.fs.Dir,
|
||||
/// Relative to `base_dir`.
|
||||
root_src_dir: []const u8,
|
||||
/// Relative to `root_src_dir`.
|
||||
root_src_path: []const u8,
|
||||
) !*Package {
|
||||
const ptr = try allocator.create(Package);
|
||||
errdefer allocator.destroy(ptr);
|
||||
const root_src_path_dupe = try mem.dupe(allocator, u8, root_src_path);
|
||||
errdefer allocator.free(root_src_path_dupe);
|
||||
const root_src_dir_path = try mem.dupe(allocator, u8, root_src_dir);
|
||||
errdefer allocator.free(root_src_dir_path);
|
||||
const ptr = try gpa.create(Package);
|
||||
errdefer gpa.destroy(ptr);
|
||||
const root_src_path_dupe = try mem.dupe(gpa, u8, root_src_path);
|
||||
errdefer gpa.free(root_src_path_dupe);
|
||||
const root_src_dir_path = try mem.dupe(gpa, u8, root_src_dir);
|
||||
errdefer gpa.free(root_src_dir_path);
|
||||
ptr.* = .{
|
||||
.root_src_dir = try base_dir.openDir(root_src_dir, .{}),
|
||||
.root_src_dir_path = root_src_dir_path,
|
||||
.root_src_directory = .{
|
||||
.path = root_src_dir_path,
|
||||
.handle = try base_dir.openDir(root_src_dir, .{}),
|
||||
},
|
||||
.root_src_path = root_src_path_dupe,
|
||||
.table = Table.init(allocator),
|
||||
.table = .{},
|
||||
};
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pub fn destroy(self: *Package) void {
|
||||
const allocator = self.table.allocator;
|
||||
self.root_src_dir.close();
|
||||
allocator.free(self.root_src_path);
|
||||
allocator.free(self.root_src_dir_path);
|
||||
pub fn destroy(pkg: *Package, gpa: *Allocator) void {
|
||||
pkg.root_src_directory.handle.close();
|
||||
gpa.free(pkg.root_src_path);
|
||||
if (pkg.root_src_directory.path) |p| gpa.free(p);
|
||||
{
|
||||
var it = self.table.iterator();
|
||||
var it = pkg.table.iterator();
|
||||
while (it.next()) |kv| {
|
||||
allocator.free(kv.key);
|
||||
gpa.free(kv.key);
|
||||
}
|
||||
}
|
||||
self.table.deinit();
|
||||
allocator.destroy(self);
|
||||
pkg.table.deinit(gpa);
|
||||
gpa.destroy(pkg);
|
||||
}
|
||||
|
||||
pub fn add(self: *Package, name: []const u8, package: *Package) !void {
|
||||
try self.table.ensureCapacity(self.table.items().len + 1);
|
||||
const name_dupe = try mem.dupe(self.table.allocator, u8, name);
|
||||
self.table.putAssumeCapacityNoClobber(name_dupe, package);
|
||||
pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void {
|
||||
try pkg.table.ensureCapacity(gpa, pkg.table.items().len + 1);
|
||||
const name_dupe = try mem.dupe(gpa, u8, name);
|
||||
pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const Package = @This();
|
||||
const Module = @import("Module.zig");
|
||||
|
||||
@ -2,6 +2,9 @@ const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const target_util = @import("target.zig");
|
||||
const mem = std.mem;
|
||||
const Module = @import("Module.zig");
|
||||
const path = std.fs.path;
|
||||
const build_options = @import("build_options");
|
||||
|
||||
pub const Lib = struct {
|
||||
name: []const u8,
|
||||
@ -60,7 +63,7 @@ pub fn loadMetaData(gpa: *Allocator, zig_lib_dir: std.fs.Dir) LoadMetaDataError!
|
||||
var version_table = std.AutoHashMapUnmanaged(target_util.ArchOsAbi, [*]VerList){};
|
||||
errdefer version_table.deinit(gpa);
|
||||
|
||||
var glibc_dir = zig_lib_dir.openDir("libc" ++ std.fs.path.sep_str ++ "glibc", .{}) catch |err| {
|
||||
var glibc_dir = zig_lib_dir.openDir("libc" ++ path.sep_str ++ "glibc", .{}) catch |err| {
|
||||
std.log.err("unable to open glibc dir: {}", .{@errorName(err)});
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
@ -229,3 +232,394 @@ fn findLib(name: []const u8) ?*const Lib {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub const CRTFile = enum {
|
||||
crti_o,
|
||||
crtn_o,
|
||||
start_os,
|
||||
abi_note_o,
|
||||
scrt1_o,
|
||||
libc_nonshared_a,
|
||||
};
|
||||
|
||||
pub fn buildCRTFile(mod: *Module, crt_file: CRTFile) !void {
|
||||
if (!build_options.have_llvm) {
|
||||
return error.ZigCompilerNotBuiltWithLLVMExtensions;
|
||||
}
|
||||
const gpa = mod.gpa;
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
||||
errdefer arena_allocator.deinit();
|
||||
const arena = &arena_allocator.allocator;
|
||||
|
||||
switch (crt_file) {
|
||||
.crti_o => {
|
||||
var args = std.ArrayList([]const u8).init(arena);
|
||||
try add_include_dirs(mod, arena, &args);
|
||||
try args.appendSlice(&[_][]const u8{
|
||||
"-D_LIBC_REENTRANT",
|
||||
"-include",
|
||||
try lib_path(mod, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-modules.h"),
|
||||
"-DMODULE_NAME=libc",
|
||||
"-Wno-nonportable-include-path",
|
||||
"-include",
|
||||
try lib_path(mod, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-symbols.h"),
|
||||
"-DTOP_NAMESPACE=glibc",
|
||||
"-DASSEMBLER",
|
||||
"-g",
|
||||
"-Wa,--noexecstack",
|
||||
});
|
||||
const c_source_file: Module.CSourceFile = .{
|
||||
.src_path = try start_asm_path(mod, arena, "crti.S"),
|
||||
.extra_flags = args.items,
|
||||
};
|
||||
return build_libc_object(mod, "crti.o", c_source_file);
|
||||
},
|
||||
.crtn_o => {
|
||||
var args = std.ArrayList([]const u8).init(arena);
|
||||
try add_include_dirs(mod, arena, &args);
|
||||
try args.appendSlice(&[_][]const u8{
|
||||
"-D_LIBC_REENTRANT",
|
||||
"-DMODULE_NAME=libc",
|
||||
"-DTOP_NAMESPACE=glibc",
|
||||
"-DASSEMBLER",
|
||||
"-g",
|
||||
"-Wa,--noexecstack",
|
||||
});
|
||||
const c_source_file: Module.CSourceFile = .{
|
||||
.src_path = try start_asm_path(mod, arena, "crtn.S"),
|
||||
.extra_flags = args.items,
|
||||
};
|
||||
return build_libc_object(mod, "crtn.o", c_source_file);
|
||||
},
|
||||
.start_os => {
|
||||
var args = std.ArrayList([]const u8).init(arena);
|
||||
try add_include_dirs(mod, arena, &args);
|
||||
try args.appendSlice(&[_][]const u8{
|
||||
"-D_LIBC_REENTRANT",
|
||||
"-include",
|
||||
try lib_path(mod, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-modules.h"),
|
||||
"-DMODULE_NAME=libc",
|
||||
"-Wno-nonportable-include-path",
|
||||
"-include",
|
||||
try lib_path(mod, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-symbols.h"),
|
||||
"-DPIC",
|
||||
"-DSHARED",
|
||||
"-DTOP_NAMESPACE=glibc",
|
||||
"-DASSEMBLER",
|
||||
"-g",
|
||||
"-Wa,--noexecstack",
|
||||
});
|
||||
const c_source_file: Module.CSourceFile = .{
|
||||
.src_path = try start_asm_path(mod, arena, "start.S"),
|
||||
.extra_flags = args.items,
|
||||
};
|
||||
return build_libc_object(mod, "start.os", c_source_file);
|
||||
},
|
||||
.abi_note_o => {
|
||||
var args = std.ArrayList([]const u8).init(arena);
|
||||
try args.appendSlice(&[_][]const u8{
|
||||
"-I",
|
||||
try lib_path(mod, arena, lib_libc_glibc ++ "glibc" ++ path.sep_str ++ "csu"),
|
||||
});
|
||||
try add_include_dirs(mod, arena, &args);
|
||||
try args.appendSlice(&[_][]const u8{
|
||||
"-D_LIBC_REENTRANT",
|
||||
"-DMODULE_NAME=libc",
|
||||
"-DTOP_NAMESPACE=glibc",
|
||||
"-DASSEMBLER",
|
||||
"-g",
|
||||
"-Wa,--noexecstack",
|
||||
});
|
||||
const c_source_file: Module.CSourceFile = .{
|
||||
.src_path = try lib_path(mod, arena, lib_libc_glibc ++ "csu" ++ path.sep_str ++ "abi-note.S"),
|
||||
.extra_flags = args.items,
|
||||
};
|
||||
return build_libc_object(mod, "abi-note.o", c_source_file);
|
||||
},
|
||||
.scrt1_o => {
|
||||
return error.Unimplemented; // TODO
|
||||
},
|
||||
.libc_nonshared_a => {
|
||||
return error.Unimplemented; // TODO
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn start_asm_path(mod: *Module, arena: *Allocator, basename: []const u8) ![]const u8 {
|
||||
const arch = mod.getTarget().cpu.arch;
|
||||
const is_ppc = arch == .powerpc or arch == .powerpc64 or arch == .powerpc64le;
|
||||
const is_aarch64 = arch == .aarch64 or arch == .aarch64_be;
|
||||
const is_sparc = arch == .sparc or arch == .sparcel or arch == .sparcv9;
|
||||
const is_64 = arch.ptrBitWidth() == 64;
|
||||
|
||||
const s = path.sep_str;
|
||||
|
||||
var result = std.ArrayList(u8).init(arena);
|
||||
try result.appendSlice(mod.zig_lib_directory.path.?);
|
||||
try result.appendSlice(s ++ "libc" ++ s ++ "glibc" ++ s ++ "sysdeps" ++ s);
|
||||
if (is_sparc) {
|
||||
if (is_64) {
|
||||
try result.appendSlice("sparc" ++ s ++ "sparc64");
|
||||
} else {
|
||||
try result.appendSlice("sparc" ++ s ++ "sparc32");
|
||||
}
|
||||
} else if (arch.isARM()) {
|
||||
try result.appendSlice("arm");
|
||||
} else if (arch.isMIPS()) {
|
||||
try result.appendSlice("mips");
|
||||
} else if (arch == .x86_64) {
|
||||
try result.appendSlice("x86_64");
|
||||
} else if (arch == .i386) {
|
||||
try result.appendSlice("i386");
|
||||
} else if (is_aarch64) {
|
||||
try result.appendSlice("aarch64");
|
||||
} else if (arch.isRISCV()) {
|
||||
try result.appendSlice("riscv");
|
||||
} else if (is_ppc) {
|
||||
if (is_64) {
|
||||
try result.appendSlice("powerpc" ++ s ++ "powerpc64");
|
||||
} else {
|
||||
try result.appendSlice("powerpc" ++ s ++ "powerpc32");
|
||||
}
|
||||
}
|
||||
|
||||
try result.appendSlice(s);
|
||||
try result.appendSlice(basename);
|
||||
return result.items;
|
||||
}
|
||||
|
||||
fn add_include_dirs(mod: *Module, arena: *Allocator, args: *std.ArrayList([]const u8)) error{OutOfMemory}!void {
|
||||
const target = mod.getTarget();
|
||||
const arch = target.cpu.arch;
|
||||
const opt_nptl: ?[]const u8 = if (target.os.tag == .linux) "nptl" else "htl";
|
||||
const glibc = try lib_path(mod, arena, lib_libc ++ "glibc");
|
||||
|
||||
const s = path.sep_str;
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "include"));
|
||||
|
||||
if (target.os.tag == .linux) {
|
||||
try add_include_dirs_arch(arena, args, arch, null, try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix" ++ s ++ "sysv" ++ s ++ "linux"));
|
||||
}
|
||||
|
||||
if (opt_nptl) |nptl| {
|
||||
try add_include_dirs_arch(arena, args, arch, nptl, try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps"));
|
||||
}
|
||||
|
||||
if (target.os.tag == .linux) {
|
||||
try args.append("-I");
|
||||
try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++
|
||||
"unix" ++ s ++ "sysv" ++ s ++ "linux" ++ s ++ "generic"));
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++
|
||||
"unix" ++ s ++ "sysv" ++ s ++ "linux" ++ s ++ "include"));
|
||||
try args.append("-I");
|
||||
try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++
|
||||
"unix" ++ s ++ "sysv" ++ s ++ "linux"));
|
||||
}
|
||||
if (opt_nptl) |nptl| {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ mod.zig_lib_directory.path.?, lib_libc_glibc ++ "sysdeps", nptl }));
|
||||
}
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "pthread"));
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix" ++ s ++ "sysv"));
|
||||
|
||||
try add_include_dirs_arch(arena, args, arch, null, try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix"));
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix"));
|
||||
|
||||
try add_include_dirs_arch(arena, args, arch, null, try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps"));
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "generic"));
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ mod.zig_lib_directory.path.?, lib_libc ++ "glibc" }));
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try std.fmt.allocPrint(arena, "{}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{}-{}-{}", .{
|
||||
mod.zig_lib_directory.path.?, @tagName(arch), @tagName(target.os.tag), @tagName(target.abi),
|
||||
}));
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try lib_path(mod, arena, lib_libc ++ "include" ++ s ++ "generic-glibc"));
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try std.fmt.allocPrint(arena, "{}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{}-linux-any", .{
|
||||
mod.zig_lib_directory.path.?, @tagName(arch),
|
||||
}));
|
||||
|
||||
try args.append("-I");
|
||||
try args.append(try lib_path(mod, arena, lib_libc ++ "include" ++ s ++ "any-linux-any"));
|
||||
}
|
||||
|
||||
fn add_include_dirs_arch(
|
||||
arena: *Allocator,
|
||||
args: *std.ArrayList([]const u8),
|
||||
arch: std.Target.Cpu.Arch,
|
||||
opt_nptl: ?[]const u8,
|
||||
dir: []const u8,
|
||||
) error{OutOfMemory}!void {
|
||||
const is_x86 = arch == .i386 or arch == .x86_64;
|
||||
const is_aarch64 = arch == .aarch64 or arch == .aarch64_be;
|
||||
const is_ppc = arch == .powerpc or arch == .powerpc64 or arch == .powerpc64le;
|
||||
const is_sparc = arch == .sparc or arch == .sparcel or arch == .sparcv9;
|
||||
const is_64 = arch.ptrBitWidth() == 64;
|
||||
|
||||
const s = path.sep_str;
|
||||
|
||||
if (is_x86) {
|
||||
if (arch == .x86_64) {
|
||||
if (opt_nptl) |nptl| {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "x86_64", nptl }));
|
||||
} else {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "x86_64" }));
|
||||
}
|
||||
} else if (arch == .i386) {
|
||||
if (opt_nptl) |nptl| {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "i386", nptl }));
|
||||
} else {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "i386" }));
|
||||
}
|
||||
}
|
||||
if (opt_nptl) |nptl| {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "x86", nptl }));
|
||||
} else {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "x86" }));
|
||||
}
|
||||
} else if (arch.isARM()) {
|
||||
if (opt_nptl) |nptl| {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "arm", nptl }));
|
||||
} else {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "arm" }));
|
||||
}
|
||||
} else if (arch.isMIPS()) {
|
||||
if (opt_nptl) |nptl| {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "mips", nptl }));
|
||||
} else {
|
||||
if (is_64) {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "mips" ++ s ++ "mips64" }));
|
||||
} else {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "mips" ++ s ++ "mips32" }));
|
||||
}
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "mips" }));
|
||||
}
|
||||
} else if (is_sparc) {
|
||||
if (opt_nptl) |nptl| {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc", nptl }));
|
||||
} else {
|
||||
if (is_64) {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc" ++ s ++ "sparc64" }));
|
||||
} else {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc" ++ s ++ "sparc32" }));
|
||||
}
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc" }));
|
||||
}
|
||||
} else if (is_aarch64) {
|
||||
if (opt_nptl) |nptl| {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "aarch64", nptl }));
|
||||
} else {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "aarch64" }));
|
||||
}
|
||||
} else if (is_ppc) {
|
||||
if (opt_nptl) |nptl| {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc", nptl }));
|
||||
} else {
|
||||
if (is_64) {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc" ++ s ++ "powerpc64" }));
|
||||
} else {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc" ++ s ++ "powerpc32" }));
|
||||
}
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc" }));
|
||||
}
|
||||
} else if (arch.isRISCV()) {
|
||||
if (opt_nptl) |nptl| {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "riscv", nptl }));
|
||||
} else {
|
||||
try args.append("-I");
|
||||
try args.append(try path.join(arena, &[_][]const u8{ dir, "riscv" }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn path_from_lib(mod: *Module, arena: *Allocator, sub_path: []const u8) ![]const u8 {
|
||||
return path.join(arena, &[_][]const u8{ mod.zig_lib_directory.path.?, sub_path });
|
||||
}
|
||||
|
||||
const lib_libc = "libc" ++ path.sep_str;
|
||||
const lib_libc_glibc = lib_libc ++ "glibc" ++ path.sep_str;
|
||||
|
||||
fn lib_path(mod: *Module, arena: *Allocator, sub_path: []const u8) ![]const u8 {
|
||||
return path.join(arena, &[_][]const u8{ mod.zig_lib_directory.path.?, sub_path });
|
||||
}
|
||||
|
||||
fn build_libc_object(mod: *Module, basename: []const u8, c_source_file: Module.CSourceFile) !void {
|
||||
// TODO: This is extracted into a local variable to work around a stage1 miscompilation.
|
||||
const emit_bin = Module.EmitLoc{
|
||||
.directory = null, // Put it in the cache directory.
|
||||
.basename = basename,
|
||||
};
|
||||
const sub_module = try Module.create(mod.gpa, .{
|
||||
// TODO use the global cache directory here
|
||||
.zig_cache_directory = mod.zig_cache_directory,
|
||||
.zig_lib_directory = mod.zig_lib_directory,
|
||||
.target = mod.getTarget(),
|
||||
.root_name = mem.split(basename, ".").next().?,
|
||||
.root_pkg = null,
|
||||
.output_mode = .Obj,
|
||||
.rand = mod.rand,
|
||||
.libc_installation = mod.bin_file.options.libc_installation,
|
||||
.emit_bin = emit_bin,
|
||||
.optimize_mode = mod.bin_file.options.optimize_mode,
|
||||
.want_sanitize_c = false,
|
||||
.want_stack_check = false,
|
||||
.want_valgrind = false,
|
||||
.want_pic = mod.bin_file.options.pic,
|
||||
.emit_h = null,
|
||||
.strip = mod.bin_file.options.strip,
|
||||
.is_native_os = mod.bin_file.options.is_native_os,
|
||||
.self_exe_path = mod.self_exe_path,
|
||||
.c_source_files = &[1]Module.CSourceFile{c_source_file},
|
||||
.debug_cc = mod.debug_cc,
|
||||
.debug_link = mod.bin_file.options.debug_link,
|
||||
});
|
||||
defer sub_module.destroy();
|
||||
|
||||
try sub_module.update();
|
||||
|
||||
try mod.crt_files.ensureCapacity(mod.gpa, mod.crt_files.count() + 1);
|
||||
const artifact_path = try std.fs.path.join(mod.gpa, &[_][]const u8{
|
||||
sub_module.zig_cache_artifact_directory.path.?, basename,
|
||||
});
|
||||
mod.crt_files.putAssumeCapacityNoClobber(basename, artifact_path);
|
||||
}
|
||||
|
||||
@ -1,77 +1,65 @@
|
||||
//! Introspection and determination of system libraries needed by zig.
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const fs = std.fs;
|
||||
const CacheHash = std.cache_hash.CacheHash;
|
||||
const Module = @import("Module.zig");
|
||||
|
||||
/// Caller must free result
|
||||
pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
|
||||
{
|
||||
const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });
|
||||
errdefer allocator.free(test_zig_dir);
|
||||
/// Returns the sub_path that worked, or `null` if none did.
|
||||
/// The path of the returned Directory is relative to `base`.
|
||||
/// The handle of the returned Directory is open.
|
||||
fn testZigInstallPrefix(base_dir: fs.Dir) ?Module.Directory {
|
||||
const test_index_file = "std" ++ fs.path.sep_str ++ "std.zig";
|
||||
|
||||
const test_index_file = try fs.path.join(allocator, &[_][]const u8{ test_zig_dir, "std", "std.zig" });
|
||||
defer allocator.free(test_index_file);
|
||||
|
||||
if (fs.cwd().openFile(test_index_file, .{})) |file| {
|
||||
zig_dir: {
|
||||
// Try lib/zig/std/std.zig
|
||||
const lib_zig = "lib" ++ fs.path.sep_str ++ "zig";
|
||||
var test_zig_dir = base_dir.openDir(lib_zig, .{}) catch break :zig_dir;
|
||||
const file = test_zig_dir.openFile(test_index_file, .{}) catch {
|
||||
test_zig_dir.close();
|
||||
break :zig_dir;
|
||||
};
|
||||
file.close();
|
||||
return test_zig_dir;
|
||||
} else |err| switch (err) {
|
||||
error.FileNotFound => {
|
||||
allocator.free(test_zig_dir);
|
||||
},
|
||||
else => |e| return e,
|
||||
}
|
||||
return Module.Directory{ .handle = test_zig_dir, .path = lib_zig };
|
||||
}
|
||||
|
||||
// Also try without "zig"
|
||||
const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib" });
|
||||
errdefer allocator.free(test_zig_dir);
|
||||
|
||||
const test_index_file = try fs.path.join(allocator, &[_][]const u8{ test_zig_dir, "std", "std.zig" });
|
||||
defer allocator.free(test_index_file);
|
||||
|
||||
const file = try fs.cwd().openFile(test_index_file, .{});
|
||||
// Try lib/std/std.zig
|
||||
var test_zig_dir = base_dir.openDir("lib", .{}) catch return null;
|
||||
const file = test_zig_dir.openFile(test_index_file, .{}) catch {
|
||||
test_zig_dir.close();
|
||||
return null;
|
||||
};
|
||||
file.close();
|
||||
|
||||
return test_zig_dir;
|
||||
return Module.Directory{ .handle = test_zig_dir, .path = "lib" };
|
||||
}
|
||||
|
||||
/// Caller must free result
|
||||
pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 {
|
||||
const self_exe_path = try fs.selfExePathAlloc(allocator);
|
||||
defer allocator.free(self_exe_path);
|
||||
/// Both the directory handle and the path are newly allocated resources which the caller now owns.
|
||||
pub fn findZigLibDir(gpa: *mem.Allocator) !Module.Directory {
|
||||
const self_exe_path = try fs.selfExePathAlloc(gpa);
|
||||
defer gpa.free(self_exe_path);
|
||||
|
||||
return findZigLibDirFromSelfExe(gpa, self_exe_path);
|
||||
}
|
||||
|
||||
/// Both the directory handle and the path are newly allocated resources which the caller now owns.
|
||||
pub fn findZigLibDirFromSelfExe(
|
||||
allocator: *mem.Allocator,
|
||||
self_exe_path: []const u8,
|
||||
) error{ OutOfMemory, FileNotFound }!Module.Directory {
|
||||
const cwd = fs.cwd();
|
||||
var cur_path: []const u8 = self_exe_path;
|
||||
while (true) {
|
||||
const test_dir = fs.path.dirname(cur_path) orelse ".";
|
||||
while (fs.path.dirname(cur_path)) |dirname| : (cur_path = dirname) {
|
||||
var base_dir = cwd.openDir(dirname, .{}) catch continue;
|
||||
defer base_dir.close();
|
||||
|
||||
if (mem.eql(u8, test_dir, cur_path)) {
|
||||
break;
|
||||
}
|
||||
|
||||
return testZigInstallPrefix(allocator, test_dir) catch |err| {
|
||||
cur_path = test_dir;
|
||||
continue;
|
||||
const sub_directory = testZigInstallPrefix(base_dir) orelse continue;
|
||||
return Module.Directory{
|
||||
.handle = sub_directory.handle,
|
||||
.path = try fs.path.join(allocator, &[_][]const u8{ dirname, sub_directory.path.? }),
|
||||
};
|
||||
}
|
||||
|
||||
return error.FileNotFound;
|
||||
}
|
||||
|
||||
pub fn resolveZigLibDir(allocator: *mem.Allocator) ![]u8 {
|
||||
return findZigLibDir(allocator) catch |err| {
|
||||
std.debug.print(
|
||||
\\Unable to find zig lib directory: {}.
|
||||
\\Reinstall Zig or use --zig-install-prefix.
|
||||
\\
|
||||
, .{@errorName(err)});
|
||||
|
||||
return error.ZigLibDirNotFound;
|
||||
};
|
||||
}
|
||||
|
||||
/// Caller owns returned memory.
|
||||
pub fn resolveGlobalCacheDir(allocator: *mem.Allocator) ![]u8 {
|
||||
const appname = "zig";
|
||||
|
||||
@ -11,11 +11,9 @@ const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||
pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
|
||||
|
||||
pub const Options = struct {
|
||||
dir: fs.Dir,
|
||||
/// Redundant with dir. Needed when linking with LLD because we have to pass paths rather
|
||||
/// than file descriptors. `null` means cwd. OK to pass `null` when `use_lld` is `false`.
|
||||
dir_path: ?[]const u8,
|
||||
/// Path to the output file, relative to dir.
|
||||
/// Where the output will go.
|
||||
directory: Module.Directory,
|
||||
/// Path to the output file, relative to `directory`.
|
||||
sub_path: []const u8,
|
||||
target: std.Target,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
@ -53,6 +51,11 @@ pub const Options = struct {
|
||||
z_defs: bool = false,
|
||||
bind_global_refs_locally: bool,
|
||||
is_native_os: bool,
|
||||
pic: bool,
|
||||
valgrind: bool,
|
||||
stack_check: bool,
|
||||
single_threaded: bool,
|
||||
debug_link: bool = false,
|
||||
gc_sections: ?bool = null,
|
||||
allow_shlib_undefined: ?bool = null,
|
||||
linker_script: ?[]const u8 = null,
|
||||
@ -154,7 +157,7 @@ pub const File = struct {
|
||||
switch (base.tag) {
|
||||
.coff, .elf, .macho => {
|
||||
if (base.file != null) return;
|
||||
base.file = try base.options.dir.createFile(base.options.sub_path, .{
|
||||
base.file = try base.options.directory.handle.createFile(base.options.sub_path, .{
|
||||
.truncate = false,
|
||||
.read = true,
|
||||
.mode = determineMode(base.options),
|
||||
|
||||
@ -28,7 +28,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
if (options.use_llvm) return error.LLVMHasNoCBackend;
|
||||
if (options.use_lld) return error.LLDHasNoCBackend;
|
||||
|
||||
const file = try options.dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) });
|
||||
const file = try options.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) });
|
||||
errdefer file.close();
|
||||
|
||||
var c_file = try allocator.create(C);
|
||||
|
||||
@ -116,7 +116,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
if (options.use_llvm) return error.LLVM_BackendIsTODO_ForCoff; // TODO
|
||||
if (options.use_lld) return error.LLD_LinkingIsTODO_ForCoff; // TODO
|
||||
|
||||
const file = try options.dir.createFile(sub_path, .{
|
||||
const file = try options.directory.handle.createFile(sub_path, .{
|
||||
.truncate = false,
|
||||
.read = true,
|
||||
.mode = link.determineMode(options),
|
||||
|
||||
@ -19,6 +19,7 @@ const File = link.File;
|
||||
const Elf = @This();
|
||||
const build_options = @import("build_options");
|
||||
const target_util = @import("../target.zig");
|
||||
const fatal = @import("main.zig").fatal;
|
||||
|
||||
const default_entry_addr = 0x8000000;
|
||||
|
||||
@ -222,7 +223,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
|
||||
if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO
|
||||
|
||||
const file = try options.dir.createFile(sub_path, .{
|
||||
const file = try options.directory.handle.createFile(sub_path, .{
|
||||
.truncate = false,
|
||||
.read = true,
|
||||
.mode = link.determineMode(options),
|
||||
@ -844,7 +845,7 @@ fn flushInner(self: *Elf, module: *Module) !void {
|
||||
}
|
||||
// Write the form for the compile unit, which must match the abbrev table above.
|
||||
const name_strp = try self.makeDebugString(self.base.options.root_pkg.?.root_src_path);
|
||||
const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.?.root_src_dir_path);
|
||||
const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.?.root_src_directory.path.?);
|
||||
const producer_strp = try self.makeDebugString(link.producer_string);
|
||||
// Currently only one compilation unit is supported, so the address range is simply
|
||||
// identical to the main program header virtual address and memory size.
|
||||
@ -1199,11 +1200,6 @@ fn flushInner(self: *Elf, module: *Module) !void {
|
||||
}
|
||||
|
||||
fn linkWithLLD(self: *Elf, module: *Module) !void {
|
||||
// If there is no Zig code to compile, then we should skip flushing the output file because it
|
||||
// will not be part of the linker line anyway.
|
||||
if (module.root_pkg != null) {
|
||||
try self.flushInner(module);
|
||||
}
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
|
||||
defer arena_allocator.deinit();
|
||||
const arena = &arena_allocator.allocator;
|
||||
@ -1292,7 +1288,7 @@ fn linkWithLLD(self: *Elf, module: *Module) !void {
|
||||
try argv.append("-pie");
|
||||
}
|
||||
|
||||
const full_out_path = if (self.base.options.dir_path) |dir_path|
|
||||
const full_out_path = if (self.base.options.directory.path) |dir_path|
|
||||
try std.fs.path.join(arena, &[_][]const u8{dir_path, self.base.options.sub_path})
|
||||
else
|
||||
self.base.options.sub_path;
|
||||
@ -1382,6 +1378,30 @@ fn linkWithLLD(self: *Elf, module: *Module) !void {
|
||||
// Positional arguments to the linker such as object files.
|
||||
try argv.appendSlice(self.base.options.objects);
|
||||
|
||||
for (module.c_object_table.items()) |entry| {
|
||||
const c_object = entry.key;
|
||||
switch (c_object.status) {
|
||||
.new => unreachable,
|
||||
.failure => return error.NotAllCSourceFilesAvailableToLink,
|
||||
.success => |full_obj_path| {
|
||||
try argv.append(full_obj_path);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no Zig code to compile, then we should skip flushing the output file because it
|
||||
// will not be part of the linker line anyway.
|
||||
if (module.root_pkg != null) {
|
||||
try self.flushInner(module);
|
||||
|
||||
const obj_basename = self.base.intermediary_basename.?;
|
||||
const full_obj_path = if (self.base.options.directory.path) |dir_path|
|
||||
try std.fs.path.join(arena, &[_][]const u8{dir_path, obj_basename})
|
||||
else
|
||||
obj_basename;
|
||||
try argv.append(full_obj_path);
|
||||
}
|
||||
|
||||
// TODO compiler-rt and libc
|
||||
//if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) {
|
||||
// if (g->libc_link_lib == nullptr) {
|
||||
@ -1461,10 +1481,31 @@ fn linkWithLLD(self: *Elf, module: *Module) !void {
|
||||
try argv.append("-Bsymbolic");
|
||||
}
|
||||
|
||||
for (argv.items) |arg| {
|
||||
if (self.base.options.debug_link) {
|
||||
for (argv.items[0 .. argv.items.len - 1]) |arg| {
|
||||
std.debug.print("{} ", .{arg});
|
||||
}
|
||||
@panic("invoke LLD");
|
||||
std.debug.print("{}\n", .{argv.items[argv.items.len - 1]});
|
||||
}
|
||||
|
||||
// Oh, snapplesauce! We need null terminated argv.
|
||||
// TODO allocSentinel crashed stage1 so this is working around it.
|
||||
const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1);
|
||||
new_argv_with_sentinel[argv.items.len] = null;
|
||||
const new_argv = new_argv_with_sentinel[0..argv.items.len: null];
|
||||
for (argv.items) |arg, i| {
|
||||
new_argv[i] = try arena.dupeZ(u8, arg);
|
||||
}
|
||||
|
||||
const ZigLLDLink = @import("../llvm.zig").ZigLLDLink;
|
||||
const ok = ZigLLDLink(.ELF, new_argv.ptr, new_argv.len, append_diagnostic, 0, 0);
|
||||
if (!ok) return error.LLDReportedFailure;
|
||||
}
|
||||
|
||||
fn append_diagnostic(context: usize, ptr: [*]const u8, len: usize) callconv(.C) void {
|
||||
// TODO collect diagnostics and handle cleanly
|
||||
const msg = ptr[0..len];
|
||||
std.log.err("LLD: {}", .{msg});
|
||||
}
|
||||
|
||||
fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void {
|
||||
@ -2681,7 +2722,7 @@ fn dbgLineNeededHeaderBytes(self: Elf) u32 {
|
||||
directory_count * 8 + file_name_count * 8 +
|
||||
// These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like
|
||||
// because of a workaround for readelf and gdb failing to understand DWARFv5 correctly.
|
||||
self.base.options.root_pkg.?.root_src_dir_path.len +
|
||||
self.base.options.root_pkg.?.root_src_directory.path.?.len +
|
||||
self.base.options.root_pkg.?.root_src_path.len);
|
||||
}
|
||||
|
||||
|
||||
@ -140,7 +140,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
if (options.use_llvm) return error.LLVM_BackendIsTODO_ForMachO; // TODO
|
||||
if (options.use_lld) return error.LLD_LinkingIsTODO_ForMachO; // TODO
|
||||
|
||||
const file = try options.dir.createFile(sub_path, .{
|
||||
const file = try options.directory.handle.createFile(sub_path, .{
|
||||
.truncate = false,
|
||||
.read = true,
|
||||
.mode = link.determineMode(options),
|
||||
|
||||
@ -56,7 +56,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO
|
||||
|
||||
// TODO: read the file and keep vaild parts instead of truncating
|
||||
const file = try options.dir.createFile(sub_path, .{ .truncate = true, .read = true });
|
||||
const file = try options.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });
|
||||
errdefer file.close();
|
||||
|
||||
const wasm = try allocator.create(Wasm);
|
||||
|
||||
@ -1,293 +1,20 @@
|
||||
const c = @import("c.zig");
|
||||
const assert = @import("std").debug.assert;
|
||||
//! We do this instead of @cImport because the self-hosted compiler is easier
|
||||
//! to bootstrap if it does not depend on translate-c.
|
||||
|
||||
// we wrap the c module for 3 reasons:
|
||||
// 1. to avoid accidentally calling the non-thread-safe functions
|
||||
// 2. patch up some of the types to remove nullability
|
||||
// 3. some functions have been augmented by zig_llvm.cpp to be more powerful,
|
||||
// such as ZigLLVMTargetMachineEmitToFile
|
||||
|
||||
pub const AttributeIndex = c_uint;
|
||||
pub const Bool = c_int;
|
||||
|
||||
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 AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
|
||||
pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
|
||||
pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
|
||||
pub const ConstAllOnes = c.LLVMConstAllOnes;
|
||||
pub const ConstArray = c.LLVMConstArray;
|
||||
pub const ConstBitCast = c.LLVMConstBitCast;
|
||||
pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
|
||||
pub const ConstNeg = c.LLVMConstNeg;
|
||||
pub const ConstStructInContext = c.LLVMConstStructInContext;
|
||||
pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize;
|
||||
pub const DisposeBuilder = c.LLVMDisposeBuilder;
|
||||
pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder;
|
||||
pub const DisposeMessage = c.LLVMDisposeMessage;
|
||||
pub const DisposeModule = c.LLVMDisposeModule;
|
||||
pub const DisposeTargetData = c.LLVMDisposeTargetData;
|
||||
pub const DisposeTargetMachine = c.LLVMDisposeTargetMachine;
|
||||
pub const DoubleTypeInContext = c.LLVMDoubleTypeInContext;
|
||||
pub const DumpModule = c.LLVMDumpModule;
|
||||
pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
|
||||
pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
|
||||
pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
|
||||
pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
|
||||
pub const GetUndef = c.LLVMGetUndef;
|
||||
pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
|
||||
pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
|
||||
pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters;
|
||||
pub const InitializeAllTargetInfos = c.LLVMInitializeAllTargetInfos;
|
||||
pub const InitializeAllTargetMCs = c.LLVMInitializeAllTargetMCs;
|
||||
pub const InitializeAllTargets = c.LLVMInitializeAllTargets;
|
||||
pub const InsertBasicBlockInContext = c.LLVMInsertBasicBlockInContext;
|
||||
pub const Int128TypeInContext = c.LLVMInt128TypeInContext;
|
||||
pub const Int16TypeInContext = c.LLVMInt16TypeInContext;
|
||||
pub const Int1TypeInContext = c.LLVMInt1TypeInContext;
|
||||
pub const Int32TypeInContext = c.LLVMInt32TypeInContext;
|
||||
pub const Int64TypeInContext = c.LLVMInt64TypeInContext;
|
||||
pub const Int8TypeInContext = c.LLVMInt8TypeInContext;
|
||||
pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext;
|
||||
pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext;
|
||||
pub const LabelTypeInContext = c.LLVMLabelTypeInContext;
|
||||
pub const MDNodeInContext = c.LLVMMDNodeInContext;
|
||||
pub const MDStringInContext = c.LLVMMDStringInContext;
|
||||
pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
|
||||
pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
|
||||
pub const SetAlignment = c.LLVMSetAlignment;
|
||||
pub const SetDataLayout = c.LLVMSetDataLayout;
|
||||
pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
|
||||
pub const SetInitializer = c.LLVMSetInitializer;
|
||||
pub const SetLinkage = c.LLVMSetLinkage;
|
||||
pub const SetTarget = c.LLVMSetTarget;
|
||||
pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
|
||||
pub const SetVolatile = c.LLVMSetVolatile;
|
||||
pub const StructTypeInContext = c.LLVMStructTypeInContext;
|
||||
pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
|
||||
pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
|
||||
pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
|
||||
|
||||
pub const AddGlobal = LLVMAddGlobal;
|
||||
extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]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: [*:0]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: [*:0]const u8, FunctionTy: *Type) ?*Value;
|
||||
|
||||
pub const CreateCompileUnit = ZigLLVMCreateCompileUnit;
|
||||
extern fn ZigLLVMCreateCompileUnit(
|
||||
dibuilder: *DIBuilder,
|
||||
lang: c_uint,
|
||||
difile: *DIFile,
|
||||
producer: [*:0]const u8,
|
||||
is_optimized: bool,
|
||||
flags: [*:0]const u8,
|
||||
runtime_version: c_uint,
|
||||
split_name: [*:0]const u8,
|
||||
dwo_id: u64,
|
||||
emit_debug_info: bool,
|
||||
) ?*DICompileUnit;
|
||||
|
||||
pub const CreateFile = ZigLLVMCreateFile;
|
||||
extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*:0]const u8, directory: [*:0]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: [*:0]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) ?[*:0]u8;
|
||||
|
||||
pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout;
|
||||
extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData;
|
||||
|
||||
pub const CreateTargetMachine = ZigLLVMCreateTargetMachine;
|
||||
extern fn ZigLLVMCreateTargetMachine(
|
||||
T: *Target,
|
||||
Triple: [*:0]const u8,
|
||||
CPU: [*:0]const u8,
|
||||
Features: [*:0]const u8,
|
||||
Level: CodeGenOptLevel,
|
||||
Reloc: RelocMode,
|
||||
CodeModel: CodeModel,
|
||||
function_sections: bool,
|
||||
) ?*TargetMachine;
|
||||
|
||||
pub const GetHostCPUName = LLVMGetHostCPUName;
|
||||
extern fn LLVMGetHostCPUName() ?[*:0]u8;
|
||||
|
||||
pub const GetNativeFeatures = ZigLLVMGetNativeFeatures;
|
||||
extern fn ZigLLVMGetNativeFeatures() ?[*:0]u8;
|
||||
|
||||
pub const GetElementType = LLVMGetElementType;
|
||||
extern fn LLVMGetElementType(Ty: *Type) *Type;
|
||||
|
||||
pub const TypeOf = LLVMTypeOf;
|
||||
extern fn LLVMTypeOf(Val: *Value) *Type;
|
||||
|
||||
pub const BuildStore = LLVMBuildStore;
|
||||
extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value;
|
||||
|
||||
pub const BuildAlloca = LLVMBuildAlloca;
|
||||
extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*:0]const u8) ?*Value;
|
||||
|
||||
pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
|
||||
pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value;
|
||||
|
||||
pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
|
||||
extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **Target, ErrorMessage: ?*[*:0]u8) Bool;
|
||||
|
||||
pub const VerifyModule = LLVMVerifyModule;
|
||||
extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*:0]u8) Bool;
|
||||
|
||||
pub const GetInsertBlock = LLVMGetInsertBlock;
|
||||
extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock;
|
||||
|
||||
pub const FunctionType = LLVMFunctionType;
|
||||
extern fn LLVMFunctionType(
|
||||
ReturnType: *Type,
|
||||
ParamTypes: [*]*Type,
|
||||
ParamCount: c_uint,
|
||||
IsVarArg: Bool,
|
||||
) ?*Type;
|
||||
|
||||
pub const GetParam = LLVMGetParam;
|
||||
extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value;
|
||||
|
||||
pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext;
|
||||
extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*:0]const u8) ?*BasicBlock;
|
||||
|
||||
pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd;
|
||||
extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void;
|
||||
|
||||
pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction;
|
||||
pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction;
|
||||
pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction;
|
||||
pub const VerifierFailureAction = c.LLVMVerifierFailureAction;
|
||||
|
||||
pub const CodeGenLevelNone = CodeGenOptLevel.LLVMCodeGenLevelNone;
|
||||
pub const CodeGenLevelLess = CodeGenOptLevel.LLVMCodeGenLevelLess;
|
||||
pub const CodeGenLevelDefault = CodeGenOptLevel.LLVMCodeGenLevelDefault;
|
||||
pub const CodeGenLevelAggressive = CodeGenOptLevel.LLVMCodeGenLevelAggressive;
|
||||
pub const CodeGenOptLevel = c.LLVMCodeGenOptLevel;
|
||||
|
||||
pub const RelocDefault = RelocMode.LLVMRelocDefault;
|
||||
pub const RelocStatic = RelocMode.LLVMRelocStatic;
|
||||
pub const RelocPIC = RelocMode.LLVMRelocPIC;
|
||||
pub const RelocDynamicNoPic = RelocMode.LLVMRelocDynamicNoPic;
|
||||
pub const RelocMode = c.LLVMRelocMode;
|
||||
|
||||
pub const CodeModelDefault = CodeModel.LLVMCodeModelDefault;
|
||||
pub const CodeModelJITDefault = CodeModel.LLVMCodeModelJITDefault;
|
||||
pub const CodeModelSmall = CodeModel.LLVMCodeModelSmall;
|
||||
pub const CodeModelKernel = CodeModel.LLVMCodeModelKernel;
|
||||
pub const CodeModelMedium = CodeModel.LLVMCodeModelMedium;
|
||||
pub const CodeModelLarge = CodeModel.LLVMCodeModelLarge;
|
||||
pub const CodeModel = c.LLVMCodeModel;
|
||||
|
||||
pub const EmitAssembly = EmitOutputType.ZigLLVM_EmitAssembly;
|
||||
pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary;
|
||||
pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr;
|
||||
pub const EmitOutputType = c.ZigLLVM_EmitOutputType;
|
||||
|
||||
pub const CCallConv = CallConv.LLVMCCallConv;
|
||||
pub const FastCallConv = CallConv.LLVMFastCallConv;
|
||||
pub const ColdCallConv = CallConv.LLVMColdCallConv;
|
||||
pub const WebKitJSCallConv = CallConv.LLVMWebKitJSCallConv;
|
||||
pub const AnyRegCallConv = CallConv.LLVMAnyRegCallConv;
|
||||
pub const X86StdcallCallConv = CallConv.LLVMX86StdcallCallConv;
|
||||
pub const X86FastcallCallConv = CallConv.LLVMX86FastcallCallConv;
|
||||
pub const CallConv = c.LLVMCallConv;
|
||||
|
||||
pub const CallAttr = extern enum {
|
||||
Auto,
|
||||
NeverTail,
|
||||
NeverInline,
|
||||
AlwaysTail,
|
||||
AlwaysInline,
|
||||
};
|
||||
|
||||
fn removeNullability(comptime T: type) type {
|
||||
comptime assert(@typeInfo(T).Pointer.size == .C);
|
||||
return *T.Child;
|
||||
}
|
||||
|
||||
pub const BuildRet = LLVMBuildRet;
|
||||
extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value;
|
||||
|
||||
pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
|
||||
extern fn ZigLLVMTargetMachineEmitToFile(
|
||||
targ_machine_ref: *TargetMachine,
|
||||
module_ref: *Module,
|
||||
filename: [*:0]const u8,
|
||||
output_type: EmitOutputType,
|
||||
error_message: *[*:0]u8,
|
||||
is_debug: bool,
|
||||
is_small: bool,
|
||||
pub extern fn ZigLLDLink(
|
||||
oformat: ZigLLVM_ObjectFormatType,
|
||||
args: [*:null]const ?[*:0]const u8,
|
||||
arg_count: usize,
|
||||
append_diagnostic: fn (context: usize, ptr: [*]const u8, len: usize) callconv(.C) void,
|
||||
context_stdout: usize,
|
||||
context_stderr: usize,
|
||||
) bool;
|
||||
|
||||
pub const BuildCall = ZigLLVMBuildCall;
|
||||
extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: CallConv, fn_inline: CallAttr, Name: [*:0]const u8) ?*Value;
|
||||
|
||||
pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;
|
||||
pub const ZigLLVM_ObjectFormatType = extern enum(c_int) {
|
||||
Unknown,
|
||||
COFF,
|
||||
ELF,
|
||||
MachO,
|
||||
Wasm,
|
||||
XCOFF,
|
||||
};
|
||||
|
||||
@ -191,7 +191,14 @@ const usage_build_generic =
|
||||
\\ ReleaseSmall Optimize for small binary, safety off
|
||||
\\ -fPIC Force-enable Position Independent Code
|
||||
\\ -fno-PIC Force-disable Position Independent Code
|
||||
\\ -fstack-check Enable stack probing in unsafe builds
|
||||
\\ -fno-stack-check Disable stack probing in safe builds
|
||||
\\ -fsanitize-c Enable C undefined behavior detection in unsafe builds
|
||||
\\ -fno-sanitize-c Disable C undefined behavior detection in safe builds
|
||||
\\ -fvalgrind Include valgrind client requests in release builds
|
||||
\\ -fno-valgrind Omit valgrind client requests in debug builds
|
||||
\\ --strip Exclude debug symbols
|
||||
\\ --single-threaded Code assumes it is only used single-threaded
|
||||
\\ -ofmt=[mode] Override target object format
|
||||
\\ elf Executable and Linking Format
|
||||
\\ c Compile to C source code
|
||||
@ -262,6 +269,7 @@ pub fn buildOutputType(
|
||||
var root_src_file: ?[]const u8 = null;
|
||||
var version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 };
|
||||
var strip = false;
|
||||
var single_threaded = false;
|
||||
var watch = false;
|
||||
var debug_tokenize = false;
|
||||
var debug_ast_tree = false;
|
||||
@ -287,6 +295,8 @@ pub fn buildOutputType(
|
||||
var enable_cache: ?bool = null;
|
||||
var want_pic: ?bool = null;
|
||||
var want_sanitize_c: ?bool = null;
|
||||
var want_stack_check: ?bool = null;
|
||||
var want_valgrind: ?bool = null;
|
||||
var rdynamic: bool = false;
|
||||
var only_pp_or_asm = false;
|
||||
var linker_script: ?[]const u8 = null;
|
||||
@ -320,7 +330,7 @@ pub fn buildOutputType(
|
||||
var rpath_list = std.ArrayList([]const u8).init(gpa);
|
||||
defer rpath_list.deinit();
|
||||
|
||||
var c_source_files = std.ArrayList([]const u8).init(gpa);
|
||||
var c_source_files = std.ArrayList(Module.CSourceFile).init(gpa);
|
||||
defer c_source_files.deinit();
|
||||
|
||||
var link_objects = std.ArrayList([]const u8).init(gpa);
|
||||
@ -463,6 +473,18 @@ pub fn buildOutputType(
|
||||
want_pic = true;
|
||||
} else if (mem.eql(u8, arg, "-fno-PIC")) {
|
||||
want_pic = false;
|
||||
} else if (mem.eql(u8, arg, "-fstack-check")) {
|
||||
want_stack_check = true;
|
||||
} else if (mem.eql(u8, arg, "-fno-stack-check")) {
|
||||
want_stack_check = false;
|
||||
} else if (mem.eql(u8, arg, "-fsanitize-c")) {
|
||||
want_sanitize_c = true;
|
||||
} else if (mem.eql(u8, arg, "-fno-sanitize-c")) {
|
||||
want_sanitize_c = false;
|
||||
} else if (mem.eql(u8, arg, "-fvalgrind")) {
|
||||
want_valgrind = true;
|
||||
} else if (mem.eql(u8, arg, "-fno-valgrind")) {
|
||||
want_valgrind = false;
|
||||
} else if (mem.eql(u8, arg, "-fLLVM")) {
|
||||
use_llvm = true;
|
||||
} else if (mem.eql(u8, arg, "-fno-LLVM")) {
|
||||
@ -501,6 +523,8 @@ pub fn buildOutputType(
|
||||
link_mode = .Static;
|
||||
} else if (mem.eql(u8, arg, "--strip")) {
|
||||
strip = true;
|
||||
} else if (mem.eql(u8, arg, "--single-threaded")) {
|
||||
single_threaded = true;
|
||||
} else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
|
||||
link_eh_frame_hdr = true;
|
||||
} else if (mem.eql(u8, arg, "-Bsymbolic")) {
|
||||
@ -541,7 +565,8 @@ pub fn buildOutputType(
|
||||
{
|
||||
try link_objects.append(arg);
|
||||
} else if (Module.hasAsmExt(arg) or Module.hasCExt(arg) or Module.hasCppExt(arg)) {
|
||||
try c_source_files.append(arg);
|
||||
// TODO a way to pass extra flags on the CLI
|
||||
try c_source_files.append(.{ .src_path = arg });
|
||||
} else if (mem.endsWith(u8, arg, ".so") or
|
||||
mem.endsWith(u8, arg, ".dylib") or
|
||||
mem.endsWith(u8, arg, ".dll"))
|
||||
@ -586,7 +611,7 @@ pub fn buildOutputType(
|
||||
.positional => {
|
||||
const file_ext = Module.classifyFileExt(mem.spanZ(it.only_arg));
|
||||
switch (file_ext) {
|
||||
.assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(it.only_arg),
|
||||
.assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(.{ .src_path = it.only_arg }),
|
||||
.unknown, .so => try link_objects.append(it.only_arg),
|
||||
}
|
||||
},
|
||||
@ -812,7 +837,7 @@ pub fn buildOutputType(
|
||||
// .yes => |p| p,
|
||||
// else => c_source_file.source_path,
|
||||
// };
|
||||
// const basename = std.fs.path.basename(src_path);
|
||||
// const basename = fs.path.basename(src_path);
|
||||
// c_source_file.preprocessor_only_basename = basename;
|
||||
//}
|
||||
//emit_bin = .no;
|
||||
@ -839,7 +864,7 @@ pub fn buildOutputType(
|
||||
const basename = fs.path.basename(file);
|
||||
break :blk mem.split(basename, ".").next().?;
|
||||
} else if (c_source_files.items.len == 1) {
|
||||
const basename = fs.path.basename(c_source_files.items[0]);
|
||||
const basename = fs.path.basename(c_source_files.items[0].src_path);
|
||||
break :blk mem.split(basename, ".").next().?;
|
||||
} else if (link_objects.items.len == 1) {
|
||||
const basename = fs.path.basename(link_objects.items[0]);
|
||||
@ -966,11 +991,14 @@ pub fn buildOutputType(
|
||||
}
|
||||
};
|
||||
|
||||
const bin_path = switch (emit_bin) {
|
||||
.no => {
|
||||
fatal("-fno-emit-bin not supported yet", .{});
|
||||
},
|
||||
.yes_default_path => try std.zig.binNameAlloc(
|
||||
var cleanup_emit_bin_dir: ?fs.Dir = null;
|
||||
defer if (cleanup_emit_bin_dir) |*dir| dir.close();
|
||||
|
||||
const emit_bin_loc: ?Module.EmitLoc = switch (emit_bin) {
|
||||
.no => null,
|
||||
.yes_default_path => Module.EmitLoc{
|
||||
.directory = .{ .path = null, .handle = fs.cwd() },
|
||||
.basename = try std.zig.binNameAlloc(
|
||||
arena,
|
||||
root_name,
|
||||
target_info.target,
|
||||
@ -978,7 +1006,56 @@ pub fn buildOutputType(
|
||||
link_mode,
|
||||
object_format,
|
||||
),
|
||||
.yes => |p| p,
|
||||
},
|
||||
.yes => |full_path| b: {
|
||||
const basename = fs.path.basename(full_path);
|
||||
if (fs.path.dirname(full_path)) |dirname| {
|
||||
const handle = try fs.cwd().openDir(dirname, .{});
|
||||
cleanup_emit_bin_dir = handle;
|
||||
break :b Module.EmitLoc{
|
||||
.basename = basename,
|
||||
.directory = .{
|
||||
.path = dirname,
|
||||
.handle = handle,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
break :b Module.EmitLoc{
|
||||
.basename = basename,
|
||||
.directory = .{ .path = null, .handle = fs.cwd() },
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
var cleanup_emit_h_dir: ?fs.Dir = null;
|
||||
defer if (cleanup_emit_h_dir) |*dir| dir.close();
|
||||
|
||||
const emit_h_loc: ?Module.EmitLoc = switch (emit_h) {
|
||||
.no => null,
|
||||
.yes_default_path => Module.EmitLoc{
|
||||
.directory = .{ .path = null, .handle = fs.cwd() },
|
||||
.basename = try std.fmt.allocPrint(arena, "{}.h", .{root_name}),
|
||||
},
|
||||
.yes => |full_path| b: {
|
||||
const basename = fs.path.basename(full_path);
|
||||
if (fs.path.dirname(full_path)) |dirname| {
|
||||
const handle = try fs.cwd().openDir(dirname, .{});
|
||||
cleanup_emit_h_dir = handle;
|
||||
break :b Module.EmitLoc{
|
||||
.basename = basename,
|
||||
.directory = .{
|
||||
.path = dirname,
|
||||
.handle = handle,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
break :b Module.EmitLoc{
|
||||
.basename = basename,
|
||||
.directory = .{ .path = null, .handle = fs.cwd() },
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const zir_out_path: ?[]const u8 = switch (emit_zir) {
|
||||
@ -995,19 +1072,13 @@ pub fn buildOutputType(
|
||||
};
|
||||
|
||||
const root_pkg = if (root_src_file) |src_path| try Package.create(gpa, fs.cwd(), ".", src_path) else null;
|
||||
defer if (root_pkg) |pkg| pkg.destroy();
|
||||
|
||||
const emit_h_path: ?[]const u8 = switch (emit_h) {
|
||||
.yes => |p| p,
|
||||
.no => null,
|
||||
.yes_default_path => try std.fmt.allocPrint(arena, "{}.h", .{root_name}),
|
||||
};
|
||||
defer if (root_pkg) |pkg| pkg.destroy(gpa);
|
||||
|
||||
const self_exe_path = try fs.selfExePathAlloc(arena);
|
||||
const zig_lib_dir = introspect.resolveZigLibDir(gpa) catch |err| {
|
||||
var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
|
||||
fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});
|
||||
};
|
||||
defer gpa.free(zig_lib_dir);
|
||||
defer zig_lib_directory.handle.close();
|
||||
|
||||
const random_seed = blk: {
|
||||
var random_seed: u64 = undefined;
|
||||
@ -1025,17 +1096,32 @@ pub fn buildOutputType(
|
||||
};
|
||||
}
|
||||
|
||||
const cache_parent_dir = if (root_pkg) |pkg| pkg.root_src_directory.handle else fs.cwd();
|
||||
var cache_dir = try cache_parent_dir.makeOpenPath("zig-cache", .{});
|
||||
defer cache_dir.close();
|
||||
const zig_cache_directory: Module.Directory = .{
|
||||
.handle = cache_dir,
|
||||
.path = blk: {
|
||||
if (root_pkg) |pkg| {
|
||||
if (pkg.root_src_directory.path) |p| {
|
||||
break :blk try fs.path.join(arena, &[_][]const u8{ p, "zig-cache" });
|
||||
}
|
||||
}
|
||||
break :blk "zig-cache";
|
||||
},
|
||||
};
|
||||
|
||||
const module = Module.create(gpa, .{
|
||||
.zig_lib_dir = zig_lib_dir,
|
||||
.zig_lib_directory = zig_lib_directory,
|
||||
.zig_cache_directory = zig_cache_directory,
|
||||
.root_name = root_name,
|
||||
.target = target_info.target,
|
||||
.is_native_os = cross_target.isNativeOs(),
|
||||
.dynamic_linker = target_info.dynamic_linker.get(),
|
||||
.output_mode = output_mode,
|
||||
.root_pkg = root_pkg,
|
||||
.bin_file_dir_path = null,
|
||||
.bin_file_dir = fs.cwd(),
|
||||
.bin_file_path = bin_path,
|
||||
.emit_bin = emit_bin_loc,
|
||||
.emit_h = emit_h_loc,
|
||||
.link_mode = link_mode,
|
||||
.object_format = object_format,
|
||||
.optimize_mode = build_mode,
|
||||
@ -1049,11 +1135,12 @@ pub fn buildOutputType(
|
||||
.framework_dirs = framework_dirs.items,
|
||||
.frameworks = frameworks.items,
|
||||
.system_libs = system_libs.items,
|
||||
.emit_h = emit_h_path,
|
||||
.link_libc = link_libc,
|
||||
.link_libcpp = link_libcpp,
|
||||
.want_pic = want_pic,
|
||||
.want_sanitize_c = want_sanitize_c,
|
||||
.want_stack_check = want_stack_check,
|
||||
.want_valgrind = want_valgrind,
|
||||
.use_llvm = use_llvm,
|
||||
.use_lld = use_lld,
|
||||
.use_clang = use_clang,
|
||||
@ -1070,11 +1157,14 @@ pub fn buildOutputType(
|
||||
.link_eh_frame_hdr = link_eh_frame_hdr,
|
||||
.stack_size_override = stack_size_override,
|
||||
.strip = strip,
|
||||
.single_threaded = single_threaded,
|
||||
.self_exe_path = self_exe_path,
|
||||
.rand = &default_prng.random,
|
||||
.clang_passthrough_mode = arg_mode != .build,
|
||||
.version = version,
|
||||
.libc_installation = if (libc_installation) |*lci| lci else null,
|
||||
.debug_cc = debug_cc,
|
||||
.debug_link = debug_link,
|
||||
}) catch |err| {
|
||||
fatal("unable to create module: {}", .{@errorName(err)});
|
||||
};
|
||||
@ -1121,9 +1211,7 @@ pub fn buildOutputType(
|
||||
}
|
||||
|
||||
fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !void {
|
||||
var timer = try std.time.Timer.start();
|
||||
try module.update();
|
||||
const update_nanos = timer.read();
|
||||
|
||||
var errors = try module.getAllErrorsAlloc();
|
||||
defer errors.deinit(module.gpa);
|
||||
|
||||
@ -2,15 +2,19 @@ const std = @import("std");
|
||||
const build_options = @import("build_options");
|
||||
const introspect = @import("introspect.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const fatal = @import("main.zig").fatal;
|
||||
|
||||
pub fn cmdEnv(gpa: *Allocator, args: []const []const u8, stdout: anytype) !void {
|
||||
const zig_lib_dir = introspect.resolveZigLibDir(gpa) catch |err| {
|
||||
std.debug.print("unable to find zig installation directory: {}\n", .{@errorName(err)});
|
||||
std.process.exit(1);
|
||||
};
|
||||
defer gpa.free(zig_lib_dir);
|
||||
const self_exe_path = try std.fs.selfExePathAlloc(gpa);
|
||||
defer gpa.free(self_exe_path);
|
||||
|
||||
const zig_std_dir = try std.fs.path.join(gpa, &[_][]const u8{ zig_lib_dir, "std" });
|
||||
var zig_lib_directory = introspect.findZigLibDirFromSelfExe(gpa, self_exe_path) catch |err| {
|
||||
fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});
|
||||
};
|
||||
defer gpa.free(zig_lib_directory.path.?);
|
||||
defer zig_lib_directory.handle.close();
|
||||
|
||||
const zig_std_dir = try std.fs.path.join(gpa, &[_][]const u8{ zig_lib_directory.path.?, "std" });
|
||||
defer gpa.free(zig_std_dir);
|
||||
|
||||
const global_cache_dir = try introspect.resolveGlobalCacheDir(gpa);
|
||||
@ -22,8 +26,11 @@ pub fn cmdEnv(gpa: *Allocator, args: []const []const u8, stdout: anytype) !void
|
||||
var jws = std.json.WriteStream(@TypeOf(bos_stream), 6).init(bos_stream);
|
||||
try jws.beginObject();
|
||||
|
||||
try jws.objectField("zig_exe");
|
||||
try jws.emitString(self_exe_path);
|
||||
|
||||
try jws.objectField("lib_dir");
|
||||
try jws.emitString(zig_lib_dir);
|
||||
try jws.emitString(zig_lib_directory.path.?);
|
||||
|
||||
try jws.objectField("std_dir");
|
||||
try jws.emitString(zig_std_dir);
|
||||
|
||||
@ -17,16 +17,14 @@ pub fn cmdTargets(
|
||||
stdout: anytype,
|
||||
native_target: Target,
|
||||
) !void {
|
||||
const zig_lib_dir_path = introspect.resolveZigLibDir(allocator) catch |err| {
|
||||
var zig_lib_directory = introspect.findZigLibDir(allocator) catch |err| {
|
||||
fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});
|
||||
};
|
||||
defer allocator.free(zig_lib_dir_path);
|
||||
defer zig_lib_directory.handle.close();
|
||||
defer allocator.free(zig_lib_directory.path.?);
|
||||
|
||||
var zig_lib_dir = try fs.cwd().openDir(zig_lib_dir_path, .{});
|
||||
defer zig_lib_dir.close();
|
||||
|
||||
const glibc_abi = try glibc.loadMetaData(allocator, zig_lib_dir);
|
||||
errdefer glibc_abi.destroy(allocator);
|
||||
const glibc_abi = try glibc.loadMetaData(allocator, zig_lib_directory.handle);
|
||||
defer glibc_abi.destroy(allocator);
|
||||
|
||||
var bos = io.bufferedOutStream(stdout);
|
||||
const bos_stream = bos.outStream();
|
||||
|
||||
@ -117,10 +117,10 @@ pub fn cannotDynamicLink(target: std.Target) bool {
|
||||
};
|
||||
}
|
||||
|
||||
/// On Darwin, we always link libSystem which contains libc.
|
||||
/// Similarly on FreeBSD and NetBSD we always link system libc
|
||||
/// since this is the stable syscall interface.
|
||||
pub fn osRequiresLibC(target: std.Target) bool {
|
||||
// On Darwin, we always link libSystem which contains libc.
|
||||
// Similarly on FreeBSD and NetBSD we always link system libc
|
||||
// since this is the stable syscall interface.
|
||||
return switch (target.os.tag) {
|
||||
.freebsd, .netbsd, .dragonfly, .macosx, .ios, .watchos, .tvos => true,
|
||||
else => false,
|
||||
@ -131,6 +131,40 @@ pub fn requiresPIE(target: std.Target) bool {
|
||||
return target.isAndroid();
|
||||
}
|
||||
|
||||
/// This function returns whether non-pic code is completely invalid on the given target.
|
||||
pub fn requiresPIC(target: std.Target, linking_libc: bool) bool {
|
||||
return target.isAndroid() or
|
||||
target.os.tag == .windows or target.os.tag == .uefi or
|
||||
osRequiresLibC(target) or
|
||||
(linking_libc and target.isGnuLibC());
|
||||
}
|
||||
|
||||
/// This is not whether the target supports Position Independent Code, but whether the -fPIC
|
||||
/// C compiler argument is valid to Clang.
|
||||
pub fn supports_fpic(target: std.Target) bool {
|
||||
return target.os.tag != .windows;
|
||||
}
|
||||
|
||||
pub fn libc_needs_crti_crtn(target: std.Target) bool {
|
||||
return !(target.cpu.arch.isRISCV() or target.isAndroid());
|
||||
}
|
||||
|
||||
pub fn isSingleThreaded(target: std.Target) bool {
|
||||
return target.isWasm();
|
||||
}
|
||||
|
||||
/// Valgrind supports more, but Zig does not support them yet.
|
||||
pub fn hasValgrindSupport(target: std.Target) bool {
|
||||
switch (target.cpu.arch) {
|
||||
.x86_64 => {
|
||||
return target.os.tag == .linux or target.isDarwin() or target.os.tag == .solaris or
|
||||
(target.os.tag == .windows and target.abi != .msvc);
|
||||
},
|
||||
else => return false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn supportsStackProbing(target: std.Target) bool {
|
||||
return target.os.tag != .windows and target.os.tag != .uefi and
|
||||
(target.cpu.arch == .i386 or target.cpu.arch == .x86_64);
|
||||
}
|
||||
|
||||
@ -407,8 +407,9 @@ pub const TestContext = struct {
|
||||
const root_node = try progress.start("tests", self.cases.items.len);
|
||||
defer root_node.end();
|
||||
|
||||
const zig_lib_dir = try introspect.resolveZigLibDir(std.testing.allocator);
|
||||
defer std.testing.allocator.free(zig_lib_dir);
|
||||
var zig_lib_directory = try introspect.findZigLibDir(std.testing.allocator);
|
||||
defer zig_lib_directory.handle.close();
|
||||
defer std.testing.allocator.free(zig_lib_directory.path.?);
|
||||
|
||||
const random_seed = blk: {
|
||||
var random_seed: u64 = undefined;
|
||||
@ -427,7 +428,7 @@ pub const TestContext = struct {
|
||||
progress.initial_delay_ns = 0;
|
||||
progress.refresh_rate_ns = 0;
|
||||
|
||||
try self.runOneCase(std.testing.allocator, &prg_node, case, zig_lib_dir, &default_prng.random);
|
||||
try self.runOneCase(std.testing.allocator, &prg_node, case, zig_lib_directory, &default_prng.random);
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,7 +437,7 @@ pub const TestContext = struct {
|
||||
allocator: *Allocator,
|
||||
root_node: *std.Progress.Node,
|
||||
case: Case,
|
||||
zig_lib_dir: []const u8,
|
||||
zig_lib_directory: Module.Directory,
|
||||
rand: *std.rand.Random,
|
||||
) !void {
|
||||
const target_info = try std.zig.system.NativeTargetInfo.detect(allocator, case.target);
|
||||
@ -449,15 +450,32 @@ pub const TestContext = struct {
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
var cache_dir = try tmp.dir.makeOpenPath("zig-cache", .{});
|
||||
defer cache_dir.close();
|
||||
const bogus_path = "bogus"; // TODO this will need to be fixed before we can test LLVM extensions
|
||||
const zig_cache_directory: Module.Directory = .{
|
||||
.handle = cache_dir,
|
||||
.path = try std.fs.path.join(arena, &[_][]const u8{ bogus_path, "zig-cache" }),
|
||||
};
|
||||
|
||||
const tmp_src_path = if (case.extension == .Zig) "test_case.zig" else if (case.extension == .ZIR) "test_case.zir" else unreachable;
|
||||
const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
|
||||
defer root_pkg.destroy();
|
||||
defer root_pkg.destroy(allocator);
|
||||
|
||||
const ofmt: ?std.builtin.ObjectFormat = if (case.cbe) .c else null;
|
||||
const bin_name = try std.zig.binNameAlloc(arena, "test_case", target, case.output_mode, null, ofmt);
|
||||
|
||||
const emit_directory: Module.Directory = .{
|
||||
.path = bogus_path,
|
||||
.handle = tmp.dir,
|
||||
};
|
||||
const emit_bin: Module.EmitLoc = .{
|
||||
.directory = emit_directory,
|
||||
.basename = bin_name,
|
||||
};
|
||||
const module = try Module.create(allocator, .{
|
||||
.zig_lib_dir = zig_lib_dir,
|
||||
.zig_cache_directory = zig_cache_directory,
|
||||
.zig_lib_directory = zig_lib_directory,
|
||||
.rand = rand,
|
||||
.root_name = "test_case",
|
||||
.target = target,
|
||||
@ -467,8 +485,7 @@ pub const TestContext = struct {
|
||||
.output_mode = case.output_mode,
|
||||
// TODO: support testing optimizations
|
||||
.optimize_mode = .Debug,
|
||||
.bin_file_dir = tmp.dir,
|
||||
.bin_file_path = bin_name,
|
||||
.emit_bin = emit_bin,
|
||||
.root_pkg = root_pkg,
|
||||
.keep_source_files_loaded = true,
|
||||
.object_format = ofmt,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user