I'm trying to use roc_dbg
with roc build --no-link ...
and I'm thinking roc must be throwing away the calls or something because it doesn't seem to be getting called. Just wondering if anyone knows what might be happening here?
Oh wait... I think I know
Relevant previous discussion https://roc.zulipchat.com/#narrow/channel/304641-ideas/topic/Roc.20cli.20workflow/near/451019991
At what stage do we remove the Dbg statements?
(deleted)
Found something that looks relevant in crates/compiler/mono/src/ir.rs
Stmt::Dbg
which is used to code gen the lowlevel call...
Ok, I got something working using this
diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs
index 83c7270350..15a737595a 100644
--- a/crates/cli/src/lib.rs
+++ b/crates/cli/src/lib.rs
@@ -845,7 +845,7 @@ pub fn build(
} else {
let backend_mode = match opt_level {
OptLevel::Development => LlvmBackendMode::BinaryDev,
- OptLevel::Normal | OptLevel::Size | OptLevel::Optimize => LlvmBackendMode::Binary,
+ OptLevel::Normal | OptLevel::Size | OptLevel::Optimize => LlvmBackendMode::BinaryDev,
};
CodeGenBackend::Llvm(backend_mode)
I'm thinking if we want to modify this behaviour in the cli so we always generate dbg
statements, we'll need to see how that get's threaded through and what it affects.
Anyway... generating dbg
statements when using roc build
enables me to have the graphics platform "pause" when it hits a dbg
statement and await for user input. I thought about more exciting things like a msgbox popup, but it seems raylib doesn't support multiple windows by default and this is ok to to test the idea.
Screenshot 2024-10-17 at 17.33.33.png
The issues is that dbg
and expect
are linked in compiler lowering currently
But expect
is not wired up to the platform interface currently
So it requires running through the roc
executable to function
This does not work with roc build
, so it is set to be stripped out.
The change you made above would probably break if someone added an inline expect.
We could just unlink them to fix this, though the more full fix is to update expect
to work the the platform api and then keep both by default
I'm ok with a quick fix. I think it will be pretty helpful for graphics users to have even something basic working.
Is this something I could implement?
Is the plan to make dbg always included?
If so, I think you just have to delete the conditional on line 3563 of llvm/build.rs
Though I know there are other pieces to actually including/generating expect and dbg. So not 100% sure that will be engouh
That works. Thank you @Brendan Hansknecht
The next issue is that for some reason it seems like roc_dbg is getting called many times...
LLVM IR looks ok, like just one call in init
... (as in there are no other calls to dbg anywhere)
define internal fastcc { { { i32, i32 }, {} }, {} } @"#UserApp_init_7ceb2e607d153edd175217b82e8ded113c6e4df27e27777d9f9694c716aa427"() !dbg !269 {
entry:
%const_str_store1 = alloca %str.RocStr, align 8
%const_str_store = alloca %str.RocStr, align 8
%result_value = alloca %str.RocStr, align 8
call fastcc void @Inspect_toStr_21b5c7d5305aa5ff4df495f05c9e59c37d76367eacec9dd321a0e78143dfc4a3(i64 1234, ptr nonnull %result_value), !dbg !270
store ptr getelementptr inbounds ([36 x i8], ptr @_str_literal_5112864010422196678, i64 0, i64 8), ptr %const_str_store, align 8, !dbg !270
%const_str_store.repack6 = getelementptr inbounds %str.RocStr, ptr %const_str_store, i64 0, i32 1, !dbg !270
store i64 28, ptr %const_str_store.repack6, align 8, !dbg !270
%const_str_store.repack7 = getelementptr inbounds %str.RocStr, ptr %const_str_store, i64 0, i32 2, !dbg !270
store i64 28, ptr %const_str_store.repack7, align 8, !dbg !270
store ptr inttoptr (i64 875770417 to ptr), ptr %const_str_store1, align 8, !dbg !270
%const_str_store1.repack8 = getelementptr inbounds %str.RocStr, ptr %const_str_store1, i64 0, i32 1, !dbg !270
store i64 0, ptr %const_str_store1.repack8, align 8, !dbg !270
%const_str_store1.repack9 = getelementptr inbounds %str.RocStr, ptr %const_str_store1, i64 0, i32 2, !dbg !270
store i64 -8935141660703064064, ptr %const_str_store1.repack9, align 8, !dbg !270
call void @roc_dbg(ptr %const_str_store, ptr %result_value, ptr %const_str_store1), !dbg !270
call fastcc void @"#Attr_#dec_8"(ptr nonnull %result_value), !dbg !270
%call = call fastcc float @"#UserApp_height_8256d790c99390129cd6628d4d43bc44f55cfb83af722d8248666b192be24d65"(), !dbg !270
%call2 = call fastcc float @"#UserApp_width_6fdff3e812be393e397a32aeb76ae96155b45793f22c8c7f8b12de3628ba863"(), !dbg !270
%insert_record_field = insertvalue { float, float } zeroinitializer, float %call, 0, !dbg !270
%insert_record_field3 = insertvalue { float, float } %insert_record_field, float %call2, 1, !dbg !270
%call4 = call fastcc { { i32, i32 }, {} } @RocRay_setWindowSize_5c8e2eddb65717d2b7a69c4d944bbaab3db37fe30ea4d8f6e4bc9d32cef({ float, float } %insert_record_field3), !dbg !270
%call5 = call fastcc { { { i32, i32 }, {} }, {} } @Task_await_f411d2d207cb75ff49124b128ee5a4cdec2daf8d1cf0a733c3c7d426729b6b({ { i32, i32 }, {} } %call4, {} zeroinitializer), !dbg !270
ret { { { i32, i32 }, {} }, {} } %call5, !dbg !270
}
Here is the impl
#[no_mangle]
pub unsafe extern "C" fn roc_dbg(loc: &RocStr, msg: &RocStr) {
let msg = CString::new(format!("[{}] {}\n", loc, msg)).unwrap();
bindings::TraceLog(bindings::TraceLogLevel_LOG_DEBUG as i32, msg.as_ptr());
}
and this is what I see when I run the program...
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
.... etc
Same behaviour with
#[no_mangle]
pub unsafe extern "C" fn roc_dbg(loc: &RocStr, msg: &RocStr) {
eprintln!("[{}] {}", loc, msg);
}
I realised the roc_dbg takes three pointers from reading the LLVM... so fixed that... but still get the same repeated calls
#[no_mangle]
pub unsafe extern "C" fn roc_dbg(loc: &RocStr, msg: &RocStr, src: &RocStr) {
let msg = CString::new(format!("[{}] {} = {}", loc, src, msg)).unwrap();
bindings::TraceLog(bindings::TraceLogLevel_LOG_DEBUG as i32, msg.as_ptr());
}
I need to get back to investigating this. It's such a helpful tool to have print debugging available and we're currently missing it in roc-ray.
Last updated: Jul 06 2025 at 12:14 UTC