The more I dig into Sele, the less likely I want to incorporate something like e-mail to be part of one's core identity. It does provide a failsafe in the event one loses their domain name (has happened to be more times than I've lost my email address) but e-mails can't be easily linked to and don't have explicit profiles that can be discerned from them. Profile discernment is important for portable identities (and allowing URLs to operate as a localized lookup system for the such makes things a bit easier).

Making Rust binaries smaller by default

Have you ever tried to compile a helloworld Rust program in --release mode? If yes, have
you seen its binary size? Suffice to say, it’s not exactly small. Or at least it wasn’t small
until recently. This post details how I found about the issue and my attempt to fix it in Cargo.



Binary size analysis


I’m a member of the (relatively recently established)
#wg-binary-size working group,
which is trying to find opportunities to reduce the binary size footprint of Rust programs and libraries.
Since I also maintain the Rust benchmark suite, my main
task within the working group is to improve our tooling that measures and tracks the binary size of Rust programs.



As part of that effort, I recently added a new command to
the benchmark suite, which allows examining and comparing the sizes of individual sections and symbols of a Rust
binary (or a library) between two versions of the compiler.



The output of the command looks like this:



Output of the binary analysis command



While testing the command, I noticed something peculiar. When compiling the test binary in release mode
(using --release), the analysis command showed that there are (DWARF) debug symbols in the binary. My
immediate reaction was that I have a bug in my command and that I have to be compiling in debug mode by accident.
Surely Cargo wouldn’t add debug symbols to my binary in release mode by default, right? Right?




My reaction to Cargo's behavior

Anakin/Padmé meme about Cargo and debug symbols








I spent maybe 15 minutes looking for the bug before I realized that there is no bug in my code. There are debug
symbols in each Rust binary compiled in release mode by default, and this has been true for a long time. In fact,
there is an old Cargo issue (almost 7-year-old, to be precise) that
mentions this exact problem.



Why does this happen?


This is consequence of how the Rust standard library is distributed. When you compile a Rust crate, you don’t also
compile the standard library1. It comes precompiled, typically using Rustup, in the rust-std component.
To reduce download bandwidth2, it does not come in two variants (with and without debug symbols), but only in the
more general variant with debug symbols.



On Linux (and also other platforms), the debug symbols are embedded directly in the object files of the library itself
by default (instead of being distributed via
separate files). Therefore, when you link
to the standard library, you get these debug symbols “for free” also in your final binary, which causes binary size
bloat.



This actually contradicts Cargo’s own documentation,
which claims that if you use debug = 0 (which is the default for release builds), the resulting binary will not contain
any debug symbols. But this is clearly not what happens now.



EDIT: Just to clarify, Cargo was putting the debuginfo of the Rust standard library into your program by default.
It was not including the debuginfo of your own crate in release mode by default.



Why is it a problem?


If you take a look at the binary size of a Rust helloworld program compiled in release mode on Linux, you’ll
notice that it has about ~4.3 MiB3. While it’s true that we have a lot more disk space
today than in the past, that’s still abhorrently much.



Now, you might think that this is a non-issue, because anyone who wants to have smaller binaries simply strips them.
That is a good point - in fact, after stripping the debug symbols from the mentioned helloworld binary4,
its size is reduced to merely 415 KiB, only about 10% of the original size. However, the devil is in the details
defaults.



And defaults matter! Rust advertises itself as a language that produces highly efficient and optimal code, but this
impression isn’t really supported by a helloworld application taking more than 4 megabytes of space on disk. I can
imagine a situation where a seasoned C or C++ programmer wants to try Rust, compiles a small program in release
mode, notices the resulting binary size, and then immediately gives up on the language and goes to make fun of
it on the forums.



Even though the issue goes away with just a single strip invocation, it is still a problem in my view. Rust tries to
appeal to programmers coming from many different backgrounds, and not everyone knows that something like stripping
binaries even exists. So it is important that we do a better job here, by default.




Note that the size of the libstd debug symbols is around 4 megabytes on Linux, and this size is constant, so even
though for helloworld it takes ~90% of the size of the resulting binary, for larger programs its effect will be smaller.
But still, four megabytes is nothing to sneeze at, since it is included in every Rust binary built everywhere by default.




Proposing a change to Cargo


