NixOS에서 rust tauri + C# blazor wasm 를 위한 설정

nixos에서 rust tauri, blazor wasm GUI 코딩을 위한 설정

안녕하세요.
추석 연휴 기간 중 윈도우10 종료에 대비하여 nixos를 설치해봤습니다 (=윈도우11용 컴터를 살 돈이 없습니다). nixos에서 rust tauri, blazor wasm을 이용해서 개발하기 위한 설정방법을 정리해봤습니다. 제가 모르는 내용이나 잘못된 것을 댓글로 알려 주시면 감사드리겠습니다.

저는 개발자는 아닙니다. 취미 및 실험 & 연구용 GUI프로그램을 rust tauri로 주로 만들고 있습니다. 대부분 간단한 프로그램이기에 프론트앤드를 단순 html 1개 + js파일 1개로 시작했습니다. 하지만 js에 어려움이 있어 c# blazor wasm으로 변경 하였고, 이후로 rust-tauri + c#-blazor-wasm 조합을 애용하고 있습니다.

NixOS, Nix패키지 매니저는 대부분 chatgpt 도움으로 작성했습니다. 윈도우에서 tauri+blazor설정은 문서와 예제보고 가능했지만, nixos는 제 머리로는 아직 힘들었습니다. 특히, nix | nix+홈매니저 | 홈매니저+flake | nix develop+flake | nix-shell 등 달라지는 사용법이나 nix패키지 채널(24.05, 25.05, 언스테이블 등)을 다수 조합하는 경우에 chatgpt의 도움이 많았습니다.

제가 만든 gui들은 대부분 저 혼자만 사용하기 때문에 배포부분에 대해서는 아직 찾아보지 않았습니다. 아마도 앱이미지로 빌드하면 해결될것으로 예상합니다.

요약

  1. tauri 문서의 Nixos설정
    • nix develop으로 User Space + 현재 쉘에서만 코딩용 패키지 환경 구축
  2. dotnet 설치
    • nix develop으로 설치하려 했지만, 동작하지 않음.
      nix 패키지 매니저는 dotnet을 읽기전용으로설치, workload설치가 불가
    • dotnet-install.sh 사용 (유저스페이스)
    • $PATH 추가 (유저스페이스 home.nix 수정)
    • nix-ld 사용 (시스템 configuration.nix 수정)
  3. dotnet workload install wasm-tool
    • libicu를 찾지 못해서 설치 불가
    • pkg.icu 추가 (유저스페이스 home.nix 수정)
    • $LD_LIBRARY_PATH 추가 (유저스페이스 home.nix 수정)
  4. nvidea 드라이버로 변경 (시스템 configuration.nix 수정)
  5. WebKitGTK 문제 우회
    • WEBKIT_DISABLE_DMABUF_RENDERER=1 (유저스페이스 nix develop)
  6. 개발할때
    • 터미널에서 blazor 프로젝트 폴더로 이동
    • dotnet watch run
    • 새 터미널, tauri 폴더(src-tauri)로 이동
    • cargo tauri dev (tauri.conf.json의 build.devUrl을 blazor watch url로 지정)
  7. 배포할때
    • blazor wasm 먼저 빌드
    • (프로잭트를 처음 빌드하는 경우) dotnet msbuild --restore
    • visual studio에서 설정한 배포 설정 (pubxml)을 이용해서 배포용 빌드
    • dotnet msbuild /p:DeployOnBuild=true /p:PublishProfile=MyReleaseProfile /p:Configuration=Release
    • tauri 빌드
    • cargo tauri build -b deb
    • tauri 빌드(release or dev) 결과 실행할경우,
      WEBKIT_DISABLE_DMABUF_RENDERER=1 필요.
      유저스페이스 home.nix에서 설정 필요할 수 있음.

설명

tauri 공식문서

tauri공식문서
해당 문서에 링크걸린 nixos 위키에서 tauri 개발에 필요한 패키지 환경을 설치할 수 있다.

nix-shell 방법

# Run with `nix-shell shell.nix`
let
  pkgs = import <nixpkgs> { };
in
pkgs.mkShell {
  nativeBuildInputs = with pkgs; [
    pkg-config
    gobject-introspection
    cargo
    cargo-tauri # Optional, Only needed if Tauri doesn't work through the traditional way.
    nodejs # Optional, this is for if you have a js frontend
  ];

  buildInputs = with pkgs;[
    at-spi2-atk
    atkmm
    cairo
    gdk-pixbuf
    glib
    gtk3
    harfbuzz
    librsvg
    libsoup_3
    pango
    webkitgtk_4_1
    openssl
  ];
  # shellHook = "";
}

해당 위키에서 제공하는 nix코드는, nix-shell을 사용하는것에 맞춰있다.
nix-shell은 현재 쉘에만 개발용 패키지가 설치되는 환경이다.
nix-shell은 채널(24.05, 25.05 등의 패키지 채널)이 외부설정(nix채널로설정)에 영향을 받는다.
flake로 채널을 고정하고, lock파일로 만들기 위해서 nix develop를 사용하기로 한다.

