Just cool ...

Feel the Power of Nix

To build a reproducible env is the Nix's Ultimate Power. You can live without NixOS or not using Home-Manager. But this one is the essential of Nix. This post is to illustrate what you can perform with Nix.

Direnv

Nix ❀ Direnv. These two are so powerful that it could be illegal to use both 😆. Direnv grants you seamless environment while Nix guarantees they are reliable and reproducible instantly. My rest blogs are merely snippets and tips to showcase/advertise this combination (all in my dotfiles repo). BTW, direnv can work with conda too!

NodeJS

# Nixpkgs 20.09
# no -g/global install needed! node_modules/.bin is in PATH when in this folder
# { pkgs ? import <nixpkgs> {} }:
{ pkgs ? 
import (builtins.fetchTarball {
      name = "nixos-20.09";
      url = "https://codeload.github.com/NixOS/nixpkgs/tar.gz/20.09";
      sha256 = "1wg61h4gndm3vcprdcg7rc4s1v3jkm5xd7lw8r2f67w502y94gcy";
  }) {}
}:

pkgs.mkShell {
  buildInputs = with pkgs; [
    nodejs
    yarn
  ];

  shellHook = ''
    export PATH="$PWD/node_modules/.bin/:$PATH"
    echo "🚀 nodejs ready!"
  '';

  MY_ENVIRONMENT_VARIABLE = "dummy";
}

Here usually you pin down to a particular nixpkgs to make sure the reproducibility. Remember npm install -g? Now it's not allowed and neither good practice. You just install to local node_modules folder and export the node_modules/.bin path.

Emscripten

Webassembly? Easy piece:

let
   emscriptenPackages.zlib
in 
pkgs.mkShell {
  buildInputs = with pkgs; [
    emscripten
    emscriptenPackages.zlib
    webfs # webfs -F -p 3000 to serve current folder
  ];
}

Nixpkgs already has common emscriptenPackages ready but if you can compile your own as shown here.

Rust

let
  moz_overlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz);
  nixpkgs = import <nixpkgs> { overlays = [ moz_overlay ]; };
  ruststable = (nixpkgs.latest.rustChannels.stable.rust.override { extensions = [ "rust-src" "clippy-preview" "rls-preview" "rust-analysis" "rustfmt-preview" ];});
in
with nixpkgs;
mkShell {
  buildInputs = [ 
    openssl 
    pkg-config
    nasm
    ruststable
    rustup
    cmake
    zlib 
  ];

  shellHook = ''
    export PATH=$HOME/.cargo/bin:$PATH
  '';
}

New and fast evolving lang, you have to overlay nightly pkgs from Mozilla. Relax, nixpkgs master is stable than you thought!

Python

Install pkgs in read-only nix python is impossible. You either use local pip (virtual python env) or manage packages in nix. With nix, you don't need to worry about the native package like cython etc..

...
:
let
  pythonEnv = pkgs.python38.withPackages (ps: [
    ps.numpy
    ps.pytorch
    ps.dateutil
  ]);
in pkgs.mkShell {
  buildInputs = with pkgs; [
    pythonEnv
    libffi
    openssl
  ];
}

If you are dealing with mostly pure py pkgs or has no admin permission, you might consider conda. It's also powerful: before my Nix age, conda is my environment pkgs manager. Another way is to use mach-nix, which can help pack pypi into nix pkgs.

C++

Nix is the out of box C++ dev pkg manager in *nix OS I'd say, since C++ pkgs are mostly low level and OS related. However, nix expression is not as good for incremental build, yet you can integrate with powerful like bazel etc. If you just need some scratch start, here you go:


let
  version = "0.1";
in pkgs.mkShell {
  name = "my-cpp-app";
  src = "./.";

  nativeBuildInputs = with pkgs; [ cmake meson ninja ];
  # phases: unpackPhase -> configurePhase -> buildPhase -> installPhase
  buildInputs = with pkgs; [ 
    boost
    poco
  ];

  configurePhase = ''
    cmake -G Ninja .
    #meson setup builddir
  '';

  buildPhase = ''
    c++ -o main main.cpp -lPocoFoundation -lboost_system
    #meson compile
  '';

  installPhase = ''
    mkdir -p $out/bin
    cp main $out/bin
    #cd builddir && meson compile
  '';

  enableParallelBuilding = true;
}

These buildPhase will be called in order if you build *.nix file. You can manually revoke them in nix-shell or just make it as Nix derivative and build.

🚧Jdk

TODO:

    buildInputs = with pkgs; [ jdk11 ];
    
    shellHook = ''
      export JAVA_HOME=${pkgs.jdk11}
      PATH="${pkgs.jdk11}/bin:$PATH"
    '';

Android

https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/mobile/androidenv/examples/shell.nix Finally, we got some updates from nix community for license issue.

You'll need to accept a bunch of licenses, config.androidenv.accept_licneses = true only help some core licenses, you need to specify extra licenses

Non-Root

If this bothers you ...

  1. Namespace nix-user-chroot. However, it cannot support tmux reattachment (hope this is tmux fault).
  2. Proot allow tmux to reattach, however, it has limit os support for certain system call which is very hard to find out when it happens.
  3. Build your own stuff and troubleshooting all on your own.

Namespace is recommended however in Mac it seems to be impossible.

...