|
23 | 23 | file = ./rust-toolchain.toml; |
24 | 24 | sha256 = "sha256-Qxt8XAuaUR2OMdKbN4u8dBJOhSHxS+uS06Wl9+flVEk="; |
25 | 25 | }; |
| 26 | + |
| 27 | + # Helper function to build the native Ruby recorder for a given pkgs and Ruby. |
| 28 | + # Consumers can call this with their own nixpkgs and Ruby version to ensure |
| 29 | + # ABI compatibility (the native .so must match the Ruby that loads it). |
| 30 | + mkRubyRecorderPackage = pkgs: ruby: let |
| 31 | + inherit (pkgs) stdenv lib; |
| 32 | + isLinux = stdenv.isLinux; |
| 33 | + in stdenv.mkDerivation { |
| 34 | + pname = "ruby-recorder-native"; |
| 35 | + version = builtins.readFile ./version.txt; |
| 36 | + |
| 37 | + src = ./.; |
| 38 | + |
| 39 | + nativeBuildInputs = [ |
| 40 | + pkgs.rustc |
| 41 | + pkgs.cargo |
| 42 | + pkgs.rustPlatform.cargoSetupHook |
| 43 | + ruby # build.rs runs `ruby` to discover RbConfig paths |
| 44 | + pkgs.pkg-config |
| 45 | + pkgs.capnproto # codetracer_trace_format_capnp build.rs needs capnp |
| 46 | + pkgs.llvmPackages.libclang # bindgen (used by rb-sys) needs libclang |
| 47 | + ] ++ lib.optionals stdenv.isDarwin [ |
| 48 | + pkgs.libiconv |
| 49 | + pkgs.darwin.apple_sdk.frameworks.CoreFoundation |
| 50 | + pkgs.darwin.apple_sdk.frameworks.Security |
| 51 | + ]; |
| 52 | + |
| 53 | + buildInputs = [ ruby ]; |
| 54 | + |
| 55 | + # bindgen needs LIBCLANG_PATH to find libclang.so |
| 56 | + LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; |
| 57 | + |
| 58 | + # bindgen also needs C standard headers (stdio.h, stddef.h, etc.) |
| 59 | + BINDGEN_EXTRA_CLANG_ARGS = lib.optionalString isLinux ( |
| 60 | + builtins.concatStringsSep " " [ |
| 61 | + "-isystem ${stdenv.cc.libc.dev}/include" |
| 62 | + "-isystem ${pkgs.llvmPackages.libclang.lib}/lib/clang/${lib.versions.major pkgs.llvmPackages.libclang.version}/include" |
| 63 | + ] |
| 64 | + ); |
| 65 | + |
| 66 | + cargoDeps = pkgs.rustPlatform.importCargoLock { |
| 67 | + lockFile = ./gems/codetracer-ruby-recorder/ext/native_tracer/Cargo.lock; |
| 68 | + }; |
| 69 | + |
| 70 | + postUnpack = '' |
| 71 | + # cargoSetupHook expects Cargo.lock at the source root |
| 72 | + cp $sourceRoot/gems/codetracer-ruby-recorder/ext/native_tracer/Cargo.lock \ |
| 73 | + $sourceRoot/Cargo.lock |
| 74 | + ''; |
| 75 | + |
| 76 | + preBuild = '' |
| 77 | + cd gems/codetracer-ruby-recorder/ext/native_tracer |
| 78 | + ''; |
| 79 | + |
| 80 | + buildPhase = '' |
| 81 | + runHook preBuild |
| 82 | + cargo build --release --offline |
| 83 | + runHook postBuild |
| 84 | + ''; |
| 85 | + |
| 86 | + installPhase = '' |
| 87 | + GEM_ROOT="$NIX_BUILD_TOP/$sourceRoot/gems/codetracer-ruby-recorder" |
| 88 | +
|
| 89 | + # Preserve gems/ path component — the native recorder's should_ignore_path() |
| 90 | + # in Rust uses "gems/" as an ignore pattern to avoid tracing kernel_patches.rb. |
| 91 | + mkdir -p $out/gems/bin $out/gems/lib/codetracer $out/gems/ext/native_tracer/target/release |
| 92 | +
|
| 93 | + # Copy compiled .so (Rust cdylib produces lib<name>.so on Linux, lib<name>.dylib on macOS) |
| 94 | + local dlext="${if isLinux then "so" else "dylib"}" |
| 95 | + cp target/release/libcodetracer_ruby_recorder.$dlext \ |
| 96 | + $out/gems/ext/native_tracer/target/release/ |
| 97 | + # Create the name the Ruby wrapper expects (codetracer_ruby_recorder.<dlext>) |
| 98 | + ln -s libcodetracer_ruby_recorder.$dlext \ |
| 99 | + $out/gems/ext/native_tracer/target/release/codetracer_ruby_recorder.$dlext |
| 100 | +
|
| 101 | + # Copy Ruby wrapper files |
| 102 | + cp "$GEM_ROOT/lib/codetracer_ruby_recorder.rb" $out/gems/lib/ |
| 103 | + cp "$GEM_ROOT/lib/codetracer/kernel_patches.rb" $out/gems/lib/codetracer/ |
| 104 | +
|
| 105 | + # Copy bin entry script |
| 106 | + cp "$GEM_ROOT/bin/codetracer-ruby-recorder" $out/gems/bin/ |
| 107 | +
|
| 108 | + # Top-level bin/ symlink so consumers' symlinkJoin picks it up |
| 109 | + mkdir -p $out/bin |
| 110 | + ln -s $out/gems/bin/codetracer-ruby-recorder $out/bin/codetracer-ruby-recorder |
| 111 | + ''; |
| 112 | + |
| 113 | + doCheck = false; |
| 114 | + }; |
26 | 115 | in { |
| 116 | + # Expose the helper function for consumers who need a custom Ruby version |
| 117 | + lib.mkRubyRecorderPackage = mkRubyRecorderPackage; |
| 118 | + |
27 | 119 | checks = forEachSystem (system: { |
28 | 120 | pre-commit-check = pre-commit-hooks.lib.${system}.run { |
29 | 121 | src = ./.; |
|
104 | 196 |
|
105 | 197 | packages = forEachSystem (system: let |
106 | 198 | pkgs = import nixpkgs { inherit system; }; |
107 | | - buildGem = gemdir: pkgs.rubyPackages.buildRubyGem { |
108 | | - pname = builtins.baseNameOf gemdir; |
109 | | - version = builtins.readFile ./version.txt; |
110 | | - src = gemdir; |
111 | | - }; |
| 199 | + ruby = pkgs.ruby; |
112 | 200 | in { |
113 | | - codetracer-ruby-recorder = buildGem ./gems/codetracer-ruby-recorder; |
114 | | - codetracer-pure-ruby-recorder = buildGem ./gems/codetracer-pure-ruby-recorder; |
| 201 | + # Native Rust extension-based recorder (default) |
| 202 | + codetracer-ruby-recorder = mkRubyRecorderPackage pkgs ruby; |
115 | 203 | default = self.packages.${system}.codetracer-ruby-recorder; |
| 204 | + |
| 205 | + # Pure Ruby recorder (fallback, no compilation needed) |
| 206 | + codetracer-pure-ruby-recorder = pkgs.stdenv.mkDerivation { |
| 207 | + pname = "ruby-recorder-pure"; |
| 208 | + version = builtins.readFile ./version.txt; |
| 209 | + src = ./.; |
| 210 | + dontInstall = true; |
| 211 | + buildPhase = '' |
| 212 | + mkdir -p $out/gems/bin $out/gems/lib |
| 213 | + cp -Lr ./gems/codetracer-pure-ruby-recorder/bin/codetracer-pure-ruby-recorder $out/gems/bin/ |
| 214 | + cp -Lr ./gems/codetracer-pure-ruby-recorder/lib/* $out/gems/lib/ |
| 215 | + mkdir -p $out/bin |
| 216 | + ln -s $out/gems/bin/codetracer-pure-ruby-recorder $out/bin/codetracer-pure-ruby-recorder |
| 217 | + ''; |
| 218 | + }; |
116 | 219 | }); |
117 | 220 | }; |
118 | 221 | } |
0 commit comments