add debug info and flag

This commit is contained in:
Luke Boswell (Linux-Desktop) 2025-12-08 20:09:31 +11:00
parent 3ea7667c2f
commit 0e964059b1
No known key found for this signature in database
GPG key ID: D6342798C85F1BDD
3 changed files with 31 additions and 6 deletions

View file

@ -33,6 +33,7 @@ pub const CompileConfig = struct {
target: RocTarget,
cpu: []const u8 = "",
features: []const u8 = "",
debug: bool = false, // Enable debug info generation in output
/// Check if compiling for the current machine
pub fn isNative(self: CompileConfig) bool {
@ -284,7 +285,8 @@ pub fn compileBitcodeToObject(gpa: Allocator, config: CompileConfig) !bool {
coverage_options.CoverageType = .ZigLLVMCoverageType_None;
const emit_options = ZigLLVMEmitOptions{
.is_debug = false,
// Auto-enable debug when roc is built in debug mode, OR when explicitly requested via --debug
.is_debug = (builtin.mode == .Debug) or config.debug,
.is_small = config.optimization == .size,
.time_report_out = null,
.tsan = false,

View file

@ -86,6 +86,7 @@ pub const BuildArgs = struct {
opt: OptLevel, // the optimization level
target: ?[]const u8 = null, // the target to compile for (e.g., x64musl, x64glibc)
output: ?[]const u8 = null, // the path where the output binary should be created
debug: bool = false, // include debug information in the output binary
z_bench_tokenize: ?[]const u8 = null, // benchmark tokenizer on a file or directory
z_bench_parse: ?[]const u8 = null, // benchmark parser on a file or directory
};
@ -243,6 +244,7 @@ fn parseBuild(args: []const []const u8) CliArgs {
var opt: OptLevel = .dev;
var target: ?[]const u8 = null;
var output: ?[]const u8 = null;
var debug: bool = false;
var z_bench_tokenize: ?[]const u8 = null;
var z_bench_parse: ?[]const u8 = null;
for (args) |arg| {
@ -259,6 +261,7 @@ fn parseBuild(args: []const []const u8) CliArgs {
\\ --output=<output> The full path to the output binary, including filename. To specify directory only, specify a path that ends in a directory separator (e.g. a slash)
\\ --opt=<size|speed|dev> Optimize the build process for binary size, execution speed, or compilation speed. Defaults to compilation speed (dev)
\\ --target=<target> Target to compile for (e.g., x64musl, x64glibc, arm64musl). Defaults to native target with musl for static linking
\\ --debug Include debug information in the output binary
\\ --z-bench-tokenize=<path> Benchmark tokenizer on a file or directory
\\ --z-bench-parse=<path> Benchmark parser on a file or directory
\\ -h, --help Print help
@ -298,6 +301,8 @@ fn parseBuild(args: []const []const u8) CliArgs {
} else {
return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--z-bench-parse" } } };
}
} else if (mem.eql(u8, arg, "--debug")) {
debug = true;
} else {
if (path != null) {
return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "build", .arg = arg } } };
@ -305,7 +310,7 @@ fn parseBuild(args: []const []const u8) CliArgs {
path = arg;
}
}
return CliArgs{ .build = BuildArgs{ .path = path orelse "main.roc", .opt = opt, .target = target, .output = output, .z_bench_tokenize = z_bench_tokenize, .z_bench_parse = z_bench_parse } };
return CliArgs{ .build = BuildArgs{ .path = path orelse "main.roc", .opt = opt, .target = target, .output = output, .debug = debug, .z_bench_tokenize = z_bench_tokenize, .z_bench_parse = z_bench_parse } };
}
fn parseBundle(alloc: mem.Allocator, args: []const []const u8) std.mem.Allocator.Error!CliArgs {
@ -918,6 +923,19 @@ test "roc build" {
defer result.deinit(gpa);
try testing.expectEqualStrings("bar.roc", result.problem.unexpected_argument.arg);
}
{
// Test --debug flag
const result = try parse(gpa, &[_][]const u8{ "build", "--debug", "foo.roc" });
defer result.deinit(gpa);
try testing.expectEqualStrings("foo.roc", result.build.path);
try testing.expect(result.build.debug);
}
{
// Test that debug defaults to false
const result = try parse(gpa, &[_][]const u8{ "build", "foo.roc" });
defer result.deinit(gpa);
try testing.expect(!result.build.debug);
}
{
const result = try parse(gpa, &[_][]const u8{ "build", "-h" });
defer result.deinit(gpa);

View file

@ -743,7 +743,8 @@ fn mainArgs(allocs: *Allocators, args: []const []const u8) !void {
/// Returns the path to the generated object file (allocated from arena, no need to free), or null if LLVM unavailable.
/// If serialized_module is provided, it will be embedded in the binary (for roc build).
/// If serialized_module is null, the binary will use IPC to get module data (for roc run).
fn generatePlatformHostShim(allocs: *Allocators, cache_dir: []const u8, entrypoint_names: []const []const u8, target: builder.RocTarget, serialized_module: ?[]const u8) !?[]const u8 {
/// If debug is true, include debug information in the generated object file.
fn generatePlatformHostShim(allocs: *Allocators, cache_dir: []const u8, entrypoint_names: []const []const u8, target: builder.RocTarget, serialized_module: ?[]const u8, debug: bool) !?[]const u8 {
// Check if LLVM is available (this is a compile-time check)
if (!llvm_available) {
std.log.debug("LLVM not available, skipping platform host shim generation", .{});
@ -820,6 +821,7 @@ fn generatePlatformHostShim(allocs: *Allocators, cache_dir: []const u8, entrypoi
.output_path = object_path,
.optimization = .speed,
.target = target,
.debug = debug, // Use the debug flag passed from caller
};
if (builder.compileBitcodeToObject(allocs.gpa, compile_config)) |success| {
@ -1019,7 +1021,8 @@ fn rocRun(allocs: *Allocators, args: cli_args.RunArgs) !void {
// Generate platform host shim using the detected entrypoints
// Use temp dir to avoid race conditions when multiple processes run in parallel
// Pass null for serialized_module since roc run uses IPC mode
const platform_shim_path = generatePlatformHostShim(allocs, temp_dir_path, entrypoints.items, shim_target, null) catch |err| {
// Auto-enable debug when roc is built in debug mode (no explicit --debug flag for roc run)
const platform_shim_path = generatePlatformHostShim(allocs, temp_dir_path, entrypoints.items, shim_target, null, builtin.mode == .Debug) catch |err| {
std.log.err("Failed to generate platform host shim: {}", .{err});
return err;
};
@ -3214,8 +3217,10 @@ fn rocBuildEmbedded(allocs: *Allocators, args: cli_args.BuildArgs) !void {
};
// Generate platform host shim with embedded module data
std.log.debug("Generating platform host shim with {} bytes of embedded data...", .{serialized_module.len});
const platform_shim_path = generatePlatformHostShim(allocs, build_cache_dir, entrypoints.items, target, serialized_module) catch |err| {
// Enable debug if explicitly requested via --debug OR if roc is built in debug mode
const enable_debug = args.debug or (builtin.mode == .Debug);
std.log.debug("Generating platform host shim with {} bytes of embedded data (debug={})...", .{ serialized_module.len, enable_debug });
const platform_shim_path = generatePlatformHostShim(allocs, build_cache_dir, entrypoints.items, target, serialized_module, enable_debug) catch |err| {
std.log.err("Failed to generate platform host shim: {}", .{err});
return err;
};