After I have realized that this is the default behavior of Cargo, I have actually remembered that I have just
rediscovered this exact issue perhaps for the third time already. I have just never really acted upon it before and then
always managed to forget about it.



This time, I was determined to do something about it. But where to start? Well, usually it’s not a bad idea to just
ask around on the Rust Zulip, so I did exactly that.
It turns out that I wasn’t the first person to ask that very same question, and that it came up multiple times over the years.
The proposed solution was to simply strip debug symbols from Rust programs in release mode by default, which would remove
the binary size bloat problem. In the past, this used to be blocked by the stabilization of strip support in Cargo,
but that has actually already happened back at the
beginning of 2022.



So, why wasn’t this proposal implemented yet? Were there any big concerns or blockers? Well, not really. When I
have asked around on Zulip, pretty much everyone thought that it would be a good idea. And while there were some
earlier attempts to do this, they haven’t been pushed through.



So, to sum up, it hasn’t been done yet because no one had done it yet :) So I set out to fix that. To test
if stripping by default could work, I created a PR to the compiler and started a perf benchmark. The binary size
results (for tiny crates) looked pretty good, so that gave me hope that the approach of stripping by default
could indeed work.



Funnily enough, this change also made compilation time of tiny crates (like helloworld) up to
2x faster
on Linux! How could that be, when we’re doing more work, by including stripping in the compilation process? Well,
it turns out that the default Linux linker (bfd)
is brutally slow5, so by removing the debug symbols from the final binary, we actually reduce the amount
of work the linker needs to perform, which makes compilation faster. Sadly, this has an observable effect only for really
tiny crates.




There is an ongoing effort to use a faster linker (lld) by default on Linux (again, defaults matter :smile:). Stay tuned!




After showing these results to the Cargo maintainers, they have asked
me to write down a proposal
on the original Cargo issue. In this mini-proposal, I have explained what change to the Cargo defaults I want to make,
how it could be implemented, and what are other considerations of the change.



For example, one thing that was noted is that if we strip the debug symbols by default, then backtraces of release builds
will… not contain any debug info, such as line numbers. That is indeed true, but my claim is that these have not been useful
anyway. If you have a binary that only has debug symbols for the standard library, but not for your own code, then even
though the backtrace will contain some line numbers from stdlib, it will not really give you any useful context (you
can compare the difference here).
There were also some implementation considerations, for example how to handle situations where only some of your target’s
dependencies request debug symbols. You can find more details in the
proposal.



After I wrote the proposal, it went through the FCP process. The Cargo team members voted
on it, and once it was accepted after a
10-day waiting period designed for any last concerns (the FCP), I could implement
the proposal, which was actually surprisingly straightforward.



The PR has been merged
a week ago, and it is now in nightly! :tada:



The TLDR of the change is that Cargo will now by default use strip = "debuginfo" for the release profile
(unless you explicitly request debuginfo for some dependency):


[profile.release]
# v This is now used by default, if not provided
strip = "debuginfo"


In fact, this new default will be used for any profile which does not enable debuginfo anywhere in its dependency
chain, not just for the release profile.



There was one unresolved concern about using strip on macOS, because it seems that there can be some
issues with it. The change has been in nightly for a week and
I haven’t seen any problems, but if this will cause any issues, we can also perform the debug symbols stripping selectively,
only on some platforms (e.g. Linux and Windows). Let us know if you find any issues with stripping using Cargo on macOS!



Conclusion


In the end, this was yet another case of “if you want it done, just do it”, which is common in open-source projects :)
I’m glad the change went through, and I hope that we won’t find any major issues with it and that it will be stabilized
in the upcoming months.



If you have any comments or questions, please let me know on Reddit.





  1. Unless you use build-std, which is
    however sadly still unstable. 




  2. While at the same time, ironically, increasing the size of Rust binaries on disk. 




  3. Tested with rustc 1.75.0




  4. For example with strip --strip-debug <binary>




  5. Although recently, there have been an effort to speed it up. 




• posted archived copycurrent

The hope of Sele is to make it "easy" to deploy. This version is focused on the "community" edition that'll be hosted for general use. I'm already looking to what parts can be shaved down for its underlying libraries that separate attestation and the general IndieAuth endpoints (so any Axum-powered Rust project can drop in IndieAuth support with WebAuthn support by only providing a means of data persistence). This is important for the rewrite of this site (Shock, namely, this is stored into something else) because I'd want to bake in the IndieAuth provider logic from a battle tested implementation.

