Skip to content

Commit

Permalink
FDB: update the FoundationDB.Client.Native package to add UseNativeCl…
Browse files Browse the repository at this point in the history
…ient() extension method

- change the package to reference FoundationDB.Client nuget package
- add UseNativeClient() extension method on FdbDatabaseProviderOptions that will locate the correct library on disk
- handle both Portable and platform specific build and publish
- For now, we include the binaries for all the platforms (~52MB), maybe later find a way to split into multiple libs for each platform? (seems to be not that easy, cf dotnet/sdk/issues/33845)
  • Loading branch information
KrzysFR committed Oct 20, 2024
1 parent 12a84ff commit 70fde69
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 25 deletions.
111 changes: 111 additions & 0 deletions FoundationDB.Client.Native/FdbClientNativeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#region Copyright (c) 2023-2024 SnowBank SAS, (c) 2005-2023 Doxense SAS
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of SnowBank nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL SNOWBANK SAS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

namespace FoundationDB.Client
{
using System;
using System.IO;
using System.Runtime.InteropServices;
using FoundationDB.DependencyInjection;

public static class FdbClientNativeExtensions
{

/// <summary>Configures the <see cref="FdbDatabaseProviderOptions"/> to use the native FoundationDB client library that is redistributed with the <c>FoundationDB.Client.Native</c> package.</summary>
/// <param name="options">The <see cref="FdbDatabaseProviderOptions"/> to configure.</param>
/// <returns>The configured <see cref="FdbDatabaseProviderOptions"/>.</returns>
/// <exception cref="FileNotFoundException">
/// Thrown when the native FoundationDB client library for the running platform could not be found.
/// </exception>
/// <remarks>
/// <para>This method determines the runtime identifier (<c>win-x64</c>, <c>linux-x64</c>, <c>linux-arm64</c>, ...) and the appropriate file name (<c>fdb_c.dll</c>, <c>libfdbc.so</c>, ...) based on the current platform.</para>
/// <para>
/// The probed directories are, in order: <list type="bullet">
/// <item>The <c>runtimes/{rid}/native/</c> subfolder under the application's base directory.</item>
/// <item>The application's base directory.</item>
/// </list></para>
/// <para>The loader will <b>NOT</b> probe any other locations, like the default system folders (<c>System32</c>, ...) or any location defined in the <c>PATH</c> environment variable.</para>
/// </remarks>
public static FdbDatabaseProviderOptions UseNativeClient(this FdbDatabaseProviderOptions options)
{
// find out the platform we are running on ("win-x64", "linux-x64", ...)
var (rid, fileName) = GetRuntimeIdentifierForCurrentPlatform();

// Depending on how the application is built/published, there are two main locations where the native libs will be copied:
// - Under ./runtimes/{rid}/native/ when running in Visual Studio, or in "Portable mode" (no rid specified during publish)
// - In the application base directory, when published with a specific rid (ex: win-x64)
//
// We DO NOT allow loading from another location, system System32, or $PATH
// => The intent of "UseNativeClient()" is to use ONLY libs that came from the package,
// and not inherit form a (probably incompatible) fdb_c.dll that would be there from
// previous experiments, or a locally installed fdbserver.

// first probe in the runtimes/... subfolder for the native library
var runtimesNativePath = Path.Combine(AppContext.BaseDirectory, "runtimes", rid, "native");
var nativeLibraryPath = Path.Combine(runtimesNativePath, fileName);
if (!File.Exists(nativeLibraryPath))
{
// is it in the current directory?
nativeLibraryPath = Path.Combine(AppContext.BaseDirectory, fileName);
if (!File.Exists(nativeLibraryPath))
{
// we could not find the correct library!
throw new FileNotFoundException($"Could not find native FoundationDB Client Library '{fileName}' for platform '{rid}' under either '{runtimesNativePath}' nor the base directory '{AppContext.BaseDirectory}'");
}
}

options.NativeLibraryPath = nativeLibraryPath;
return options;
}

private static (string Rid, string FileName) GetRuntimeIdentifierForCurrentPlatform()
{
// Determine the path to the native libraries based on the platform
string? platform =
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "win"
: RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux"
: RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx"
: null;

string? arch =
RuntimeInformation.OSArchitecture == Architecture.X64 ? "x64"
: RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm64"
: null;

string fileName = platform == "win" ? "fdb_c.dll" : "libfbb_c.so";

if (platform is null || arch is null)
{
throw new PlatformNotSupportedException("Unsupported platform");
}

return (platform + "-" + arch, fileName);
}

}


}
57 changes: 32 additions & 25 deletions FoundationDB.Client.Native/FoundationDB.Client.Native.csproj
Original file line number Diff line number Diff line change
@@ -1,47 +1,54 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworks>$(CoreSdkRuntimeVersions)</TargetFrameworks>
<AssemblyName>FoundationDB.Client.Native</AssemblyName>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<SignAssembly>true</SignAssembly>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\Common\foundationdb-net-client.snk</AssemblyOriginatorKeyFile>
<Deterministic>true</Deterministic>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">true</IsAotCompatible>
<!-- Define the platforms that we support -->
<RuntimeIdentifiers>win-x64;linux-x64;linux-arm64</RuntimeIdentifiers>
</PropertyGroup>

<Import Project="..\Common\VersionInfo.props" />

