Commit 0afb5b2ec6

Andrew Kelley <andrew@ziglang.org>
2021-05-29 05:54:11
stage2: add `zig ar` subcommand
The same entrypoint supports the following commands: * ar * ranlib * dlltool * lib For now, our strategy is to bundle the (renamed) `main()` function of llvm-ar, same as our strategy for `zig clang`. However, as Zig matures, a goal will be to replace the dependency on LLVM with our own implementation of this tool, so that it is available in builds of zig that do not have LLVM extensions enabled. This commit also categorizes the subcommands into categories in the --help menu.
1 parent e248de9
src/main.zig
@@ -43,22 +43,29 @@ const normal_usage =
     \\Commands:
     \\
     \\  build            Build project from build.zig
+    \\  init-exe         Initialize a `zig build` application in the cwd
+    \\  init-lib         Initialize a `zig build` library in the cwd
+    \\
+    \\  ast-check        Look for simple compile errors in any set of files
     \\  build-exe        Create executable from source or object files
     \\  build-lib        Create library from source or object files
     \\  build-obj        Create object from source or object files
+    \\  fmt              Reformat Zig source into canonical form
+    \\  run              Create executable and run immediately
+    \\  test             Create and run a test build
+    \\  translate-c      Convert C code to Zig code
+    \\
+    \\  ar               Use Zig as a drop-in archiver
     \\  cc               Use Zig as a drop-in C compiler
     \\  c++              Use Zig as a drop-in C++ compiler
+    \\  dlltool          Use Zig as a drop-in dlltool.exe
+    \\  lib              Use Zig as a drop-in lib.exe
+    \\  ranlib           Use Zig as a drop-in ranlib
+    \\
     \\  env              Print lib path, std path, cache directory, and version
-    \\  fmt              Reformat Zig source into canonical form
-    \\  ast-check        Look for simple compile errors in any set of files
     \\  help             Print this help and exit
-    \\  init-exe         Initialize a `zig build` application in the cwd
-    \\  init-lib         Initialize a `zig build` library in the cwd
     \\  libc             Display native libc paths file or validate one
-    \\  run              Create executable and run immediately
-    \\  translate-c      Convert C code to Zig code
     \\  targets          List available compilation targets
-    \\  test             Create and run a test build
     \\  version          Print version number and exit
     \\  zen              Print Zen of Zig and exit
     \\
@@ -201,6 +208,12 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
         return buildOutputType(gpa, arena, args, .zig_test);
     } else if (mem.eql(u8, cmd, "run")) {
         return buildOutputType(gpa, arena, args, .run);
+    } else if (mem.eql(u8, cmd, "dlltool") or
+        mem.eql(u8, cmd, "ranlib") or
+        mem.eql(u8, cmd, "lib") or
+        mem.eql(u8, cmd, "ar"))
+    {
+        return punt_to_llvm_ar(arena, args);
     } else if (mem.eql(u8, cmd, "cc")) {
         return buildOutputType(gpa, arena, args, .cc);
     } else if (mem.eql(u8, cmd, "c++")) {
@@ -3197,6 +3210,7 @@ pub const info_zen =
 ;
 
 extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
+extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
 
 /// TODO https://github.com/ziglang/zig/issues/3257
 fn punt_to_clang(arena: *Allocator, args: []const []const u8) error{OutOfMemory} {
@@ -3212,6 +3226,23 @@ fn punt_to_clang(arena: *Allocator, args: []const []const u8) error{OutOfMemory}
     process.exit(@bitCast(u8, @truncate(i8, exit_code)));
 }
 
+/// TODO https://github.com/ziglang/zig/issues/3257
+fn punt_to_llvm_ar(arena: *Allocator, args: []const []const u8) error{OutOfMemory} {
+    if (!build_options.have_llvm)
+        fatal("`zig ar`, `zig dlltool`, `zig ranlib', and `zig lib` unavailable: compiler built without LLVM extensions", .{});
+
+    // Convert the args to the format llvm-ar expects.
+    // We subtract 1 to shave off the zig binary from args[0].
+    const argv = try arena.allocSentinel(?[*:0]u8, args.len - 1, null);
+    for (args[1..]) |arg, i| {
+        // TODO If there was an argsAllocZ we could avoid this allocation.
+        argv[i] = try arena.dupeZ(u8, arg);
+    }
+    const argc = @intCast(c_int, argv.len);
+    const exit_code = ZigLlvmAr_main(argc, argv.ptr);
+    process.exit(@bitCast(u8, @truncate(i8, exit_code)));
+}
+
 /// The first argument determines which backend is invoked. The options are:
 /// * `ld.lld` - ELF
 /// * `ld64.lld` - Mach-O
src/zig_llvm-ar.cpp
@@ -1260,7 +1260,8 @@ static int ranlib_main(int argc, char **argv) {
   return performOperation(CreateSymTab, nullptr);
 }
 
-int main(int argc, char **argv) {
+extern "C" int ZigLlvmAr_main(int argc, char **argv);
+int ZigLlvmAr_main(int argc, char **argv) {
   InitLLVM X(argc, argv);
   ToolName = argv[0];
 
CMakeLists.txt
@@ -319,6 +319,7 @@ set(OPTIMIZED_C_SOURCES
 set(ZIG_CPP_SOURCES
     # These are planned to stay even when we are self-hosted.
     "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
+    "${CMAKE_SOURCE_DIR}/src/zig_llvm-ar.cpp"
     "${CMAKE_SOURCE_DIR}/src/zig_clang.cpp"
     "${CMAKE_SOURCE_DIR}/src/zig_clang_driver.cpp"
     "${CMAKE_SOURCE_DIR}/src/zig_clang_cc1_main.cpp"