Skip to content

Commit 08613f6

Browse files
authored
Add the ability to supply multiple library paths in SearchPathContainer (#1351)
* Add the ability to supply multiple library paths in SearchPathContainer * OpenAL: Change `soft` parameter from exclusive to preference This means that now if loading OpenAL soft fails, ittl try to fall back to native, and if loading OpenAL native fails, ittl fall back to OpenAL soft * SingletonSeparatedList -> SeparatedList * Loader: Allow fallible loading of native contexts and libraries * SilkTouch: Use fallible codepath for multiple libname fallback
1 parent 614c48c commit 08613f6

File tree

48 files changed

+393
-186
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+393
-186
lines changed

src/Assimp/Silk.NET.Assimp/Assimp.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public partial class Assimp
1313
{
1414
public static Assimp GetApi()
1515
{
16-
return new Assimp(CreateDefaultContext(new AssimpLibraryNameContainer().GetLibraryName()));
16+
return new Assimp(CreateDefaultContext(new AssimpLibraryNameContainer().GetLibraryNames()));
1717
}
1818

1919
public override bool IsExtensionPresent(string extension) => IsExtensionSupported(extension) == 1;

src/Assimp/Silk.NET.Assimp/AssimpLibraryNameContainer.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@ namespace Silk.NET.Assimp
1111
internal class AssimpLibraryNameContainer : SearchPathContainer
1212
{
1313
/// <inheritdoc />
14-
public override string Linux => "libassimp.so.5";
14+
public override string[] Linux => new[] { "libassimp.so.5" };
1515

1616
/// <inheritdoc />
17-
public override string MacOS => "libassimp.5.dylib";
17+
public override string[] MacOS => new[] { "libassimp.5.dylib" };
1818

1919
/// <inheritdoc />
20-
public override string Android => "libassimp.so.5";
20+
public override string[] Android => new[] { "libassimp.so.5" };
2121

2222
/// <inheritdoc />
23-
public override string IOS => "__Internal";
23+
public override string[] IOS => new[] { "__Internal" };
2424

2525
/// <inheritdoc />
26-
public override string Windows64 => "Assimp64.dll";
26+
public override string[] Windows64 => new[] { "Assimp64.dll" };
2727

2828
/// <inheritdoc />
29-
public override string Windows86 => "Assimp32.dll";
29+
public override string[] Windows86 => new[] { "Assimp32.dll" };
3030
}
3131
}

src/Core/Silk.NET.BuildTools/Bind/ClassWriter.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,22 @@ public static void WriteNameContainer(this Project project, Profile profile, str
3939
sw.WriteLine($" internal class {task.Task.NameContainer.ClassName} : SearchPathContainer");
4040
sw.WriteLine(" {");
4141
sw.WriteLine(" /// <inheritdoc />");
42-
sw.WriteLine($" public override string Linux => \"{task.Task.NameContainer.Linux}\";");
42+
sw.WriteLine($" public override string[] Linux => new[] {{ \"{task.Task.NameContainer.Linux}\" }};");
4343
sw.WriteLine();
4444
sw.WriteLine(" /// <inheritdoc />");
45-
sw.WriteLine($" public override string MacOS => \"{task.Task.NameContainer.MacOS}\";");
45+
sw.WriteLine($" public override string[] MacOS => new[] {{ \"{task.Task.NameContainer.MacOS}\" }};");
4646
sw.WriteLine();
4747
sw.WriteLine(" /// <inheritdoc />");
48-
sw.WriteLine($" public override string Android => \"{task.Task.NameContainer.Android}\";");
48+
sw.WriteLine($" public override string[] Android => new[] {{ \"{task.Task.NameContainer.Android}\" }};");
4949
sw.WriteLine();
5050
sw.WriteLine(" /// <inheritdoc />");
51-
sw.WriteLine($" public override string IOS => \"{task.Task.NameContainer.IOS}\";");
51+
sw.WriteLine($" public override string[] IOS => {{ \"{task.Task.NameContainer.IOS}\" }};");
5252
sw.WriteLine();
5353
sw.WriteLine(" /// <inheritdoc />");
54-
sw.WriteLine($" public override string Windows64 => \"{task.Task.NameContainer.Windows64}\";");
54+
sw.WriteLine($" public override string[] Windows64 => {{ \"{task.Task.NameContainer.Windows64}\" }};");
5555
sw.WriteLine();
5656
sw.WriteLine(" /// <inheritdoc />");
57-
sw.WriteLine($" public override string Windows86 => \"{task.Task.NameContainer.Windows86}\";");
57+
sw.WriteLine($" public override string[] Windows86 => {{ \"{task.Task.NameContainer.Windows86}\" }};");
5858
sw.WriteLine(" }");
5959
sw.WriteLine("}");
6060
}
@@ -264,7 +264,7 @@ static string GetSignature(Function func)
264264
sw.WriteLine
265265
(
266266
$" return new(CreateDefaultContext" +
267-
$"(new {task.Task.NameContainer.ClassName}().GetLibraryName()));"
267+
$"(new {task.Task.NameContainer.ClassName}().GetLibraryNames()));"
268268
);
269269
}
270270
else

