## Background

I’ve been experimenting with NixOS and running Nix on macOS, and I’ve been documenting some of the problems and solutions I’ve encountered in the process.

## NixOS

### Global configuration

Global configuration paths for NixOS: /etc/nixos/configuration.nix and /etc/nixos/hardware-configuration.nix.

Apply the updated global configuration.

 1 2 3  nixos-rebuild switch # or nixos-rebuild switch --upgrade 

### Updating major releases

If you want to update NixOS 21.11 to 22.05:

 1 2 3  nix-channel --list nix-channel --add https://nixos.org/channels/nixos-22.05 nixos nixos-rebuild switch --upgrade 

Consider changing or not changing system.stateVersion in /etc/nixos/configuration.nix.

### Common configurations

Commonly used NixOS configurations.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41  # Enable XFCE services.xserver.enable = true; services.xserver.desktopManager.xfce.enable = true; # System wide packages environment.systemPackages = with pkgs; [ xxx ]; # Fish shell programs.fish.enable = true; users.users.xxx = { shell = pkgs.fish; } # Command not found programs.command-not-found.enable = true; # Steam gaming nixpkgs.config.allowUnfree = true; programs.steam.enable = true; # NOPASSWD for sudo security.sudo.wheelNeedsPassword = false; # QEMU guest services.qemuGuest.enable = true; services.spice-vdagentd.enable = true; # XRDP services.xrdp.enable = true; services.xrdp.defaultWindowManager = "xfce4-session"; services.xrdp.openFirewall = true; # OpenSSH server services.openssh.enable = true; # Udev rules for Altera USB Blaster services.udev.packages = with pkgs; [ usb-blaster-udev-rules ]; 

## Home Manager

Home Manager describes the program that users see by default, while NixOS is configured for all users.

### Configuration files

Configuration file: ~/.config/nixpkgs/home.nix

Application configuration file.

 1  home-manager switch 

### Commonly used configurations

Commonly used Home Manager configurations.

 1 2 3 4 5 6 7  # Allow unfree nixpkgs.config.allowUnfree = true; # User wide packages home.packages = with pkgs; [ xxx ]; 

### Overriding Dependency Versions

Set the JDK version that the JVM program depends on.

  1 2 3 4 5 6 7 8 9 10 11 12  # Maven with java 11 home.packages = with pkgs; [ (maven.override { jdk = jdk11; }) ]; # Many packages with the same JDK home.packages = let java = pkgs.jdk11; in with pkgs; [ (maven.override { jdk = java; }) (sbt.override { jre = java; }) ]; 

The specific naming of parameters depends on the beginning of the corresponding package on nixpkgs.

## Utilities

### nixpkgs-fmt

nixpkgs-fmt is used to format Nix code.

### search.nixos.org

search.nixos.org You can search for various packages on nixpkgs and also see the different platform support. The downside is that you can’t see if the packages are unfree or broken, and some darwin os-specific packages are not shown.

## Packaging

It is easy to write default.nix to package your project.

### CMake

For a simple cmake program, you can write default.nix in the following format: default.nix.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  with import {}; stdenv.mkDerivation { name = "xyz"; version = "1.0"; src = ./.; nativeBuildInputs = [ cmake ]; buildInputs = [ xxx yyy ]; } 

You can use the nix-build command to build, and the result will create a result softlink in the current directory, which is the installation directory.

Since nix-build also creates a build directory, it is recommended to use a different name when developing to prevent conflicts.

### Qt

For Qt projects, the implementation is a little more complicated because there are different big versions of Qt, so it has to be split into two files, first default.nix: default.nix.

 1 2 3  with import {}; libsForQt5.callPackage ./xxx.nix { } 

Here it means compiling with qt5, then when writing xxx.nix, the libraries passed in such as qtbase are the version of qt5.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  { stdenv, qtbase, wrapQtAppsHook, cmake }: stdenv.mkDerivation { name = "xxx"; version = "1.0"; src = ./.; nativeBuildInputs = [ cmake wrapQtAppsHook # must-have for qt apps ]; buildInputs = [ qtbase ]; } 

In actual testing, we found that the running program may report Could not initialize GLX error, which can be solved by adding environment variables via wrapProgram.

 1 2 3 4 5   # https://github.com/NixOS/nixpkgs/issues/66755#issuecomment-657305962 # Fix "Could not initialize GLX" error postInstall = '' wrapProgram "\$out/bin/xxx" --set QT_XCB_GL_INTEGRATION none ''; 

## Development environment

In addition to packaging, the packages needed for the development environment are usually defined in shell.nix.

 1 2 3 4 5 6 7 8  { pkgs ? import {} }: pkgs.mkShell { buildInputs = with pkgs; [ cmake ]; } 

Then you can use nix-shell to enter the development environment. If you don’t want outside environment variables to be passed in, you can use nix-shell --pure.