Compile the compiler test
This commit is contained in:
parent
bc65985a30
commit
41e566a64f
@ -2751,6 +2751,9 @@ fn llvm_emit_function_site_attributes(module: *Module, value: *Value) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub noinline fn convert(arena: *Arena, options: ConvertOptions) void {
|
pub noinline fn convert(arena: *Arena, options: ConvertOptions) void {
|
||||||
|
const build_dir = "bb-cache";
|
||||||
|
os.make_directory(build_dir);
|
||||||
|
|
||||||
var converter = Converter{
|
var converter = Converter{
|
||||||
.content = options.content,
|
.content = options.content,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
|
@ -23,21 +23,88 @@ fn invoke(name: []const u8) !void {
|
|||||||
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
|
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
|
||||||
const build_mode = @field(BuildMode, f.name);
|
const build_mode = @field(BuildMode, f.name);
|
||||||
inline for ([2]bool{ false, true }) |has_debug_info| {
|
inline for ([2]bool{ false, true }) |has_debug_info| {
|
||||||
var tmp_dir = std.testing.tmpDir(.{});
|
// Bootstrap
|
||||||
defer tmp_dir.cleanup();
|
{
|
||||||
const base_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
|
var tmp_dir = std.testing.tmpDir(.{});
|
||||||
const executable_path = base_path;
|
defer tmp_dir.cleanup();
|
||||||
const directory_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
|
const base_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
|
||||||
const object_path = arena.join_string(&.{ base_path, ".o" });
|
const executable_path = base_path;
|
||||||
try unit_test(arena, allocator, .{
|
const directory_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
|
||||||
.object_paths = if (lib.string.equal(name, "c_abi")) &.{ object_path, c_abi_object_path } else &.{object_path},
|
const object_path = arena.join_string(&.{ base_path, ".o" });
|
||||||
.executable_path = executable_path,
|
try unit_test(arena, allocator, .{
|
||||||
.file_path = arena.join_string(&.{ "tests/", name, ".bbb" }),
|
.object_paths = if (lib.string.equal(name, "c_abi")) &.{ object_path, c_abi_object_path } else &.{object_path},
|
||||||
.name = name,
|
.executable_path = executable_path,
|
||||||
.directory_path = directory_path,
|
.file_path = arena.join_string(&.{ "tests/", name, ".bbb" }),
|
||||||
.build_mode = build_mode,
|
.name = name,
|
||||||
.has_debug_info = has_debug_info,
|
.directory_path = directory_path,
|
||||||
});
|
.build_mode = build_mode,
|
||||||
|
.has_debug_info = has_debug_info,
|
||||||
|
.self_hosted_path = null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Self-hosted
|
||||||
|
{
|
||||||
|
var tmp_dir = std.testing.tmpDir(.{});
|
||||||
|
defer tmp_dir.cleanup();
|
||||||
|
const base_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
|
||||||
|
const executable_path = base_path;
|
||||||
|
const directory_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
|
||||||
|
const object_path = arena.join_string(&.{ base_path, ".o" });
|
||||||
|
try unit_test(arena, allocator, .{
|
||||||
|
.object_paths = if (lib.string.equal(name, "c_abi")) &.{ object_path, c_abi_object_path } else &.{object_path},
|
||||||
|
.executable_path = executable_path,
|
||||||
|
.file_path = arena.join_string(&.{ "tests/", name, ".bbb" }),
|
||||||
|
.name = name,
|
||||||
|
.directory_path = directory_path,
|
||||||
|
.build_mode = build_mode,
|
||||||
|
.has_debug_info = has_debug_info,
|
||||||
|
.self_hosted_path = arena.join_string(&.{ "bb-cache/", compiler_basename(arena, build_mode, has_debug_info) }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compiler_basename(arena: *Arena, build_mode: BuildMode, has_debug_info: bool) [:0]const u8 {
|
||||||
|
return arena.join_string(&.{ "compiler_", @tagName(build_mode), if (has_debug_info) "_di" else "_nodi" });
|
||||||
|
}
|
||||||
|
|
||||||
|
var compiler_compiled = false;
|
||||||
|
fn compile_the_compiler() !void {
|
||||||
|
if (!compiler_compiled) {
|
||||||
|
defer compiler_compiled = true;
|
||||||
|
|
||||||
|
if (!lib.GlobalState.initialized) {
|
||||||
|
lib.GlobalState.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
comptime assert(lib.is_test);
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const arena = lib.global.arena;
|
||||||
|
const arena_position = arena.position;
|
||||||
|
defer arena.restore(arena_position);
|
||||||
|
|
||||||
|
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
|
||||||
|
const build_mode = @field(BuildMode, f.name);
|
||||||
|
inline for ([2]bool{ false, true }) |has_debug_info| {
|
||||||
|
var tmp_dir = std.testing.tmpDir(.{});
|
||||||
|
defer tmp_dir.cleanup();
|
||||||
|
const base_path = arena.join_string(&.{ "bb-cache/", compiler_basename(arena, build_mode, has_debug_info) });
|
||||||
|
const executable_path = base_path;
|
||||||
|
const directory_path = "bb-cache";
|
||||||
|
const object_path = arena.join_string(&.{ base_path, ".o" });
|
||||||
|
try unit_test(arena, allocator, .{
|
||||||
|
.object_paths = &.{object_path},
|
||||||
|
.executable_path = executable_path,
|
||||||
|
.file_path = arena.join_string(&.{"src/compiler.bbb"}),
|
||||||
|
.name = "compiler",
|
||||||
|
.directory_path = directory_path,
|
||||||
|
.build_mode = build_mode,
|
||||||
|
.has_debug_info = has_debug_info,
|
||||||
|
.self_hosted_path = null,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,44 +117,67 @@ const InvokeWrapper = struct {
|
|||||||
build_mode: BuildMode,
|
build_mode: BuildMode,
|
||||||
has_debug_info: bool,
|
has_debug_info: bool,
|
||||||
directory_path: [:0]const u8,
|
directory_path: [:0]const u8,
|
||||||
|
self_hosted_path: ?[]const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn unit_test(arena: *Arena, allocator: std.mem.Allocator, options: InvokeWrapper) !void {
|
fn unit_test(arena: *Arena, allocator: std.mem.Allocator, options: InvokeWrapper) anyerror!void {
|
||||||
|
const position = arena.position;
|
||||||
|
defer arena.restore(position);
|
||||||
|
|
||||||
const file_content = lib.file.read(arena, options.file_path);
|
const file_content = lib.file.read(arena, options.file_path);
|
||||||
|
|
||||||
converter.convert(arena, .{
|
if (options.self_hosted_path) |self_hosted_path| {
|
||||||
.path = options.file_path,
|
try compile_the_compiler();
|
||||||
.content = file_content,
|
const run_result = try std.process.Child.run(.{
|
||||||
.objects = options.object_paths,
|
|
||||||
.executable = options.executable_path,
|
|
||||||
.build_mode = options.build_mode,
|
|
||||||
.name = options.name,
|
|
||||||
.has_debug_info = options.has_debug_info,
|
|
||||||
.target = converter.Target.get_native(),
|
|
||||||
});
|
|
||||||
const run_result = std.process.Child.run(.{
|
|
||||||
.allocator = allocator,
|
|
||||||
.argv = &.{options.executable_path},
|
|
||||||
}) catch |err| {
|
|
||||||
std.debug.print("error: {}\n", .{err});
|
|
||||||
const r = try std.process.Child.run(.{
|
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.argv = &.{ "/usr/bin/ls", "-lasR", options.directory_path },
|
.argv = &.{
|
||||||
.max_output_bytes = std.math.maxInt(usize),
|
self_hosted_path,
|
||||||
|
options.file_path,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
defer allocator.free(r.stdout);
|
const success = switch (run_result.term) {
|
||||||
defer allocator.free(r.stderr);
|
.Exited => |exit_code| exit_code == 0,
|
||||||
std.debug.print("ls {s} {s}\n", .{ options.directory_path, r.stdout });
|
else => false,
|
||||||
return err;
|
};
|
||||||
};
|
if (!success) {
|
||||||
|
std.debug.print("{}\n{}\n", .{ run_result, options });
|
||||||
|
return error.compiler_failed_to_run_successfully;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
converter.convert(arena, .{
|
||||||
|
.path = options.file_path,
|
||||||
|
.content = file_content,
|
||||||
|
.objects = options.object_paths,
|
||||||
|
.executable = options.executable_path,
|
||||||
|
.build_mode = options.build_mode,
|
||||||
|
.name = options.name,
|
||||||
|
.has_debug_info = options.has_debug_info,
|
||||||
|
.target = converter.Target.get_native(),
|
||||||
|
});
|
||||||
|
const run_result = std.process.Child.run(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
.argv = &.{options.executable_path},
|
||||||
|
}) catch |err| {
|
||||||
|
std.debug.print("error: {}\n", .{err});
|
||||||
|
const r = try std.process.Child.run(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
.argv = &.{ "/usr/bin/ls", "-lasR", options.directory_path },
|
||||||
|
.max_output_bytes = std.math.maxInt(usize),
|
||||||
|
});
|
||||||
|
defer allocator.free(r.stdout);
|
||||||
|
defer allocator.free(r.stderr);
|
||||||
|
std.debug.print("ls {s} {s}\n", .{ options.directory_path, r.stdout });
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
||||||
const success = switch (run_result.term) {
|
const success = switch (run_result.term) {
|
||||||
.Exited => |exit_code| exit_code == 0,
|
.Exited => |exit_code| exit_code == 0,
|
||||||
else => false,
|
else => false,
|
||||||
};
|
};
|
||||||
if (!success) {
|
if (!success) {
|
||||||
std.debug.print("{}\n{}\n", .{ run_result, options });
|
std.debug.print("{}\n{}\n", .{ run_result, options });
|
||||||
return error.executable_failed_to_run_successfully;
|
return error.executable_failed_to_run_successfully;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
146
src/lib.zig
146
src/lib.zig
@ -515,7 +515,10 @@ pub const os = struct {
|
|||||||
if (os.is_being_debugged()) {
|
if (os.is_being_debugged()) {
|
||||||
@trap();
|
@trap();
|
||||||
} else {
|
} else {
|
||||||
libc.exit(1);
|
switch (is_test) {
|
||||||
|
true => @panic("aborting"),
|
||||||
|
false => libc.exit(1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2668,3 +2671,144 @@ pub fn print_string_stdout(str: []const u8) void {
|
|||||||
pub fn print_string_stderr(str: []const u8) void {
|
pub fn print_string_stderr(str: []const u8) void {
|
||||||
os.get_stderr().write(str);
|
os.get_stderr().write(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const panic_struct = switch (is_test) {
|
||||||
|
true => @import("std").debug.FullPanic(@import("std").debug.defaultPanic),
|
||||||
|
false => struct {
|
||||||
|
const abort = os.abort;
|
||||||
|
pub fn call(_: []const u8, _: ?usize) noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sentinelMismatch(_: anytype, _: anytype) noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrapError(_: anyerror) noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn outOfBounds(_: usize, _: usize) noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startGreaterThanEnd(_: usize, _: usize) noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inactiveUnionField(_: anytype, _: anytype) noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reachedUnreachable() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrapNull() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn castToNull() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn incorrectAlignment() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invalidErrorCode() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn castTruncatedData() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn negativeToUnsigned() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn integerOverflow() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shlOverflow() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shrOverflow() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn divideByZero() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exactDivisionRemainder() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn integerPartOutOfBounds() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn corruptSwitch() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shiftRhsTooBig() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invalidEnumValue() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn forLenMismatch() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memcpyLenMismatch() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memcpyAlias() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn noreturnReturned() noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sliceCastLenRemainder(_: usize) noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
139
src/main.zig
139
src/main.zig
@ -5,143 +5,7 @@ const llvm = @import("LLVM.zig");
|
|||||||
const converter = @import("converter.zig");
|
const converter = @import("converter.zig");
|
||||||
const Arena = lib.Arena;
|
const Arena = lib.Arena;
|
||||||
|
|
||||||
pub const panic = struct {
|
pub const panic = lib.panic_struct;
|
||||||
const abort = lib.os.abort;
|
|
||||||
pub fn call(_: []const u8, _: ?usize) noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sentinelMismatch(_: anytype, _: anytype) noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unwrapError(_: anyerror) noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn outOfBounds(_: usize, _: usize) noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn startGreaterThanEnd(_: usize, _: usize) noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inactiveUnionField(_: anytype, _: anytype) noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reachedUnreachable() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unwrapNull() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn castToNull() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn incorrectAlignment() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn invalidErrorCode() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn castTruncatedData() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn negativeToUnsigned() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn integerOverflow() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn shlOverflow() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn shrOverflow() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn divideByZero() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exactDivisionRemainder() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn integerPartOutOfBounds() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn corruptSwitch() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn shiftRhsTooBig() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn invalidEnumValue() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn forLenMismatch() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn memcpyLenMismatch() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn memcpyAlias() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn noreturnReturned() noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sliceCastLenRemainder(_: usize) noreturn {
|
|
||||||
@branchHint(.cold);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int {
|
pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int {
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
@ -167,7 +31,6 @@ pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int
|
|||||||
const arena = lib.global.arena;
|
const arena = lib.global.arena;
|
||||||
|
|
||||||
const build_dir = "bb-cache";
|
const build_dir = "bb-cache";
|
||||||
os.make_directory(build_dir);
|
|
||||||
const output_path_base = arena.join_string(&.{ build_dir, "/", base_name, "_", @tagName(lib.optimization_mode) });
|
const output_path_base = arena.join_string(&.{ build_dir, "/", base_name, "_", @tagName(lib.optimization_mode) });
|
||||||
const output_object_path = arena.join_string(&.{ output_path_base, ".o" });
|
const output_object_path = arena.join_string(&.{ output_path_base, ".o" });
|
||||||
const output_executable_path = output_path_base;
|
const output_executable_path = output_path_base;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user