zig build system: ability to link against dynamic library step
This commit is contained in:
parent
3a8490f7e9
commit
d16ce67106
254
std/build.zig
254
std/build.zig
@ -10,6 +10,7 @@ const StdIo = os.ChildProcess.StdIo;
|
||||
const Term = os.ChildProcess.Term;
|
||||
const BufSet = @import("buf_set.zig").BufSet;
|
||||
const BufMap = @import("buf_map.zig").BufMap;
|
||||
const fmt = @import("fmt.zig");
|
||||
|
||||
error ExtraArg;
|
||||
error UncleanExit;
|
||||
@ -32,7 +33,7 @@ pub const Builder = struct {
|
||||
env_map: BufMap,
|
||||
top_level_steps: List(&TopLevelStep),
|
||||
prefix: []const u8,
|
||||
out_dir: []const u8,
|
||||
out_dir: []u8,
|
||||
|
||||
const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
@ -84,7 +85,7 @@ pub const Builder = struct {
|
||||
.default_step = undefined,
|
||||
.env_map = %%os.getEnvMap(allocator),
|
||||
.prefix = undefined,
|
||||
.out_dir = ".", // TODO organize
|
||||
.out_dir = %%os.getCwd(allocator),
|
||||
};
|
||||
self.processNixOSEnvVars();
|
||||
self.default_step = self.step("default", "Build the project");
|
||||
@ -92,6 +93,7 @@ pub const Builder = struct {
|
||||
}
|
||||
|
||||
pub fn deinit(self: &Builder) {
|
||||
self.allocator.free(self.out_dir);
|
||||
self.lib_paths.deinit();
|
||||
self.include_paths.deinit();
|
||||
self.rpaths.deinit();
|
||||
@ -410,6 +412,17 @@ const CrossTarget = struct {
|
||||
const Target = enum {
|
||||
Native,
|
||||
Cross: CrossTarget,
|
||||
|
||||
pub fn oFileExt(self: &const Target) -> []const u8 {
|
||||
const environ = switch (*self) {
|
||||
Target.Native => @compileVar("environ"),
|
||||
Target.Cross => |t| t.environ,
|
||||
};
|
||||
return switch (environ) {
|
||||
Environ.msvc => ".obj",
|
||||
else => ".o",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const LinkerScript = enum {
|
||||
@ -562,28 +575,23 @@ const Exe = struct {
|
||||
var child = os.ChildProcess.spawn(builder.zig_exe, zig_args.toSliceConst(), &builder.env_map,
|
||||
StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
|
||||
%% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err));
|
||||
const term = %%child.wait();
|
||||
switch (term) {
|
||||
Term.Clean => |code| {
|
||||
if (code != 0) {
|
||||
return error.UncleanExit;
|
||||
}
|
||||
},
|
||||
else => {
|
||||
return error.UncleanExit;
|
||||
},
|
||||
};
|
||||
%return waitForCleanExit(&child);
|
||||
}
|
||||
};
|
||||
|
||||
const CLibrary = struct {
|
||||
step: Step,
|
||||
name: []const u8,
|
||||
out_filename: []const u8,
|
||||
static: bool,
|
||||
version: Version,
|
||||
cflags: List([]const u8),
|
||||
source_files: List([]const u8),
|
||||
object_files: List([]const u8),
|
||||
link_libs: BufSet,
|
||||
target: Target,
|
||||
builder: &Builder,
|
||||
include_dirs: List([]const u8),
|
||||
|
||||
pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary {
|
||||
return init(builder, name, version, false);
|
||||
@ -594,14 +602,30 @@ const CLibrary = struct {
|
||||
}
|
||||
|
||||
fn init(builder: &Builder, name: []const u8, version: &const Version, static: bool) -> CLibrary {
|
||||
CLibrary {
|
||||
var clib = CLibrary {
|
||||
.builder = builder,
|
||||
.name = name,
|
||||
.version = *version,
|
||||
.static = static,
|
||||
.target = Target.Native,
|
||||
.cflags = List([]const u8).init(builder.allocator),
|
||||
.source_files = List([]const u8).init(builder.allocator),
|
||||
.object_files = List([]const u8).init(builder.allocator),
|
||||
.step = Step.init(name, builder.allocator, make),
|
||||
.link_libs = BufSet.init(builder.allocator),
|
||||
.include_dirs = List([]const u8).init(builder.allocator),
|
||||
.out_filename = undefined,
|
||||
};
|
||||
clib.computeOutFileName();
|
||||
return clib;
|
||||
}
|
||||
|
||||
fn computeOutFileName(self: &CLibrary) {
|
||||
if (self.static) {
|
||||
self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.a", self.name);
|
||||
} else {
|
||||
self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.so.{d}.{d}.{d}",
|
||||
self.name, self.version.major, self.version.minor, self.version.patch);
|
||||
}
|
||||
}
|
||||
|
||||
@ -618,6 +642,14 @@ const CLibrary = struct {
|
||||
%%self.source_files.append(file);
|
||||
}
|
||||
|
||||
pub fn addObjectFile(self: &CLibrary, file: []const u8) {
|
||||
%%self.object_files.append(file);
|
||||
}
|
||||
|
||||
pub fn addIncludeDir(self: &CLibrary, path: []const u8) {
|
||||
%%self.include_dirs.append(path);
|
||||
}
|
||||
|
||||
pub fn addCompileFlagsForRelease(self: &CLibrary, release: bool) {
|
||||
if (release) {
|
||||
%%self.cflags.append("-g");
|
||||
@ -637,29 +669,115 @@ const CLibrary = struct {
|
||||
// TODO issue #320
|
||||
//const self = @fieldParentPtr(CLibrary, "step", step);
|
||||
const self = @ptrcast(&CLibrary, step);
|
||||
const cc = os.getEnv("CC") ?? "cc";
|
||||
const builder = self.builder;
|
||||
|
||||
const cc = os.getEnv("CC") ?? {
|
||||
%%io.stderr.printf("Unable to find C compiler\n");
|
||||
return error.NoCompilerFound;
|
||||
var cc_args = List([]const u8).init(builder.allocator);
|
||||
defer cc_args.deinit();
|
||||
|
||||
for (self.source_files.toSliceConst()) |source_file| {
|
||||
%%cc_args.resize(0);
|
||||
|
||||
if (!self.static) {
|
||||
%%cc_args.append("-fPIC");
|
||||
}
|
||||
|
||||
%%cc_args.append("-c");
|
||||
%%cc_args.append(source_file);
|
||||
|
||||
// TODO don't dump the .o file in the same place as the source file
|
||||
const o_file = %%fmt.allocPrint(builder.allocator, "{}{}", source_file, self.target.oFileExt());
|
||||
defer builder.allocator.free(o_file);
|
||||
%%cc_args.append("-o");
|
||||
%%cc_args.append(o_file);
|
||||
|
||||
for (self.cflags.toSliceConst()) |cflag| {
|
||||
%%cc_args.append(cflag);
|
||||
}
|
||||
|
||||
for (self.include_dirs.toSliceConst()) |dir| {
|
||||
%%cc_args.append("-I");
|
||||
%%cc_args.append(dir);
|
||||
}
|
||||
|
||||
if (builder.verbose) {
|
||||
printInvocation(cc, cc_args);
|
||||
}
|
||||
|
||||
var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
|
||||
StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
|
||||
%% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
|
||||
%return waitForCleanExit(&child);
|
||||
|
||||
%%self.object_files.append(o_file);
|
||||
}
|
||||
|
||||
if (self.static) {
|
||||
debug.panic("TODO static library");
|
||||
} else {
|
||||
%%cc_args.resize(0);
|
||||
|
||||
%%cc_args.append("-fPIC");
|
||||
%%cc_args.append("-shared");
|
||||
|
||||
const soname_arg = %%fmt.allocPrint(builder.allocator, "-Wl,-soname,lib{}.so.{d}",
|
||||
self.name, self.version.major);
|
||||
defer builder.allocator.free(soname_arg);
|
||||
%%cc_args.append(soname_arg);
|
||||
|
||||
%%cc_args.append("-o");
|
||||
%%cc_args.append(self.out_filename);
|
||||
|
||||
for (self.object_files.toSliceConst()) |object_file| {
|
||||
%%cc_args.append(object_file);
|
||||
}
|
||||
|
||||
if (builder.verbose) {
|
||||
printInvocation(cc, cc_args);
|
||||
}
|
||||
|
||||
var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
|
||||
StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
|
||||
%% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
|
||||
%return waitForCleanExit(&child);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setTarget(self: &CLibrary, target_arch: Arch, target_os: Os, target_environ: Environ) {
|
||||
self.target = Target.Cross {
|
||||
CrossTarget {
|
||||
.arch = target_arch,
|
||||
.os = target_os,
|
||||
.environ = target_environ,
|
||||
}
|
||||
};
|
||||
%%io.stderr.printf("TODO: build c library\n");
|
||||
}
|
||||
};
|
||||
|
||||
const CExecutable = struct {
|
||||
step: Step,
|
||||
builder: &Builder,
|
||||
name: []const u8,
|
||||
cflags: List([]const u8),
|
||||
source_files: List([]const u8),
|
||||
object_files: List([]const u8),
|
||||
full_path_libs: List([]const u8),
|
||||
link_libs: BufSet,
|
||||
target: Target,
|
||||
include_dirs: List([]const u8),
|
||||
|
||||
pub fn init(builder: &Builder, name: []const u8) -> CExecutable {
|
||||
CExecutable {
|
||||
.builder = builder,
|
||||
.name = name,
|
||||
.target = Target.Native,
|
||||
.cflags = List([]const u8).init(builder.allocator),
|
||||
.source_files = List([]const u8).init(builder.allocator),
|
||||
.object_files = List([]const u8).init(builder.allocator),
|
||||
.full_path_libs = List([]const u8).init(builder.allocator),
|
||||
.step = Step.init(name, builder.allocator, make),
|
||||
.link_libs = BufSet.init(builder.allocator),
|
||||
.include_dirs = List([]const u8).init(builder.allocator),
|
||||
}
|
||||
}
|
||||
|
||||
@ -669,13 +787,21 @@ const CExecutable = struct {
|
||||
|
||||
pub fn linkCLibrary(self: &CExecutable, clib: &CLibrary) {
|
||||
self.step.dependOn(&clib.step);
|
||||
%%self.link_libs.put(clib.name);
|
||||
%%self.full_path_libs.append(clib.out_filename);
|
||||
}
|
||||
|
||||
pub fn addSourceFile(self: &CExecutable, file: []const u8) {
|
||||
%%self.source_files.append(file);
|
||||
}
|
||||
|
||||
pub fn addObjectFile(self: &CExecutable, file: []const u8) {
|
||||
%%self.object_files.append(file);
|
||||
}
|
||||
|
||||
pub fn addIncludeDir(self: &CExecutable, path: []const u8) {
|
||||
%%self.include_dirs.append(path);
|
||||
}
|
||||
|
||||
pub fn addCompileFlagsForRelease(self: &CExecutable, release: bool) {
|
||||
if (release) {
|
||||
%%self.cflags.append("-g");
|
||||
@ -695,8 +821,82 @@ const CExecutable = struct {
|
||||
// TODO issue #320
|
||||
//const self = @fieldParentPtr(CExecutable, "step", step);
|
||||
const self = @ptrcast(&CExecutable, step);
|
||||
const cc = os.getEnv("CC") ?? "cc";
|
||||
const builder = self.builder;
|
||||
|
||||
%%io.stderr.printf("TODO: build c exe\n");
|
||||
var cc_args = List([]const u8).init(builder.allocator);
|
||||
defer cc_args.deinit();
|
||||
|
||||
for (self.source_files.toSliceConst()) |source_file| {
|
||||
%%cc_args.resize(0);
|
||||
|
||||
%%cc_args.append("-c");
|
||||
%%cc_args.append(source_file);
|
||||
|
||||
// TODO don't dump the .o file in the same place as the source file
|
||||
const o_file = %%fmt.allocPrint(builder.allocator, "{}{}", source_file, self.target.oFileExt());
|
||||
defer builder.allocator.free(o_file);
|
||||
%%cc_args.append("-o");
|
||||
%%cc_args.append(o_file);
|
||||
|
||||
for (self.cflags.toSliceConst()) |cflag| {
|
||||
%%cc_args.append(cflag);
|
||||
}
|
||||
|
||||
for (self.include_dirs.toSliceConst()) |dir| {
|
||||
%%cc_args.append("-I");
|
||||
%%cc_args.append(dir);
|
||||
}
|
||||
|
||||
if (builder.verbose) {
|
||||
printInvocation(cc, cc_args);
|
||||
}
|
||||
|
||||
var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
|
||||
StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
|
||||
%% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
|
||||
%return waitForCleanExit(&child);
|
||||
|
||||
%%self.object_files.append(o_file);
|
||||
}
|
||||
|
||||
%%cc_args.resize(0);
|
||||
|
||||
for (self.object_files.toSliceConst()) |object_file| {
|
||||
%%cc_args.append(object_file);
|
||||
}
|
||||
|
||||
%%cc_args.append("-o");
|
||||
%%cc_args.append(self.name);
|
||||
|
||||
const rpath_arg = %%fmt.allocPrint(builder.allocator, "-Wl,-rpath,{}", builder.out_dir);
|
||||
defer builder.allocator.free(rpath_arg);
|
||||
%%cc_args.append(rpath_arg);
|
||||
|
||||
%%cc_args.append("-rdynamic");
|
||||
|
||||
for (self.full_path_libs.toSliceConst()) |full_path_lib| {
|
||||
%%cc_args.append(full_path_lib);
|
||||
}
|
||||
|
||||
if (builder.verbose) {
|
||||
printInvocation(cc, cc_args);
|
||||
}
|
||||
|
||||
var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
|
||||
StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
|
||||
%% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
|
||||
%return waitForCleanExit(&child);
|
||||
}
|
||||
|
||||
pub fn setTarget(self: &CExecutable, target_arch: Arch, target_os: Os, target_environ: Environ) {
|
||||
self.target = Target.Cross {
|
||||
CrossTarget {
|
||||
.arch = target_arch,
|
||||
.os = target_os,
|
||||
.environ = target_environ,
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@ -770,3 +970,17 @@ fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) {
|
||||
}
|
||||
%%io.stderr.printf("\n");
|
||||
}
|
||||
|
||||
fn waitForCleanExit(child: &os.ChildProcess) -> %void {
|
||||
const term = %%child.wait();
|
||||
switch (term) {
|
||||
Term.Clean => |code| {
|
||||
if (code != 0) {
|
||||
return error.UncleanExit;
|
||||
}
|
||||
},
|
||||
else => {
|
||||
return error.UncleanExit;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ pub const ChildProcess = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// Blocks until child process terminates and then cleans up all resources.
|
||||
pub fn wait(self: &ChildProcess) -> %Term {
|
||||
defer {
|
||||
os.posixClose(self.err_pipe[0]);
|
||||
|
@ -364,3 +364,20 @@ pub const args = struct {
|
||||
return s[0...cstr.len(s)];
|
||||
}
|
||||
};
|
||||
|
||||
/// Caller must free the returned memory.
|
||||
pub fn getCwd(allocator: &Allocator) -> %[]u8 {
|
||||
var buf = %return allocator.alloc(u8, 1024);
|
||||
%defer allocator.free(buf);
|
||||
while (true) {
|
||||
const err = posix.getErrno(posix.getcwd(buf.ptr, buf.len));
|
||||
if (err == errno.ERANGE) {
|
||||
buf = %return allocator.realloc(u8, buf, buf.len * 2);
|
||||
continue;
|
||||
} else if (err > 0) {
|
||||
return error.Unexpected;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
@ -269,6 +269,10 @@ pub fn fork() -> usize {
|
||||
arch.syscall0(arch.SYS_fork)
|
||||
}
|
||||
|
||||
pub fn getcwd(buf: &u8, size: usize) -> usize {
|
||||
arch.syscall2(arch.SYS_getcwd, usize(buf), size)
|
||||
}
|
||||
|
||||
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize)
|
||||
-> usize
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user