cross
This commit is contained in:
119
src/main.zig
119
src/main.zig
@@ -19,22 +19,75 @@ pub fn main(init: std.process.Init) !void {
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.len < 3) {
|
||||
printUsage();
|
||||
return;
|
||||
// Parse flags and positional arguments
|
||||
var input_path: ?[]const u8 = null;
|
||||
var target_config = sx.codegen.TargetConfig{};
|
||||
var lib_paths = std.ArrayList([]const u8).empty;
|
||||
|
||||
var i: usize = 2;
|
||||
while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
if (std.mem.eql(u8, arg, "--target")) {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: --target requires a value\n", .{}); return; }
|
||||
target_config.triple = (try allocator.dupeZ(u8, args[i])).ptr;
|
||||
} else if (std.mem.eql(u8, arg, "--cpu")) {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: --cpu requires a value\n", .{}); return; }
|
||||
target_config.cpu = (try allocator.dupeZ(u8, args[i])).ptr;
|
||||
} else if (std.mem.eql(u8, arg, "--opt")) {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: --opt requires a value\n", .{}); return; }
|
||||
target_config.opt_level = parseOptLevel(args[i]) orelse {
|
||||
std.debug.print("error: invalid --opt value '{s}' (expected: none/0, less/1, default/2, aggressive/3)\n", .{args[i]});
|
||||
return;
|
||||
};
|
||||
} else if (std.mem.eql(u8, arg, "-o")) {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: -o requires a value\n", .{}); return; }
|
||||
target_config.output_path = args[i];
|
||||
} else if (std.mem.eql(u8, arg, "--linker")) {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: --linker requires a value\n", .{}); return; }
|
||||
target_config.linker = args[i];
|
||||
} else if (std.mem.eql(u8, arg, "--sysroot")) {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: --sysroot requires a value\n", .{}); return; }
|
||||
target_config.sysroot = args[i];
|
||||
} else if (std.mem.startsWith(u8, arg, "-L")) {
|
||||
if (arg.len > 2) {
|
||||
try lib_paths.append(allocator, arg[2..]);
|
||||
} else {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: -L requires a value\n", .{}); return; }
|
||||
try lib_paths.append(allocator, args[i]);
|
||||
}
|
||||
} else if (!std.mem.startsWith(u8, arg, "-")) {
|
||||
input_path = arg;
|
||||
} else {
|
||||
std.debug.print("error: unknown flag '{s}'\n", .{arg});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const input_path = args[2];
|
||||
target_config.lib_paths = try lib_paths.toOwnedSlice(allocator);
|
||||
|
||||
const path = input_path orelse {
|
||||
printUsage();
|
||||
return;
|
||||
};
|
||||
|
||||
if (std.mem.eql(u8, command, "build")) {
|
||||
const output_name = deriveOutputName(input_path);
|
||||
compile(allocator, io, input_path, output_name) catch return;
|
||||
const output_name = target_config.output_path orelse deriveOutputName(path);
|
||||
compile(allocator, io, path, output_name, target_config) catch return;
|
||||
std.debug.print("compiled: {s}\n", .{output_name});
|
||||
} else if (std.mem.eql(u8, command, "ir")) {
|
||||
emitIR(allocator, io, input_path) catch return;
|
||||
emitIR(allocator, io, path, target_config) catch return;
|
||||
} else if (std.mem.eql(u8, command, "asm")) {
|
||||
emitAsm(allocator, io, path, target_config) catch return;
|
||||
} else if (std.mem.eql(u8, command, "run")) {
|
||||
const tmp_bin = "/tmp/sx_run_tmp";
|
||||
compile(allocator, io, input_path, tmp_bin) catch return;
|
||||
const tmp_bin = if (comptime @import("builtin").os.tag == .windows) "sx_run_tmp.exe" else "/tmp/sx_run_tmp";
|
||||
compile(allocator, io, path, tmp_bin, target_config) catch return;
|
||||
defer {
|
||||
std.Io.Dir.deleteFile(.cwd(), io, tmp_bin) catch {};
|
||||
}
|
||||
@@ -53,16 +106,34 @@ pub fn main(init: std.process.Init) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn parseOptLevel(s: []const u8) ?sx.codegen.TargetConfig.OptLevel {
|
||||
if (std.mem.eql(u8, s, "none") or std.mem.eql(u8, s, "0")) return .none;
|
||||
if (std.mem.eql(u8, s, "less") or std.mem.eql(u8, s, "1")) return .less;
|
||||
if (std.mem.eql(u8, s, "default") or std.mem.eql(u8, s, "2")) return .default;
|
||||
if (std.mem.eql(u8, s, "aggressive") or std.mem.eql(u8, s, "3")) return .aggressive;
|
||||
return null;
|
||||
}
|
||||
|
||||
fn printUsage() void {
|
||||
std.debug.print(
|
||||
\\Usage: sx <command> [file.sx]
|
||||
\\Usage: sx <command> [options] <file.sx>
|
||||
\\
|
||||
\\Commands:
|
||||
\\ run Build and run immediately
|
||||
\\ build Build binary in current directory
|
||||
\\ ir Print LLVM IR to stdout
|
||||
\\ asm Emit assembly (.s) file
|
||||
\\ lsp Start language server (LSP)
|
||||
\\
|
||||
\\Options:
|
||||
\\ --target <triple> Target triple (default: host)
|
||||
\\ --cpu <name> CPU name (default: generic)
|
||||
\\ --opt <level> Optimization: none/0, less/1, default/2, aggressive/3
|
||||
\\ -o <path> Output path
|
||||
\\ -L <path> Library search path (repeatable)
|
||||
\\ --linker <cmd> Linker command (default: cc)
|
||||
\\ --sysroot <path> Sysroot for cross-compilation
|
||||
\\
|
||||
, .{});
|
||||
}
|
||||
|
||||
@@ -96,7 +167,7 @@ fn deriveOutputName(input_path: []const u8) []const u8 {
|
||||
// Get basename (strip directory)
|
||||
var start: usize = 0;
|
||||
for (input_path, 0..) |ch, i| {
|
||||
if (ch == '/') start = i + 1;
|
||||
if (ch == '/' or ch == '\\') start = i + 1;
|
||||
}
|
||||
const basename = input_path[start..];
|
||||
// Strip .sx extension
|
||||
@@ -115,10 +186,10 @@ fn readSource(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8)
|
||||
return try allocator.dupeZ(u8, source_bytes);
|
||||
}
|
||||
|
||||
fn compilePipeline(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8) !sx.core.Compilation {
|
||||
fn compilePipeline(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.codegen.TargetConfig) !sx.core.Compilation {
|
||||
const source = try readSource(allocator, io, input_path);
|
||||
|
||||
var comp = sx.core.Compilation.init(allocator, io, input_path, source);
|
||||
var comp = sx.core.Compilation.init(allocator, io, input_path, source, target_config);
|
||||
errdefer comp.deinit();
|
||||
|
||||
comp.parse() catch { comp.renderErrors(); return error.CompileError; };
|
||||
@@ -131,14 +202,26 @@ fn compilePipeline(allocator: std.mem.Allocator, io: std.Io, input_path: []const
|
||||
return comp;
|
||||
}
|
||||
|
||||
fn emitIR(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8) !void {
|
||||
var comp = try compilePipeline(allocator, io, input_path);
|
||||
fn emitIR(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.codegen.TargetConfig) !void {
|
||||
var comp = try compilePipeline(allocator, io, input_path, target_config);
|
||||
defer comp.deinit();
|
||||
comp.cg.?.printIR();
|
||||
}
|
||||
|
||||
fn compile(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, output_path: []const u8) !void {
|
||||
var comp = try compilePipeline(allocator, io, input_path);
|
||||
fn emitAsm(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.codegen.TargetConfig) !void {
|
||||
var comp = try compilePipeline(allocator, io, input_path, target_config);
|
||||
defer comp.deinit();
|
||||
const asm_path = target_config.output_path orelse blk: {
|
||||
const name = deriveOutputName(input_path);
|
||||
break :blk try std.fmt.allocPrint(allocator, "{s}.s", .{name});
|
||||
};
|
||||
const asm_path_z = try allocator.dupeZ(u8, asm_path);
|
||||
comp.cg.?.emitAssembly(asm_path_z.ptr) catch { comp.renderErrors(); return error.CompileError; };
|
||||
std.debug.print("emitted: {s}\n", .{asm_path});
|
||||
}
|
||||
|
||||
fn compile(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, output_path: []const u8, target_config: sx.codegen.TargetConfig) !void {
|
||||
var comp = try compilePipeline(allocator, io, input_path, target_config);
|
||||
defer comp.deinit();
|
||||
|
||||
var cg = &comp.cg.?;
|
||||
@@ -148,7 +231,7 @@ fn compile(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, out
|
||||
cg.emitObject(obj_path.ptr) catch { comp.renderErrors(); return error.CompileError; };
|
||||
|
||||
// Link
|
||||
sx.codegen.CodeGen.link(allocator, io, obj_path, output_path, cg.foreign_libraries.items) catch {
|
||||
sx.codegen.CodeGen.link(allocator, io, obj_path, output_path, cg.foreign_libraries.items, target_config) catch {
|
||||
std.debug.print("error: linking failed\n", .{});
|
||||
return error.CompileError;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user