diff --git a/build.rs b/build.rs index 7bcefe68..e3a06aa7 100644 --- a/build.rs +++ b/build.rs @@ -56,7 +56,7 @@ fn emit_build_info(manifest_dir: &std::path::Path) -> Result<(), Box> .add_instructions(&rustc)? .emit()?; - provenance::git_instructions(manifest_dir)?.emit()?; + emit_git_provenance(manifest_dir)?; for name in [ "RUSTIQ_BUILD_GIT_COMMIT", @@ -96,6 +96,22 @@ fn emit_build_info(manifest_dir: &std::path::Path) -> Result<(), Box> Ok(()) } +fn emit_git_provenance(manifest_dir: &std::path::Path) -> Result<(), Box> { + let sha = env::var("VERGEN_GIT_SHA").unwrap_or_default(); + let dirty = env::var("VERGEN_GIT_DIRTY").unwrap_or_default(); + + if !sha.is_empty() && !dirty.is_empty() { + println!("cargo:rerun-if-env-changed=VERGEN_GIT_SHA"); + println!("cargo:rerun-if-env-changed=VERGEN_GIT_DIRTY"); + println!("cargo:rustc-env=VERGEN_GIT_SHA={sha}"); + println!("cargo:rustc-env=VERGEN_GIT_DIRTY={dirty}"); + } else { + provenance::git_instructions(manifest_dir)?.emit()?; + } + + Ok(()) +} + fn emit_declared_profile_settings(manifest_dir: &std::path::Path) -> Result<(), Box> { use std::str::FromStr; diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 8fed6f28..c43f7229 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -5,6 +5,7 @@ # Getting started - [Installation](getting-started/installation.md) + - [Installing with Nix](getting-started/installation-nix.md) - [First Hâ‚‚ calculation](getting-started/first-calculation.md) - [Interpreting output](getting-started/output.md) diff --git a/docs/src/development/nix-packages.md b/docs/src/development/nix-packages.md index ad27d39e..992060bb 100644 --- a/docs/src/development/nix-packages.md +++ b/docs/src/development/nix-packages.md @@ -1,5 +1,10 @@ # Nix packages and shells +The flake also exposes `legacyPackages..cpuTarget`, a function accepting +an LLVM CPU name and returning a CPU-specific RustiQ package. See the +[installation guide](../getting-started/installation.md#install-with-nix) for +commands and portability considerations. The default package remains portable. + The packages below are declared in [`flake.nix`](https://github.com/mveril/RustiQ/blob/main/flake.nix). All four shells share Rust build essentials. `rust` adds Rust development tools; `mini-pyscf` adds the Python reference-test environment to the minimal Rust diff --git a/docs/src/development/nix-setup.md b/docs/src/development/nix-setup.md index 65ea8c96..9061249e 100644 --- a/docs/src/development/nix-setup.md +++ b/docs/src/development/nix-setup.md @@ -73,7 +73,15 @@ Choose the case that matches your machine: instructions](https://nixos.org/download/) for your platform, restart the shell if requested, and verify the installation with `nix --version`. The official page recommends a multi-user installation when the platform supports - it. + it. To enable the commands used here, add the following line to your user + configuration file, `~/.config/nix/nix.conf` (create the directory and file + if needed): + + ```text + experimental-features = nix-command flakes + ``` + + Merge these features with any existing `experimental-features` setting. In either case, Nix reads `flake.nix` and `flake.lock` from this repository to create the same project-specific toolchain without installing those development diff --git a/docs/src/getting-started/installation-nix.md b/docs/src/getting-started/installation-nix.md new file mode 100644 index 00000000..a9709ea0 --- /dev/null +++ b/docs/src/getting-started/installation-nix.md @@ -0,0 +1,174 @@ +# Installing with Nix + +Install [Nix](https://nixos.org/download/) and enable the `nix-command` and +`flakes` experimental features. The flake supports x86-64 Linux, ARM64 Linux, +and Apple Silicon macOS. On Windows, use Nix inside WSL2 to run the Linux +package. See [Nix setup](../development/nix-setup.md#getting-nix) for enabling +flakes and platform prerequisites. The first install needs network access and +may compile dependencies. Install the standard package from any directory with: + +```sh +nix profile install github:mveril/RustiQ +rustiq --version +``` + +## Home Manager without a configuration flake + +If your Home Manager configuration uses `home.nix` directly, create a +`rustiq.nix` file beside it: + +```nix +{ pkgs, ... }: +let + rustiq = builtins.getFlake "github:mveril/RustiQ"; +in +{ + home.packages = [ + (rustiq.legacyPackages.${pkgs.stdenv.hostPlatform.system}.cpuTarget "native") + ]; +} +``` + +Add the module to the imports in `home.nix`, keeping any existing imports: + +```nix +imports = [ ./rustiq.nix ]; +``` + +Apply the configuration using your usual command. For Home Manager integrated +as a NixOS module, run `sudo nixos-rebuild switch --impure`; for standalone Home +Manager, run `home-manager switch --impure`. The unlocked GitHub reference +requires impure evaluation. Check `rustiq --version` afterward. The reference tracks the default branch +and is not pinned by a configuration `flake.lock`; use a revision in the URL +for a fixed version. See the [CPU-specific build](#optional-cpu-specific-build) +caveats before using `native`. To use the standard package, replace the entry +in `home.packages` with `rustiq.packages.${pkgs.stdenv.hostPlatform.system}.default`. + +## Home Manager and NixOS + +The following snippets extend an existing **flake-based** configuration. Add +RustiQ as an input to your configuration's `flake.nix`: + +```nix +inputs.rustiq.url = "github:mveril/RustiQ"; +``` + +The configuration's `flake.lock` pins that input. To update it later, run +`nix flake update rustiq` in the configuration directory, then apply the +configuration again. Keep your existing inputs, modules, and state version. +If the configuration is a Git flake, add any newly created module files to Git +before applying it so that Nix can see them. + +### Home Manager + +In the existing `outputs` function, bind the inputs as `inputs@{ ... }`, and +pass them to your existing `home-manager.lib.homeManagerConfiguration`: + +```nix +extraSpecialArgs = { inherit inputs; }; +``` + +Merge this with any existing `extraSpecialArgs`. In your `home.nix`, add +`inputs` to the module arguments and add RustiQ to `home.packages`: + +```nix +{ pkgs, inputs, ... }: +{ + home.packages = [ + inputs.rustiq.packages.${pkgs.stdenv.hostPlatform.system}.default + ]; +} +``` + +Merge the list with your existing packages. From your configuration directory, +apply it with `home-manager switch --flake .#YOUR_USER` and check +`rustiq --version`. Replace `YOUR_USER` with your Home Manager configuration +name. See the [Home Manager flake guide](https://nix-community.github.io/home-manager/nix-flakes/standalone.html). +For Home Manager as a NixOS module, pass the inputs through +`home-manager.extraSpecialArgs` instead. + +### NixOS configuration.nix + +In the existing `outputs` function, bind the inputs as `inputs@{ ... }`, and +pass them to your existing `nixpkgs.lib.nixosSystem`: + +```nix +specialArgs = { inherit inputs; }; +``` + +Merge this with any existing `specialArgs`. Create `rustiq.nix` beside your +`configuration.nix`. This complete NixOS module installs a RustiQ build +optimized for the build machine's CPU: + +```nix +{{#include rustiq.nix}} +``` + +Then import it in the existing `configuration.nix`, preserving any other imports: + +```nix +{ ... }: +{ + imports = [ ./rustiq.nix ]; +} +``` + +Alternatively, add `./rustiq.nix` to the `modules` list in `nixosSystem`. +See the CPU caveats below before using `native`. To use the standard package, +replace the expression inside the list with: + +```nix +inputs.rustiq.packages.${pkgs.stdenv.hostPlatform.system}.default +``` + +From the configuration directory, apply it with +`sudo nixos-rebuild switch --flake .#YOUR_HOST` and check `rustiq --version`. +Replace `YOUR_HOST` with your NixOS configuration name. See the +[NixOS package management guide](https://nixos.org/manual/nixos/stable/#sec-declarative-package-management). + +## Optional CPU-specific build + +The NixOS module above uses this expression. For Home Manager, you can also +replace the standard package entry in `home.packages` with it: + +```nix +(inputs.rustiq.legacyPackages.${pkgs.stdenv.hostPlatform.system}.cpuTarget "native") +``` + +For a profile installation from any directory, use one command instead: + +```sh +nix profile install --impure --expr '(builtins.getFlake "github:mveril/RustiQ").legacyPackages.${builtins.currentSystem}.cpuTarget "native"' +``` + +List compiler CPU names with `rustc --print target-cpus` (for example inside +`nix develop github:mveril/RustiQ#rust`). `native` selects the **build machine's CPU**, which may differ from the machine +running RustiQ when using remote builders. Its detected CPU is not recorded in +the Nix build identity: cached results may have been built for a different CPU. +For reproducible builds or deployment across machines, replace `native` with a +compatible explicit CPU name such as `znver3`. A binary may fail on machines +with fewer processor features. This setting applies to Rust-compiled code and +does not promise optimization of every native dependency. The `--impure` flag +allows the command-line expression to obtain the current system and resolve the +unlocked GitHub reference. + +## Build from a checkout + +From the root of a RustiQ checkout, build the default package and run it +without adding it to your profile: + +```sh +nix build +./result/bin/rustiq --version +``` + +The package includes the offline manual and shell completions. Run `rustiq docs` +after installing, or `./result/bin/rustiq docs` from the checkout. See the +[manual instructions](installation.md#consult-the-manual) and the +[Nix package guide](../development/nix-packages.md#installed-manual-and-completions). + +The package enables online basis downloads but does not bundle sample inputs or basis sets. +Download or import a basis before running a calculation; see +[make basis sets available](installation.md#make-basis-sets-available) and the +[first calculation](first-calculation.md). For development shells, see +[Nix setup](../development/nix-setup.md). diff --git a/docs/src/getting-started/installation.md b/docs/src/getting-started/installation.md index 380ac32f..4da57ce8 100644 --- a/docs/src/getting-started/installation.md +++ b/docs/src/getting-started/installation.md @@ -1,5 +1,10 @@ # Installation +## Install with Nix + +See [installing with Nix](installation-nix.md) for the supported platforms, +profile installation, and CPU-specific builds. + ## Install a prebuilt release binary When a release is available, ordinary users can download the archive for their diff --git a/docs/src/getting-started/rustiq.nix b/docs/src/getting-started/rustiq.nix new file mode 100644 index 00000000..d02128da --- /dev/null +++ b/docs/src/getting-started/rustiq.nix @@ -0,0 +1,7 @@ +# NixOS module: provide the RustiQ flake through specialArgs.inputs. +{ pkgs, inputs, ... }: +{ + environment.systemPackages = [ + (inputs.rustiq.legacyPackages.${pkgs.stdenv.hostPlatform.system}.cpuTarget "native") + ]; +} diff --git a/flake.nix b/flake.nix index fa8224a6..18d03ed4 100644 --- a/flake.nix +++ b/flake.nix @@ -157,6 +157,13 @@ src = cargoSource; strictDeps = true; cargoExtraArgs = "--locked --workspace --no-default-features --features online"; + # Crane builds from a filtered source tree without .git. Supply + # the same flake provenance used by the installed package so + # vergen-gix does not warn or emit placeholder Git metadata. + VERGEN_GIT_SHA = pkgs.lib.removeSuffix "-dirty" ( + inputs.self.rev or inputs.self.dirtyRev or "unknown" + ); + VERGEN_GIT_DIRTY = if inputs.self ? rev then "false" else "true"; }; cargoArtifacts = craneLib.buildDepsOnly commonCargoArgs; @@ -442,6 +449,17 @@ pyscf-environment = pythonPyscf; }; + legacyPackages.cpuTarget = + cpu: + let + cpuFlags = "-C target-cpu=${cpu}"; + cpuArtifacts = craneLib.buildDepsOnly (commonCargoArgs // { RUSTFLAGS = cpuFlags; }); + in + rustiq.overrideAttrs (_: { + RUSTFLAGS = cpuFlags; + cargoArtifacts = cpuArtifacts; + }); + apps = { pyscf-check = { type = "app";