Nuke.Unreal
Build Unreal apps in Style.
Loading...
Searching...
No Matches
XRepoLibrary.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text.RegularExpressions;
5using System.Threading.Tasks;
6using Nuke.Cola;
7using Nuke.Cola.Tooling;
8using Nuke.Common.IO;
9using Nuke.Common.Utilities;
10using Nuke.Common.Utilities.Collections;
11using Serilog;
12
14
15/// <summary>
16/// Utility classes for working with XRepo (or XMake) packages
17/// </summary>
18public static partial class XRepoLibrary
19{
20 [GeneratedRegex(
21 """
22 ^
23 (?<SPEC>
24 (?:(?<PROVIDER>\w+)\:\:)?
25 (?<NAME>[\w\-\.]+)
26 (?:\[
27 (?<FEATURES>[\w\-,]+)
28 \])?
29 (?:[\s\/-]
30 (?<VERSION>[0-9\.x#]+)
31 )?
32 )
33 (?:\s(?<OPTIONS>[\w=,']+))?
34 $
35 """,
36 RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace
37 )]
38 private static partial Regex SpecRegex();
39
40 /// <summary>
41 /// Parses an input library spec string as a record
42 /// </summary>
43 public static LibrarySpec ParseSpec(string spec)
44 {
45 var matches = spec.Parse(SpecRegex(), forceNullOnWhitespce: true);
46 return new(
47 matches("SPEC")!,
48 matches("NAME")!,
49 matches("VERSION"),
50 matches("PROVIDER"),
51 matches("OPTIONS"),
52 matches("FEATURES")
53 );
54 }
55
56 internal static IEnumerable<XRepoLibraryRecord> InstallXRepoLibrary(UnrealBuild self, LibrarySpec spec, string options, AbsolutePath targetPath, bool debug, string runtime = "MD")
57 {
58 var libraryFiles = targetPath / "LibraryFiles";
59 options = options.AppendNonEmpty(",") + $"runtimes='{runtime}'";
60 var xrepoPlatArch = self.Platform.GetXRepoPlatformArch();
61
62 var extraArgs =
63 $"""
64 -p {xrepoPlatArch.Platform}
65 -a {xrepoPlatArch.Arch}
66 -m {(debug ? "debug" : "release")}
67 """.AsSingleLine();
68
69 // TODO: pass NDK location in
70
71 XRepoTasks.Install(spec.Spec, options, extraArgs)("");
72
73 string[] ProcessPaths(string? paths, AbsolutePath dstDir)
74 {
75 if (paths == null) return [];
76
77 return paths!.Split(" ")
78 .Select(i =>
79 {
80 var currPath = (AbsolutePath) i;
81 var dstPath = dstDir / currPath.Name;
82 if (currPath.FileExists() || currPath.DirectoryExists())
83 currPath.Copy(dstPath, ExistsPolicy.MergeAndOverwrite);
84 else
85 {
86 Log.Warning("A library is referring to a non-existing file or folder: {0}", currPath);
87 return "";
88 }
89 return dstPath.Name;
90 })
91 .Where(p => !string.IsNullOrWhiteSpace(p))
92 .ToArray();
93 };
94
95 return XRepoTasks.Info(spec.Spec, options, extraArgs)("").ParseXRepoInfo()
96 .Where(i => i["fetchinfo"] != null) // needs fetchinfo
97 .Where(i => !i["fetchinfo"]!.Any(i => i.Key?.ContainsOrdinalIgnoreCase("program") ?? false)) // ignore required programs
98 .Where(i => !i["fetchinfo"]!["kind"]?.Value?.EqualsOrdinalIgnoreCase("binary") ?? true) // ignore required executables
99 .Select(i =>
100 {
101 Log.Information("Parsing library (dependency) {0}", i.Key);
102 var currSpec = ParseSpec(i.Key!) with {
103 Version = i["version"]!.Value!
104 };
105 Log.Information(" Name: {0}", currSpec.Name);
106 Log.Information(" Version: {0}", currSpec.Version);
107 Log.Information(" Provider: {0}", currSpec.Provider ?? "xrepo");
108 Log.Information(" Features: {0}", currSpec.Features);
109
110 return new XRepoLibraryRecord(
111 Spec: currSpec,
112 Description: i["description"]?.Value,
113 Options: i["requires"]!["configs"]
114 !.Select(c => c.Key.AppendNonEmpty(": ") + c.Value)
115 .JoinNewLine(),
116 OptionsHelp: i["configs"]
117 ?.Select(c => c.Key.AppendNonEmpty(": ") + c.Value)
118 ?.JoinNewLine()
119 ?? "",
120 IncludePaths: ProcessPaths(
121 i["fetchinfo"]!["includedirs"]?.Value,
122 libraryFiles / currSpec.Name / "Includes"
123 ),
124 SysIncludePaths: ProcessPaths(
125 i["fetchinfo"]!["sysincludedirs"]?.Value,
126 libraryFiles / currSpec.Name / "SysIncludes"
127 ),
128 LibFiles: ProcessPaths(
129 i["fetchinfo"]!["libfiles"]?.Value,
130 libraryFiles / currSpec.Name / "Libs" / self.Platform / (debug ? "Debug" : "Release")
131 ),
132 SysLibs: i["fetchinfo"]!["syslinks"]?.Value
133 ?.Split(" ")
134 ?.Select(l => self.Platform.IsWindows && !l.EndsWith(".lib") ? l + ".lib" : l)
135 ?? [],
136 Defines: i["fetchinfo"]!["defines"]?.Value?.Split(" ") ?? []
137 );
138 })
139 .ToArray();
140 }
141
142 /// <summary>
143 /// Prepare a third-party library from an XRepo library spec for Unreal engine's consumption
144 /// </summary>
145 /// <param name="self">The build context</param>
146 /// <param name="specIn">The library spec specified here (without the options) https://mcro.de/Nuke.Unreal/d2/d84/CppLibraries.html</param>
147 /// <param name="options">Comma separated '=' delimited key-value pairs. Space is not allowed around commas</param>
148 /// <param name="targetPath">Where library files should be organized</param>
149 /// <param name="suffix">Optional addition to the name of library name exposed to Unreal</param>
150 /// <param name="releaseRuntime">Windows CRT linkage for release versions (default is MD)</param>
151 /// <param name="debugRuntime">Windows CRT linkage for debug versions (default is MD)</param>
152 public static void InstallXRepoLibrary(this UnrealBuild self, string specIn, string options, AbsolutePath targetPath, string? suffix = null, string releaseRuntime = "MD", string debugRuntime = "MD")
153 {
154 Log.Information("Installing library {0} via xrepo", specIn);
155 var spec = ParseSpec(specIn) with { Options = options };
156 Log.Information(" Name: {0}", spec.Name);
157 Log.Information(" Version: {0}", spec.Version);
158 Log.Information(" Provider: {0}", spec.Provider ?? "xrepo");
159 Log.Information(" Options: {0}", spec.Options);
160 Log.Information(" Features: {0}", spec.Features);
161
162 Log.Information("Installing debug build");
163 var debugLibs = InstallXRepoLibrary(self, spec, options, targetPath, true, debugRuntime);
164
165 Log.Information("Installing release build (metadata will be used from release build)");
166 var releaseLibs = InstallXRepoLibrary(self, spec, options, targetPath, false, releaseRuntime);
167
168 Log.Information("Generating partial module rule class for {0}", self.Platform);
169 new XRepoLibraryModuleGenerator().Generate(
170 self.TemplatesPath,
171 targetPath,
172 spec,
173 self.Platform,
174 releaseLibs,
175 suffix
176 );
177 }
178}
Utility classes for working with XRepo (or XMake) packages.
static LibrarySpec ParseSpec(string spec)
Parses an input library spec string as a record.
static void InstallXRepoLibrary(this UnrealBuild self, string specIn, string options, AbsolutePath targetPath, string? suffix=null, string releaseRuntime="MD", string debugRuntime="MD")
Prepare a third-party library from an XRepo library spec for Unreal engine's consumption.
The main build class Unreal projects using Nuke.Unreal should inherit from. This class contains all b...