kivikakk.ee

“a gender terrorism, if you will.”

I’ve just had the pleasure of reading three interesting pieces of discourse.

First up, Alyson Escalante’s 2016 piece “Gender Nihilism: An Anti-Manifesto”. There is very little about this I have to disagree with.

Then, her own 2018 response to that work, “Beyond Negativity: What Comes After Gender Nihilism?”. On the one hand, pushing for a more material analysis is excellent, though I feel like all the work is actually done here by Wittig and this merely restates it

On the other hand, what on earth is this ending? It reads just like any other wishy-washy proclamation, missing only a communism,-now!.88x31.gif to slap on your homepage in solidarity. This anti-anti-manifesto is decidedly a manifesto.

The comments, however, conceal a banger which I nearly missed. “blister” (@destroysound) starts, and then wow, they continue. I don’t trust Medium to continue existing for that much longer — or even the Wayback machine (which Medium very carefully tries to break :) love it) — so I’m reproducing it here in its entirety.

There is very little about this I have to disagree with.


Read more

íqán — sync Nix flake pins between projects.

I use Nix flakes a lot — both in development, and in how I deploy artefacts. (You can see my primary flake’s 17 inputs!)

One thing that has gotten a bit annoying, though, has been keeping the pins somewhat in sync. I regularly end up with a dozen nixpkgs and fenix and (etc. etc. etc.) variants in my Nix store, meaning I’d also have half a dozen different Rust, Erlang, Elixir and whatever other versions installed too. If I dare nix-collect-garbage -d, then working on any given project might give me a surprise as it turns out it had a slightly older pin and I actually need to wait for its special magical Elixir version.

And so on!

Using inputs.X.follows is all good and well when combining them into a unified whole, but I don’t use (and don’t intend to use) global devShells — I want each project to stand on its own. So, instead, I want a way to compare and optionally sync the locked versions from some reference to my projects. For a while I found it was a good enough hack to just cp ~/g/vyx/flake.lock . and then let the next Nix invocation remove all the irrelevant ones … but then I’d introduce a dependency which hitched its own nixpkgs along for the ride, and for Reasons™ that would get called "nixpkgs" in flake.lock, and my actual primary Nixpkgs pin called "nixpkgs_2". For a while I was then accidentally using that reference everywhere. Goodness.

Here’s íqán. It takes a plan file, which specifies the source (Vyx, for me), and then a list of targets along with which inputs should be synced. Here’s an excerpt of a sample run:

$ iqan ./iqan.json
Source: /Users/kivikakk/g/vyx
Target: /Users/kivikakk/g/a1d
-----------------------------
input nixpkgs is synced
input fenix is synced
Target: /Users/kivikakk/g/chog
------------------------------
input nixpkgs is synced
Target: /Users/kivikakk/g/cmark-gfm-hs
--------------------------------------
input nixpkgs is synced
Target: /Users/kivikakk/g/comenzar
----------------------------------
input nixpkgs is ahead of source (!)
source: 1751741127 (2025-07-05 18:45:27 UTC)
target: 1752620740 (2025-07-15 23:05:40 UTC)
(S)ync to source, or (I)gnore? s
Target: /Users/kivikakk/g/comrak
--------------------------------
input nixpkgs is behind source
source: 1751741127 (2025-07-05 18:45:27 UTC)
target: 1748437600 (2025-05-28 13:06:40 UTC)
(S)ync to source, or (I)gnore? s
input "fenix" has an original mismatch
source: github:nix-community/fenix
target: github:nix-community/fenix/monthly
(S)ync to source, or (I)gnore? s
[!!!] update flake.nix please!
Target: /Users/kivikakk/g/iqan
------------------------------
input nixpkgs is synced
input fenix is synced
Target: /Users/kivikakk/g/kivikakk
----------------------------------
input nixpkgs is synced
Target: /Users/kivikakk/g/koino
-------------------------------
input nixpkgs is synced
Target: /Users/kivikakk/g/kv
----------------------------
input nixpkgs is synced
input fenix is synced
Target: /Users/kivikakk/g/nossa
-------------------------------
input nixpkgs is synced
input fenix is synced
Target: /Users/kivikakk/g/notes
-------------------------------
input nixpkgs is synced
Target: /Users/kivikakk/g/outfoxsync
------------------------------------
input "nixpkgs" has an original mismatch
source: github:NixOS/nixpkgs/nixos-25.05
target: github:NixOS/nixpkgs/nixos-24.11
(S)ync to source, or (I)gnore? s
[!!!] update flake.nix please!
$

It does the job. :)

Argon ONE V3 fan/power controller.

Seems almost a rite of passage to write one’s own for this accursed piece of hardware.

(The hardware’s actually quite OK, screw threading notwithstanding, but Argon 40 cannot write software to save themselves.)

https://nossa.ee/~talya/a1d

tangential

cw: death, drugs, I am Sad

Read more

