Commit 54fee419 authored by David McFarland's avatar David McFarland
Browse files

godot: package export templates

parent 312201ae
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
{
  version = "4.3-stable";
  hash = "sha256-MzElflwXHWLgPtoOIhPLA00xX8eEdQsexZaGIEOzbj0=";
  default = {
    exportTemplatesHash = "sha256-9fENuvVqeQg0nmS5TqjCyTwswR+xAUyVZbaKK7Q3uSI=";
  };
  mono = {
    exportTemplatesHash = "sha256-pkDZfkJHiDtY05TGERwTNDES88SbuFfZVYb5hln6O+U=";
    nugetDeps = ./deps.json;
  };
}
+7 −2
Original line number Diff line number Diff line
{
  version = "4.4.1-stable";
  hash = "sha256-O4TdPYu1K2zWKMBP/7xd0UPLDb7/4dBnkGM7QydD3Yo=";
  default = {
    exportTemplatesHash = "sha256-eo0UreSJ/U0i8XgZMCH+iodqnlEGjtTd4m2sOuTFmog=";
  };
  mono = {
    exportTemplatesHash = "sha256-tk0WS5axndcXWhuj86blg+nU3FB7PRMzVj8ka1gRgj4=";
    nugetDeps = ./deps.json;
  };
}
+30 −0
Original line number Diff line number Diff line
From 42f89dd50dde0896d6c55282c82db9af41cd12d8 Mon Sep 17 00:00:00 2001
From: David McFarland <corngood@gmail.com>
Date: Wed, 26 Mar 2025 09:52:17 -0300
Subject: [PATCH] CSharpLanguage: fix crash in reload_assemblies after editor
 shutdown

---
 modules/mono/csharp_script.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 36c8a40ed9..2b161fb69b 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1001,8 +1001,10 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
 #ifdef TOOLS_ENABLED
 	// FIXME: Hack to refresh editor in order to display new properties and signals. See if there is a better alternative.
 	if (Engine::get_singleton()->is_editor_hint()) {
-		InspectorDock::get_inspector_singleton()->update_tree();
-		NodeDock::get_singleton()->update_lists();
+		if (InspectorDock::get_singleton())
+			InspectorDock::get_inspector_singleton()->update_tree();
+		if (NodeDock::get_singleton())
+			NodeDock::get_singleton()->update_lists();
 	}
 #endif
 }
-- 
2.48.1
+476 −321
Original line number Diff line number Diff line
@@ -2,8 +2,10 @@
  alsa-lib,
  autoPatchelfHook,
  buildPackages,
  callPackage,
  dbus,
  dotnetCorePackages,
  exportTemplatesHash,
  fetchFromGitHub,
  fontconfig,
  hash,
@@ -30,6 +32,7 @@
  stdenvNoCC,
  testers,
  udev,
  updateScript,
  version,
  vulkan-loader,
  wayland,
@@ -42,7 +45,6 @@
  withPrecision ? "single",
  withPulseaudio ? true,
  withSpeechd ? true,
  withTarget ? "editor",
  withTouch ? true,
  withUdev ? true,
  # Wayland in Godot requires X11 until upstream fix is merged