src/Core/Silk.NET.Core/Contexts/DefaultNativeContext.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ namespace Silk.NET.Core.Contexts
1111
/// </summary>
1212
public class DefaultNativeContext : INativeContext
1313
{
14+
public static bool TryCreate(string name, out DefaultNativeContext context)
15+
{
16+
if(!UnmanagedLibrary.TryCreate(name, LibraryLoader.GetPlatformDefaultLoader(), PathResolver.Default, out UnmanagedLibrary library))
17+
{
18+
context = null;
19+
return false;
20+
}
21+
22+
context = new DefaultNativeContext(library);
23+
return true;
24+
}
25+
1426
/// <summary>
1527
/// Creates a new native context for the given underlying library.
1628
/// </summary>

src/Core/Silk.NET.Core/Loader/SearchPathContainer.cs

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,40 +47,40 @@ public abstract class SearchPathContainer
4747
#endif
4848

4949
/// <summary>
50-
/// Gets the library name to use on Windows 64-bit.
50+
/// Gets the library names to use on Windows 64-bit.
5151
/// </summary>
52-
public abstract string Windows64 { get; }
52+
public abstract string[] Windows64 { get; }
5353

5454
/// <summary>
55-
/// Gets the library name to use on Windows 32-bit.
55+
/// Gets the library names to use on Windows 32-bit.
5656
/// </summary>
57-
public abstract string Windows86 { get; }
57+
public abstract string[] Windows86 { get; }
5858

5959
/// <summary>
60-
/// Gets the library name to use on Linux.
60+
/// Gets the library names to use on Linux.
6161
/// </summary>
62-
public abstract string Linux { get; }
62+
public abstract string[] Linux { get; }
6363

6464
/// <summary>
65-
/// Gets the library name to use on MacOS.
65+
/// Gets the library names to use on MacOS.
6666
/// </summary>
67-
public abstract string MacOS { get; }
67+
public abstract string[] MacOS { get; }
6868

6969
/// <summary>
70-
/// Gets the library name to use on Android.
70+
/// Gets the library names to use on Android.
7171
/// </summary>
72-
public virtual string Android => Linux;
72+
public virtual string[] Android => Linux;
7373

7474
/// <summary>
75-
/// Gets the library name to use on iOS.
75+
/// Gets the library names to use on iOS.
7676
/// </summary>
77-
public virtual string IOS => MacOS;
77+
public virtual string[] IOS => MacOS;
7878

7979
/// <summary>
80-
/// Gets the library name to use on the current platform.
80+
/// Gets the possible library names to use for the current platform.
8181
/// </summary>
82-
/// <returns>The library name.</returns>
83-
public string GetLibraryName() => Platform switch
82+
/// <returns>The library names.</returns>
83+
public string[] GetLibraryNames() => Platform switch
8484
{
8585
UnderlyingPlatform.Unknown => ThrowInvalidPlatform(),
8686
UnderlyingPlatform.Windows64 => Windows64,
@@ -92,7 +92,14 @@ public abstract class SearchPathContainer
9292
_ => ThrowInvalidPlatform()
9393
};
9494

95-
private static string ThrowInvalidPlatform()
95+
/// <summary>
96+
/// Gets the library name to use on the current platform.
97+
/// </summary>
98+
/// <returns>The library name.</returns>
99+
[Obsolete("This method is obsolete! Use GetLibraryNames")]
100+
public string GetLibraryName() => GetLibraryNames()[0];
101+
102+
private static string[] ThrowInvalidPlatform()
96103
{
97104
throw new PlatformNotSupportedException("Invalid/unsupported operating system.");
98105
}

src/Core/Silk.NET.Core/Loader/UnmanagedLibrary.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,30 @@ public UnmanagedLibrary(string[] names, LibraryLoader loader) : this(names, load
4949
{
5050
}
5151

52+
/// <summary>
53+
/// Constructs a new UnmanagedLibrary with only a loader and handle specified
54+
/// </summary>
55+
private UnmanagedLibrary(LibraryLoader loader, nint handle)
56+
{
57+
_loader = loader;
58+
Handle = handle;
59+
}
60+
61+
/// <summary>
62+
/// Tries to create a new UnmanagedLibrary, safely failing
63+
/// </summary>
64+
public static bool TryCreate(string name, LibraryLoader loader, PathResolver pathResolver, out UnmanagedLibrary library)
65+
{
66+
if(!loader.TryLoadNativeLibrary(name, pathResolver, out nint handle))
67+
{
68+
library = null;
69+
return false;
70+
}
71+
72+
library = new UnmanagedLibrary(loader, handle);
73+
return true;
74+
}
75+
5276
/// <summary>
5377
/// Constructs a new NativeLibrary using the specified library loader.
5478
/// </summary>

src/Core/Silk.NET.SilkTouch/NativeContextOverrideGeneration.cs

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
@@ -49,6 +49,35 @@ Compilation comp
4949
IdentifierName("n")))))
5050
);
5151

