Besides compiling : Judge a compiled bin by its wrapper#

Answers I stumbled upon as I was building and refactoring my systems with nix 1 , which has a parser combinator for nearly all the langs I need#

ways to write Flake outputs as functions of inputs#

for inputs = { x; y; z;}

  outputs = inputs: {
  g = inputs.x.fx {

};
}

or

outputs = {
x, y, z
}@inputs:
let
params
in
{
...
modules = {}
_module_args = inherit inputs;
g = x.fx
imports = [./x.nix]
};
# cat ./x.nix
#{params, inputs}:
#{
## expression for the function x
#}

Text sorting#

Why would do SDE tools eg package or toochain managers crate env , programs compile ( in c or rust) and end up executing user inputs in bash2 Term#

  • environment wrappers of these can output environment variables with the –shell-paths.

    Everything in linux is a file path.

    SDE tools have the grammar of the language being edited built in, which means they know which trees are syntactically valid

    1. rustup env
      export PATH="$HOME/.cargo/bin:$PATH".
      

    Cargo needs workspace steup & so does eglot

    1. Opam

      • opam env returns the current bash env variables for the current switch (i.e. switch approximately euqal to opam environment

      • eval ${opam env}

        • runs in a subshell because thats what $(cmd) does. It’s [command substitution][1]. Usually used to nest commands.
        • then it’s output (so the output string of $(opam env)) is given to eval. opam env returns a string of env variables needed to “activate: the current opam env (similar to how you activate virtual envs in python).
        • eval evaluates the string it receives from the command substitution i.e. it parses the string as a bash command and runs it
      • eval evaluates the string it receives from the command substitution i.e. it parses the string as a bash command and runs it

    2. Cabal 3

      #+begin_src

      read -p “Enter fullname: " fullname

      read -p “Enter user: " user #+begin_src

Direnv , dir-locals.el & workkspace#

the dlenv–split-null-delimited-string function is provided so that you might parse the output of the printenv -0; shell command and produce an environment data structure suitable for use with Emacs’s process-environment variable. Setting this variable in a dir-local environment is similar to using direnv in the command line 4 =eglot= in perticular prompts for setting dir-locals.

Figure 1: Prompt

Devenv#

  • Emacs & dir-locals

    Emacs has bad default behavior when it comes to window handling: many commands and modes have a habit of splitting existing windows and changing the user’s carefully thought-out window layout. This tends to be a more serious problem for people who run Emacs on large displays (possibly in full-screen mode): the greater amount of screen real estate makes it easy to split the frame into many smaller windows, making any unexpected alterations more disruptive5

    Lazy loading (also known as asynchronous loading) is a technique commonly used in computer programming to defer initialization of an object until the point at which it is needed. It can contribute to efficiency in the program operation if properly and appropriately used.

    The autoload facility lets you register the existence of a function or macro, but put off loading the file that defines it. The first call to the function automatically loads the proper library, in order to install the real definition and other associated code, then runs the real definition as if it had been loaded all along.

    This library it’s capable of monitoring arbitrary directories and automatic generate load definitions, also provides interactive functions to trigger the described feature

    When you compile a file, you can optionally enable the dynamic function loading feature (also known as lazy loading). With dynamic function loading, loading the file doesn’t fully read the function definitions in the file. Instead, each function definition contains a place-holder which refers to the file. The first time each function is called, it reads the full definition from the file, to replace the place-holder. (sic. Man)

    Let’s say you SSH into a host, start tmux, and then run Emacs. A little later you detach your session and log out. You then SSH back into the same host, and re-attach your session. Your Emacs process is still running right where you left it, but the $SSH_TTY environment variable it inherited from the shell is now stale (or longer accurate) as it still points to your old SSH tty. This means that Clipetty will no longer function in tmux windows that were created during your previous login until you manually update the $SSH_TTY environment variable.

    See also , tramp options in init.el

  • Nix

    Binding - When you write a = f b in a lazy functional language like Haskell or Nix, the meaning is stronger than just assignment. a and f b will be the same thing

    recursive sets & Fixed point - let in block in Nix works is that any variable declared in the let section will be defined in the in section. Since Nix is a lazy-evaluated language, that means that if you define something in the let block, but don’t use it in the in block, then it will never be evaluated.

    Lists in Nix can’t be infinite,as they are not actually cons/nil linked lists under the hood, but arrays. They are strict in their length and lazy in their values.6

XDG_DATA_DIRS, env shims & direnv#

Issue#

Upon launching, an emacs binary built with src & make loads var user-emacs-dir is not free and is defined as ~/.emacs.d (defvar ) and the data here is mutable , unlike $XDG_CONFIG_HOME or ~/.config , where the nix build of Emacs client loads the init elisp config from, whereas a standalone Emacs service/ server ( with a different display & session ID), may find it’s init files by how you ve defined it.

For the purpose of consistent behavior of runtime env , the init data & lib paths in the Nix build of Emacs ( or any other language runtime env, like Rust, for that matter ) need be sourced from XDG paths for binary, state, cache etc. So that, upon launching they act as specified their native build scripts & the languages / tools they re written in for any OS.

with nix-direnv & devshell 7

Retro note#

On *ubuntu* I rarely set bash profile , so I d end up rebooting/ reinstalling , On windows, the blackbox never needed it and the blackhole sucked the time and energy.

  • XDG & unix sockets

    • Protection from other local users

      Unlike other unix systems, on Linux, filesystem permissions are enforced for UDS: a user can only connect to a (non-asbtract) UDS socket if it has executable permissions on all parent directories and if it has write permission on the socket. Storing the SOCKS5 socket under `{XDG_RUNTIME_DIR}` for services prevents other users from accessing them.8

Currying in Nix#

genAttrs: it’s a function that generates an attribute set when you call it with a list and a function. It will iterate over each element in the list (systems), and call the function (f) with it as an argument. The element will become the attribute-set element name, and the function result will be the value

All xdg.configFile does is prefix the location of your config home to the filename so you don’t have to do it yourself9

{
  home.file =
    mapAttrs'
      (name: file: lib.nameValuePair "${config.xdg.configHome}/${name}" file)
      config.xdg.configFile);
}