nix develop . 방법

nix develop는 프로젝트별로 flake.nix파일을 생성한 후, 해당 파일이 있는 위치에서 nix develop .로 사용한다.

rust tauri, blazor wasm을 개발하기위한 flake.nix는 다음처럼 작성하였다.

{
  inputs = {
    nixpkgs = { url = "github:nixos/nixpkgs/nixos-25.05"; };
    oldPkgs = { url = "github:nixos/nixpkgs/nixos-25.05"; };
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, oldPkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        # 패키지 채널을 여러개를 사용한다면, 오버레이가 필요하다. (지금은 25.05로 동일하지만)
        pkgs = nixpkgs.legacyPackages.${system};
        old = oldPkgs.legacyPackages.${system};
        overlayDotnet = final: prev: {
          dotnetCorePackages = prev.dotnetCorePackages // {
            sdk_9_0_1xx-bin = old.dotnetCorePackages.sdk_9_0_1xx-bin;
            sdklib = old.dotnet-sdk_9;
          };
        };
        pkgsWithOverlay = import nixpkgs {
          inherit system;
          overlays = [ overlayDotnet ];
        };
      in
      {
        devShell = pkgsWithOverlay.mkShell {
          nativeBuildInputs = with pkgsWithOverlay; [
            pkg-config
            gobject-introspection
            # dotnetCorePackages.sdk_9_0_1xx-bin
            # dotnetCorePackages.sdklib
          ];
          buildInputs = with pkgsWithOverlay; [
            at-spi2-atk
            atkmm
            cairo
            gdk-pixbuf
            glib
            gtk3
            harfbuzz
            librsvg
            libsoup_3
            pango
            webkitgtk_4_1
            openssl

          ];
          shellHook = ''
            export WEBKIT_DISABLE_DMABUF_RENDERER="1";
          '';
        };
      });
}

이 flake에서는 채널을 2개 사용하고, 서로다른 채널에서 nix패키지를 사용하는것을 가정하였다. dotnet을 24.05에서 설치하는것을 시도하였다가, 제거하였다. WebKitGTK 문제때문에 WEBKIT_DISABLE_DMABUF_RENDERER=1이 필요하여 추가하였다.

(추천하는 flake.nix)
일반적으로 채널을 분리할 필요가 없으므로, 1개 채널만 사용한다고 한다면, 아래 코드처럼 작성할 수 있으며, 마찬가지로 nix develop .로 사용한다.

