# Precompiled native code seems unused when a package is sourced from a git rev instead of a local path

**URL:** <https://discourse.julialang.org/t/precompiled-native-code-seems-unused-when-a-package-is-sourced-from-a-git-rev-instead-of-a-local-path/138584>\
**Category:** General Usage\
**Tags:** question, package, modelingtoolkit\
**Created:** [August 3, 2026, 9:31pm UTC](https://discourse.julialang.org/t/precompiled-native-code-seems-unused-when-a-package-is-sourced-from-a-git-rev-instead-of-a-local-path/138584 "2026-08-03T21:31:09Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [August 3, 2026, 9:31pm UTC](https://discourse.julialang.org/t/precompiled-native-code-seems-unused-when-a-package-is-sourced-from-a-git-rev-instead-of-a-local-path/138584/1 "2026-08-03T21:31:10Z")

</div>

On Julia 1.12.6, the same package at the same commit runs ~20x slower when it comes from `Pkg.add(url=..., rev=...)` than from a local `path`. The hot workload is a ModelingToolkit-generated, `RuntimeGeneratedFunctions`-wrapped ODE right-hand side that the package compiles in a `PrecompileTools.@compile_workload`; with the git-rev source it appears to be re-JIT’ed in every fresh process.

Repro ([V3Kite.jl](https://github.com/OpenSourceAWE/V3Kite.jl) v1.0.1, ~3 min precompile per environment, two fresh processes):

```julia

using Pkg; Pkg.activate(tempname())

Pkg.add(url="https://github.com/OpenSourceAWE/V3Kite.jl", rev="v1.0.1")
Pkg.precompile()
using V3Kite; @time init(9.0, 200.0) # 38.2 s

```

Fresh process; local clone of the same repo, checked out at v1.0.1

```julia-auto
using Pkg; Pkg.activate(tempname())

Pkg.develop(path="/path/to/V3Kite.jl")
Pkg.precompile()
using V3Kite; @time init(9.0, 200.0) # 1.8 s

```

| `V3Kite` source | plain `julia --project` | with a PackageCompiler sysimage |
| --- | --- | --- |
| `url` + `rev` | 38.2 s | 33.6 s |
| `path` | 1.77 s | 2.25 s |

Under the git-rev source the workload **does** run: `Pkg.precompile()` logs it executing `init`, and leaves a ~141 MB pkgimage — same size class as the `path` build. So it compiles and is cached to disk, the native code is simply not used at runtime. Ruled out: the system image, the package’s own on-disk model cache, and the `RuntimeGeneratedFunctions` version (identical `git-tree-sha1` in both manifests). Full measurement log incl. the dead ends: [docs/sysimage\_notes.md](https://github.com/OpenSourceAWE/SimpleKiteControllers.jl/blob/main/docs/sysimage_notes.md).

Is this expected — does a git-rev source invalidate RGF-backed precompiled code somehow — or is it a bug?

**Disclaimer:**  
Written by Claude, manually proof-read and corrected

This is somewhat annoying, because it means I can make the original V3Kite package fast, but if I use that package as a dependency in another package it will be slow. Unless I dev it.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [August 4, 2026, 7:26am UTC](https://discourse.julialang.org/t/precompiled-native-code-seems-unused-when-a-package-is-sourced-from-a-git-rev-instead-of-a-local-path/138584/2 "2026-08-04T07:26:14Z")

</div>

> [@ufechner7](#):
>
> does a git-rev source invalidate RGF-backed precompiled

I have seen cases where RGF code does not get cached but that has been when it is put into a sysimage and even that case should have been fixed.

Tell the robot to run with --trace-compile and see what signatures are getting compiled and ask it to try figure out the root cause.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [August 4, 2026, 6:04pm UTC](https://discourse.julialang.org/t/precompiled-native-code-seems-unused-when-a-package-is-sourced-from-a-git-rev-instead-of-a-local-path/138584/3 "2026-08-04T18:04:20Z")

</div>

One more aspect of the issue:

We serialize the simplified model in a bin file. A bin file created from our program without a system image cannot be read by the same program with a system image, and vice versa.

I get the error message:

```julia-auto
Deserialization failed at 1.785854577145231e9
Path: /home/ufechner/.julia/scratchspaces/4caac9c8-c726-438f-ab10-3553e918eab1/v3kite_cache/model_v0.11.1_jl1.12_v3_particle_dir_dynamic_44pnt_95seg_0grp_1wng_1wch.bin
ArgumentError: cannot deserialize a dropped RuntimeGeneratedFunction; serialize it before calling drop_expr
Stacktrace:
  [1] deserialize(s::Serialization.AbstractSerializer, ::Type{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(: ___mtkunknowns___ , : ___mtkparameters___ , :__argₛᵧₘ1249670312406203976), ModelingToolkitBase.var"#_RGF_ModTag", ModelingToolkitBase.var"#_RGF_ModTag", (0xcfd89363, 0x1321e11e, 0x550d3a0b, 0x3787cb31, 0xc00bf369), Nothing}})
    @ RuntimeGeneratedFunctions ~/.julia/packages/RuntimeGeneratedFunctions/odmYb/src/RuntimeGeneratedFunctions.jl:571
  [2] handle_deserialize(s::Serialization.Serializer{IOStream}, b::Int32)
    @ Serialization ~/.julia/juliaup/julia-1.12.6+0.x64.linux.gnu/share/julia/stdlib/v1.12/Serialization/src/Serialization.jl:915
  [3] deserialize(s::Serialization.Serializer{IOStream}, t::DataType)

```

The full error log can be found [here](https://github.com/OpenSourceAWE/SimpleKiteControllers.jl/blob/main/docs/model_v0.11.1_jl1.12_v3_particle_dir_dynamic_44pnt_95seg_0grp_1wng_1wch.bin.error.log).

I already see one potential issue: there might be multiple versions of the bin file in different locations. The file created during pre-compilation is going to a scratchspace, bin files created during normal operation not.

**UPDATE:**  
There are four evironments being used, the main and the examples environment of SimpleKiteControllers, and the main and the examples environment of V3Kite. The main environment of V3Kite still had the broken version of RuntimeGeneratedFunctions. That is fixed now.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [August 5, 2026, 4:09am UTC](https://discourse.julialang.org/t/precompiled-native-code-seems-unused-when-a-package-is-sourced-from-a-git-rev-instead-of-a-local-path/138584/5 "2026-08-05T04:09:29Z")

</div>

### 45 s of re-JIT because precompilation compiled against a **different**  **serialized model**

We had an ODE `init` that cost **45 s** in one environment and **2.5 s** in another, with identical code, identical Manifest, identical system image. The only difference was whether our plant package was sourced by `{url, rev}` or by `{path}`, which made no sense.

It had nothing to do with `[sources]`. The model is a ModelingToolkit system serialized to a `.bin`, so its RHS is a `RuntimeGeneratedFunction` — and **the RGF `id` (a hash of the generated body) is a type parameter**:

```julia-auto
ODEFunction{true, AutoSpecialize, GeneratedFunctionWrapper{(2,3,true),
    RuntimeGeneratedFunction{(...), _RGF_ModTag, _RGF_ModTag, (0xc03b7c9f, 0x507d5098, ...)}}}

```

The package’s `@compile_workload` runs `init`, which caches the **external** specializations keyed to that type into its pkgimage — `DiffEqBase.promote_f` (22 s to compile!), 74 `SymbolicIndexingInterface` observed-getter closures, the RGF `generated_callfunc`’s.

But two independently built model binaries get **different RGF ids**. Ours were:

- `data/*.bin` is gitignored, so a Pkg-installed copy ships no model — the workload builds its own into `scratchspaces/<uuid>/`;
- a `dev`ed checkout instead caches into its own writable `data/`, which is the file our downstream project had copied.

So under `url`/`rev`, every specialization in the pkgimage was keyed to a type that never came into existence at runtime, and all of it re-JIT’ed. Swapping only the `.bin` gives a clean crossover — the source contributes nothing:

| model binary used at runtime | `path` source | `url/rev` source |
| --- | --- | --- |
| built by the dev checkout | **6.2 s** | 47.1 s |
| built by the workload in the scratchspace | 47.1 s | **5.7 s** |

Fix: stop overriding `cache_path`, so the run deserializes exactly the binary the workload compiled against. 44.8 s → 2.9 s, no sysimage, no `dev` needed.

**Lesson:** if your precompile workload deserializes generated code, precompilation only pays off when the runtime loads the _same bytes_. Ship the artifact, or make sure the workload and the run resolve to one cache — otherwise `@compile_workload` is burning 40 s per precompile on code nobody will ever use.
