Skip to content

Commit 28aebf1

Browse files
committed
new build
1 parent c923c21 commit 28aebf1

File tree

1 file changed

+27
-27
lines changed
  • docs/blog/2024/12-12-rust-feature-debugging

1 file changed

+27
-27
lines changed

docs/blog/2024/12-12-rust-feature-debugging/index.html

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,44 +28,44 @@
2828
<div class="hidden">hidden</div>
2929

3030
<h1 class="title">
31-
Rust crate feature debugging
31+
Rust Crate Feature Debugging
3232
</h1>
3333
<div class="content">
34-
<p>In this short post we look at how to debug a recent build breakage we encountered due to a <em>feature</em> being enabled on one of our dependencies that is not compatible with our build target: <strong>wasm</strong>.</p>
35-
<h1 id="what-happened">What happened</h1>
36-
<p>After porting our bevy based game <a href="https://tinytakeoff.com">tinytakeoff</a> to the newest Bevy release: <a href="https://bevyengine.org/news/bevy-0-15/">0.15</a> our build broke with the following error on <strong>wasm</strong>:</p>
34+
<p>In this short post, we will look at how we recently debugged a build breaking due to a <em>feature</em> being enabled on one of our dependencies that is not compatible with one of our build targets: <strong>Wasm</strong>.</p>
35+
<h1 id="what-happened">What Happened</h1>
36+
<p>After porting our Bevy-based game, <a href="https://tinytakeoff.com">TinyTakeoff</a> to the newest Bevy release at the time of writing this, <a href="https://bevyengine.org/news/bevy-0-15/">0.15</a>, our build broke with the following error on <strong>Wasm</strong>:</p>
3737
<pre data-lang="sh" style="background-color:#212121;color:#eeffff;" class="language-sh "><code class="language-sh" data-lang="sh"><span>cargo:warning</span><span style="color:#89ddff;">=</span><span style="color:#c3e88d;">In </span><span style="color:#82aaff;">file included from vendor/basis_universal/encoder/pvpngreader.cpp:14:
3838
</span><span>cargo:warning</span><span style="color:#89ddff;">=</span><span style="color:#c3e88d;">vendor/basis_universal/encoder/../transcoder/basisu.h:53:10: </span><span style="color:#82aaff;">fatal error: </span><span style="color:#89ddff;">&#39;</span><span style="color:#c3e88d;">stdlib.h</span><span style="color:#89ddff;">&#39;</span><span style="color:#82aaff;"> file not found
3939
</span><span>cargo:warning</span><span style="color:#89ddff;">= </span><span style="color:#82aaff;">53 </span><span style="color:#89ddff;">| </span><span style="font-style:italic;color:#4a4a4a;">#include &lt;stdlib.h&gt;
4040
</span><span>cargo:warning</span><span style="color:#89ddff;">= | </span><span style="color:#82aaff;">^</span><span style="font-style:italic;color:#ff5370;">~~~~~~~~~
4141
</span><span>cargo:warning</span><span style="color:#89ddff;">=</span><span style="color:#c3e88d;">1 </span><span style="color:#82aaff;">error generated.
4242
</span></code></pre>
43-
<p>So it looks like some crate is trying to build C-code under the hood which depends on <code>stdlib.h</code>. That is not a problem on native build targets but it won't fly on <strong>wasm</strong>.</p>
44-
<p>This happens in the <code>basis-universal</code> crate, what could that be good for? Reading up on it's <a href="https://crates.io/crates/basis-universal">crates.io page</a> we find out that it is:</p>
43+
<p>Looks like some crate is trying to build C-code under the hood, which depends on <code>stdlib.h</code>. That is not a problem on native build targets, but it won't work on <strong>Wasm</strong>.</p>
44+
<p>This happens in the <code>basis-universal</code> crate. Wonder what that is for? Reading up on its <a href="https://crates.io/crates/basis-universal">crates.io page</a>, we can see that it is:</p>
4545
<blockquote>
4646
<p>Bindings for Binomial LLC's basis-universal Supercompressed GPU Texture Codec</p>
4747
</blockquote>
48-
<p>Looking into the <a href="https://bevyengine.org/learn/migration-guides/0-14-to-0-15">Bevy Migration Guide for 0.14 to 0.15</a> we find exactly one <a href="https://bevyengine.org/learn/migration-guides/0-14-to-0-15/#add-feature-requirement-info-to-image-loading-docs">place</a> of it being mentioned:</p>
48+
<p>Looking into the <a href="https://bevyengine.org/learn/migration-guides/0-14-to-0-15">Bevy Migration Guide for 0.14 to 0.15</a> we find exactly one <a href="https://bevyengine.org/learn/migration-guides/0-14-to-0-15/#add-feature-requirement-info-to-image-loading-docs">place</a> where it is mentioned:</p>
4949
<img src="screen1.png" alt="changelog screenshot" class="centered" style="max-width: 70%"/>
50-
<p>So this dependency is for sure nothing we need as we did not start making use of said image format. How did it get introduced?</p>
51-
<p>Let's find the cause for this.</p>
52-
<h1 id="how-to-find-the-cause">How to find the cause</h1>
53-
<p>We first want to find out where in our tree of dependencies this one is used. <code>cargo tree</code> is the tool to help you analyze your dependencies as the graph structure they make up.</p>
54-
<p>When running <code>cargo tree</code> we get over 1.000 lines of output where we can search for <code>basis-universal</code>:</p>
50+
<p>So, this dependency is nothing that we need or want, given we are not making use of that image format. How did it get introduced into our dependencies in the first place?</p>
51+
<p>Let's dive right in and find out!</p>
52+
<h1 id="how-to-find-the-cause">How to Find the Cause</h1>
53+
<p>We first want to find out <em>where</em> in our dependency tree that <code>basis-universal</code> is brought in from. <code>cargo tree</code> is the tool to help you analyze your dependencies by showing them in a nifty graph structure.</p>
54+
<p>When running <code>cargo tree</code>, we get over 1.000 outputted lines that we have to search, for somewhere inside this haystack is <code>basis-universal</code>:</p>
5555
<pre data-lang="sh" style="background-color:#212121;color:#eeffff;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#82aaff;">│ │ ├── bevy_image v0.15.0
5656
</span><span style="color:#82aaff;">│ │ │ ├── basis-universal v0.3.1
5757
</span><span style="color:#82aaff;">│ │ │ │ ├── basis-universal-sys v0.3.1
5858
</span><span style="color:#82aaff;">│ │ │ │ │ </span><span style="font-style:italic;color:#c792ea;">[</span><span style="color:#82aaff;">build</span><span style="color:#89ddff;">-</span><span style="color:#82aaff;">dependencies</span><span style="font-style:italic;color:#c792ea;">]
5959
</span><span style="color:#82aaff;">│ │ │ │ │ └── cc v1.2.3 (</span><span style="color:#89ddff;">*</span><span>)
6060
</span></code></pre>
61-
<p>We got a winner. It is used by <code>bevy_image</code>. The problem is that we do not know why. Based on the changelog linked above we know it is supposed to be behind a <code>feature</code> flag called <code>basis_universal</code>, looking at our <code>Cargo.toml</code> we do not enable it though.</p>
61+
<p>We got a winner! It is used by <code>bevy_image</code>. The problem now is that we do not know why <code>bevy_image</code> is suddenly bringing this in. Based on the changelog linked above, we know it is supposed to be behind a <code>feature</code> flag on the <code>bevy</code> crate, called <code>basis_universal</code>. Looking at our <code>Cargo.toml</code>, we don't enable it.</p>
6262
<blockquote>
6363
<p>Cargo will enable the minimum subset of <code>features</code> needed so that every dependency using <code>bevy</code> gets the features they ask for.</p>
6464
</blockquote>
65-
<p>The question therefore is: Which crate asks for this feature?</p>
65+
<p>The question therefore is, which crate enables this feature?</p>
6666
<h1 id="playing-cargo-feature-detective">Playing Cargo Feature Detective</h1>
67-
<p>There is a little-known feature in <code>cargo tree</code> that allows us to not only see our dependency tree but also the features that are enabled in each crate.</p>
68-
<p>Running <code>cargo tree -e features</code> in our repository root we get over 3.000 lines of this:</p>
67+
<p>There is a little-known feature in <code>cargo tree</code> that allows us to not only see our dependency tree, but also the features that are enabled in each crate that is pulled in.</p>
68+
<p>Running <code>cargo tree -e features</code> in our repository root, we get over 3.000 lines of this:</p>
6969
<pre data-lang="sh" style="background-color:#212121;color:#eeffff;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#82aaff;">├── winit v0.30.5
7070
</span><span style="color:#82aaff;">│ ├── tracing v0.1.41
7171
</span><span style="color:#82aaff;">│ │ ├── tracing-core v0.1.33
@@ -82,30 +82,30 @@ <h1 id="playing-cargo-feature-detective">Playing Cargo Feature Detective</h1>
8282
</span><span style="color:#82aaff;">│ │ └── tracing-attributes feature </span><span style="color:#89ddff;">&quot;</span><span style="color:#c3e88d;">default</span><span style="color:#89ddff;">&quot;
8383
</span><span style="color:#82aaff;">│ │ └── tracing-attributes v0.1.28 (proc-macro</span><span>)
8484
</span></code></pre>
85-
<p>Luckily we now know already what feature we are looking for: <code>basis-universal</code>, so let's search for <code>bevy feature "basis-universal"</code>:</p>
85+
<p>Luckily, we now know what feature we are looking for, <code>basis-universal</code>. So, let's search for <code>bevy feature "basis-universal"</code>:</p>
8686
<pre data-lang="sh" style="background-color:#212121;color:#eeffff;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#82aaff;">├── bevy_libgdx_atlas feature </span><span style="color:#89ddff;">&quot;</span><span style="color:#c3e88d;">default</span><span style="color:#89ddff;">&quot;
8787
</span><span style="color:#82aaff;">│ └── bevy_libgdx_atlas v0.3.0
8888
</span><span style="color:#82aaff;">│ ├── bevy feature </span><span style="color:#89ddff;">&quot;</span><span style="color:#c3e88d;">basis-universal</span><span style="color:#89ddff;">&quot;
8989
</span><span style="color:#82aaff;">│ │ ├── bevy v0.15.0 (</span><span style="color:#89ddff;">*</span><span>)
9090
</span></code></pre>
91-
<p>Here we go. Our own crate <code>bevy_libgdx_atlas</code> enables the feature <code>basis-universal</code> which in turn enables the dependency <code>basis-universal</code> which breaks our build on <strong>wasm</strong>. That makes it easier to fix. Funny enough it was used to enable <code>bevy_image</code> while trying to depend on the smallest subset of features of <code>bevy</code>. This is a known issue in Bevy 0.15, see <a href="https://github.com/bevyengine/bevy/issues/16563">#16563</a>. But there is a cleaner workaround by just enabling the <code>bevy_image</code> feature in <code>bevy_internal</code> see <a href="https://github.com/rustunit/bevy_libgdx_atlas/commit/20cb2e99ef8dd696dfbbff3ef120591cae82703b">here</a>.</p>
92-
<h2 id="improving-ergonomics">Improving ergonomics</h2>
93-
<p>In case you run into multiple crates doing this and depending on said feature it is more ergonomic to invert the tree using: <code>cargo tree -e features -p bevy --invert</code>.
94-
With this we limit our root to <code>bevy</code> and we will find <em>one</em> entry for the feature and a subtree of dependencies using it:</p>
91+
<p>There we go, and would you look at that? One of our own crates, <code>bevy_libgdx_atlas</code>, enables the feature <code>basis-universal</code>, which in turn enables the dependency <code>basis-universal</code>, which then breaks our build on <strong>Wasm</strong>. At least it being our own crate will make it easier to fix this time around. Funnily enough, it was used to enable <code>bevy_image</code> while trying to depend on the smallest subset of features of <code>bevy</code>. This is a known issue in Bevy 0.15, see <a href="https://github.com/bevyengine/bevy/issues/16563">#16563</a>, but, luckily, there is a cleaner workaround to this issue. You just need to enable the <code>bevy_image</code> feature in <code>bevy_internal</code> see <a href="https://github.com/rustunit/bevy_libgdx_atlas/commit/20cb2e99ef8dd696dfbbff3ef120591cae82703b">here</a>.</p>
92+
<h2 id="improving-ergonomics">Improving Ergonomics</h2>
93+
<p>In case you run into multiple crates enabling an unwanted feature, it can be more ergonomic to invert the tree using: <code>cargo tree -e features -p bevy --invert</code>.
94+
With this command, we limit our root to <code>bevy</code>, and we will find <em>one</em> entry for the feature, and a subtree of dependencies using it:</p>
9595
<pre data-lang="sh" style="background-color:#212121;color:#eeffff;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#82aaff;">├── bevy feature </span><span style="color:#89ddff;">&quot;</span><span style="color:#c3e88d;">basis-universal</span><span style="color:#89ddff;">&quot;
9696
</span><span style="color:#82aaff;">│ └── bevy_libgdx_atlas v0.3.0
9797
</span><span style="color:#82aaff;">│ └── bevy_libgdx_atlas feature </span><span style="color:#89ddff;">&quot;</span><span style="color:#c3e88d;">default</span><span style="color:#89ddff;">&quot;
9898
</span><span style="color:#82aaff;">│ └── tinytakeoff v0.1.1
9999
</span></code></pre>
100100
<h1 id="conclusion">Conclusion</h1>
101-
<p>The feature option in <code>cargo tree</code> is a very powerful tool in fighting against the subtle way dependencies and features in them can creep into your codebase.</p>
102-
<p>Since it is close to Christmas I want to make a wishlist to improve the situation:</p>
101+
<p>The feature option in <code>cargo tree</code> is a powerful tool in fighting against the subtle ways that dependencies, and the features enabled by them, can creep into your codebase.</p>
102+
<p>Since it is close to Christmas, I want to make a small wishlist to improve the situation:</p>
103103
<ol>
104-
<li>A <code>cargo deny</code> like tool that allows me to white/blacklist features in dependencies.</li>
105-
<li><code>cargo tree</code> should generate a computer-readable format (ron/json whatever) to facilitate point 1.</li>
106-
<li>In a perfect world there would be a <code>cargo tree-tui</code> allowing to interactively inspect dependencies, their features, and fan in (who uses it) and fan out (what it is using).</li>
104+
<li>A <code>cargo deny</code>-like tool that allows me to whitelist, and or blacklist, features in dependencies.</li>
105+
<li><code>cargo tree</code> should generate a computer-readable format (RON, JSON, or whatever) to help with the first point.</li>
106+
<li>In a perfect world, there would be a <code>cargo tree-tui</code> allowing me to interactively inspect dependencies, their features, and fan in (who uses it) and fan out (what it is using).</li>
107107
</ol>
108-
<p>That being said <code>cargo tree</code> seems underutilized, so go and run it on your Bevy project to figure out what features of dependencies like Bevy you actually compile. This can have a huge impact on your wasm binary size!</p>
108+
<p>That being said, <code>cargo tree</code> seems underused, so go and run it on your Bevy project yourself and see what features of dependencies like Bevy you actually compile. This can have a huge impact on your Wasm binary size!</p>
109109
<hr />
110110
<p>Do you need support building your Bevy or Rust project? Our team of experts can support you! <a href="https://rustunit.com/contact/">Contact us.</a></p>
111111

0 commit comments

Comments
 (0)