Skip to content

Commit be6f766

Browse files
authored
Merge pull request #18055 from ziglang/zig-init
2 parents 27b34a5 + 9f363cd commit be6f766

File tree

8 files changed

+164
-140
lines changed

8 files changed

+164
-140
lines changed

lib/init-lib/build.zig

Lines changed: 0 additions & 47 deletions
This file was deleted.

lib/init-exe/build.zig renamed to lib/init/build.zig

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,22 @@ pub fn build(b: *std.Build) void {
1515
// set a preferred release mode, allowing the user to decide how to optimize.
1616
const optimize = b.standardOptimizeOption(.{});
1717

18-
const exe = b.addExecutable(.{
18+
const lib = b.addStaticLibrary(.{
1919
.name = "$",
2020
// In this case the main source file is merely a path, however, in more
2121
// complicated build scripts, this could be a generated file.
22+
.root_source_file = .{ .path = "src/root.zig" },
23+
.target = target,
24+
.optimize = optimize,
25+
});
26+
27+
// This declares intent for the library to be installed into the standard
28+
// location when the user invokes the "install" step (the default step when
29+
// running `zig build`).
30+
b.installArtifact(lib);
31+
32+
const exe = b.addExecutable(.{
33+
.name = "$",
2234
.root_source_file = .{ .path = "src/main.zig" },
2335
.target = target,
2436
.optimize = optimize,
@@ -54,17 +66,26 @@ pub fn build(b: *std.Build) void {
5466

5567
// Creates a step for unit testing. This only builds the test executable
5668
// but does not run it.
57-
const unit_tests = b.addTest(.{
69+
const lib_unit_tests = b.addTest(.{
70+
.root_source_file = .{ .path = "src/root.zig" },
71+
.target = target,
72+
.optimize = optimize,
73+
});
74+
75+
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
76+
77+
const exe_unit_tests = b.addTest(.{
5878
.root_source_file = .{ .path = "src/main.zig" },
5979
.target = target,
6080
.optimize = optimize,
6181
});
6282

63-
const run_unit_tests = b.addRunArtifact(unit_tests);
83+
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
6484

6585
// Similar to creating the run step earlier, this exposes a `test` step to
6686
// the `zig build --help` menu, providing a way for the user to request
6787
// running the unit tests.
6888
const test_step = b.step("test", "Run unit tests");
69-
test_step.dependOn(&run_unit_tests.step);
89+
test_step.dependOn(&run_lib_unit_tests.step);
90+
test_step.dependOn(&run_exe_unit_tests.step);
7091
}

lib/init/build.zig.zon

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
.{
2+
.name = "$",
3+
// This is a [Semantic Version](https://semver.org/).
4+
// In a future version of Zig it will be used for package deduplication.
5+
.version = "0.0.0",
6+
7+
// This field is optional.
8+
// This is currently advisory only; Zig does not yet do anything
9+
// with this value.
10+
//.minimum_zig_version = "0.11.0",
11+
12+
// This field is optional.
13+
// Each dependency must either provide a `url` and `hash`, or a `path`.
14+
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
15+
// Once all dependencies are fetched, `zig build` no longer requires
16+
// Internet connectivity.
17+
.dependencies = .{
18+
// A future version of Zig will provide a `zig add <url>` subcommand
19+
// for easily adding dependencies.
20+
//.example = .{
21+
// // When updating this field to a new URL, be sure to delete the corresponding
22+
// // `hash`, otherwise you are communicating that you expect to find the old hash at
23+
// // the new URL.
24+
// .url = "https://example.com/foo.tar.gz",
25+
//
26+
// // This is computed from the file contents of the directory of files that is
27+
// // obtained after fetching `url` and applying the inclusion rules given by
28+
// // `paths`.
29+
// //
30+
// // This field is the source of truth; packages do not come from an `url`; they
31+
// // come from a `hash`. `url` is just one of many possible mirrors for how to
32+
// // obtain a package matching this `hash`.
33+
// //
34+
// // Uses the [multihash](https://multiformats.io/multihash/) format.
35+
// .hash = "...",
36+
//
37+
// // When this is provided, the package is found in a directory relative to the
38+
// // build root. In this case the package's hash is irrelevant and therefore not
39+
// // computed.
40+
// .path = "foo",
41+
//},
42+
},
43+
44+
// Specifies the set of files and directories that are included in this package.
45+
// Only files and directories listed here are included in the `hash` that
46+
// is computed for this package.
47+
// Paths are relative to the build root. Use the empty string (`""`) to refer to
48+
// the build root itself.
49+
// A directory listed here means that all files within, recursively, are included.
50+
.paths = .{
51+
// This makes *all* files, recursively, included in this package. It is generally
52+
// better to explicitly list the files and directories instead, to insure that
53+
// fetching from tarballs, file system paths, and version control all result
54+
// in the same contents hash.
55+
"",
56+
// For example...
57+
//"build.zig",
58+
//"build.zig.zon",
59+
//"src",
60+
},
61+
}
File renamed without changes.
File renamed without changes.

lib/std/fs.zig

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2564,12 +2564,28 @@ pub const Dir = struct {
25642564
};
25652565
}
25662566

2567-
/// Writes content to the file system, creating a new file if it does not exist, truncating
2568-
/// if it already exists.
2569-
pub fn writeFile(self: Dir, sub_path: []const u8, data: []const u8) !void {
2570-
var file = try self.createFile(sub_path, .{});
2567+
pub const WriteFileError = File.WriteError || File.OpenError;
2568+
2569+
/// Deprecated: use `writeFile2`.
2570+
pub fn writeFile(self: Dir, sub_path: []const u8, data: []const u8) WriteFileError!void {
2571+
return writeFile2(self, .{
2572+
.sub_path = sub_path,
2573+
.data = data,
2574+
.flags = .{},
2575+
});
2576+
}
2577+
2578+
pub const WriteFileOptions = struct {
2579+
sub_path: []const u8,
2580+
data: []const u8,
2581+
flags: File.CreateFlags = .{},
2582+
};
2583+
2584+
/// Writes content to the file system, using the file creation flags provided.
2585+
pub fn writeFile2(self: Dir, options: WriteFileOptions) WriteFileError!void {
2586+
var file = try self.createFile(options.sub_path, options.flags);
25712587
defer file.close();
2572-
try file.writeAll(data);
2588+
try file.writeAll(options.data);
25732589
}
25742590

25752591
pub const AccessError = os.AccessError;

src/main.zig

Lines changed: 49 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,7 @@ const normal_usage =
8686
\\
8787
\\ build Build project from build.zig
8888
\\ fetch Copy a package into global cache and print its hash
89-
\\ init-exe Initialize a `zig build` application in the cwd
90-
\\ init-lib Initialize a `zig build` library in the cwd
89+
\\ init Initialize a Zig package in the current directory
9190
\\
9291
\\ ast-check Look for simple compile errors in any set of files
9392
\\ build-exe Create executable from source or object files
@@ -320,10 +319,8 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
320319
return cmdFetch(gpa, arena, cmd_args);
321320
} else if (mem.eql(u8, cmd, "libc")) {
322321
return cmdLibC(gpa, cmd_args);
323-
} else if (mem.eql(u8, cmd, "init-exe")) {
324-
return cmdInit(gpa, arena, cmd_args, .Exe);
325-
} else if (mem.eql(u8, cmd, "init-lib")) {
326-
return cmdInit(gpa, arena, cmd_args, .Lib);
322+
} else if (mem.eql(u8, cmd, "init")) {
323+
return cmdInit(gpa, arena, cmd_args);
327324
} else if (mem.eql(u8, cmd, "targets")) {
328325
const info = try detectNativeTargetInfo(.{});
329326
const stdout = io.getStdOut().writer();
@@ -4835,8 +4832,7 @@ pub fn cmdLibC(gpa: Allocator, args: []const []const u8) !void {
48354832
}
48364833

48374834
pub const usage_init =
4838-
\\Usage: zig init-exe
4839-
\\ zig init-lib
4835+
\\Usage: zig init
48404836
\\
48414837
\\ Initializes a `zig build` project in the current working
48424838
\\ directory.
@@ -4847,12 +4843,7 @@ pub const usage_init =
48474843
\\
48484844
;
48494845

4850-
pub fn cmdInit(
4851-
gpa: Allocator,
4852-
arena: Allocator,
4853-
args: []const []const u8,
4854-
output_mode: std.builtin.OutputMode,
4855-
) !void {
4846+
pub fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
48564847
_ = gpa;
48574848
{
48584849
var i: usize = 0;
@@ -4877,61 +4868,65 @@ pub fn cmdInit(
48774868
defer zig_lib_directory.handle.close();
48784869

48794870
const s = fs.path.sep_str;
4880-
const template_sub_path = switch (output_mode) {
4881-
.Obj => unreachable,
4882-
.Lib => "init-lib",
4883-
.Exe => "init-exe",
4884-
};
4871+
const template_sub_path = "init";
48854872
var template_dir = zig_lib_directory.handle.openDir(template_sub_path, .{}) catch |err| {
48864873
const path = zig_lib_directory.path orelse ".";
4887-
fatal("unable to open zig project template directory '{s}{s}{s}': {s}", .{ path, s, template_sub_path, @errorName(err) });
4874+
fatal("unable to open zig project template directory '{s}{s}{s}': {s}", .{
4875+
path, s, template_sub_path, @errorName(err),
4876+
});
48884877
};
48894878
defer template_dir.close();
48904879

48914880
const cwd_path = try process.getCwdAlloc(arena);
48924881
const cwd_basename = fs.path.basename(cwd_path);
48934882

48944883
const max_bytes = 10 * 1024 * 1024;
4895-
const build_zig_contents = template_dir.readFileAlloc(arena, "build.zig", max_bytes) catch |err| {
4896-
fatal("unable to read template file 'build.zig': {s}", .{@errorName(err)});
4884+
const template_paths = [_][]const u8{
4885+
"build.zig",
4886+
"build.zig.zon",
4887+
"src" ++ s ++ "main.zig",
4888+
"src" ++ s ++ "root.zig",
48974889
};
4898-
var modified_build_zig_contents = try std.ArrayList(u8).initCapacity(arena, build_zig_contents.len);
4899-
for (build_zig_contents) |c| {
4900-
if (c == '$') {
4901-
try modified_build_zig_contents.appendSlice(cwd_basename);
4902-
} else {
4903-
try modified_build_zig_contents.append(c);
4890+
var ok_count: usize = 0;
4891+
4892+
for (template_paths) |template_path| {
4893+
if (fs.path.dirname(template_path)) |dirname| {
4894+
fs.cwd().makePath(dirname) catch |err| {
4895+
fatal("unable to make path '{s}': {s}", .{ dirname, @errorName(err) });
4896+
};
49044897
}
4905-
}
4906-
const main_zig_contents = template_dir.readFileAlloc(arena, "src" ++ s ++ "main.zig", max_bytes) catch |err| {
4907-
fatal("unable to read template file 'main.zig': {s}", .{@errorName(err)});
4908-
};
4909-
if (fs.cwd().access("build.zig", .{})) |_| {
4910-
fatal("existing build.zig file would be overwritten", .{});
4911-
} else |err| switch (err) {
4912-
error.FileNotFound => {},
4913-
else => fatal("unable to test existence of build.zig: {s}\n", .{@errorName(err)}),
4914-
}
4915-
if (fs.cwd().access("src" ++ s ++ "main.zig", .{})) |_| {
4916-
fatal("existing src" ++ s ++ "main.zig file would be overwritten", .{});
4917-
} else |err| switch (err) {
4918-
error.FileNotFound => {},
4919-
else => fatal("unable to test existence of src" ++ s ++ "main.zig: {s}\n", .{@errorName(err)}),
4920-
}
4921-
var src_dir = try fs.cwd().makeOpenPath("src", .{});
4922-
defer src_dir.close();
49234898

4924-
try src_dir.writeFile("main.zig", main_zig_contents);
4925-
try fs.cwd().writeFile("build.zig", modified_build_zig_contents.items);
4899+
const contents = template_dir.readFileAlloc(arena, template_path, max_bytes) catch |err| {
4900+
fatal("unable to read template file '{s}': {s}", .{ template_path, @errorName(err) });
4901+
};
4902+
var modified_contents = try std.ArrayList(u8).initCapacity(arena, contents.len);
4903+
for (contents) |c| {
4904+
if (c == '$') {
4905+
try modified_contents.appendSlice(cwd_basename);
4906+
} else {
4907+
try modified_contents.append(c);
4908+
}
4909+
}
49264910

4927-
std.log.info("Created build.zig", .{});
4928-
std.log.info("Created src" ++ s ++ "main.zig", .{});
4911+
if (fs.cwd().writeFile2(.{
4912+
.sub_path = template_path,
4913+
.data = modified_contents.items,
4914+
.flags = .{ .exclusive = true },
4915+
})) |_| {
4916+
std.log.info("created {s}", .{template_path});
4917+
ok_count += 1;
4918+
} else |err| switch (err) {
4919+
error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{
4920+
template_path,
4921+
}),
4922+
else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }),
4923+
}
4924+
}
49294925

4930-
switch (output_mode) {
4931-
.Lib => std.log.info("Next, try `zig build --help` or `zig build test`", .{}),
4932-
.Exe => std.log.info("Next, try `zig build --help` or `zig build run`", .{}),
4933-
.Obj => unreachable,
4926+
if (ok_count == template_paths.len) {
4927+
std.log.info("see `zig build --help` for a menu of options", .{});
49344928
}
4929+
return cleanExit();
49354930
}
49364931

49374932
pub const usage_build =

test/tests.zig

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -776,39 +776,17 @@ pub fn addCliTests(b: *std.Build) *Step {
776776
const s = std.fs.path.sep_str;
777777

778778
{
779-
780-
// Test `zig init-lib`.
781-
const tmp_path = b.makeTempPath();
782-
const init_lib = b.addSystemCommand(&.{ b.zig_exe, "init-lib" });
783-
init_lib.setCwd(.{ .cwd_relative = tmp_path });
784-
init_lib.setName("zig init-lib");
785-
init_lib.expectStdOutEqual("");
786-
init_lib.expectStdErrEqual("info: Created build.zig\n" ++
787-
"info: Created src" ++ s ++ "main.zig\n" ++
788-
"info: Next, try `zig build --help` or `zig build test`\n");
789-
790-
const run_test = b.addSystemCommand(&.{ b.zig_exe, "build", "test" });
791-
run_test.setCwd(.{ .cwd_relative = tmp_path });
792-
run_test.setName("zig build test");
793-
run_test.expectStdOutEqual("");
794-
run_test.step.dependOn(&init_lib.step);
795-
796-
const cleanup = b.addRemoveDirTree(tmp_path);
797-
cleanup.step.dependOn(&run_test.step);
798-
799-
step.dependOn(&cleanup.step);
800-
}
801-
802-
{
803-
// Test `zig init-exe`.
779+
// Test `zig init`.
804780
const tmp_path = b.makeTempPath();
805-
const init_exe = b.addSystemCommand(&.{ b.zig_exe, "init-exe" });
781+
const init_exe = b.addSystemCommand(&.{ b.zig_exe, "init" });
806782
init_exe.setCwd(.{ .cwd_relative = tmp_path });
807-
init_exe.setName("zig init-exe");
783+
init_exe.setName("zig init");
808784
init_exe.expectStdOutEqual("");
809-
init_exe.expectStdErrEqual("info: Created build.zig\n" ++
810-
"info: Created src" ++ s ++ "main.zig\n" ++
811-
"info: Next, try `zig build --help` or `zig build run`\n");
785+
init_exe.expectStdErrEqual("info: created build.zig\n" ++
786+
"info: created build.zig.zon\n" ++
787+
"info: created src" ++ s ++ "main.zig\n" ++
788+
"info: created src" ++ s ++ "root.zig\n" ++
789+
"info: see `zig build --help` for a menu of options\n");
812790

813791
// Test missing output path.
814792
const bad_out_arg = "-femit-bin=does" ++ s ++ "not" ++ s ++ "exist" ++ s ++ "foo.exe";

0 commit comments

Comments
 (0)