{
    inputs = {
        nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
        flake-utils.url = "github:numtide/flake-utils";
    };

    outputs = { self, nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (system:
    let
        pkgs = nixpkgs.legacyPackages.${system};
    in
    {
        devShells = {
            default = pkgs.mkShell {
                nativeBuildInputs = [
                    pkgs.pkg-config
                    pkgs.gobject-introspection
                ];
                buildInputs = [
                    pkgs.at-spi2-atk
                    pkgs.atkmm
                    pkgs.cairo
                    pkgs.gdk-pixbuf
                    pkgs.glib
                    pkgs.gtk3
                    pkgs.harfbuzz
                    pkgs.librsvg
                    pkgs.libsoup_3
                    pkgs.pango
                    pkgs.webkitgtk_4_1
                    pkgs.openssl
                ];
                shellHook = ''
                    export WEBKIT_DISABLE_DMABUF_RENDERER="1";
                '';
            };
        };
    });
}

이처럼 일반적인 방식으로 변경할 수 있다.
(pkgs, pkgs2로 분리하여 채널을 사용하는 경우의 위험성에 대해서는 아직 몰?루 ㅠㅠㅠ)

dotnet설치

dotnet을 nixos에 설치하기 위해서 nix패키지를 사용하는 방식을 먼저 시도하였다.
nix develop의 flake.nix에 dotnet-sdk_9를 추가하였다.
하지만 blazor wasm 프로젝트를 빌드하려고 하니, workload가 필요하고, workload를 설치하려고 하니 불가능 하였다. 이는 nix패키지 매니저가 패키지를 설치할때, 읽기전용으로 추가하기 때문이다.

이를 해결하기 위해서 dotnet에서 제공하는 dotnet-install.sh를 사용하였다. dotnet버전등의 파라미터에 대한 설명은 링크를 참조하여 STS (9.0)을 설치하였다.

dotnet의 설치는 유저스페이스에서 설치하였다. 따라서 개발하고자 하는 프로젝트별 dotnet설치가 아니라 로그인한 유저는 동일한 dotnet을 사용한다.

dotnet을 사용하기 위해서는 path에 등록해야 하고, 이는 유저스페이스 home.nix에 작성하였다.

{
    (...)
    programs.bash = {
        enable = true;
        shellAliases = {
            #ll = "ls -alh --color=auto";
            ls = "eza -1 -l --color=auto --git --git-repos";
            ll = "eza -1 -l --color=auto --git --git-repos --all";
        };
        initExtra = ''
            export PATH="$PATH:/home/ks/.local/bin:/home/ks/.dotnet"
        '';
    };
    (...)
}

하지만 nix패키지로 설치하지 않은 바이너리(여기서는 dotnet)을 사용하기 위해서는 nix-ld를 사용하도록 설정해야한다. 그리고 이 설정은 root로 시스템레벨에서 설정해야한다. 유저스페이스에서 설정하는것은 동작하지 않는다.
이를위해, configuration.nix를 수정한다.

{
    (...)
    programs.nix-ld.enable = true;
    (...)
}

dotnet workload 설치

이제 dotnet 명령어를 사용할 수있다. 하지만 blazor wasm을 빌드하기 위해서는 wasm-tool workload 설치가 필요하다.
dotnet workload install wasm-tools을 실행하면, libicu가 필요하다는 에러가 발생한다.

이를 해결하기 위해서 유저스페이스에서 pkgs.icu를 설치하였지만, 여전히 wasm-tool이 설치되지 않았다. libicu는 설치되었지만, dotnet이 찾지 못하는 것이 문제로, LD_LIBRARY_PATH에 추가해서 해결하였다.
이는 dotnet을 path에 추가한것과 마찬가지로 home.nix에 작성하였다.

{
    home.packages = [
        (유저스페이스 패키지들)
        pkgs.icu
    ]

    (...)

    programs.bash = {
        enable = true;
        shellAliases = {
            #ll = "ls -alh --color=auto";
            ls = "eza -1 -l --color=auto --git --git-repos";
            ll = "eza -1 -l --color=auto --git --git-repos --all";
        };
        initExtra = ''
            export PATH="$PATH:/home/ks/.local/bin:/home/ks/.dotnet"
            export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${pkgs.icu}/lib"
        '';
    };

    (...)
}

이후 dotnet workload install wasm-tool를 실행할 수 있다.
dotnet과 마찬가지로 패키지별 개발환경이 아닌 유저스페이스 환경에서 설치된다.

tauri+blazor 빌드 후 실행

wasm-tool까지 설치하면, dotnet watch가 가능해진다.
cargo tauri dev로 실행시키면, nouveau: kernel rejected pushbuf: No such device 로 시작하는 에러가 발생한다.
이를 해결하기 위해서는 NVIDIA proprietary driver를 사용해야 한다.
그래픽 드라이버를 변경하기 위해서는 root로 configuration.nix를 수정한다.

{
    (...)
    # nvidia 그래픽 드라이버 사용
    services.xserver.videoDrivers = [ "nvidia" ];
    hardware.nvidia = {
        modesetting.enable = true;
        # GTX 1660 super라서, open소스 드라이버가 아닌것 사용
        open = false;
        nvidiaSettings = true; # 밝기 조절 등 설정가능
    };

    # Allow unfree packages
    nixpkgs.config.allowUnfree = true;

    environment.systemPackages = with pkgs; [
        pkgs.gpu-viewer # 어떤 드라이버가 설치되었는지 확인용
    ];

    (...)
}

nixos-rebuild switch --flake . 이후 재부팅한다.
이렇게 할경우 앞서 발생한 nouveau 에러가 해결된다. 하지만 여전히 tauri dev에서 gui가 작동하지 않는다.

WebKitGTK 문제 우회

nvidia 드라이버를 설정한 이후에는
Failed to create GBM buffer of size 800x600: Invalid argument 에러가 발생한다.
이는 WebKitGTK에서 발생하는 문제로, WEBKIT_DISABLE_DMABUF_RENDERER=1환경변수 설정이 필요하다.

앞서 flake.nix에서 작성한것처럼 개발환경(nix develop) or 유저스페이스(home.nix)에 설정한다.

    # nix develop + flake.nix
    shellHook = ''
        export WEBKIT_DISABLE_DMABUF_RENDERER="1";
    '';

    # home.nix의 경우
    initExtra = ''
        export WEBKIT_DISABLE_DMABUF_RENDERER="1";
    '';

배포

(해결중) 아마도 앱이미지로 빌드하고, 이를 nix로 배포해야할것 같습니다.

스크린샷

8 Likes

추후에 Microsoft가 닷넷을 설치할 수 있는 패키지 시스템 중에 nixos에 대한 지원도 추가될 수 있도록 신경써준다면 더 좋겠네요! 풍부하고 깊은 인사이트를 공유해주셔서 감사합니다. :smiling_face_with_three_hearts:

1 Like

글을 흥미롭게 잘 봤습니다.

사실, 닷넷의 GUI 기술이 윈도우에 특화되어서 리눅스에서는 한계가 많습니다.

지금 시도하고 있는 방식(웹뷰 + 블레이저 와즘)과 유사한 방식 중, 닷넷의 공식 지원은 아니지만, 리눅스 운영체제에서 사용 가능한 대안은 아래와 같으니 참고하세요.

  1. Uno Platform Webview2
  2. photino

그리고, 아래는 콘솔을 Razor 컴포넌트로 정의하는 특이한 시도입니다.

  1. RazorConsole
1 Like