TODO Observation#

For one, To export this file to markdown with org-hugo , I load a custom elisp lib blog 10 & until I fix my current nix build of Emacs 11 , I need root perms to do just this from $HOME.

Figure 2: Nix build of Emacs
  • TODO Other issues with blog lib

    • Fix Timestamp for drafts

No FHS & stdenv#

Runtime loading of libs built with nix & linking bins with linkers ie loaders#

On NixOs, there’s no global folder a-la /usr/lib where all shared libraries are stored. Instead, libX.so is well-hidden behind the hash on a nix/store path. So we need a pkg-config binary at compile time to get from libX name to actual location. 12

As this is a dynamic library, we need it not only during compilation, but during runtime as well. And at runtime loader13 (AKA dynamic linker14 , an executable), loads the executable together with shared libraries required by it. Normally, the loader looks for libraries in well-known locations. But on NixOs, they need be found from nix store path hash.Just like, RUNPATH , here LD_LIBRARY_PATH, just hard-coded into the executable.

NixOs provides, buildinputs in shells or nix-ld flake, for this.

NIX_LD = builtins.readFile "${stdenv.cc}/nix-support/dynamic-linker";

ld , lld on nix is just a shell script wrapper#

It passes -rpath nix/store… flag to the linker at compile time. The linker then just embeds the specified string as rpath field in the executable, without really inspecting it in any way.

Semantics, Scoping of bound variables, inheritance and Closures#

Haskell closures (lambdas and curried functions) don’t capture variables, but rather values, thanks to the immutability of its vars. But elsewhere , knowing the scope of the (captured) variable matters, as it decides, where it’s used (see Let In block above) what our nix expr ll eval to and will it do , what you wrote it for.. In a Nix REPL you add an attrset entirely to the scope of imported variables with :add or :a .

Observation#

  1. obtain the dependencies from Nixpkgs by importing the composition attribute set into the lexical scope of the expression through with import <nixpkgs> {};

Parsing AST, /nix/store & Nix Path Type#

Parsing is the act of taking a stream of characters and deducing if and how they conform to an underlying grammar grammar composition, which is where we add one grammar to another and have the combined grammar parse text in the new language (exactly the sort of thing we want to do with Domain Specific Languages (DSLs)).15

