This will be the first post in a series of 3 about trying out some new linux distros, basically. I also built a fun tool for helping me migrate between these systems, so I’ll talk about that in part 2. For now, let’s talk about asahi linux!
So I have two main computers that I use: a Thinkbook 13s that I used to only have arch linux running on, and an apple silicon macbook pro. And I always felt kinda weird about this situation. See, I really liked using linux on my thinkbook - I had it set up (inspired by so many posts in r/unixporn) with hyprland and wofi, using widgets I built for elkowar’s wacky widgets, etc etc. I had tried to replicate aspects of this setup using things like yabai, sketchybar, and skhd on macOS, but they were inherently limited by macOS itself, and some things just never felt or worked right (for example, I really like to use three-finger gestures to swipe between workspaces. On hyprland, swiping to a new workspace will automatically create one for you and changing workspaces happens basically instantaneously. on macOS, however, you have to manually open the desktop switcher and click the plus button to make a new workspace, and swiping to it invokes a slow slide animation which swallows early keystrokes that I try to enter before the workspace has slowly slid into view).
However, on the other hand, my macOS computer is very powerful when compared to my thinkbook. Not to say that my thinkbook is weak - it has a ryzen 7 4800u, so it’s not too old - but the M2 Pro that sits in my macbook is much newer, uses a different architecture, uses a P/E core design, and has many more things that just make it run much better (for example, it compiles the backend binary for this website in 60% of the time the thinkbook takes, and most rust projects compile 1.4x-2x faster). But if I’m doing something that requires long recompilation cycles, it just doesn’t make sense to use my thinkbook when my mac is available.
Now, as many of you may remember, the asahi linux project was started about 3 years ago and produced their first alpha release a bit more than a year after. I had been following this project closely, watching all the incredible progress that was being made on getting linux to run on these new macbooks (I also was aware of the progress correlium had made on this same front, but it seemed that they were more focused on getting only a POC working, while asahi was dedicated to creating a well-functioning system, so I didn’t pay attention to correlium as much at this time). But as all the hubbub about the new arm macs died down, I kinda forgot about the project for a bit (so much so that I tried installing nix on my mac - that really didn’t go well, but I can’t tell if it was due to me doing something wrong with the (un)installation, or if it’s just hard to get right on macOS. Either way, I tried it again recently, and boy do I have opinions™. But that’s for part 3.).
Well, I forgot about the project until a week or two ago, when I decided to check up on it to see how it would go if I installed it on my machine. So I headed on over to the feature support page, expecting to see that many important components were still experimental or works-in-progress, but was pleasantly surprised to find that basically every feature I cared about was online! Even something like the webcam (which I only use for work zoom calls, and I have to use macOS for work anyways, so I don’t care too much about linux support) was apparently fully supported. There were some things which would be nice to have work (such as thunderbolt and the on-chip video encoder), but all of them were far from dealbreakers, so I decided to jump in!
Looking at asahi’s website, they have a nice little install script that you run once and should do everything for you. They’re also using fedora as the base distribution right now, which I’m the slightest bit sad about - not for any serious reason, it’s just that they used Arch for the alpha and I just like the amount of packages that exist in the AUR and will miss not having them available. But, looking at the various posts on their blog, they seem to have had good reason to switch, and I do think my system will be better for it.
So I run the install script, it asks me to setup some partitions, wait a bit while install takes place, etc etc, then it boots into the new system. So my experience with asahi finally begins.
Before installing asahi, I was only sharing configs between two computers - the macbook’s macOS install and the thinkbook’s linux install (I removed windows from it, so there’s nothing to worry about there). Since they were for different operating systems and desktop environments, though, not much of the config needed to be shared between the two systems, so I never set up anything to manage dotfiles. On the things that were shared (such as my neovim config, or my ~/.zshrc, etc), I just copied over the changes I made on one machine whenever I felt I needed them on the other machine.
Now that I’d have effectively three systems to keep my config between and two of them would be on linux, I figured that I might as well set up some sort of dotfile management system. I looked at chezmoi for a bit, but it didn’t seem to be what I wanted - I was hoping to use a system that operated on symlinks so that I wouldn’t need to manually copy over my config files every time I updated them, and thankfully yadm does just that. I installed it, set it up, and it it set up a git repo somewhere in like ~/.local/state to track files in ~. It’s basically a thin wrapper around git, so any commands that I would run on a git repo to manage the files can also be ran with yadm, which I really like. I add the files I want to track, push them to a new private git repo, and then install yadm on a second machine and pull them down.
yadm does about as good a job as I would expect it to, which is a very good thing. I’d say that I’m productive with git, so learning yadm was extremely easy. It also forced me to universalize my config scripts, which was probably a smart thing to do. For example, my ~/.zshrc on macOS had a lot of homebrew- and theos-specific stuff, so I gated that all behind if [[ "$(uname)" == Darwin ]] and added the linux-specific stuff behind a similar flag.
I also use kitty as my terminal emulator, and they set the env var $KITTY_OS to whatever OS kitty is running in, such as macos, bsd, or linux (yes, i know, GNU/Linux, blah blah blah), so I can just add a include ${KITTY_OS}.conf at the top of my kitty.conf to include the os-specific config file. It’s very nice.
By default, asahi installs KDE as the default DE, and leaves it to the user to customize any further. I’ve used KDE before, and quite like it (as desktop environments go). I played with the idea of using KDE for a while to see if I’d enjoy it now, and I did use it a little bit, but I’ve really already set up exactly the environment I like using the aforementioned hyprland and elkowar’s wacky widgets, so it didn’t last long. I’m already very productive in that environment, so trying to learn and customize KDE again would kinda be a waste of time.
With regard to fedora specifically, mostly everything was the same as other distros I’ve used besides, of course, the package manager. dnf doesn’t have anywhere near as many packages as arch’s AUR, so installing a lot of my regular packges took a lot more than sudo dnf install $PACKAGE, as is the case on arch. Fedora, it seems, has what are called copr repositories, where package maintainers can set up repositories for their projects, and which end users will then have to enable to install. These definitely get the job done and aren’t too much of a hassle, but it can be kind of annoying to, for every project that’s not available in the default repositories, have to find the project’s repo or homepage, find their install instructions, and find exactly which repo to enable to install.
For example, before I could set up anything else, I had to install yadm to pull down my dotfiles. Since it didn’t seem to be available in the default repos (as evidenced by a simple sudo dnf search yadm), I had to go to its homepage, click on INSTALL NOW, click on the link for repositories and installation instructions, select Fedora, select Add repository and install manually, then under Fedora 39 I’m provided with the commands to run: dnf config-manager --add-repo https://download.opensuse.org/repositories/home:TheLocehiliosan:yadm/Fedora_39/home:TheLocehiliosan:yadm.repo && sudo dnf install yadm. All in all, it could be much worse, it’s just not as nice as a simple paru install yadm. And, of course, yadm is not the only package I’ve had to do this with - it seems common for packages to simply not be available in the default repos or have only a very outdated version available (for example, zig is still at version 0.9.1, despite the fact that there have been 3 releases since, with the most recent one being released nearly 6 months ago).
Also, as a very small nitpick: it’s kind of weird for dnf to have user-specific package list caches, imo. To demonstrate what I mean: I regularly run sudo dnf update, so my package lists are very up-to-date whenever I need to search for a package. Normally I search for a packge with sudo dnf search, and it’s nearly instantaneous, but one time I instead just ran dnf search, and it had to take a few minutes to download and process the whole package list (since I had never ran that without sudo before). Once it had done that and showed me my results, I ran dnf search again, and it pulled up the results instantly. I feel like it would make the most sense to just have one package list cache per machine, but regardless, it’s more weird than annoying.
For a long time, I’d wanted to set up firefox in a more custom way - I’d seen how pretty people’s firefox configs were over at r/firefoxCSS, and though I didn’t necessarily want to spend the time to change the whole look of firefox (though that could be fun sometime), I definitely wanted to setup a custom homepage. I know that I could install a custom new tab extension to do that for me, but I’d kinda prefer to just use my own plain html file to do the customization. I like the freedom that kind of customization gives me, and it would also make it easier for me to transport my config between computers (if I just need to move a single html file around, as opposed to having to install an extra extension each time - and yes, I do know about firefox sync, I would just prefer not to mess with that. I normally only install two extensions, uBlock Origin and Dark Reader, and don’t have any bookmarks or themes or passwords, so I really don’t need to sync).
So, I set out on my quest. I’d set up my own custom homepage at some time in the past, so I knew it was possible, and started searching. I happened upon a firefoxCSS post that wasn’t really any help, then found a mozilla support post that sent me to another mozilla support post which actually contained information to help me.
It contained the following code:
//
var {classes:Cc,interfaces:Ci,utils:Cu} = Components;
/* set new tab page */
try {
Cu.import("resource:///modules/AboutNewTab.jsm");
var newTabURL = "file:///G:/Documents/Newtab.html";
AboutNewTab.newTabURL = newTabURL;
} catch(e){Cu.reportError(e);} // report errors in the Browser Console
The user seemed to state that this needed to be placed in their firefox.cfg file, but I wasn’t quite sure what that was. Googled around some, and I found “Customizing Firefox Using Autoconfig”, a mozilla support article that basically gives us everything we need to know. It says:
To use AutoConfig, you need to create two files, one at the top level, and one in a subdirectory. On Windows, paths are based on directory where Firefox is installed. On macOS, paths are based on the Contents/Resources directory of the Firefox.app.
The first file to create is named autoconfig.js and it must be placed into the defaults/pref directory. It should contain the following two lines:
pref("general.config.filename", "firefox.cfg"); pref("general.config.obscure_value", 0);…
The second file to create is called firefox.cfg and it is placed at the top level of the Firefox directory. It should always begin with a commented line…
Ok, that seems pretty simple. However, it doesn’t really tell me exactly where these files should go (yes, it says ‘where Firefox is installed’, but that’s incredibly vague). I found some more details on another mozilla support page, but it once again seemed to avoid saying the exact directory for linux. After some more poking around online and a quick fd firefox /, it seemed that firefox.cfg needed to be put at /usr/lib/firefox/firefox.cfg, while autoconfig.js should be put at /usr/lib/firefox/defaults/pref/autoconfig.js
So I copy that stuff over to those files (modifying it to point to the address of my html file, of course), and…. nothing happens. I open firefox and it looks just like before. hmm.
Google some more, and find another mozilla support post where somebody (specifically, the same person helping out on all the other support posts) recommended adding pref("general.config.sandbox_enabled", false); to the autoconfig.js file:
pref("general.config.filename", "firefox.cfg");
pref("general.config.obscure_value", 0);
pref("general.config.sandbox_enabled", false);
So we add that as recommended, open firefox again, and… once again, the main page of firefox looks just like normal.
Wait, no - the main page looks just like normal, but if I open a new tab, it shows my html page! Well, that’s most of the battle, but still not what I was looking for. I still wanted my html page to show when I first opened up firefox. And, unfortunately, googling around doesn’t seem to be much help. I clicked on a lot of different links, but they all contained information I’d already tried to apply or things that were outright wrong.
So I decided to figure it out myself.
I noticed in the firefox.cfg that I’d copied from the internet that it referenced a /modules/AboutNewTab.jsm, which, I guessed, was contained in the firefox source code. And if there’s a /modules/AboutNewTab.jsm, there’s probably like a /modules/HomePage.jsm, right?
So I poke around and find firefox’s source code, where I simply searched for AboutNewTab and found browser/modules/AboutNewTab.sys.mjs, which is probably what I want, right? It seemed to have a _newTabURL variable, so this was probably what that code currently used.
So let’s go up a directory, and what do you know! There’s a HomePage.sys.mjs in the same folder! We open it, and get the whole content of the home page module. After scrolling around for a bit, I find the following function, HomePage.safeSet:
/**
* Sets the homepage preference to a new page. This is an synchronous version
* that should only be used when we know the source is safe as it bypasses the
* ignore list, e.g. when setting directly to about:blank or a value not
* supplied externally.
*
* @param {string} value
* The new value to set the preference to. This could be a single url, or a
* `|` separated list of URLs.
*/
safeSet(value) {
Services.prefs.setStringPref(kPrefName, value);
},
Well, that looks like what we want, right? We just want to give firefox a local url to show when we open it up. So, let’s try to pull it into firefox.cfg, using the same format as when the other module was used:
var {classes:Cc,interfaces:Ci,utils:Cu} = Components;
/* set new tab page */
try {
Cu.import("resource:///modules/AboutNewTab.jsm");
var newTabURL = "file:///home/june/.config/firefox/homepage.html";
AboutNewTab.newTabURL = newTabURL;
// Set the HomePage
Cu.import("resource:///modules/HomePage.jsm");
HomePage.safeSet(newTabURL);
} catch(e){Cu.reportError(e);} // report errors in the Browser Console
So we save that, restart firefox and… voila! It just works! We have the homepage and new tab page we wanted! Woohoo!
Unfortunately, the only downside about this is that yadm, the dotfiles manager I’m using to set this all up, doesn’t support config files outside of $HOME :(. It makes sense (yadm just initializes a git repo inside ~/.local/share/yadm/repo.git that points to $HOME), but the workarounds are still annoying and not necessarily something that I want to deal with. So for now, I just copied over the important files to ~/.config/firefox/ with comments about where they should be placed on the system, and decided that if that ever gets annoying, I’ll find some better solution.
As I alluded to earlier, I’m used to the vast amount of packages available on the AUR. Thankfully, fedora has copr repos, which somewhat fix that problem. Not completely, though. For example, eww has a closed issue of people asking for a copr package, implying that they don’t ever intend to add one. And that’s not just the case for eww - swww, tyspt-lsp, numbat, oxipng, and pazi all have this problem. Thankfully, all of these tools (and even more that I use) are all written in the same language - rust. And they all use cargo’s (rust’s package manager) build system, which means that I can install them with cargo by running cargo install --git $GIT_REPO_URL, then keep them fully updated with cargo-update by running cargo install-update -ag.
However, it’s kinda annoying to have to run cargo install for every single package you want to add - especially since you can’t install multiple packages when using the --git switch (whereas dnf will allow you to run sudo dnf install $PACKAGE_1 $PACKAGE_2 $PACKAGE_3 to install them all at once). So I built something to help with that (specifically, with sharing a list of cargo packages to install across different systems)! I’ll be talking about that in the next little article of this series, so stay tuned if that sounds fascinating to you.