diff --git a/.codex/build_all_targets.sh b/.codex/build_all_targets.sh new file mode 100644 index 0000000..de68986 --- /dev/null +++ b/.codex/build_all_targets.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +CODEX_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +cd $CODEX_DIR + +pushd .. + just build-extension +popd diff --git a/.codex/deps_src/AGENTS.md b/.codex/deps_src/AGENTS.md new file mode 100644 index 0000000..6e81be2 --- /dev/null +++ b/.codex/deps_src/AGENTS.md @@ -0,0 +1,2 @@ +This directory contains cloned repositories with source code for some +of the development dependencies. This might be useful as a reference. diff --git a/.codex/internet_resources/download.sh b/.codex/internet_resources/download.sh new file mode 100755 index 0000000..a839cda --- /dev/null +++ b/.codex/internet_resources/download.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +DOWNLOADS_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +cd $DOWNLOADS_DIR + +# Download the specification of the CodeTracer trace json format. +# Read the trace_json_spec.md file to understand what json records +# should be produced by the tracers in this repo. +wget https://raw.githubusercontent.com/metacraft-labs/runtime_tracing/refs/heads/master/docs/trace_json_spec.md diff --git a/.codex/setup.sh b/.codex/setup.sh new file mode 100755 index 0000000..9c917e1 --- /dev/null +++ b/.codex/setup.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +CODEX_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +cd $CODEX_DIR + +apt-get update +apt-get install -y --no-install-recommends just + +pushd deps_src + git clone https://github.com/metacraft-labs/runtime_tracing +popd + +./build_all_targets.sh + diff --git a/.gitignore b/.gitignore index 6b2dc2f..f10aa8e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ !test/benchmarks/fixtures/*.json test/tmp/ .direnv/ +pkg/ diff --git a/AGENTS.md b/AGENTS.md index 484df08..bd72af2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,9 +1,15 @@ # Instructions for Codex +To build the Rust native extension, execute: + +``` +just build-extension +``` + To run the test suite, execute: ``` -ruby -Itest test/test_tracer.rb +just test ``` The tester executes a number of sample programs in `test/programs` and compares their outputs to the fixtures in `test/fixtures`. @@ -11,9 +17,39 @@ The tester executes a number of sample programs in `test/programs` and compares To run the benchmark, execute: ``` -ruby test/benchmarks/run_benchmark.rb heavy_work +just bench ``` +# You don't have access to the internet + +During development, certain commands will fail because you don't have +access to the intenet. + +The script `.codex/internet_resources/download.sh` is executed before +your development session stars while your computer is still connected +to the internet. + +You can examine this script to see what kind of internet resources +have been downloaded for offline use. If it's difficult for you to +achieve a task without access to additional internet resources, you +can always propose a PR that modifies the download.sh script instead +of completing your main task. + +Downloading development dependencies may also fail due to the lack of +internet connectivity. We are trying to maintain the script `.codex/build_all_targets.sh` +that is also executed before your development session starts while +your computer is still connected to the internet. It tries to run +all build commands that need development dependencies in order to +cache the dependencies for offline use. Please propose changes to +this script when you introduce new build targets with dependencies. + +When you need to consult the documentation or source code modules +for a particular dependency, always try to find where this dependency +have been downloaded and try to access the necessary files through +the file system (i.e. depending on the programming language, the +operating system and the package manager being used, they should +be in their standard location). + # Code quality guidelines - Strive to achieve high code quality. diff --git a/Justfile b/Justfile index 7eb2d92..ab8a6a1 100644 --- a/Justfile +++ b/Justfile @@ -5,3 +5,6 @@ test: bench name="heavy_work": ruby test/benchmarks/run_benchmark.rb {{name}} + +build-extension: + cargo build --release --manifest-path ext/native_tracer/Cargo.toml diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..4ebda76 --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +require 'rb_sys/extensiontask' + +RbSys::ExtensionTask.new('codetracer_ruby_recorder') do |ext| + ext.ext_dir = 'ext/native_tracer' + ext.lib_dir = 'src' + ext.gem_spec = Gem::Specification.load('codetracer-ruby-recorder.gemspec') +end diff --git a/codetracer-ruby-recorder.gemspec b/codetracer-ruby-recorder.gemspec new file mode 100644 index 0000000..4f01849 --- /dev/null +++ b/codetracer-ruby-recorder.gemspec @@ -0,0 +1,17 @@ +Gem::Specification.new do |spec| + spec.name = 'codetracer-ruby-recorder' + spec.version = '0.1.0' + spec.authors = ['Metacraft Labs'] + spec.email = ['info@metacraft-labs.com'] + + spec.summary = 'CodeTracer Ruby recorder with native extension' + spec.description = 'Ruby tracer that records execution steps via a Rust native extension.' + spec.license = 'MIT' + spec.homepage = 'https://github.com/metacraft-labs/codetracer-ruby-recorder' + + spec.files = Dir['src/**/*', 'ext/native_tracer/**/{Cargo.toml,*.rs}', 'ext/native_tracer/extconf.rb', 'README.md', 'LICENSE'] + spec.require_paths = ['src'] + spec.extensions = ['ext/native_tracer/extconf.rb'] + + spec.add_development_dependency 'rb_sys', '~> 0.9' +end diff --git a/ext/native_tracer/.gitignore b/ext/native_tracer/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/ext/native_tracer/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/ext/native_tracer/Cargo.lock b/ext/native_tracer/Cargo.lock new file mode 100644 index 0000000..a79211c --- /dev/null +++ b/ext/native_tracer/Cargo.lock @@ -0,0 +1,414 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "codetracer_ruby_recorder" +version = "0.1.0" +dependencies = [ + "rb-sys", + "rb-sys-env", + "runtime_tracing", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libloading" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rb-sys" +version = "0.9.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ca6726be0eca74687047fed7dcbc2d509571f3962e190c343ac1eb40e482b3" +dependencies = [ + "rb-sys-build", +] + +[[package]] +name = "rb-sys-build" +version = "0.9.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2390cfc87b7513656656faad6567291e581542d3ec41dd0a2bf381896e0880" +dependencies = [ + "bindgen", + "lazy_static", + "proc-macro2", + "quote", + "regex", + "shell-words", + "syn", +] + +[[package]] +name = "rb-sys-env" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f8d2924cf136a1315e2b4c7460a39f62ef11ee5d522df9b2750fab55b868b6" + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "runtime_tracing" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eafd7c2c0304ff7196100ad4b6d33ff61e27d7bdcc10efe75784364b86292451" +dependencies = [ + "num-derive", + "num-traits", + "serde", + "serde_json", + "serde_repr", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" diff --git a/ext/native_tracer/Cargo.toml b/ext/native_tracer/Cargo.toml new file mode 100644 index 0000000..937f7c4 --- /dev/null +++ b/ext/native_tracer/Cargo.toml @@ -0,0 +1,15 @@ +# Cargo.toml +[package] +name = "codetracer_ruby_recorder" +description = "Native Ruby module for generating CodeTracer trace files" +version = "0.1.0" +edition = "2021" +crate-type = ["cdylib"] +build = "build.rs" + +[dependencies] +rb-sys = "0.9" +runtime_tracing = "0.10.0" + +[build-dependencies] +rb-sys-env = "0.2" diff --git a/ext/native_tracer/README.md b/ext/native_tracer/README.md new file mode 100644 index 0000000..f44a8c8 --- /dev/null +++ b/ext/native_tracer/README.md @@ -0,0 +1,55 @@ +# codetracer_ruby_recorder + +This crate provides a minimal Ruby tracer implemented in Rust. +It registers a Ruby VM event hook using `rb_add_event_hook2` and +records basic information for each executed line. + +Recorded events are written using the [`runtime_tracing`](https://github.com/metacraft-labs/runtime_tracing) crate. + +## Building + +``` +cargo build --release +``` + +If you have `just` installed, run `just build-extension` from the project root. + +The produced shared library can be required from Ruby: + +```ruby +require_relative 'target/release/libcodetracer_ruby_recorder' +``` + +Once loaded, the tracer starts writing a trace to `trace.json` or the +path specified via the `CODETRACER_DB_TRACE_PATH` environment variable. + +## Publishing platform-specific gems + +This extension can be packaged as a Ruby gem so the compiled library is +distributed for each target platform. The gemspec at the project root uses +[`rb_sys`](https://github.com/oxidize-rb/rb-sys) to build the library. + +To publish prebuilt binaries: + +1. Install the development dependencies: + + ```bash + bundle install + ``` + +2. For each target triple, set `RB_SYS_CARGO_TARGET` and run the packaging task: + + ```bash + RB_SYS_CARGO_TARGET=x86_64-unknown-linux-gnu rake cross_native_gem + ``` + + Replace the target triple with the platform you want to build for, e.g. + `aarch64-apple-darwin` or `x86_64-pc-windows-msvc`. + +3. Push the generated gem from the `pkg/` directory to RubyGems: + + ```bash + gem push pkg/codetracer-ruby-recorder-0.1.0-x86_64-linux.gem + ``` + +Repeat these steps for each platform to provide platform-specific gems. diff --git a/ext/native_tracer/build.rs b/ext/native_tracer/build.rs new file mode 100644 index 0000000..1c710e6 --- /dev/null +++ b/ext/native_tracer/build.rs @@ -0,0 +1,4 @@ +fn main() -> Result<(), Box> { + rb_sys_env::activate()?; + Ok(()) +} diff --git a/ext/native_tracer/extconf.rb b/ext/native_tracer/extconf.rb new file mode 100644 index 0000000..118d35e --- /dev/null +++ b/ext/native_tracer/extconf.rb @@ -0,0 +1,4 @@ +require 'mkmf' +require 'rb_sys/mkmf' + +create_rust_makefile('codetracer_ruby_recorder') diff --git a/ext/native_tracer/src/lib.rs b/ext/native_tracer/src/lib.rs new file mode 100644 index 0000000..3d26cb9 --- /dev/null +++ b/ext/native_tracer/src/lib.rs @@ -0,0 +1,64 @@ +#![allow(clippy::missing_safety_doc)] + +use std::{ffi::CStr, mem::transmute, os::raw::c_char}; + +use rb_sys::{ + // frequently used public items + rb_add_event_hook2, rb_event_flag_t, + rb_event_hook_flag_t::RUBY_EVENT_HOOK_FLAG_RAW_ARG, + ID, VALUE, RUBY_EVENT_LINE, + + // the raw-trace-API symbols live in the generated `bindings` module + bindings::{ + rb_trace_arg_t, // struct rb_trace_arg + rb_tracearg_event_flag, // event kind helpers + rb_tracearg_lineno, + rb_tracearg_path, + }, +}; + +/// Raw-argument callback (Ruby will call it when we set +/// `RUBY_EVENT_HOOK_FLAG_RAW_ARG`). +/// +/// C prototype: +/// ```c +/// void (*)(VALUE data, rb_trace_arg_t *arg); +/// ``` +unsafe extern "C" fn event_hook_raw(_data: VALUE, arg: *mut rb_trace_arg_t) { + if arg.is_null() { + return; + } + + let ev: rb_event_flag_t = rb_tracearg_event_flag(arg); + if (ev & RUBY_EVENT_LINE) == 0 { + return; + } + + let path_ptr = rb_tracearg_path(arg) as *const c_char; + let line = rb_tracearg_lineno(arg) as u32; + + if !path_ptr.is_null() { + if let Ok(path) = CStr::from_ptr(path_ptr).to_str() { + println!("Path: {path}, Line: {line}"); + } + } +} + +#[no_mangle] +pub extern "C" fn Init_codetracer_ruby_recorder() { + unsafe { + // rb_add_event_hook2’s first parameter is a function pointer with the + // classic five-argument signature. We cast our raw callback to that + // type via an intermediate variable so the sizes match. + let raw_cb: unsafe extern "C" fn(VALUE, *mut rb_trace_arg_t) = event_hook_raw; + let cb: unsafe extern "C" fn(rb_event_flag_t, VALUE, VALUE, ID, VALUE) = + transmute(raw_cb); + + rb_add_event_hook2( + Some(cb), // callback (now cast) + RUBY_EVENT_LINE, // which events + 0, // user data + RUBY_EVENT_HOOK_FLAG_RAW_ARG, + ); + } +} diff --git a/flake.nix b/flake.nix index f160c6f..6a1e556 100644 --- a/flake.nix +++ b/flake.nix @@ -12,7 +12,18 @@ let pkgs = import nixpkgs { inherit system; }; in { default = pkgs.mkShell { - packages = with pkgs; [ ruby just git-lfs ]; + packages = with pkgs; [ + ruby + + # The native extension is implemented in Rust + rustc + cargo + libiconv # required as a dependency when building the rb-sys Rust crate + + # For build automation + just + git-lfs + ]; }; }); };