@@ -59,14 +61,30 @@ let
    k: v: if builtins.isString v then "${k}=${v}" else "${k}=${builtins.toJSON v}"
  );

  suffix = if withMono then "-mono" else "";

  arch = stdenv.hostPlatform.linuxArch;

  dotnet-sdk = dotnetCorePackages.sdk_8_0-source;

  attrs = finalAttrs: rec {
    pname = "godot4${suffix}";
  dottedVersion = lib.replaceStrings [ "-" ] [ "." ] version + lib.optionalString withMono ".mono";

  attrsForTarget =
    target: finalAttrs:
    let
      editor = target == "editor";
      suffix = lib.optionalString withMono "-mono" + lib.optionalString (!editor) "-template";
      binary = lib.concatStringsSep "." (
        [
          "godot"
          withPlatform
          target
        ]
        ++ lib.optional (withPrecision != "single") withPrecision
        ++ [ arch ]
        ++ lib.optional withMono "mono"
      );
    in
    rec {
      pname = "godot${suffix}";
      inherit version;

      src = fetchFromGitHub {
@@ -94,8 +112,7 @@ let

      outputs = [
        "out"
      "man"
    ];
      ] ++ lib.optional (editor) "man";
      separateDebugInfo = true;

      # Set the build name which is part of the version. In official downloads, this
@@ -123,7 +140,7 @@ let
        precision = withPrecision; # Floating-point precision level
        production = true; # Set defaults to build Godot for use in production
        platform = withPlatform;
      target = withTarget;
        inherit target;
        debug_symbols = true;

        # Options from 'platform/linuxbsd/detect.py'
@@ -145,6 +162,12 @@ let

      strictDeps = true;

      patches = lib.optionals (lib.versionOlder version "4.4") [
        # Fix a crash in the mono test project build. It no longer seems to
        # happen in 4.4, but an existing fix couldn't be identified.
        ./CSharpLanguage-fix-crash-in-reload_assemblies-after-.patch
      ];

      depsBuildBuild = lib.optionals (stdenv.buildPlatform != stdenv.hostPlatform) [
        buildPackages.stdenv.cc
        pkg-config
@@ -165,13 +188,9 @@ let
          makeWrapper
        ];

    postBuild = lib.optionalString withMono ''
      postBuild = lib.optionalString (editor && withMono) ''
        echo "Generating Glue"
      if [[ ${withPrecision} == *double* ]]; then
          bin/godot.${withPlatform}.${withTarget}.${withPrecision}.${arch}.mono --headless --generate-mono-glue modules/mono/glue
      else
          bin/godot.${withPlatform}.${withTarget}.${arch}.mono --headless --generate-mono-glue modules/mono/glue
      fi
        bin/${binary} --headless --generate-mono-glue modules/mono/glue
        echo "Building C#/.NET Assemblies"
        python modules/mono/build_scripts/build_assemblies.py --godot-output-dir bin --precision=${withPrecision}
      '';
@@ -213,22 +232,35 @@ let
        ''
          runHook preInstall

        mkdir -p "$out/bin"
        cp bin/godot.* $out/bin/godot4${suffix}
          mkdir -p "$out"/{bin,libexec}
          cp -r bin/* "$out"/libexec

          cd "$out"/bin
          ln -s ../libexec/${binary} godot${lib.versions.majorMinor version}${suffix}
          ln -s godot${lib.versions.majorMinor version}${suffix} godot${lib.versions.major version}${suffix}
          ln -s godot${lib.versions.major version}${suffix} godot${suffix}
          cd -
        ''
        + (
          if editor then
            ''
              installManPage misc/dist/linux/godot.6

              mkdir -p "$out"/share/{applications,icons/hicolor/scalable/apps}
        cp misc/dist/linux/org.godotengine.Godot.desktop "$out/share/applications/org.godotengine.Godot4${suffix}.desktop"
        substituteInPlace "$out/share/applications/org.godotengine.Godot4${suffix}.desktop" \
          --replace "Exec=godot" "Exec=$out/bin/godot4${suffix}" \
          --replace "Godot Engine" "Godot Engine 4"
              cp misc/dist/linux/org.godotengine.Godot.desktop "$out/share/applications/org.godotengine.Godot${lib.versions.majorMinor version}${suffix}.desktop"
              substituteInPlace "$out/share/applications/org.godotengine.Godot${lib.versions.majorMinor version}${suffix}.desktop" \
                --replace "Exec=godot" "Exec=$out/bin/godot${suffix}" \
                --replace "Godot Engine" "Godot Engine ${
                  lib.versions.majorMinor version + lib.optionalString withMono " (Mono)"
                }"
              cp icon.svg "$out/share/icons/hicolor/scalable/apps/godot.svg"
              cp icon.png "$out/share/icons/godot.png"
            ''
            + lib.optionalString withMono ''
        cp -r bin/GodotSharp/ $out/bin/
        wrapProgram $out/bin/godot4${suffix} \
              mkdir -p "$out"/share/nuget
              mv "$out"/libexec/GodotSharp/Tools/nupkgs "$out"/share/nuget/source

              wrapProgram $out/libexec/${binary} \
                --set DOTNET_ROOT ${dotnet-sdk}/share/dotnet \
                --prefix PATH : "${
                  lib.makeBinPath [
@@ -236,8 +268,29 @@ let
                  ]
                }"
            ''
          else
            let
              template =
                (lib.replaceStrings
                  [ "template" ]
                  [
                    {
                      linuxbsd = "linux";
                    }
                    .${withPlatform}
                  ]
                  target
                )
                + "."
                + arch;
            in
            ''
              templates="$out"/share/godot/export_templates/${dottedVersion}
              mkdir -p "$templates"
              ln -s "$out"/libexec/${binary} "$templates"/${template}
            ''
        )
        + ''
        ln -s godot4${suffix} "$out"/bin/godot
          runHook postInstall
        '';

@@ -249,37 +302,25 @@ let
        autoPatchelf "$out"
      '';

    passthru = {
      passthru =
        {
          inherit updateScript;

          tests =
            {
              version = testers.testVersion {
                package = finalAttrs.finalPackage;
                version = dottedVersion;
              };
            }
            // lib.optionalAttrs (editor) (
              let
                pkg = finalAttrs.finalPackage;
          dottedVersion = lib.replaceStrings [ "-" ] [ "." ] version;
          exportedProject = stdenvNoCC.mkDerivation {
            name = "${pkg.name}-project-export";

            nativeBuildInputs = [
              pkg
              autoPatchelfHook
            ];

            runtimeDependencies = map lib.getLib [
              alsa-lib
              libGL
              libpulseaudio
              libX11
              libXcursor
              libXext
              libXi
              libXrandr
              udev
              vulkan-loader
            ];

            unpackPhase = ''
              runHook preUnpack

              mkdir test
              cd test
                project-src = runCommand "${pkg.name}-project-src" { } (
                  ''
                    mkdir "$out"
                    cd "$out"
                    touch project.godot

                    cat >create-scene.gd <<'EOF'
@@ -288,15 +329,24 @@ let
                    func _initialize():
                      var node = Node.new()
                      var script = ResourceLoader.load("res://test.gd")
                print(script)
                      node.set_script(script)
                  ''
                  + lib.optionalString withMono ''
                    ${""}
                      var monoNode = Node.new()
                      var monoScript = ResourceLoader.load("res://Test.cs")
                      monoNode.set_script(monoScript)
                      node.add_child(monoNode)
                      monoNode.owner = node
                  ''
                  + ''
                      var scene = PackedScene.new()
                      var scenePath = "res://test.tscn"
                      scene.pack(node)
                      node.free()
                      var x = ResourceSaver.save(scene, scenePath)
                      ProjectSettings["application/run/main_scene"] = scenePath
                      ProjectSettings.save()
                node.free()
                      quit()
                    EOF

@@ -318,18 +368,64 @@ let
                    [preset.0.options]
                    __empty=""
                    EOF
                  ''
                  + lib.optionalString withMono ''
                    cat >Test.cs <<'EOF'
                    using Godot;
                    using System;

                    public partial class Test : Node
                    {
                      public override void _Ready()
                      {
                        GD.Print("Hello, Mono!");
                        GetTree().Quit();
                      }
                    }
                    EOF

                    sdk_version=$(basename ${pkg}/share/nuget/packages/godot.net.sdk/*)
                    cat >UnnamedProject.csproj <<EOF
                    <Project Sdk="Godot.NET.Sdk/$sdk_version">
                      <PropertyGroup>
                        <TargetFramework>net8.0</TargetFramework>
                        <EnableDynamicLoading>true</EnableDynamicLoading>
                      </PropertyGroup>
                    </Project>
                    EOF
                  ''
                );

              runHook postUnpack
                export-tests = lib.makeExtensible (final: {
                  inherit (pkg) export-template;

                  export = stdenvNoCC.mkDerivation {
                    name = "${final.export-template.name}-export";

                    nativeBuildInputs = [
                      pkg
                    ] ++ lib.optional withMono dotnet-sdk;

                    src = project-src;

                    postConfigure = lib.optionalString withMono ''
                      dotnet new sln -n UnnamedProject
                      message=$(dotnet sln add UnnamedProject.csproj)
                      echo "$message"
                      # dotnet sln doesn't return an error when it fails to add the project
                      [[ $message == "Project \`UnnamedProject.csproj\` added to the solution." ]]
                    '';

                    exportTemplate = pkg.export-template;

                    buildPhase = ''
                      runHook preBuild

                      export HOME=$(mktemp -d)
                      mkdir -p $HOME/.local/share/godot/
              ln -s "${pkg.export-templates-bin}"/share/godot/export_templates "$HOME"/.local/share/godot/
                      ln -s "${final.export-template}"/share/godot/export_templates "$HOME"/.local/share/godot/

              godot --headless -s create-scene.gd
                      godot${suffix} --headless --build-solutions -s create-scene.gd

                      runHook postBuild
                    '';
@@ -338,23 +434,28 @@ let
                      runHook preInstall

                      mkdir -p "$out"/bin
              godot --headless --export-release build "$out"/bin/test
                      godot${suffix} --headless --export-release build "$out"/bin/test

                      runHook postInstall
                    '';
                  };
        in
        {
          version = testers.testVersion {
            package = pkg;
            version = dottedVersion;
          };

          project-runs = runCommand "${pkg.name}-project-runs" { } ''
                  run = runCommand "${final.export.name}-runs" { passthru = { inherit (final) export; }; } (
                    ''
                      (
                        set -eo pipefail
                        HOME=$(mktemp -d)
              "${exportedProject}"/bin/test --headless | tail -n1 | (
                        "${final.export}"/bin/test --headless | tail -n+3 | (
                    ''
                    + lib.optionalString withMono ''
                      # indent
                          read output
                          if [[ "$output" != "Hello, Mono!" ]]; then
                            echo "unexpected output: $output" >&2
                            exit 1
                          fi
                    ''
                    + ''
                          read output
                          if [[ "$output" != "Hello, World!" ]]; then
                            echo "unexpected output: $output" >&2
@@ -363,8 +464,56 @@ let
                        )
                        touch "$out"
                      )
          '';
        };
                    ''
                  );
                });

              in
              {
                export-runs = export-tests.run;

                export-bin-runs =
                  (export-tests.extend (
                    final: prev: {
                      export-template = pkg.export-templates-bin;

                      export = prev.export.overrideAttrs (prev: {
                        nativeBuildInputs = prev.nativeBuildInputs or [ ] ++ [
                          autoPatchelfHook
                        ];

                        # stripping dlls results in:
                        # Failed to load System.Private.CoreLib.dll (error code 0x8007000B)
                        stripExclude = lib.optional withMono [ "*.dll" ];

                        runtimeDependencies =
                          prev.runtimeDependencies or [ ]
                          ++ map lib.getLib [
                            alsa-lib
                            libpulseaudio
                            libX11
                            libXcursor
                            libXext
                            libXi
                            libXrandr
                            udev
                            vulkan-loader
                          ];
                      });
                    }
                  )).run;
              }
            );
        }
        // lib.optionalAttrs editor {
          export-template = mkTarget "template_release";
          export-templates-bin = (
            callPackage ./export-templates-bin.nix {
              inherit version withMono;
              godot = finalAttrs.finalPackage;
              hash = exportTemplatesHash;
            }
          );
        };

      requiredSystemFeatures = [
@@ -385,10 +534,14 @@ let
          shiryel
          corngood
        ];
      mainProgram = "godot4${suffix}";
        mainProgram = "godot${suffix}";
      };
    };

  mkTarget =
    target:
    let
      attrs = attrsForTarget target;
    in
    stdenv.mkDerivation (
      if withMono then
@@ -403,4 +556,6 @@ stdenv.mkDerivation (
        } attrs
      else
        attrs
)
    );
in
mkTarget "editor"
+35 −29
Original line number Diff line number Diff line
# TODO:
# - combine binary and source tests
# - filter builtInputs by builtin_ flags
{
  callPackage,
  lib,
  nix-update-script,
  fetchzip,
}:
@@ -8,43 +12,40 @@ let
    versionPrefix:
    let
      attrs = import (./. + "/${versionPrefix}/default.nix");
      inherit (attrs)
        version
        hash
        exportTemplatesHash
        nugetDeps
        ;
    in
    rec {
      godot = (callPackage ./common.nix { inherit version hash nugetDeps; }).overrideAttrs (old: {
        passthru = old.passthru or { } // {
          inherit export-templates-bin;
      updateScript = [
        ./update.sh
        versionPrefix
        (builtins.unsafeGetAttrPos "version" attrs).file
      ];
    in
    lib.recurseIntoAttrs rec {
      godot = callPackage ./common.nix {
        inherit updateScript;
        inherit (attrs)
          version
          hash
          ;
        inherit (attrs.default)
          exportTemplatesHash
          ;
      };
      });

      godot-mono = godot.override {
        withMono = true;
        inherit (attrs.mono)
          exportTemplatesHash
          nugetDeps
          ;
      };

      export-templates-bin = (
        callPackage ./export-templates-bin.nix {
          inherit version godot;
          hash = exportTemplatesHash;
        }
      );
    };
      export-template = godot.export-template;
      export-template-mono = godot-mono.export-template;

  godotPackages_4_3 = mkGodotPackages "4.3";
  godotPackages_4_4 = mkGodotPackages "4.4";
  godotPackages_4 = godotPackages_4_4;
  godotPackages = godotPackages_4;
      export-templates-bin = godot.export-templates-bin;
      export-templates-mono-bin = godot-mono.export-templates-bin;
    };
in
{
rec {
  godot3 = callPackage ./3 { };
  godot3-export-templates = callPackage ./3/export-templates.nix { };
  godot3-headless = callPackage ./3/headless.nix { };
@@ -56,6 +57,11 @@ in
  godot3-mono-debug-server = callPackage ./3/mono/debug-server.nix { };
  godot3-mono-server = callPackage ./3/mono/server.nix { };

  godotPackages_4_3 = mkGodotPackages "4.3";
  godotPackages_4_4 = mkGodotPackages "4.4";
  godotPackages_4 = godotPackages_4_4;
  godotPackages = godotPackages_4;

  godot_4_3 = godotPackages_4_3.godot;
  godot_4_3-mono = godotPackages_4_3.godot-mono;
  godot_4_3-export-templates-bin = godotPackages_4_3.export-templates-bin;
Loading