authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-16 14:14:11-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-17 06:47:20-04:00
logd16ce67106796011706e9f3653bb843c21c9d708
treef5c767fa0ebd503f78ba47b638366c04d380b9a2
parent3a8490f7e95faeff6be9b65c93cd55c8dd11ed1e

zig build system: ability to link against dynamic library step


4 files changed, 256 insertions(+), 20 deletions(-)

std/build.zig+234-20
......@@ -10,6 +10,7 @@ const StdIo = os.ChildProcess.StdIo;
1010const Term = os.ChildProcess.Term;
1111const BufSet = @import("buf_set.zig").BufSet;
1212const BufMap = @import("buf_map.zig").BufMap;
13const fmt = @import("fmt.zig");
1314
1415error ExtraArg;
1516error UncleanExit;
......@@ -32,7 +33,7 @@ pub const Builder = struct {
3233 env_map: BufMap,
3334 top_level_steps: List(&TopLevelStep),
3435 prefix: []const u8,
35 out_dir: []const u8,
36 out_dir: []u8,
3637
3738 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
3839 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
......@@ -84,7 +85,7 @@ pub const Builder = struct {
8485 .default_step = undefined,
8586 .env_map = %%os.getEnvMap(allocator),
8687 .prefix = undefined,
87 .out_dir = ".", // TODO organize
88 .out_dir = %%os.getCwd(allocator),
8889 };
8990 self.processNixOSEnvVars();
9091 self.default_step = self.step("default", "Build the project");
......@@ -92,6 +93,7 @@ pub const Builder = struct {
9293 }
9394
9495 pub fn deinit(self: &Builder) {
96 self.allocator.free(self.out_dir);
9597 self.lib_paths.deinit();
9698 self.include_paths.deinit();
9799 self.rpaths.deinit();
......@@ -410,6 +412,17 @@ const CrossTarget = struct {
410412const Target = enum {
411413 Native,
412414 Cross: CrossTarget,
415
416 pub fn oFileExt(self: &const Target) -> []const u8 {
417 const environ = switch (*self) {
418 Target.Native => @compileVar("environ"),
419 Target.Cross => |t| t.environ,
420 };
421 return switch (environ) {
422 Environ.msvc => ".obj",
423 else => ".o",
424 };
425 }
413426};
414427
415428const LinkerScript = enum {
......@@ -562,28 +575,23 @@ const Exe = struct {
562575 var child = os.ChildProcess.spawn(builder.zig_exe, zig_args.toSliceConst(), &builder.env_map,
563576 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
564577 %% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err));
565 const term = %%child.wait();
566 switch (term) {
567 Term.Clean => |code| {
568 if (code != 0) {
569 return error.UncleanExit;
570 }
571 },
572 else => {
573 return error.UncleanExit;
574 },
575 };
578 %return waitForCleanExit(&child);
576579 }
577580};
578581
579582const CLibrary = struct {
580583 step: Step,
581584 name: []const u8,
585 out_filename: []const u8,
582586 static: bool,
583587 version: Version,
584588 cflags: List([]const u8),
585589 source_files: List([]const u8),
590 object_files: List([]const u8),
586591 link_libs: BufSet,
592 target: Target,
593 builder: &Builder,
594 include_dirs: List([]const u8),
587595
588596 pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary {
589597 return init(builder, name, version, false);
......@@ -594,14 +602,30 @@ const CLibrary = struct {
594602 }
595603
596604 fn init(builder: &Builder, name: []const u8, version: &const Version, static: bool) -> CLibrary {
597 CLibrary {
605 var clib = CLibrary {
606 .builder = builder,
598607 .name = name,
599608 .version = *version,
600609 .static = static,
610 .target = Target.Native,
601611 .cflags = List([]const u8).init(builder.allocator),
602612 .source_files = List([]const u8).init(builder.allocator),
613 .object_files = List([]const u8).init(builder.allocator),
603614 .step = Step.init(name, builder.allocator, make),
604615 .link_libs = BufSet.init(builder.allocator),
616 .include_dirs = List([]const u8).init(builder.allocator),
617 .out_filename = undefined,
618 };
619 clib.computeOutFileName();
620 return clib;
621 }
622
623 fn computeOutFileName(self: &CLibrary) {
624 if (self.static) {
625 self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.a", self.name);
626 } else {
627 self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.so.{d}.{d}.{d}",
628 self.name, self.version.major, self.version.minor, self.version.patch);
605629 }
606630 }
607631
......@@ -618,6 +642,14 @@ const CLibrary = struct {
618642 %%self.source_files.append(file);
619643 }
620644
645 pub fn addObjectFile(self: &CLibrary, file: []const u8) {
646 %%self.object_files.append(file);
647 }
648
649 pub fn addIncludeDir(self: &CLibrary, path: []const u8) {
650 %%self.include_dirs.append(path);
651 }
652
621653 pub fn addCompileFlagsForRelease(self: &CLibrary, release: bool) {
622654 if (release) {
623655 %%self.cflags.append("-g");
......@@ -637,29 +669,115 @@ const CLibrary = struct {
637669 // TODO issue #320
638670 //const self = @fieldParentPtr(CLibrary, "step", step);
639671 const self = @ptrcast(&CLibrary, step);
672 const cc = os.getEnv("CC") ?? "cc";
673 const builder = self.builder;
674
675 var cc_args = List([]const u8).init(builder.allocator);
676 defer cc_args.deinit();
677
678 for (self.source_files.toSliceConst()) |source_file| {
679 %%cc_args.resize(0);
680
681 if (!self.static) {
682 %%cc_args.append("-fPIC");
683 }
684
685 %%cc_args.append("-c");
686 %%cc_args.append(source_file);
640687
641 const cc = os.getEnv("CC") ?? {
642 %%io.stderr.printf("Unable to find C compiler\n");
643 return error.NoCompilerFound;
688 // TODO don't dump the .o file in the same place as the source file
689 const o_file = %%fmt.allocPrint(builder.allocator, "{}{}", source_file, self.target.oFileExt());
690 defer builder.allocator.free(o_file);
691 %%cc_args.append("-o");
692 %%cc_args.append(o_file);
693
694 for (self.cflags.toSliceConst()) |cflag| {
695 %%cc_args.append(cflag);
696 }
697
698 for (self.include_dirs.toSliceConst()) |dir| {
699 %%cc_args.append("-I");
700 %%cc_args.append(dir);
701 }
702
703 if (builder.verbose) {
704 printInvocation(cc, cc_args);
705 }
706
707 var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
708 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
709 %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
710 %return waitForCleanExit(&child);
711
712 %%self.object_files.append(o_file);
713 }
714
715 if (self.static) {
716 debug.panic("TODO static library");
717 } else {
718 %%cc_args.resize(0);
719
720 %%cc_args.append("-fPIC");
721 %%cc_args.append("-shared");
722
723 const soname_arg = %%fmt.allocPrint(builder.allocator, "-Wl,-soname,lib{}.so.{d}",
724 self.name, self.version.major);
725 defer builder.allocator.free(soname_arg);
726 %%cc_args.append(soname_arg);
727
728 %%cc_args.append("-o");
729 %%cc_args.append(self.out_filename);
730
731 for (self.object_files.toSliceConst()) |object_file| {
732 %%cc_args.append(object_file);
733 }
734
735 if (builder.verbose) {
736 printInvocation(cc, cc_args);
737 }
738
739 var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
740 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
741 %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
742 %return waitForCleanExit(&child);
743 }
744 }
745
746 pub fn setTarget(self: &CLibrary, target_arch: Arch, target_os: Os, target_environ: Environ) {
747 self.target = Target.Cross {
748 CrossTarget {
749 .arch = target_arch,
750 .os = target_os,
751 .environ = target_environ,
752 }
644753 };
645 %%io.stderr.printf("TODO: build c library\n");
646754 }
647755};
648756
649757const CExecutable = struct {
650758 step: Step,
759 builder: &Builder,
651760 name: []const u8,
652761 cflags: List([]const u8),
653762 source_files: List([]const u8),
763 object_files: List([]const u8),
764 full_path_libs: List([]const u8),
654765 link_libs: BufSet,
766 target: Target,
767 include_dirs: List([]const u8),
655768
656769 pub fn init(builder: &Builder, name: []const u8) -> CExecutable {
657770 CExecutable {
771 .builder = builder,
658772 .name = name,
773 .target = Target.Native,
659774 .cflags = List([]const u8).init(builder.allocator),
660775 .source_files = List([]const u8).init(builder.allocator),
776 .object_files = List([]const u8).init(builder.allocator),
777 .full_path_libs = List([]const u8).init(builder.allocator),
661778 .step = Step.init(name, builder.allocator, make),
662779 .link_libs = BufSet.init(builder.allocator),
780 .include_dirs = List([]const u8).init(builder.allocator),
663781 }
664782 }
665783
......@@ -669,13 +787,21 @@ const CExecutable = struct {
669787
670788 pub fn linkCLibrary(self: &CExecutable, clib: &CLibrary) {
671789 self.step.dependOn(&clib.step);
672 %%self.link_libs.put(clib.name);
790 %%self.full_path_libs.append(clib.out_filename);
673791 }
674792
675793 pub fn addSourceFile(self: &CExecutable, file: []const u8) {
676794 %%self.source_files.append(file);
677795 }
678796
797 pub fn addObjectFile(self: &CExecutable, file: []const u8) {
798 %%self.object_files.append(file);
799 }
800
801 pub fn addIncludeDir(self: &CExecutable, path: []const u8) {
802 %%self.include_dirs.append(path);
803 }
804
679805 pub fn addCompileFlagsForRelease(self: &CExecutable, release: bool) {
680806 if (release) {
681807 %%self.cflags.append("-g");
......@@ -695,8 +821,82 @@ const CExecutable = struct {
695821 // TODO issue #320
696822 //const self = @fieldParentPtr(CExecutable, "step", step);
697823 const self = @ptrcast(&CExecutable, step);
824 const cc = os.getEnv("CC") ?? "cc";
825 const builder = self.builder;
826
827 var cc_args = List([]const u8).init(builder.allocator);
828 defer cc_args.deinit();
829
830 for (self.source_files.toSliceConst()) |source_file| {
831 %%cc_args.resize(0);
832
833 %%cc_args.append("-c");
834 %%cc_args.append(source_file);
835
836 // TODO don't dump the .o file in the same place as the source file
837 const o_file = %%fmt.allocPrint(builder.allocator, "{}{}", source_file, self.target.oFileExt());
838 defer builder.allocator.free(o_file);
839 %%cc_args.append("-o");
840 %%cc_args.append(o_file);
841
842 for (self.cflags.toSliceConst()) |cflag| {
843 %%cc_args.append(cflag);
844 }
845
846 for (self.include_dirs.toSliceConst()) |dir| {
847 %%cc_args.append("-I");
848 %%cc_args.append(dir);
849 }
850
851 if (builder.verbose) {
852 printInvocation(cc, cc_args);
853 }
854
855 var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
856 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
857 %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
858 %return waitForCleanExit(&child);
859
860 %%self.object_files.append(o_file);
861 }
862
863 %%cc_args.resize(0);
698864
699 %%io.stderr.printf("TODO: build c exe\n");
865 for (self.object_files.toSliceConst()) |object_file| {
866 %%cc_args.append(object_file);
867 }
868
869 %%cc_args.append("-o");
870 %%cc_args.append(self.name);
871
872 const rpath_arg = %%fmt.allocPrint(builder.allocator, "-Wl,-rpath,{}", builder.out_dir);
873 defer builder.allocator.free(rpath_arg);
874 %%cc_args.append(rpath_arg);
875
876 %%cc_args.append("-rdynamic");
877
878 for (self.full_path_libs.toSliceConst()) |full_path_lib| {
879 %%cc_args.append(full_path_lib);
880 }
881
882 if (builder.verbose) {
883 printInvocation(cc, cc_args);
884 }
885
886 var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map,
887 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
888 %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err));
889 %return waitForCleanExit(&child);
890 }
891
892 pub fn setTarget(self: &CExecutable, target_arch: Arch, target_os: Os, target_environ: Environ) {
893 self.target = Target.Cross {
894 CrossTarget {
895 .arch = target_arch,
896 .os = target_os,
897 .environ = target_environ,
898 }
899 };
700900 }
701901};
702902
......@@ -770,3 +970,17 @@ fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) {
770970 }
771971 %%io.stderr.printf("\n");
772972}
973
974fn waitForCleanExit(child: &os.ChildProcess) -> %void {
975 const term = %%child.wait();
976 switch (term) {
977 Term.Clean => |code| {
978 if (code != 0) {
979 return error.UncleanExit;
980 }
981 },
982 else => {
983 return error.UncleanExit;
984 },
985 };
986}
std/os/child_process.zig+1
......@@ -41,6 +41,7 @@ pub const ChildProcess = struct {
4141 }
4242 }
4343
44 /// Blocks until child process terminates and then cleans up all resources.
4445 pub fn wait(self: &ChildProcess) -> %Term {
4546 defer {
4647 os.posixClose(self.err_pipe[0]);
std/os/index.zig+17
......@@ -364,3 +364,20 @@ pub const args = struct {
364364 return s[0...cstr.len(s)];
365365 }
366366};
367
368/// Caller must free the returned memory.
369pub fn getCwd(allocator: &Allocator) -> %[]u8 {
370 var buf = %return allocator.alloc(u8, 1024);
371 %defer allocator.free(buf);
372 while (true) {
373 const err = posix.getErrno(posix.getcwd(buf.ptr, buf.len));
374 if (err == errno.ERANGE) {
375 buf = %return allocator.realloc(u8, buf, buf.len * 2);
376 continue;
377 } else if (err > 0) {
378 return error.Unexpected;
379 }
380
381 return buf;
382 }
383}
std/os/linux.zig+4
......@@ -269,6 +269,10 @@ pub fn fork() -> usize {
269269 arch.syscall0(arch.SYS_fork)
270270}
271271
272pub fn getcwd(buf: &u8, size: usize) -> usize {
273 arch.syscall2(arch.SYS_getcwd, usize(buf), size)
274}
275
272276pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize)
273277 -> usize
274278{