Provide prebuilt native libraries by NuGet Packages.#257
Provide prebuilt native libraries by NuGet Packages.#257ha-ves wants to merge 9 commits intoNetCordDev:alphafrom
Conversation
1c05c69 to
6565a35
Compare
|
The documentation preview is available at https://preview.netcord.dev/257. |
|
I feel like the best option is to do something like: |
* put into nuget package
* Add native ports for libdave and mlspp * Update build workflows for native packaging * Add local targets and CI helpers for natives * Update README
- GitHub Actions tag triggers, NuGet publish job - NativesHelper, NativeLibraryVersionAttribute - vcpkg integration, static linking - zstd support - native library tests, import checks - Native AOT test app - NetCordNativesDir assembly metadata
* Add MSVC builtin add overflow patch for libdave * Add vcpkg-non-windows.targets for cross-platform support * Update libdave and mlspp portfiles with build fixes * Update build-natives workflow and vcpkg.json versions * Fix vcpkg dependency resolution for multi-platform builds
* Add dynamic library exclusion for AOT builds * Add NativeAotApp test project
* natives conditionals fix * fix nativeaot test structure * add natives tests to build workflow
- add reusable vcpkg setup - pack per-RID native nupkgs - streamline NativeAOT test logging - tighten native linking targets
66a1e8d to
ee00a64
Compare
|
@AraHaan by default CI workflow will provide per-RID packages now. But by .csproj design it will also work If anyone for some reason still needs to package all in one. |
KubaZ2
left a comment
There was a problem hiding this comment.
I haven't went through all the MSBuild stuff. I kind of hate that it takes so much and I am afraid it may require changes when new versions of binaries get released. I guess there is no better way to handle that? I think most binaries just require a single make or 2 cmake commands to build, but I think most of the MSBuild stuff is just for copying the binaries in the correct place and licensing?
| [DoNotParallelize] | ||
| [TestMethod] | ||
| [DataRow("libdave;libsodium;opus;zstd")] | ||
| public void NativeAotStaticLinking(string libName) |
There was a problem hiding this comment.
Wouldn't it be better to make tests that are built with static linking instead of building a static linking app in the tests?
There was a problem hiding this comment.
yeah, NativeAotApp can be pulled to a separate static-linked test .csproj
There was a problem hiding this comment.
I can't see how it'll work without putting more stuff than the test method,
including the new test platform is early preview.
| diff --git a/cpp/src/frame_processors.cpp b/cpp/src/frame_processors.cpp | ||
| index 37c8d70..5f0460c 100644 | ||
| --- a/cpp/src/frame_processors.cpp | ||
| +++ b/cpp/src/frame_processors.cpp | ||
| @@ -13,6 +13,9 @@ | ||
|
|
||
| #if defined(_MSC_VER) | ||
| #include <intrin.h> | ||
| +#if defined(_M_ARM64) | ||
| +#include <arm64intr.h> | ||
| +#endif | ||
| #endif | ||
|
|
||
| namespace discord { | ||
| @@ -25,6 +28,9 @@ std::pair<bool, size_t> OverflowAdd(size_t a, size_t b) | ||
| bool didOverflow = _addcarry_u64(0, a, b, &res); | ||
| #elif defined(_MSC_VER) && defined(_M_IX86) | ||
| bool didOverflow = _addcarry_u32(0, a, b, &res); | ||
| +#elif defined(_MSC_VER) && defined(_M_ARM64) | ||
| + res = a + b; | ||
| + bool didOverflow = res < a; | ||
| #else | ||
| bool didOverflow = __builtin_add_overflow(a, b, &res); | ||
| #endif |
There was a problem hiding this comment.
Was it reported to libdave maintainers? A patch may require additional maintenance in the future.
There was a problem hiding this comment.
this is an out-of-support patch for the current pinned libdave version,
No one asked them for win-arm64 yet,
in the meantime you could provide this runtimeId unsupported.
| vcpkg_from_github( | ||
| OUT_SOURCE_PATH SOURCE_PATH | ||
| REPO cisco/mlspp | ||
| REF "${VERSION}" | ||
| SHA512 5d37631e2c47daae1133ef074e60cc09ca2d395f9e11c416f829060e374051cf219d2d7fe98dae49d1d045292e07d6a09f4814a5f16e6cc05e67e7cd96f146c4 | ||
| ) | ||
|
|
||
| if(VCPKG_TARGET_IS_OSX AND EXISTS "/usr/local/include/openssl/") | ||
| set(VCPKG_INCLUDE_OVERRIDE "-DCMAKE_CXX_FLAGS=-I${CURRENT_INSTALLED_DIR}/include") | ||
| endif() | ||
|
|
||
| set(VCPKG_LIBRARY_LINKAGE static) | ||
|
|
||
| vcpkg_cmake_configure( | ||
| SOURCE_PATH "${SOURCE_PATH}" | ||
| OPTIONS | ||
| ${VCPKG_INCLUDE_OVERRIDE} | ||
| -DDISABLE_GREASE=ON | ||
| -DTESTING=OFF | ||
| -DBUILD_TESTING=OFF | ||
| -DMLS_CXX_NAMESPACE="mlspp" | ||
| MAYBE_UNUSED_VARIABLES | ||
| BUILD_TESTING | ||
| ) | ||
|
|
||
| vcpkg_cmake_install() | ||
| vcpkg_copy_pdbs() | ||
|
|
||
| vcpkg_cmake_config_fixup(PACKAGE_NAME "MLSPP" CONFIG_PATH "share/MLSPP") | ||
|
|
||
| # Remove redundant debug directories to comply with vcpkg policy | ||
| file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") | ||
| file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share") |
There was a problem hiding this comment.
cisco doesn't "port" (submit) it to vcpkg registry, this is taken from libdave's port of it.
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Reflection; | ||
|
|
||
| namespace NetCord.Natives; | ||
|
|
||
| [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] | ||
| public class NativeLibraryVersionAttribute(string name, string version) : Attribute | ||
| { | ||
| public string Name { get; } = name; | ||
| public string Version { get; } = version; | ||
| } | ||
|
|
||
| public static class NativesHelper | ||
| { | ||
| public static IEnumerable<NativeLibraryVersionAttribute> GetNativeLibraryVersions() | ||
| { | ||
| return typeof(NativesHelper).Assembly.GetCustomAttributes<NativeLibraryVersionAttribute>(); | ||
| } | ||
| } |
There was a problem hiding this comment.
I don't think I like this. I think a native package shouldn't come with any managed code.
There was a problem hiding this comment.
true, but you'd like to know which nativelib version it was when issues arise.
Probably put the versions in the package description instead
| <Solution> | ||
| <Folder Name="/Solution Items/"> | ||
| <File Path=".editorconfig" /> | ||
| <File Path="Directory.Build.props" /> | ||
| <File Path="Directory.Build.targets" /> | ||
| <File Path="Directory.Packages.props" /> | ||
| <File Path="global.json" /> | ||
| </Folder> | ||
| <Folder Name="/SourceGenerators/"> | ||
| <File Path="SourceGenerators/Directory.Build.props" /> | ||
| <File Path="SourceGenerators/Directory.Build.targets" /> | ||
| <Project Path="SourceGenerators/MethodsForPropertiesGenerator/MethodsForPropertiesGenerator.csproj" /> | ||
| <Project Path="SourceGenerators/RestClientMethodAliasesGenerator/RestClientMethodAliasesGenerator.csproj" /> | ||
| <Project Path="SourceGenerators/ShardedGatewayClientEventsGenerator/ShardedGatewayClientEventsGenerator.csproj" /> | ||
| <Project Path="SourceGenerators/Shared/Shared.csproj" /> | ||
| <Project Path="SourceGenerators/UserAgentHeaderGenerator/UserAgentHeaderGenerator.csproj" /> | ||
| <Project Path="SourceGenerators/WebSocketClientEventsGenerator/WebSocketClientEventsGenerator.csproj" /> | ||
| </Folder> | ||
| <Folder Name="/Tests/"> | ||
| <File Path="Tests/Directory.Build.props" /> | ||
| <File Path="Tests/Directory.Build.targets" /> | ||
| <Project Path="Tests/NetCord.Natives.Tests/NetCord.Natives.Tests.csproj" /> | ||
| <Project Path="Tests/NetCord.Natives.Tests/Assets/NativeAotApp/NativeAotApp.csproj" /> | ||
| </Folder> | ||
| <Project Path="NetCord.Natives/NetCord.Natives.csproj" /> | ||
| <Project Path="NetCord/NetCord.csproj" /> | ||
| </Solution> |
There was a problem hiding this comment.
What is the idea behind a separate solution? Is it build times? Also I doubt this solution needs these source generators.
There was a problem hiding this comment.
the source generators used by main NetCord, which gets referenced by NetCord.Natives.Tests.
I haven't finished wiring up the other tests how to get the nativelibs, in CI workflow should be pretty straight forward, restore cache, NetCord.slnx build will be quick.
local build from source will be very long on first-time NetCord.slnx build unless they skip the natives and tests requiring it.
| <PackageReference Include="GitHubActionsTestLogger" /> | ||
| <PackageVersion Include="GitHubActionsTestLogger" Version="3.0.4" /> |
There was a problem hiding this comment.
I think versions should be managed by Directory.Packages.props like all other packages. Also I am not sure this is needed here. Maybe this package could be added to all tests at once, ideally in a separate PR.
There was a problem hiding this comment.
it was testing artifact, though this package is very good for CI.
since this PR also (/will) modify the build workflow,
yeah I think it will still be pretty related to be included in Directory.Packages.props
| - name: Upload NuGet Package Artifacts | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: Build Artifacts | ||
| name: NuGet Packages | ||
| path: | | ||
| NetCord/bin/Release | ||
| NetCord.Services/bin/Release | ||
| Hosting/NetCord.Hosting/bin/Release | ||
| Hosting/NetCord.Hosting.Services/bin/Release | ||
| Hosting/NetCord.Hosting.AspNetCore/bin/Release | ||
| NetCord/bin/Release/*.nupkg | ||
| NetCord.Services/bin/Release/*.nupkg | ||
| Hosting/NetCord.Hosting/bin/Release/*.nupkg | ||
| Hosting/NetCord.Hosting.Services/bin/Release/*.nupkg | ||
| Hosting/NetCord.Hosting.AspNetCore/bin/Release/*.nupkg |
There was a problem hiding this comment.
I think snupkgs should also be uploaded there.
Vcpkg is the least time-consuming dependency manager, it can build and put it all together in a convenient path. The previous version of this PR was just using CMake, but it won't get the dependencies for your NativeAOT. you can refer to this when there's new version:
|
Summary
Continues from #245. Implements CI-driven distribution of prebuilt native binary dependencies.
Download size: ~112 MBExtracted size: ~429 MBSupported Platforms & Build Variants
win-x64win-arm64linux-x64linux-arm64osx-x64osx-arm64Need to Follow-Up
dotnet test Tests/NetCord.Natives.Tests/ -tl:off -clp:NoSummary,Verbosity=normal -v normal -bland then use https://github.com/JanKrivanek/MSBuildStructuredLog
Overview
This PR provides prebuilt native libraries via NuGet as per-RID packages. Each package bundles:
Packages are published automatically on successful CI builds to the configured NuGet feed.
Structure & Packaging Model
Per-RID Distribution Model:
NetCord.Natives.{win|linux|osx}-{x64|arm64}NetCord.Natives.linux-x64,NetCord.Natives.win-arm64Package Contents (per-RID package):
What Changed
CI Pruning:
Core Build & Packaging
libdave/portfile.cmake— discord/libdave with MSVC ARM64 patchmlspp/portfile.cmake— cisco/mlspp, libdave's dependencyNuGet Package build files
$(RuntimeIdentifier)Accessible Metadata
NativeLibraryVersionAttributefor runtime version discovery of bundled native libsHow to Use
CLI:
Reference the package for your target platform:
NativeAOT with Exclusion
When populating
<DirectPInvoke>for<PublishAot>, static libraries are automatically linked.You can also exclude some library if you use another external build:
Multi-Target Build with Per-RID Packages
For projects targeting multiple platforms with minimal per-platform size:
(Condition is arbitrary, each package will not conflict)
Maintainer Notes:
vcpkgBaseline & Dependency PinningAll native dependencies are pinned to a specific vcpkg baseline (vcpkg.json) to ensure reproducible builds.
When upgrading native library versions:
vcpkg.jsonResource requirements:
Testing
Comprehensive native library validation via Tests/NetCord.Natives.Tests/:
Unit Tests (NativesBuildTests.cs)
Framework: MSTest with method-level parallelization
Target: .NET 10.0
NativeLoaded— Runtime Library ResolutionNativeLibrary.Load()AllLibraryImportsExistInBinary— P/Invoke Symbol Verification[LibraryImport]entry pointsNativeLibrary.TryGetExport()NativeAotStaticLinking— NativeAOT Full Integrationdotnet publish -c Releaseon NativeAotApp with<PublishAot>enabled:win-x64,linux-x64,osx-arm64)<DirectPInvoke>Included in This PR
✓ CI multi-platform native package build and publish
✓ Per-RID targeted package distribution
✓ Direct integration usage
✓ Custom vcpkg overlay ports for libdave and mlspp &
✓ Dependencies pinning
✓ Basic Unit & Integration tests