I'm not sure how to get this into more hands outside of solving some usecases for it. The most immediate would be looking to coax folks using webmention.io to opt for this service but that could be a lot. I think, instead, I'll keep it quietly humming along and then flip my personal site to use it. And once that's cool for about a few days, I'll start working on Lighthouse to flesh out the social reader system. My site's truly going to be the last thing rebuilt, ha.

Sele's (my IndieAuth service) tracking for beta testing by early February. It won't be ready for general availability though. By then, it should have WebAuthn, email sign in and rel-me provider support with new providers rolling out when I can find time to support them and based on the kind of providers people tend to advertise (though I need to filter it for rel="authn me" for reporting). I'm glad I spent some up front time abstracting the means of attestation. I'd want to add a pre-flight page to do some testing of the inital request so I can do some stuff like checking preferences for a browser or basing it on location (I'd like to opt for WebAuthn on my preferred browsers but since GNOME Web doesn't support it yet, opting for something that could use the prompting solution by pushing a request and approving it from the GNOME desktop).

I could have done this faster in Python but I did like the challenge Rust provided and the amount of compile-time checking reduced the number of tests I'd have to write in a Python (and Node) stack anyhow. Only immediate concern is improving the security of the system. There's a fair amount of logging but no secret values are printed until needed (thanks to typing hiding that). I should look into either encrypting the database using SQLCipher or separating any secret values into an encrypted database and have them be retrieved that way.

Christianity was one of the greatest tools of oppression for Africans in the Americas. Especially the use of Protestantism ideals (and lowkey Paul fucked us up). My understanding of religious history is scant and mainly from the social impact of it. But I always think about how much of the perception of Black people's ideals mirror that of organized churches (homophobia, capitalistic gain over communual strength) and how, despite some folks speaking out, it remains that Christianity can only do so much to stop people from turning to T.D. Jakes (or maybe worse? Joel Osteen).

There's a high level of irony of me saying this today that I'm going to only address as this.

Move Purposefully And Fix Things - Doc Pop's Blog

In 2018, I created the &quot;Move Purposefully and Fix Things&quot; sticker to help counter the &quot;Move Fast And Break Things&quot; mentality of Silicone Valley.
byDoc Pop's Blog archived copycurrent

A set of collectives focused on building "Web services": things like a search engine (or expanding ones we have like https://www.marginalia.nu/ to work in semi-general purposes way), a domain name registrar, website hosting (thinking more like hosted services versus bare metal). Some folks like https://mayfirst.coop/ have their hands full with parts of this, but with the 'hunger' for search, I can see someone over on the NGL grant exploring this.

The World Of Web Browsers Is In A Bad Way

There once was a man who invented a means for publishing scientific documents using hypertext. He made his first documents available from his NeXT cube, and a lot of the academics who saw them thou…
byHackaday archived copycurrent

Two more chapters

I finished two more chapters this week in my book about ActivityPub. Chapter 2 is about Activity Streams 2.0, the social network data standard we use for ActivityPub. Appendix 1 is a reference for …
byEvan Prodromou's Blog archived copycurrent

The parallels (which, at this point, are not even 'parallels', it's the same) between the ignorance and lack of interest of US police to do anything demonstrates the vulnerability (or point) of policing: it serves to protect whiteness/property and if it's of low value, "harm rain pon dem". The expansion of even mentioning how Indigenous nations' governments that stand behind them and the United States operate as puppet governments is reminiscent of the situation unfolding in Atlanta, where the Black misleadership is trying to create an training institution of violence with Cop City and up in New York City, with Eric Adams' eagerness to return New York City to 80s-level policing violence.


All of this are irrespective of administration at the same time because the institutions on every level — municipalities, federal and state — have no interest in self-divestment. The mission is to continue the expansion and injection of hegemony at every cost.

byVectorized form of Jackyhttps://jacky.wtf • posted archived copycurrent

If this made you consider anything, I'd say checking the books aforementioned as well as Angela Davis's Are Prisons Obselete?, Dan Berger's The Struggle Within and spend some time talking to the native people of your communities. Find out what the minimum (beyond land acknowledgements — that's the same as inactive allyship) that one can involve oneself in.