=Nix_Path= type is quite clear on what kind of strings can be accepted as a valid /nix/store path and hence, can be built and then activated or not. This changes, how you write nix module for a service or program, corresponding to a package written in a language other than nix, like most of the pkgs you use

Figure 3: Nix path

You can’t just split the conf files in zsh, sh or elisp and use ecah part with one nix option and another with another , like home.file or xdg.configFile etc to merge abd source these in HM till you write a nix module or equivalent to merge those options and import them, then again , importing them from subdirs of subdirs (paths too long), your need write lib helper functions, to search for nix files on paths.

Given { a = 1 + 1; b = true; }

Nix parses it and returns a data structure like this

{ a = <thunk 1>; b = <thunk 2>; }

where a thunk is a reference to the relevant syntax tree node and a reference to the “environment”, which behaves like a dictionary from identifiers to their values, although implemented more efficiently.

Perhaps the reason we’re evaluating this file is because you requested nix-build, which will not just ask for the value of a file, but also traverse the attribute set when it sees that it is one. So nix-build will ask for the value of a, which will be computed from its thunk. When the computation is complete, the memory that held the thunk is assigned the actual value, type = tInt, value.integer = 2 16

Remote sysad#

  1. You nedd enable x-forwarding for Lunching a remote PS 17

  2. Key based Auth

    • What a keyring does is it stores passwords and encryption keys, and is usually unlocked with your login password upon login. I can use it to store my SSH keys, and have those open and available once I log into my system.
    • nix module hard-codes in “UsePAM yes” to the top of the file. What we can do, instead, is override that setting so that PAM will accept your password.
    • programs.ssh.startAgent creates a systemd unit in $HOME/.config/systemd/user/ssh-agent.service, which will export $SSH_AUTH_SOCK,
    • SSH_AUTH_SOCK variable storing the filename of the SSH agent’s Unix domain socket should be in the environment when running commands via sudo.
  3. The challengeResponseAuthentication line is needed to really prevent password login, since challengeResponseAuthentication and passwordAuthentication refer to two different modes of “password” based login, and they are enabled/disabled independently. 18

  4. pass the password to su/sudo/ssh without overriding the TTY

SSH can be used with private-public key authentication. If the private key does not have a passphrase, ssh can be used without prompting for a password.

  1. PasswordAuthentication no

With that set, password authentication is disabled for ssh, but you can still use a password for sudo.


  1. https://wiki.nixos.org/wiki/String-parsing_in_Nix ↩︎

  2. https://stackoverflow.com/questions/76245966/cannot-execute-or-install-things-with-asdf-vm-on-nixos ↩︎

  3. stub ↩︎

  4. https://github.com/RaminHAL9001/dir-local-env ↩︎

  5. https://github.com/nex3/perspective-el?tab=readme-ov-file#installation ↩︎

  6. https://github.com/NixOS/nix/issues/345 ↩︎

  7. https://hpc-demos.uni.lu/setup/ ↩︎

  8. https://github.com/randomstuff/soxidizer ↩︎

  9. https://www.reddit.com/r/NixOS/comments/1gh6fh3/xdgconfigfile_vs_homefile_home_manager/ ↩︎

  10. https://git.sr.ht/~carnotweat/blog/tree/main/item/blog.el ↩︎

  11. https://git.sr.ht/~carnotweat/for-module/tree/main/item/home.nix ↩︎

  12. https://matklad.github.io/2022/03/14/rpath-or-why-lld-doesnt-work-on-nixos.html ↩︎

  13. A dynamically loaded library (from anywhere) in EMACS is a library that is loaded on demand, when its facilities are first needed. Emacs supports such on-demand loading of support libraries for some of its features (Manual) ↩︎

  14. Unlike static linking, by copying the library code into the executable file during compilation. This makes the executable file larger and containing more code. ↩︎

  15. https://tratt.net/laurie/blog/2011/parsing_the_solved_problem_that_isnt.html ↩︎

  16. https://stackoverflow.com/questions/65153327/understanding-recurive-let-expression-in-lambda-calculus-with-haskell-ocaml-and ↩︎

  17. https://hackerone.com/reports/204802 ↩︎

  18. https://unix.stackexchange.com/questions/562807/weird-behaviour-in-per-user-ssh-password-authentication ↩︎