diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix new file mode 100644 index 00000000..e47db6ff --- /dev/null +++ b/.devops/nix/package.nix @@ -0,0 +1,100 @@ +{ + lib, + stdenv, + cmake, + ninja, + pkg-config, + rocmPackages, + cudaPackages, + vulkan-headers, + vulkan-loader, + vulkan-tools, + glslang, + shaderc, + darwin, + python-scripts, + config, + version, + + # Overridable feature flags + cudaSupport ? config.cudaSupport or false, + vulkanSupport ? false, + metalSupport ? stdenv.isDarwin, + rocmSupport ? config.rocmSupport or false, + rocmGpuTargets ? (lib.optionals rocmSupport rocmPackages.clr.gpuTargets), +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "audio.cpp"; + inherit version; + src = lib.cleanSource ../..; + + nativeBuildInputs = [ + cmake + ninja + pkg-config + ] + ++ lib.optional cudaSupport cudaPackages.cuda_nvcc + ++ lib.optional rocmSupport rocmPackages.clr; + + buildInputs = [ + python-scripts + ] + ++ lib.optionals vulkanSupport [ + vulkan-headers + vulkan-loader + vulkan-tools + glslang + shaderc + ] + ++ lib.optionals cudaSupport [ + cudaPackages.cudatoolkit + ] + ++ lib.optionals rocmSupport [ + rocmPackages.clr + rocmPackages.hipblas + rocmPackages.rocblas + ]; + + cmakeFlags = [ + "-DCMAKE_BUILD_TYPE=RelWithDebInfo" + "-DENGINE_ENABLE_NATIVE_CPU=ON" + "-DENGINE_ENABLE_LLAMAFILE=ON" + ] ++ lib.optional stdenv.isDarwin "-DENGINE_ENABLE_OPENMP=OFF" + ++ lib.optional vulkanSupport "-DENGINE_ENABLE_VULKAN=ON" + ++ lib.optional cudaSupport "-DENGINE_ENABLE_CUDA=ON" + ++ lib.optional metalSupport "-DENGINE_ENABLE_METAL=ON" + ++ lib.optional rocmSupport "-DENGINE_ENABLE_HIP=ON" + ++ lib.optional rocmSupport "-DCMAKE_HIP_COMPILER=${rocmPackages.llvm.clang}/bin/clang" + ++ lib.optional rocmSupport "-DGPU_TARGETS=${lib.concatStringsSep ";" rocmGpuTargets}"; + + env = lib.optionalAttrs rocmSupport { + ROCM_PATH = "${rocmPackages.clr}"; + }; + + installPhase = '' + runHook preInstall + + mkdir -p $out/bin + + # Copy the built C++ executables directly from the bin directory + cp bin/audiocpp_cli bin/audiocpp_server bin/audiocpp_gguf $out/bin/ + + # Install the python model manager script + cp $src/tools/model_manager.py $out/bin/audiocpp_model_manager + chmod +x $out/bin/audiocpp_model_manager + + # Patch the shebang to use our python environment with torch/safetensors/pyyaml + patchShebangs $out/bin/audiocpp_model_manager + + runHook postInstall + ''; + + meta = with lib; { + description = "A high-performance C++ audio inference framework"; + homepage = "https://github.com/0xShug0/audio.cpp"; + license = licenses.mit; + platforms = platforms.unix; + mainProgram = "audiocpp_cli"; + }; +}) diff --git a/.devops/nix/python-scripts.nix b/.devops/nix/python-scripts.nix new file mode 100644 index 00000000..15648ab0 --- /dev/null +++ b/.devops/nix/python-scripts.nix @@ -0,0 +1,11 @@ +{ + lib, + python3, +}: + +python3.withPackages (ps: with ps; [ + ps.torch + ps.safetensors + ps.pyyaml + ps.numpy +]) diff --git a/.devops/nix/scope.nix b/.devops/nix/scope.nix new file mode 100644 index 00000000..471d958b --- /dev/null +++ b/.devops/nix/scope.nix @@ -0,0 +1,12 @@ +{ + lib, + newScope, + version, + python-scripts, +}: + +lib.makeScope newScope (self: { + audiocpp = self.callPackage ./package.nix { + inherit version python-scripts; + }; +}) diff --git a/docs/build/nixos.md b/docs/build/nixos.md index 5b771a4c..a4b6e269 100644 --- a/docs/build/nixos.md +++ b/docs/build/nixos.md @@ -3,89 +3,69 @@ ## Prerequisites - The [Nix package manager](https://nixos.org/download) must be installed. -- [Flakes](https://nixos.wiki/wiki/Flakes) must be enabled in your Nix configuration. +- [Flakes](https://nixos.wiki/wiki/Flakes) must be enabled. ## Packages -The `flake.nix` provides multiple platform and hardware-specific builds. -The following backends are available: -- **`vulkan`**: Hardware-accelerated build using Vulkan. (Default on Linux) -- **`cuda`**: Hardware-accelerated build using NVIDIA CUDA. -- **`metal`**: Hardware-accelerated build using Apple Metal. (Default on macOS) -- **`cpu`**: Portable CPU-only build. +The flake provides backend-specific builds: -All packages include the main tools: ***audiocpp_cli***, ***audiocpp_server***, ***audiocpp_gguf***, and the Python-based ***audiocpp_model_manager***. +| Package | Backend | Platform | +| -------------- | ------------------------ | -------- | +| `cpu` | CPU-only | All | +| `vulkan` | Vulkan | All | +| `cuda` | NVIDIA CUDA | Linux | +| `rocm` | AMD ROCm | Linux | +| `rocm-gfx1151` | AMD ROCm (single target) | Linux | +| `metal` | Apple Metal | macOS | -## Build the package +All packages include: **audiocpp_cli**, **audiocpp_server**, **audiocpp_gguf**, and **audiocpp_model_manager**. -### Default (Auto-detected OS) - -Build the default package for your operating system: - -```bash -nix build . -``` - -### Specific Backends - -Build explicitly for a desired backend: +## Build ```bash +nix build .#cpu nix build .#vulkan nix build .#cuda -nix build .#metal -nix build .#cpu +nix build .#rocm +nix build .#rocm-gfx1151 # Single GPU target (faster) ``` -## Usage - -After building, the compiled binaries will be available in the `result/bin/` directory. - -### Running the CLI - -You can execute the CLI directly via `nix run` (which uses `audiocpp_cli` as the main program): +## Run ```bash -nix run .#vulkan -- +nix run .#rocm -- --backend hip --task tts --family supertonic --model ./model --text "hello" +./result/bin/audiocpp_cli --backend hip --device 0 ``` -### Running the Server +## Download Models -To run the server, use `nix shell` or execute from the build result: +The `python-scripts` package includes all dependencies for `model_manager.py`: ```bash -nix shell .#vulkan -c audiocpp_server -# or -./result/bin/audiocpp_server +nix shell .#python-scripts -c python3 tools/model_manager.py install supertonic_3 ``` -### Downloading Models (Model Manager) - -The flake seamlessly bundles the `model_manager.py` Python script along with all its required dependencies (PyTorch, Safetensors, etc.) as `audiocpp_model_manager`. +## Development Shell ```bash -nix shell .#vulkan -c audiocpp_model_manager install supertonic_3 +nix develop # Default backend +nix develop .#cuda # CUDA dev environment ``` -## Development Shell +## Custom GPU Target -If you want to work on `audio.cpp` and need a development environment with `cmake`, `ninja`, and all the necessary C++ and Python dependencies pre-configured, simply run: +Override `hipGpuTargets` for a specific GPU: ```bash -nix develop +nix build --impure --expr '(builtins.getFlake (toString ./.)).outputs.packages.x86_64-linux.rocm.override { rocmGpuTargets = ["gfx1151"]; }' ``` -## Using in a NixOS Configuration - -You can easily include `audio.cpp` as a flake input in your own NixOS configuration or other Nix projects. - -In your `flake.nix`, add it to your `inputs`, making sure to use `follows` to avoid duplicating `nixpkgs` versions: +## NixOS Configuration ```nix { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - audiocpp.url = "github:0xShug0/audio.cpp"; audiocpp.inputs.nixpkgs.follows = "nixpkgs"; }; @@ -94,14 +74,19 @@ In your `flake.nix`, add it to your `inputs`, making sure to use `follows` to av nixosConfigurations.my-machine = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ - ({ pkgs, ... }: { + ({ ... }: { environment.systemPackages = [ - # Add the default package (auto-detects Metal/Vulkan based on OS) audiocpp.packages.x86_64-linux.default - + # Or explicitly select a backend flavor: # audiocpp.packages.x86_64-linux.vulkan # audiocpp.packages.x86_64-linux.cuda + # audiocpp.packages.x86_64-linux.rocm + + # Custom GPU target: + # audiocpp.packages.x86_64-linux.rocm.override { + # rocmGpuTargets = [ "gfx1151" ]; + # } ]; }) ]; diff --git a/flake.nix b/flake.nix index a63b528d..1bcbd766 100644 --- a/flake.nix +++ b/flake.nix @@ -5,122 +5,94 @@ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; }; - outputs = { self, nixpkgs }: + outputs = + { self, nixpkgs }: let - supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; - forAllSystems = nixpkgs.lib.genAttrs supportedSystems; - pkgs = forAllSystems (system: import nixpkgs { - inherit system; - }); - pkgsCuda = forAllSystems (system: import nixpkgs { - inherit system; - config.cudaSupport = true; - config.allowUnfreePredicate = p: - builtins.all ( - license: - license.free - || builtins.elem license.shortName [ - "CUDA EULA" - "cuDNN EULA" - "cuSPARSELt EULA" - ] - ) (p.meta.licenses or (nixpkgs.lib.toList (p.meta.license or []))); - }); - in - { - packages = forAllSystems (system: - let - # A function to build audio.cpp with any set of features - mkAudioCpp = { pkgs, cudaSupport ? false, vulkanSupport ? false, metalSupport ? pkgs.stdenv.isDarwin }: - let - # Python environment for model_manager.py - myPython = pkgs.python3.withPackages (ps: with ps; [ - (if cudaSupport then ps.torchWithCuda else if vulkanSupport then ps.torchWithVulkan else ps.torch) - ps.safetensors - ps.pyyaml - ]); - in - pkgs.stdenv.mkDerivation { - pname = "audio.cpp"; - version = self.shortRev or self.dirtyShortRev or "dirty"; - - src = ./.; - - nativeBuildInputs = with pkgs; [ - cmake - ninja - pkg-config - ] ++ pkgs.lib.optional cudaSupport pkgs.cudaPackages.cuda_nvcc; - - buildInputs = with pkgs; [ - myPython - ] ++ pkgs.lib.optionals vulkanSupport [ - vulkan-headers - vulkan-loader - vulkan-tools - glslang - shaderc - ] ++ pkgs.lib.optionals cudaSupport [ - pkgs.cudaPackages.cudatoolkit - ] ++ pkgs.lib.optionals metalSupport [ - pkgs.apple-sdk_14 - ]; + forAllSystems = nixpkgs.lib.genAttrs [ + "x86_64-linux" + "aarch64-linux" + "aarch64-darwin" + ]; + version = self.shortRev or self.dirtyShortRev or "dirty"; - cmakeFlags = [ - "-DCMAKE_BUILD_TYPE=RelWithDebInfo" - "-DENGINE_ENABLE_NATIVE_CPU=ON" - "-DENGINE_ENABLE_LLAMAFILE=ON" - ] ++ pkgs.lib.optional vulkanSupport "-DENGINE_ENABLE_VULKAN=ON" - ++ pkgs.lib.optional cudaSupport "-DENGINE_ENABLE_CUDA=ON" - ++ pkgs.lib.optional metalSupport "-DENGINE_ENABLE_METAL=ON"; + pkgs = forAllSystems (system: import nixpkgs { inherit system; }); - installPhase = '' - runHook preInstall - - mkdir -p $out/bin - - # Copy the built C++ executables directly from the bin directory - cp bin/audiocpp_cli bin/audiocpp_server bin/audiocpp_gguf $out/bin/ - - # Install the python model manager script - cp $src/tools/model_manager.py $out/bin/audiocpp_model_manager - chmod +x $out/bin/audiocpp_model_manager - - # Patch the shebang to use our python environment with torch/safetensors/pyyaml - patchShebangs $out/bin/audiocpp_model_manager - - runHook postInstall - ''; + pkgsCuda = forAllSystems ( + system: + import nixpkgs { + inherit system; + config.cudaSupport = true; + config.allowUnfreePredicate = + p: + builtins.all ( + l: + l.free + || builtins.elem l.shortName [ + "CUDA EULA" + "cuDNN EULA" + "cuSPARSELt EULA" + ] + ) (p.meta.licenses or (nixpkgs.lib.toList (p.meta.license or [ ]))); + } + ); - meta = with pkgs.lib; { - description = "A high-performance C++ audio inference framework"; - homepage = "https://github.com/0xShug0/audio.cpp"; - license = licenses.mit; - platforms = platforms.unix; - mainProgram = "audiocpp_cli"; - }; - }; + audioPackages = forAllSystems ( + system: + pkgs.${system}.callPackage .devops/nix/scope.nix { + inherit version; + python-scripts = pythonScripts.${system}; + } + ); + audioPackagesCuda = forAllSystems ( + system: + pkgsCuda.${system}.callPackage .devops/nix/scope.nix { + inherit version; + python-scripts = pythonScripts.${system}; + } + ); + pythonScripts = forAllSystems ( + system: + pkgs.${system}.callPackage .devops/nix/python-scripts.nix { } + ); + in + { + packages = forAllSystems ( + system: + let + base = audioPackages.${system}.audiocpp; + baseCuda = audioPackagesCuda.${system}.audiocpp; in { - # Expose specific backend variants - cpu = mkAudioCpp { pkgs = pkgs.${system}; cudaSupport = false; vulkanSupport = false; metalSupport = false; }; - vulkan = mkAudioCpp { pkgs = pkgs.${system}; vulkanSupport = true; cudaSupport = false; metalSupport = false; }; - } // pkgs.${system}.lib.optionalAttrs pkgs.${system}.stdenv.isLinux { - cuda = mkAudioCpp { pkgs = pkgsCuda.${system}; cudaSupport = true; vulkanSupport = false; metalSupport = false; }; - } // pkgs.${system}.lib.optionalAttrs pkgs.${system}.stdenv.isDarwin { - metal = mkAudioCpp { pkgs = pkgs.${system}; metalSupport = true; cudaSupport = false; vulkanSupport = false; }; - } // { - # Automatically select best default for the current platform - default = if pkgs.${system}.stdenv.isDarwin then self.packages.${system}.metal else self.packages.${system}.vulkan; + cpu = base; + vulkan = base.override { vulkanSupport = true; }; + python-scripts = pythonScripts.${system}; + default = + if pkgs.${system}.stdenv.isDarwin then + self.packages.${system}.metal + else + self.packages.${system}.cpu; + } + // nixpkgs.lib.optionalAttrs pkgs.${system}.stdenv.isLinux { + cuda = baseCuda.override { cudaSupport = true; }; + rocm = base.override { rocmSupport = true; }; + rocm-gfx1151 = base.override { + rocmSupport = true; + rocmGpuTargets = [ "gfx1151" ]; + }; + } + // nixpkgs.lib.optionalAttrs pkgs.${system}.stdenv.isDarwin { + metal = base.override { metalSupport = true; }; } ); - devShells = forAllSystems (system: + devShells = forAllSystems ( + system: { default = pkgs.${system}.mkShell { inputsFrom = [ self.packages.${system}.default ]; }; - } // pkgs.${system}.lib.optionalAttrs pkgs.${system}.stdenv.isLinux { + } + // nixpkgs.lib.optionalAttrs pkgs.${system}.stdenv.isLinux { cuda = pkgsCuda.${system}.mkShell { inputsFrom = [ self.packages.${system}.cuda ]; };