From b09fbe2d9be99953554f18cc8707199f086fad6a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 22 Jan 2026 23:39:38 +0100 Subject: [PATCH] Fix deploying NuGet packages to include dependencies (recursive) #3900 --- Source/Tools/Flax.Build/Build/Builder.cs | 57 +++++++++++++++---- .../Build/NativeCpp/BuildOptions.cs | 29 +++++++++- 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/Source/Tools/Flax.Build/Build/Builder.cs b/Source/Tools/Flax.Build/Build/Builder.cs index d09947f09..775bef1dc 100644 --- a/Source/Tools/Flax.Build/Build/Builder.cs +++ b/Source/Tools/Flax.Build/Build/Builder.cs @@ -440,6 +440,7 @@ namespace Flax.Build { // Find all packages to deploy (incl. dependencies) and restore if needed var nugetPath = Utilities.GetNugetPackagesPath(); + Log.Verbose($"Deploying NuGet packages from {nugetPath}"); var restoreOnce = true; var nugetFiles = new HashSet(); foreach (var reference in targetBuildOptions.NugetPackageReferences) @@ -452,17 +453,7 @@ namespace Flax.Build restoreOnce = false; } - // Deploy library - var path = reference.GetLibPath(nugetPath, folder); - nugetFiles.Add(path); - - // Copy additional files (if included) - path = Path.ChangeExtension(path, "xml"); - if (File.Exists(path)) - nugetFiles.Add(path); - path = Path.ChangeExtension(path, "pdb"); - if (targetBuildOptions.Configuration != TargetConfiguration.Release && File.Exists(path)) - nugetFiles.Add(path); + DeployNuGetPackage(nugetPath, targetBuildOptions, nugetFiles, reference, folder); } // Copy libraries from all referenced packages to the output folder @@ -505,5 +496,49 @@ namespace Flax.Build Log.Info($"Restoring NuGet packages for target {target.Name}"); Utilities.Run(Utilities.GetDotNetPath(), $"restore \"{csprojPath}\"", null, null, Utilities.RunOptions.DefaultTool); } + + private static void DeployNuGetPackage(string nugetPath, BuildOptions targetBuildOptions, HashSet nugetFiles, NugetPackage package, string folder = null) + { + // Deploy library + var path = package.GetLibPath(nugetPath, folder); + if (!File.Exists(path)) + return; + Log.Verbose($"Deploying NuGet package {package.Name}, {package.Version}, {package.Framework}"); + nugetFiles.Add(path); + + // Copy additional files (if included) + path = Path.ChangeExtension(path, "xml"); + if (File.Exists(path)) + nugetFiles.Add(path); + path = Path.ChangeExtension(path, "pdb"); + if (targetBuildOptions.Configuration != TargetConfiguration.Release && File.Exists(path)) + nugetFiles.Add(path); + + // Read package dependencies + var nuspecFile = package.GetNuspecPath(nugetPath); + if (File.Exists(nuspecFile)) + { + var doc = System.Xml.Linq.XDocument.Load(nuspecFile); + var root = (System.Xml.Linq.XElement)doc.FirstNode; + var metadataNode = root.Descendants().First(x => x.Name.LocalName== "metadata"); + var dependenciesNode = metadataNode.Descendants().First(x => x.Name.LocalName == "dependencies"); + var groupNode = dependenciesNode.Descendants().FirstOrDefault(x => x.Attribute("targetFramework")?.Value == package.Framework); + if (groupNode == null) + { + Log.Warning($"Cannot find framework {package.Framework} inside NuGet package {package.Name}, {package.Version}"); + return; + } + foreach (var dependency in groupNode.Descendants()) + { + if (dependency.Name.LocalName != "dependency") + continue; + + // Deploy dependency package + var dependencyId = dependency.Attribute("id").Value; + var dependencyVersion = dependency.Attribute("version").Value; + DeployNuGetPackage(nugetPath, targetBuildOptions, nugetFiles, new NugetPackage { Name = dependencyId, Version = dependencyVersion, Framework = package.Framework } ); + } + } + } } } diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs index b0f116673..8251ff186 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs @@ -105,7 +105,34 @@ namespace Flax.Build.NativeCpp internal string GetLibFolder(string nugetPath) { - return Path.Combine(nugetPath, Name, Version, "lib", Framework); + var libFolder = Path.Combine(nugetPath, Name, Version, "lib", Framework); + if (Directory.Exists(libFolder)) + return libFolder; + + // Try to find nearest framework folder + if (Framework.StartsWith("net")) + { + var baseVersion = int.Parse(Framework.Substring(3, Framework.IndexOf('.') - 3)); + for (int version = baseVersion - 1; version >= 5; version--) + { + var framework = $"net{version}.0"; + libFolder = Path.Combine(nugetPath, Name, Version, "lib", framework); + if (Directory.Exists(libFolder)) + { + Framework = framework; + return libFolder; + } + } + } + + Log.Error($"Missing NuGet package \"{Name}, {Version}, {Framework}\" (nuget: {nugetPath})"); + return string.Empty; + } + + internal string GetNuspecPath(string nugetPath) + { + var files = Directory.GetFiles(Path.Combine(nugetPath, Name, Version), "*.nuspec", SearchOption.TopDirectoryOnly); + return files[0]; } internal string GetLibPath(string nugetPath, string libFolder = null)