<PropertyGroup>
<AssemblyTitle>Native client libraries for FoundationDB</AssemblyTitle>
<Description>Includes the FoundationDB Native Client (fdb_c.dll, libfdbc.so, ...) for different runtimes.</Description>
<!-- we override the version here, because it must match the verison of the native dlls, NOT the .NET binding itself! -->
<!-- Override the version here, because it must match the verison of the native dlls, NOT the .NET binding itself! -->
<VersionPrefix>7.3.52</VersionPrefix>
<VersionSuffix></VersionSuffix>
<AssemblyTitle>Native Client Libraries for FoundationDB</AssemblyTitle>
<Description>Includes the FoundationDB Native Client (fdb_c.dll, libfdbc.so, ...) for different runtimes.</Description>
</PropertyGroup>

<PropertyGroup>
<!-- These targets will be in the NuGet package -->
<TargetFrameworks>$(CoreSdkRuntimeVersions)</TargetFrameworks>
<!-- This must be present even though it's value is ignored; otherwise, "dotnet pack" will fail with NU5017 -->
<TargetFramework>net6.0</TargetFramework>
<!-- This must be set to false; otherwise, "dotnet pack" will fail with NU5017 -->
<IncludeSymbols>false</IncludeSymbols>
<!-- Gets rid of a warning when packing a project with no managed assembly -->
<NoWarn>NU5128</NoWarn>
</PropertyGroup>
<ItemGroup Condition="'$(_IsPacking)' == 'true'">
<PackageReference Include="FoundationDB.Client" VersionOverride="[7.3.*-*, 8.0.0.0)" />
</ItemGroup>

<!--Allows packing without passing the 'no-build' parameter to "dotnet pack" (which overrides both of these properties) -->
<PropertyGroup Condition="'$(_IsPacking)' == 'true'">
<NoBuild>true</NoBuild>
<IncludeBuildOutput>false</IncludeBuildOutput>
</PropertyGroup>
<ItemGroup Condition="'$(_IsPacking)' != 'true'">
<ProjectReference Include="..\FoundationDB.Client\FoundationDB.Client.csproj" />
</ItemGroup>

<!-- Include all the native libraries and tools -->
<ItemGroup>

<!-- Windows x64 -->
<None Update="native\runtimes\win-x64\fdb_c.dll" Pack="true" PackagePath="runtimes/win-x64/native/" />
<None Update="native\runtimes\win-x64\fdbcli.exe" Pack="true" PackagePath="runtimes/win-x64/native/" />
<None Include="runtimes\win-x64\native\fdb_c.dll" Pack="true" PackagePath="runtimes/win-x64/native/" />
<None Include="runtimes\win-x64\native\fdbcli.exe" Pack="true" PackagePath="runtimes/win-x64/native/" />

<!-- Linux x64 -->
<None Update="native\runtimes\linux-x64\libfdb_c.so" Pack="true" PackagePath="runtimes/linux-x64/native/" />
<None Update="native\runtimes\linux-x64\fdbcli" Pack="true" PackagePath="runtimes/linux-x64/native/" />
<None Include="runtimes\linux-x64\native\libfdb_c.so" Pack="true" PackagePath="runtimes/linux-x64/native/" />
<None Include="runtimes\linux-x64\native\fdbcli" Pack="true" PackagePath="runtimes/linux-x64/native/" />

<!-- Linux arm64 -->
<None Update="native\runtimes\linux-arm64\libfdb_c.so" Pack="true" PackagePath="runtimes/linux-arm64/native/" />
<None Update="native\runtimes\linux-arm64\fdbcli" Pack="true" PackagePath="runtimes/linux-arm64/native/" />
<None Include="runtimes\linux-arm64\native\libfdb_c.so" Pack="true" PackagePath="runtimes/linux-arm64/native/" />
<None Include="runtimes\linux-arm64\native\fdbcli" Pack="true" PackagePath="runtimes/linux-arm64/native/" />

</ItemGroup>

</Project>
7 changes: 7 additions & 0 deletions FoundationDB.Client.sln
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub Actions", "GitHub Ac
.github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoundationDB.Client.Native", "FoundationDB.Client.Native\FoundationDB.Client.Native.csproj", "{BFC416AD-C6F9-4C55-8315-90304F636660}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -133,6 +135,10 @@ Global
{0957AC74-8650-444C-AEF7-3C579578BBD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0957AC74-8650-444C-AEF7-3C579578BBD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0957AC74-8650-444C-AEF7-3C579578BBD1}.Release|Any CPU.Build.0 = Release|Any CPU
{BFC416AD-C6F9-4C55-8315-90304F636660}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BFC416AD-C6F9-4C55-8315-90304F636660}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFC416AD-C6F9-4C55-8315-90304F636660}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFC416AD-C6F9-4C55-8315-90304F636660}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -156,6 +162,7 @@ Global
{47BAC7E5-2197-4EC2-8671-A654D210DC70} = {E899F094-1A78-4652-862C-9FF6356AC738}
{0957AC74-8650-444C-AEF7-3C579578BBD1} = {E899F094-1A78-4652-862C-9FF6356AC738}
{F98174E6-7402-42CF-997E-C3DD77E17AAB} = {A7D90DEE-38B0-449C-93B5-32D7B845D990}
{BFC416AD-C6F9-4C55-8315-90304F636660} = {E899F094-1A78-4652-862C-9FF6356AC738}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {07944E4B-042C-4338-8E28-99FB373F52AA}
Expand Down

0 comments on commit 70fde69

Please sign in to comment.