Build each object's dependencies, not every object's
The deps artifact was one derivation for the whole workspace, and the
sharing was the point: three objects, one dependency build. What it cost
stayed invisible until a consumer wanted only some of them.
jolt-moq brings moq-net, iroh, quinn, rustls and aws-lc-sys behind it. A
build of libvidya alone still paid for all of it -- and a client that has
stopped loading libjoltmoq paid for it too, which is the case that made
this worth splitting. frq is that client now: its media plane is jolt over
libmoq_ffi, libopus and openh264, and it takes only libvidya and
libjolttui from here.
whole workspace lock 810 crates
vidya + tui 146
no longer built 394
Split by CONSUMER rather than per package. vidya and tui share nearly
everything, so an artifact each would trade one kind of waste for another;
two groups is where the line actually falls.
The workspace-wide artifact stays for clippy and the test run, which do
build everything and do want the sharing this gives up.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>2975a43 parent: d970307 modified
flake.nix +40 -4 | @@ -132,8 +132,40 @@ | ||
| 132 | 132 | buildInputs = desktopBuildInputs; |
| 133 | 133 | } // v4l2Env; |
| 134 | 134 | |
| 135 | - # Every external crate, compiled once and shared by the three objects, | |
| 136 | - # the clippy run and the test run. | |
| 135 | + # Every external crate, compiled once and shared by the objects that | |
| 136 | + # actually want it. | |
| 137 | + # | |
| 138 | + # This used to be ONE derivation for the whole workspace, and the | |
| 139 | + # sharing was the point: three objects, one dependency build. What it | |
| 140 | + # cost was invisible until a consumer wanted only some of them. | |
| 141 | + # jolt-moq brings moq-net, iroh, quinn, rustls and aws-lc-sys behind | |
| 142 | + # it -- 440 crates that nothing else here touches -- so a build of | |
| 143 | + # libvidya alone still paid for the media plane. A client that has | |
| 144 | + # stopped loading libjoltmoq paid for it too, which is the case that | |
| 145 | + # made this worth splitting. | |
| 146 | + # | |
| 147 | + # Split by CONSUMER rather than per package: vidya and tui share | |
| 148 | + # nearly everything, and giving them an artifact each would trade one | |
| 149 | + # kind of waste for another. | |
| 150 | + depsFor = { pname, packages }: | |
| 151 | + craneLib.buildDepsOnly (commonArgs // { | |
| 152 | + inherit pname; | |
| 153 | + version = "0.1.0"; | |
| 154 | + cargoExtraArgs = | |
| 155 | + "--locked " + lib.concatMapStringsSep " " (p: "-p " + p) packages; | |
| 156 | + }); | |
| 157 | + | |
| 158 | + uiArtifacts = depsFor { | |
| 159 | + pname = "jolt-native-ui-deps"; | |
| 160 | + packages = [ "vidya-ffi" "jolt-tui" ]; | |
| 161 | + }; | |
| 162 | + moqArtifacts = depsFor { | |
| 163 | + pname = "jolt-native-moq-deps"; | |
| 164 | + packages = [ "jolt-moq" ]; | |
| 165 | + }; | |
| 166 | + | |
| 167 | + # The whole workspace, for the clippy and test runs — those do build | |
| 168 | + # everything, and want the sharing this split gives up. | |
| 137 | 169 | cargoArtifacts = craneLib.buildDepsOnly (commonArgs // { |
| 138 | 170 | pname = "jolt-native-deps"; |
| 139 | 171 | version = "0.1.0"; |
| @@ -147,9 +179,10 @@ | ||
| 147 | 179 | # crates/jolt-vidya. Nothing is silenced — a header that stops being |
| 148 | 180 | # there should fail the build rather than ship an object with no ABI |
| 149 | 181 | # beside it. |
| 150 | - soPackage = { pname, package, dir, soname }: | |
| 182 | + soPackage = { pname, package, dir, soname, artifacts }: | |
| 151 | 183 | craneLib.buildPackage (commonArgs // { |
| 152 | - inherit pname cargoArtifacts; | |
| 184 | + inherit pname; | |
| 185 | + cargoArtifacts = artifacts; | |
| 153 | 186 | version = "0.1.0"; |
| 154 | 187 | cargoExtraArgs = "--locked -p ${package}"; |
| 155 | 188 | doCheck = false; |
| @@ -161,18 +194,21 @@ | ||
| 161 | 194 | }); |
| 162 | 195 | |
| 163 | 196 | libvidya = soPackage { |
| 197 | + artifacts = uiArtifacts; | |
| 164 | 198 | pname = "libvidya"; |
| 165 | 199 | package = "vidya-ffi"; |
| 166 | 200 | dir = "jolt-vidya"; |
| 167 | 201 | soname = "libvidya.so"; |
| 168 | 202 | }; |
| 169 | 203 | libjolttui = soPackage { |
| 204 | + artifacts = uiArtifacts; | |
| 170 | 205 | pname = "libjolttui"; |
| 171 | 206 | package = "jolt-tui"; |
| 172 | 207 | dir = "jolt-tui"; |
| 173 | 208 | soname = "libjolttui.so"; |
| 174 | 209 | }; |
| 175 | 210 | libjoltmoq = soPackage { |
| 211 | + artifacts = moqArtifacts; | |
| 176 | 212 | pname = "libjoltmoq"; |
| 177 | 213 | package = "jolt-moq"; |
| 178 | 214 | dir = "jolt-moq"; |
| @@ -132,8 +132,40 @@ | |||
| 132 | buildInputs = desktopBuildInputs; | 132 | buildInputs = desktopBuildInputs; |
| 133 | } // v4l2Env; | 133 | } // v4l2Env; |
| 134 | 134 | ||
| 135 | - # Every external crate, compiled once and shared by the three objects, | 135 | + # Every external crate, compiled once and shared by the objects that |
| 136 | - # the clippy run and the test run. | 136 | + # actually want it. |
| 137 | + # | ||
| 138 | + # This used to be ONE derivation for the whole workspace, and the | ||
| 139 | + # sharing was the point: three objects, one dependency build. What it | ||
| 140 | + # cost was invisible until a consumer wanted only some of them. | ||
| 141 | + # jolt-moq brings moq-net, iroh, quinn, rustls and aws-lc-sys behind | ||
| 142 | + # it -- 440 crates that nothing else here touches -- so a build of | ||
| 143 | + # libvidya alone still paid for the media plane. A client that has | ||
| 144 | + # stopped loading libjoltmoq paid for it too, which is the case that | ||
| 145 | + # made this worth splitting. | ||
| 146 | + # | ||
| 147 | + # Split by CONSUMER rather than per package: vidya and tui share | ||
| 148 | + # nearly everything, and giving them an artifact each would trade one | ||
| 149 | + # kind of waste for another. | ||
| 150 | + depsFor = { pname, packages }: | ||
| 151 | + craneLib.buildDepsOnly (commonArgs // { | ||
| 152 | + inherit pname; | ||
| 153 | + version = "0.1.0"; | ||
| 154 | + cargoExtraArgs = | ||
| 155 | + "--locked " + lib.concatMapStringsSep " " (p: "-p " + p) packages; | ||
| 156 | + }); | ||
| 157 | + | ||
| 158 | + uiArtifacts = depsFor { | ||
| 159 | + pname = "jolt-native-ui-deps"; | ||
| 160 | + packages = [ "vidya-ffi" "jolt-tui" ]; | ||
| 161 | + }; | ||
| 162 | + moqArtifacts = depsFor { | ||
| 163 | + pname = "jolt-native-moq-deps"; | ||
| 164 | + packages = [ "jolt-moq" ]; | ||
| 165 | + }; | ||
| 166 | + | ||
| 167 | + # The whole workspace, for the clippy and test runs — those do build | ||
| 168 | + # everything, and want the sharing this split gives up. | ||
| 137 | cargoArtifacts = craneLib.buildDepsOnly (commonArgs // { | 169 | cargoArtifacts = craneLib.buildDepsOnly (commonArgs // { |
| 138 | pname = "jolt-native-deps"; | 170 | pname = "jolt-native-deps"; |
| 139 | version = "0.1.0"; | 171 | version = "0.1.0"; |
| @@ -147,9 +179,10 @@ | |||
| 147 | # crates/jolt-vidya. Nothing is silenced — a header that stops being | 179 | # crates/jolt-vidya. Nothing is silenced — a header that stops being |
| 148 | # there should fail the build rather than ship an object with no ABI | 180 | # there should fail the build rather than ship an object with no ABI |
| 149 | # beside it. | 181 | # beside it. |
| 150 | - soPackage = { pname, package, dir, soname }: | 182 | + soPackage = { pname, package, dir, soname, artifacts }: |
| 151 | craneLib.buildPackage (commonArgs // { | 183 | craneLib.buildPackage (commonArgs // { |
| 152 | - inherit pname cargoArtifacts; | 184 | + inherit pname; |
| 185 | + cargoArtifacts = artifacts; | ||
| 153 | version = "0.1.0"; | 186 | version = "0.1.0"; |
| 154 | cargoExtraArgs = "--locked -p ${package}"; | 187 | cargoExtraArgs = "--locked -p ${package}"; |
| 155 | doCheck = false; | 188 | doCheck = false; |
| @@ -161,18 +194,21 @@ | |||
| 161 | }); | 194 | }); |
| 162 | 195 | ||
| 163 | libvidya = soPackage { | 196 | libvidya = soPackage { |
| 197 | + artifacts = uiArtifacts; | ||
| 164 | pname = "libvidya"; | 198 | pname = "libvidya"; |
| 165 | package = "vidya-ffi"; | 199 | package = "vidya-ffi"; |
| 166 | dir = "jolt-vidya"; | 200 | dir = "jolt-vidya"; |
| 167 | soname = "libvidya.so"; | 201 | soname = "libvidya.so"; |
| 168 | }; | 202 | }; |
| 169 | libjolttui = soPackage { | 203 | libjolttui = soPackage { |
| 204 | + artifacts = uiArtifacts; | ||
| 170 | pname = "libjolttui"; | 205 | pname = "libjolttui"; |
| 171 | package = "jolt-tui"; | 206 | package = "jolt-tui"; |
| 172 | dir = "jolt-tui"; | 207 | dir = "jolt-tui"; |
| 173 | soname = "libjolttui.so"; | 208 | soname = "libjolttui.so"; |
| 174 | }; | 209 | }; |
| 175 | libjoltmoq = soPackage { | 210 | libjoltmoq = soPackage { |
| 211 | + artifacts = moqArtifacts; | ||
| 176 | pname = "libjoltmoq"; | 212 | pname = "libjoltmoq"; |
| 177 | package = "jolt-moq"; | 213 | package = "jolt-moq"; |
| 178 | dir = "jolt-moq"; | 214 | dir = "jolt-moq"; |