Cross-compiling Elixir for x86_64-linux on aarch64-darwin.

  • Start with github:cpick/nix-rosetta-builder.

  • Serving suggestion (adjust for your machine):

    nix-rosetta-builder = {
    enable = true;
    cores = 12;
    diskSize = "100GiB";
    memory = "16GiB";
    onDemand = true;
    };

    That’s it! It’ll spin itself up when needed (you might need to retry the build since the first attempt might timeout while it starts up on-demand), and down again after a while of inactivity. Now you can do something like nix build .#packages.x86_64-linux.chog and it’ll Just Work™.

  • Whoops! I lied. You’ll get perhaps a lot of things like this:

    error: build of '/nix/store/9dhn75m3isw55qz29dzw1h8xzs634pim-salchicha-0.4.0.drv' on 'ssh-ng://rosetta-builder' failed: builder for '/nix/store/9dhn75m3isw55qz29dzw1h8xzs634pim-salchicha-0.4.0.drv' failed with exit code 132;
    last 9 log lines:
    > Running phase: unpackPhase
    > unpacking source archive /nix/store/l05szcgqqaxxc9i1hd16ik8kd9vv5cn2-salchicha-0.4.0
    > source root is salchicha-0.4.0
    > Running phase: patchPhase
    > Running phase: updateAutotoolsGnuConfigScriptsPhase
    > Running phase: configurePhase
    > Running phase: buildPhase
    > Compiling 3 files (.ex)
    > /nix/store/qjjpd1310d6qi63pdmjigykcznfi3n4y-stdenv-linux/setup: line 1765: 44 Illegal instruction (core dumped) mix compile --no-deps-check
    For full logs, run:
    nix log /nix/store/9dhn75m3isw55qz29dzw1h8xzs634pim-salchicha-0.4.0.drv
    error: builder for '/nix/store/9dhn75m3isw55qz29dzw1h8xzs634pim-salchicha-0.4.0.drv' failed with exit code 1
    error: build of '/nix/store/3jfv7sghsansgg4sgihqkcsxg925zfrj-jason-1.4.4.drv' on 'ssh-ng://rosetta-builder' failed: builder for '/nix/store/3jfv7sghsansgg4sgihqkcsxg925zfrj-jason-1.4.4.drv' failed with exit code 134;
    last 12 log lines:
    > Running phase: unpackPhase
    > unpacking source archive /nix/store/km205nlk52awji63d5hynwnypdpfqqm3-jason-1.4.4
    > source root is jason-1.4.4
    > Running phase: patchPhase
    > Running phase: updateAutotoolsGnuConfigScriptsPhase
    > Running phase: configurePhase
    > Running phase: buildPhase
    > Compiling 10 files (.ex)
    > no next heap size found: 2305825417165001762, offset 0
    >
    > Crash dump is being written to: erl_crash.dump...done
    > /nix/store/qjjpd1310d6qi63pdmjigykcznfi3n4y-stdenv-linux/setup: line 1765: 44 Aborted (core dumped) mix compile --no-deps-check
    For full logs, run:
    nix log /nix/store/3jfv7sghsansgg4sgihqkcsxg925zfrj-jason-1.4.4.drv
    error: builder for '/nix/store/3jfv7sghsansgg4sgihqkcsxg925zfrj-jason-1.4.4.drv' failed with exit code 1

Just give me the fix.

Assuming you have pkgs from somewhere:

let
erlang = pkgs.beam_minimal.interpreters.erlang_27;
erlang-jmsingle =
(erlang.override {
patches = [
./nix/erlang_beam_jit_main.cpp.patch
];
}).overrideAttrs
(prev: {
preConfigure = ''
${prev.preConfigure or ""}
configureFlagsArray+=(CFLAGS="-O2 -g -DFORCE_ERTS_JIT_SINGLE_MAP=1")
'';
});
mkPackageWithErlang =
erlang:
let
beamPackages = pkgs.beam_minimal.packagesWith erlang;
elixir = beamPackages.elixir_1_18;
in
pkgs.callPackage ./nix/package.nix {
inherit
beamPackages
erlang
elixir
;
};

Note that -O2 -g are defaults for the Erlang build — we have to specify them again since we’re overriding CFLAGS as a whole.

Here’s the patch:

diff --git a/erts/emulator/beam/jit/beam_jit_main.cpp b/erts/emulator/beam/jit/beam_jit_main.cpp
index 8408b25056..d941532e5f 100644
--- a/erts/emulator/beam/jit/beam_jit_main.cpp
+++ b/erts/emulator/beam/jit/beam_jit_main.cpp
@@ -188,6 +188,8 @@ static JitAllocator *pick_allocator() {
* 64-bit x86 still uses dual-mapped memory as it lacks support for per-
* thread permissions and thus gets unprotected RWX pages with MAP_JIT. */
erts_jit_single_map = 1;
+#elif defined(FORCE_ERTS_JIT_SINGLE_MAP)
+ erts_jit_single_map = 1;
#endif
#if defined(HAVE_LINUX_PERF_SUPPORT)

Now you can expose packages like:

packages = rec {
default = chog;
chog = mkPackageWithErlang erlang;
chog-jmsingle = mkPackageWithErlang erlang-jmsingle;
};

Finally, your cross compile is nix build .#packages.x86_64-linux.chog-jmsingle.

???

Let’s read the erts erl command manual together:

+JMsingle true|false - Enables or disables the use of single-mapped RWX memory for JIT code.

The default is to map JIT:ed machine code into two regions sharing the same physical pages, where one region is executable but not writable, and the other writable but not executable. As some tools, such as QEMU user mode emulation, cannot deal with the dual mapping, this flags allows it to be disabled. This flag is automatically enabled by the +JPperf flag.

Since: OTP 26.0

“Some tools” also includes Rosetta, it turns out. You’ll find some advice on Internet suggesting you use +JPperf with a variety of options to fix this issue, but it’s all cargo-culted — it’s the side-effect of setting +JMsingle true that makes it work. The above patch causes the flag to be set unilaterally.

The solution I present here has downsides:

  • You’re no longer using separate RW/RX mappings, which has (somewhat theoretical) security implications. RIP points to writeable memory!
  • We have to patch Erlang to make this happen consistently! I so wish we didn’t, but I couldn’t figure out a way to get the actual +JMsingle flag to propagate and be set in every single place necessary — namely, every single Erlang/Elixir/etc. invocation. The result is toolchain bloat.
  • The resulting builds therefore differ from those without it.

I use this for testing and building x86_64 artifacts from the comfort of my laptop, but when I actually deploy on x86_64, I build the regular versions on a target machine.

May this help someone!