52+
StatementSyntax arrLast = IfStatement
53+
(
54+
InvocationExpression
55+
(
56+
ParseName("Silk.NET.Core.Contexts.DefaultNativeContext.TryCreate"),
57+
ArgumentList
58+
(
59+
SeparatedList
60+
(
61+
new []
62+
{
63+
Argument(IdentifierName("name")),
64+
Argument
65+
(
66+
null,
67+
Token(SyntaxKind.OutKeyword),
68+
DeclarationExpression
69+
(
70+
IdentifierName("DefaultNativeContext"),
71+
SingleVariableDesignation(Identifier("context"))
72+
)
73+
)
74+
}
75+
)
76+
)
77+
),
78+
ReturnStatement(IdentifierName("context"))
79+
);
80+
5281
foreach (var (attSymbol, attId, lib, @override) in overrides.OrderBy(x => x.Item2))
5382
{
5483
var name = NameGenerator.Name($"OVERRIDE_{attId}");
@@ -61,6 +90,17 @@ Compilation comp
6190
var matchId = (int) x2.ConstructorArguments[0].Value!;
6291
return matchId != attId;
6392
})).ToArray(), comp.SyntaxTrees?.FirstOrDefault()?.IsNet5OrGreater() ?? false)));
93+
94+
arrLast = IfStatement
95+
(
96+
BinaryExpression
97+
(
98+
SyntaxKind.EqualsExpression, IdentifierName("name"),
99+
LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(lib))
100+
), ReturnStatement(ObjectCreationExpression(IdentifierName(name), ArgumentList(), null)),
101+
ElseClause(arrLast)
102+
);
103+
64104
last = IfStatement
65105
(
66106
BinaryExpression
@@ -85,6 +125,78 @@ Compilation comp
85125
)
86126
)
87127
.WithBody(Block(last))
128+
.WithAttributeLists(
129+
SingletonList
130+
(
131+
AttributeList
132+
(
133+
SingletonSeparatedList
134+
(
135+
Attribute
136+
(
137+
ParseName("System.ObsoleteAttribute"),
138+
AttributeArgumentList
139+
(
140+
SingletonSeparatedList
141+
(
142+
AttributeArgument
143+
(
144+
LiteralExpression(SyntaxKind.StringLiteralExpression,
145+
Literal("This function is obsolete! Please use the string[] overload!")
146+
)
147+
)
148+
)
149+
)
150+
)
151+
)
152+
)
153+
))
154+
);
155+
156+
//wrap arrLast into its foreach loop
157+
//eg `foreach(string name in n)`
158+
arrLast = ForEachStatement(PredefinedType(Token(SyntaxKind.StringKeyword)), Identifier("name"), IdentifierName("n"), Block(arrLast));
159+
160+
members.Add
161+
(
162+
MethodDeclaration(IdentifierName("INativeContext"), Identifier("CreateDefaultContext"))
163+
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)))
164+
.WithParameterList
165+
(
166+
ParameterList
167+
(
168+
SingletonSeparatedList
169+
(Parameter(Identifier("n")).WithType(ArrayType(PredefinedType(Token(SyntaxKind.StringKeyword)), SingletonList(ArrayRankSpecifier()))))
170+
)
171+
)
172+
.WithBody
173+
(
174+
Block
175+
(
176+
arrLast,
177+
ThrowStatement
178+
(
179+
ObjectCreationExpression(IdentifierName("System.IO.FileNotFoundException"))
180+
.WithArgumentList
181+
(
182+
ArgumentList
183+
(
184+
SingletonSeparatedList
185+
(
186+
Argument
187+
(
188+
LiteralExpression
189+
(
190+
SyntaxKind.StringLiteralExpression,
191+
Literal("Could not load from any of the possible library names! Please make sure that the library is installed and in the right place!")
192+
)
193+
)
194+
)
195+
)
196+
)
197+
)
198+
)
199+
)
88200
);
89201
}
90202

