| ... | ... | @@ -317,6 +317,8 @@ const usage_build_generic = |
| 317 | 317 | \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation |
| 318 | 318 | \\ -femit-analysis[=path] Write analysis JSON file with type information |
| 319 | 319 | \\ -fno-emit-analysis (default) Do not write analysis JSON file with type information |
| 320 | \\ -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL |
| 321 | \\ -fno-emit-implib Do not produce an import .lib when building a Windows DLL |
| 320 | 322 | \\ --show-builtin Output the source of @import("builtin") then exit |
| 321 | 323 | \\ --cache-dir [path] Override the local cache directory |
| 322 | 324 | \\ --global-cache-dir [path] Override the global cache directory |
| ... | ... | @@ -585,6 +587,8 @@ fn buildOutputType( |
| 585 | 587 | var emit_llvm_bc: Emit = .no; |
| 586 | 588 | var emit_docs: Emit = .no; |
| 587 | 589 | var emit_analysis: Emit = .no; |
| 590 | var emit_implib: Emit = .yes_default_path; |
| 591 | var emit_implib_arg_provided = false; |
| 588 | 592 | var target_arch_os_abi: []const u8 = "native"; |
| 589 | 593 | var target_mcpu: ?[]const u8 = null; |
| 590 | 594 | var target_dynamic_linker: ?[]const u8 = null; |
| ... | ... | @@ -654,7 +658,6 @@ fn buildOutputType( |
| 654 | 658 | var main_pkg_path: ?[]const u8 = null; |
| 655 | 659 | var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no; |
| 656 | 660 | var subsystem: ?std.Target.SubSystem = null; |
| 657 | | var out_implib: ?[]const u8 = null; |
| 658 | 661 | var major_subsystem_version: ?u32 = null; |
| 659 | 662 | var minor_subsystem_version: ?u32 = null; |
| 660 | 663 | var wasi_exec_model: ?std.builtin.WasiExecModel = null; |
| ... | ... | @@ -1091,6 +1094,15 @@ fn buildOutputType( |
| 1091 | 1094 | emit_analysis = .{ .yes = arg["-femit-analysis=".len..] }; |
| 1092 | 1095 | } else if (mem.eql(u8, arg, "-fno-emit-analysis")) { |
| 1093 | 1096 | emit_analysis = .no; |
| 1097 | } else if (mem.eql(u8, arg, "-femit-implib")) { |
| 1098 | emit_implib = .yes_default_path; |
| 1099 | emit_implib_arg_provided = true; |
| 1100 | } else if (mem.startsWith(u8, arg, "-femit-implib=")) { |
| 1101 | emit_implib = .{ .yes = arg["-femit-implib=".len..] }; |
| 1102 | emit_implib_arg_provided = true; |
| 1103 | } else if (mem.eql(u8, arg, "-fno-emit-implib")) { |
| 1104 | emit_implib = .no; |
| 1105 | emit_implib_arg_provided = true; |
| 1094 | 1106 | } else if (mem.eql(u8, arg, "-dynamic")) { |
| 1095 | 1107 | link_mode = .Dynamic; |
| 1096 | 1108 | } else if (mem.eql(u8, arg, "-static")) { |
| ... | ... | @@ -1650,7 +1662,8 @@ fn buildOutputType( |
| 1650 | 1662 | if (i >= linker_args.items.len) { |
| 1651 | 1663 | fatal("expected linker arg after '{s}'", .{arg}); |
| 1652 | 1664 | } |
| 1653 | | out_implib = linker_args.items[i]; |
| 1665 | emit_implib = .{ .yes = linker_args.items[i] }; |
| 1666 | emit_implib_arg_provided = true; |
| 1654 | 1667 | } else { |
| 1655 | 1668 | warn("unsupported linker arg: {s}", .{arg}); |
| 1656 | 1669 | } |
| ... | ... | @@ -1998,11 +2011,15 @@ fn buildOutputType( |
| 1998 | 2011 | const default_h_basename = try std.fmt.allocPrint(arena, "{s}.h", .{root_name}); |
| 1999 | 2012 | var emit_h_resolved = emit_h.resolve(default_h_basename) catch |err| { |
| 2000 | 2013 | switch (emit_h) { |
| 2001 | | .yes => { |
| 2002 | | fatal("unable to open directory from argument '-femit-h', '{s}': {s}", .{ emit_h.yes, @errorName(err) }); |
| 2014 | .yes => |p| { |
| 2015 | fatal("unable to open directory from argument '-femit-h', '{s}': {s}", .{ |
| 2016 | p, @errorName(err), |
| 2017 | }); |
| 2003 | 2018 | }, |
| 2004 | 2019 | .yes_default_path => { |
| 2005 | | fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_h_basename, @errorName(err) }); |
| 2020 | fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ |
| 2021 | default_h_basename, @errorName(err), |
| 2022 | }); |
| 2006 | 2023 | }, |
| 2007 | 2024 | .no => unreachable, |
| 2008 | 2025 | } |
| ... | ... | @@ -2012,11 +2029,15 @@ fn buildOutputType( |
| 2012 | 2029 | const default_asm_basename = try std.fmt.allocPrint(arena, "{s}.s", .{root_name}); |
| 2013 | 2030 | var emit_asm_resolved = emit_asm.resolve(default_asm_basename) catch |err| { |
| 2014 | 2031 | switch (emit_asm) { |
| 2015 | | .yes => { |
| 2016 | | fatal("unable to open directory from argument '-femit-asm', '{s}': {s}", .{ emit_asm.yes, @errorName(err) }); |
| 2032 | .yes => |p| { |
| 2033 | fatal("unable to open directory from argument '-femit-asm', '{s}': {s}", .{ |
| 2034 | p, @errorName(err), |
| 2035 | }); |
| 2017 | 2036 | }, |
| 2018 | 2037 | .yes_default_path => { |
| 2019 | | fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_asm_basename, @errorName(err) }); |
| 2038 | fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ |
| 2039 | default_asm_basename, @errorName(err), |
| 2040 | }); |
| 2020 | 2041 | }, |
| 2021 | 2042 | .no => unreachable, |
| 2022 | 2043 | } |
| ... | ... | @@ -2026,11 +2047,15 @@ fn buildOutputType( |
| 2026 | 2047 | const default_llvm_ir_basename = try std.fmt.allocPrint(arena, "{s}.ll", .{root_name}); |
| 2027 | 2048 | var emit_llvm_ir_resolved = emit_llvm_ir.resolve(default_llvm_ir_basename) catch |err| { |
| 2028 | 2049 | switch (emit_llvm_ir) { |
| 2029 | | .yes => { |
| 2030 | | fatal("unable to open directory from argument '-femit-llvm-ir', '{s}': {s}", .{ emit_llvm_ir.yes, @errorName(err) }); |
| 2050 | .yes => |p| { |
| 2051 | fatal("unable to open directory from argument '-femit-llvm-ir', '{s}': {s}", .{ |
| 2052 | p, @errorName(err), |
| 2053 | }); |
| 2031 | 2054 | }, |
| 2032 | 2055 | .yes_default_path => { |
| 2033 | | fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_llvm_ir_basename, @errorName(err) }); |
| 2056 | fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ |
| 2057 | default_llvm_ir_basename, @errorName(err), |
| 2058 | }); |
| 2034 | 2059 | }, |
| 2035 | 2060 | .no => unreachable, |
| 2036 | 2061 | } |
| ... | ... | @@ -2040,11 +2065,15 @@ fn buildOutputType( |
| 2040 | 2065 | const default_llvm_bc_basename = try std.fmt.allocPrint(arena, "{s}.bc", .{root_name}); |
| 2041 | 2066 | var emit_llvm_bc_resolved = emit_llvm_bc.resolve(default_llvm_bc_basename) catch |err| { |
| 2042 | 2067 | switch (emit_llvm_bc) { |
| 2043 | | .yes => { |
| 2044 | | fatal("unable to open directory from argument '-femit-llvm-bc', '{s}': {s}", .{ emit_llvm_bc.yes, @errorName(err) }); |
| 2068 | .yes => |p| { |
| 2069 | fatal("unable to open directory from argument '-femit-llvm-bc', '{s}': {s}", .{ |
| 2070 | p, @errorName(err), |
| 2071 | }); |
| 2045 | 2072 | }, |
| 2046 | 2073 | .yes_default_path => { |
| 2047 | | fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_llvm_bc_basename, @errorName(err) }); |
| 2074 | fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ |
| 2075 | default_llvm_bc_basename, @errorName(err), |
| 2076 | }); |
| 2048 | 2077 | }, |
| 2049 | 2078 | .no => unreachable, |
| 2050 | 2079 | } |
| ... | ... | @@ -2054,11 +2083,15 @@ fn buildOutputType( |
| 2054 | 2083 | const default_analysis_basename = try std.fmt.allocPrint(arena, "{s}-analysis.json", .{root_name}); |
| 2055 | 2084 | var emit_analysis_resolved = emit_analysis.resolve(default_analysis_basename) catch |err| { |
| 2056 | 2085 | switch (emit_analysis) { |
| 2057 | | .yes => { |
| 2058 | | fatal("unable to open directory from argument 'femit-analysis', '{s}': {s}", .{ emit_analysis.yes, @errorName(err) }); |
| 2086 | .yes => |p| { |
| 2087 | fatal("unable to open directory from argument '-femit-analysis', '{s}': {s}", .{ |
| 2088 | p, @errorName(err), |
| 2089 | }); |
| 2059 | 2090 | }, |
| 2060 | 2091 | .yes_default_path => { |
| 2061 | | fatal("unable to open directory from arguments 'name' or 'soname', '{s}': {s}", .{ default_analysis_basename, @errorName(err) }); |
| 2092 | fatal("unable to open directory from arguments 'name' or 'soname', '{s}': {s}", .{ |
| 2093 | default_analysis_basename, @errorName(err), |
| 2094 | }); |
| 2062 | 2095 | }, |
| 2063 | 2096 | .no => unreachable, |
| 2064 | 2097 | } |
| ... | ... | @@ -2067,8 +2100,10 @@ fn buildOutputType( |
| 2067 | 2100 | |
| 2068 | 2101 | var emit_docs_resolved = emit_docs.resolve("docs") catch |err| { |
| 2069 | 2102 | switch (emit_docs) { |
| 2070 | | .yes => { |
| 2071 | | fatal("unable to open directory from argument 'femit-docs', '{s}': {s}", .{ emit_h.yes, @errorName(err) }); |
| 2103 | .yes => |p| { |
| 2104 | fatal("unable to open directory from argument '-femit-docs', '{s}': {s}", .{ |
| 2105 | p, @errorName(err), |
| 2106 | }); |
| 2072 | 2107 | }, |
| 2073 | 2108 | .yes_default_path => { |
| 2074 | 2109 | fatal("unable to open directory 'docs': {s}", .{@errorName(err)}); |
| ... | ... | @@ -2078,6 +2113,35 @@ fn buildOutputType( |
| 2078 | 2113 | }; |
| 2079 | 2114 | defer emit_docs_resolved.deinit(); |
| 2080 | 2115 | |
| 2116 | const is_dyn_lib = switch (output_mode) { |
| 2117 | .Obj, .Exe => false, |
| 2118 | .Lib => (link_mode orelse .Static) == .Dynamic, |
| 2119 | }; |
| 2120 | const implib_eligible = is_dyn_lib and |
| 2121 | emit_bin_loc != null and target_info.target.os.tag == .windows; |
| 2122 | if (!implib_eligible) { |
| 2123 | if (!emit_implib_arg_provided) { |
| 2124 | emit_implib = .no; |
| 2125 | } else if (emit_implib != .no) { |
| 2126 | fatal("the argument -femit-implib is allowed only when building a Windows DLL", .{}); |
| 2127 | } |
| 2128 | } |
| 2129 | const default_implib_basename = try std.fmt.allocPrint(arena, "{s}.lib", .{root_name}); |
| 2130 | var emit_implib_resolved = emit_implib.resolve(default_implib_basename) catch |err| { |
| 2131 | switch (emit_implib) { |
| 2132 | .yes => |p| { |
| 2133 | fatal("unable to open directory from argument '-femit-implib', '{s}': {s}", .{ |
| 2134 | p, @errorName(err), |
| 2135 | }); |
| 2136 | }, |
| 2137 | .yes_default_path => { |
| 2138 | fatal("unable to open directory 'docs': {s}", .{@errorName(err)}); |
| 2139 | }, |
| 2140 | .no => unreachable, |
| 2141 | } |
| 2142 | }; |
| 2143 | defer emit_implib_resolved.deinit(); |
| 2144 | |
| 2081 | 2145 | const main_pkg: ?*Package = if (root_src_file) |src_path| blk: { |
| 2082 | 2146 | if (main_pkg_path) |p| { |
| 2083 | 2147 | const rel_src_path = try fs.path.relative(gpa, p, src_path); |
| ... | ... | @@ -2168,16 +2232,6 @@ fn buildOutputType( |
| 2168 | 2232 | else => false, |
| 2169 | 2233 | }; |
| 2170 | 2234 | |
| 2171 | | // Always output import libraries (.lib) when building for msvc to replicate |
| 2172 | | // `link` behavior. lld does not always output import libraries so on the |
| 2173 | | // gnu abi users must set out_implib. |
| 2174 | | if (output_mode == .Lib and emit_bin == .yes and target_info.target.abi == .msvc and out_implib == null) { |
| 2175 | | const emit_bin_ext = fs.path.extension(emit_bin.yes); |
| 2176 | | out_implib = try std.fmt.allocPrint(gpa, "{s}.lib", .{ |
| 2177 | | emit_bin.yes[0 .. emit_bin.yes.len - emit_bin_ext.len], |
| 2178 | | }); |
| 2179 | | } |
| 2180 | | |
| 2181 | 2235 | gimmeMoreOfThoseSweetSweetFileDescriptors(); |
| 2182 | 2236 | |
| 2183 | 2237 | const comp = Compilation.create(gpa, .{ |
| ... | ... | @@ -2199,6 +2253,7 @@ fn buildOutputType( |
| 2199 | 2253 | .emit_llvm_bc = emit_llvm_bc_resolved.data, |
| 2200 | 2254 | .emit_docs = emit_docs_resolved.data, |
| 2201 | 2255 | .emit_analysis = emit_analysis_resolved.data, |
| 2256 | .emit_implib = emit_implib_resolved.data, |
| 2202 | 2257 | .link_mode = link_mode, |
| 2203 | 2258 | .dll_export_fns = dll_export_fns, |
| 2204 | 2259 | .object_format = object_format, |
| ... | ... | @@ -2286,7 +2341,6 @@ fn buildOutputType( |
| 2286 | 2341 | .test_name_prefix = test_name_prefix, |
| 2287 | 2342 | .disable_lld_caching = !have_enable_cache, |
| 2288 | 2343 | .subsystem = subsystem, |
| 2289 | | .out_implib = out_implib, |
| 2290 | 2344 | .wasi_exec_model = wasi_exec_model, |
| 2291 | 2345 | .debug_compile_errors = debug_compile_errors, |
| 2292 | 2346 | .enable_link_snapshots = enable_link_snapshots, |
| ... | ... | @@ -2685,15 +2739,6 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi |
| 2685 | 2739 | |
| 2686 | 2740 | _ = try cache_dir.updateFile(src_pdb_path, cwd, dst_pdb_path, .{}); |
| 2687 | 2741 | } |
| 2688 | | |
| 2689 | | if (comp.bin_file.options.out_implib) |out_implib| { |
| 2690 | | const src_implib_path = try std.fmt.allocPrint(gpa, "{s}.lib", .{bin_sub_path}); |
| 2691 | | defer gpa.free(src_implib_path); |
| 2692 | | if (std.fs.path.dirname(out_implib)) |implib_dir| { |
| 2693 | | try cwd.makePath(implib_dir); |
| 2694 | | } |
| 2695 | | _ = try cache_dir.updateFile(src_implib_path, cwd, out_implib, .{}); |
| 2696 | | } |
| 2697 | 2742 | }, |
| 2698 | 2743 | } |
| 2699 | 2744 | } |