@@ -94,7 +206,7 @@ Compilation comp
94206
foreach (var attribute in attributes)
95207
{
96208
if (attribute.AttributeClass is null) continue;
97-
209+
98210
if (_nativeContextAttributes.TryGetValue(attribute.AttributeClass, out var f))
99211
{
100212
var v = f(attribute.ConstructorArguments);

src/Lab/Experiments/TestLib/TestClass2-1.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,6 @@ public unsafe partial nint CreateWindowExA(
5151

5252
// public partial int GetWindowTextA(IntPtr hwnd, [Count(Parameter = "hwnd")] ref string str, int maxCount);
5353

54-
public TestClass2() : base(CreateDefaultContext("user32.dll")) { }
54+
public TestClass2() : base(CreateDefaultContext(new[] { "user32.dll" })) { }
5555
}
5656
}

src/Microsoft/Silk.NET.DXGI/DXGI.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public partial class DXGI
1212
{
1313
public static DXGI GetApi()
1414
{
15-
return new DXGI(CreateDefaultContext(new DXGILibraryNameContainer().GetLibraryName()));
15+
return new DXGI(CreateDefaultContext(new DXGILibraryNameContainer().GetLibraryNames()));
1616
}
1717

1818
public bool TryGetExtension<T>(out T ext)

src/Microsoft/Silk.NET.DXGI/DXGILibraryNameContainer.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@ namespace Silk.NET.DXGI
1111
internal class DXGILibraryNameContainer : SearchPathContainer
1212
{
1313
/// <inheritdoc />
14-
public override string Linux => "libDXGI.so";
14+
public override string[] Linux => new[] { "libDXGI.so" };
1515

1616
/// <inheritdoc />
17-
public override string MacOS => "libDXGI.dylib";
17+
public override string[] MacOS => new[] { "libDXGI.dylib" };
1818

1919
/// <inheritdoc />
20-
public override string Android => "libDXGI.so";
20+
public override string[] Android => new[] { "libDXGI.so" };
2121

2222
/// <inheritdoc />
23-
public override string IOS => "__Internal"; // __Internal relies on a SilkTouch override.
23+
public override string[] IOS => new[] { "__Internal" }; // __Internal relies on a SilkTouch override.
2424

2525
/// <inheritdoc />
26-
public override string Windows64 => "DXGI.dll";
26+
public override string[] Windows64 => new[] { "DXGI.dll" };
2727

2828
/// <inheritdoc />
29-
public override string Windows86 => "DXGI.dll";
29+
public override string[] Windows86 => new[] { "DXGI.dll" };
3030
}
3131
}

0 commit comments

Comments
 (0)