Add Linux support to .NET language extension#64
Add Linux support to .NET language extension#64MarkpageBxl wants to merge 12 commits intomicrosoft:mainfrom
Conversation
SQL Server on Linux expects a .tar.gz file instead of a .zip when using CREATE EXTERNAL LANGUAGE.
We will use the nethost to locate the system's installed hostfxr, as using a local libhostfxr.so breaks the .NET runtime lookup. nethost contains the logic needed to find the .NET root based on the DOTNET_ROOT environment variable or the install_location configuration file, which we will require for .NET runtime lookup on diverging Linux distributions (e.g. RHEL and Debian packages not installing .NET in the same base directories).
|
@microsoft-github-policy-service agree company="Raincode srl" |
| @@ -0,0 +1,106 @@ | |||
| #!/usr/bin/env pwsh | |||
There was a problem hiding this comment.
Why are we using powershell script for linux instead of bash script?
There was a problem hiding this comment.
As written in the description, PowerShell was chosen as a scripting language to serve as a potential base for a cross-platform script. If this is not desired, I can rewrite it in bash.
There was a problem hiding this comment.
Do you mean this script can be used for both windows/linux now or we should have a follow-up work item for this?
language-extensions/dotnet-core-CSharp/build/linux/build-dotnet-core-CSharp-extension.ps1
Outdated
Show resolved
Hide resolved
language-extensions/dotnet-core-CSharp/build/linux/build-dotnet-core-CSharp-extension.ps1
Show resolved
Hide resolved
language-extensions/dotnet-core-CSharp/build/linux/create-dotnet-core-CSharp-extension-zip.ps1
Outdated
Show resolved
Hide resolved
language-extensions/dotnet-core-CSharp/include/DotnetEnvironment.h
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull Request Overview
This PR adds Linux support to the .NET language extension, which previously only supported Windows. The changes include:
- Platform-specific conditional compilation using preprocessor defines to support both Windows and Linux
- Integration of nethost library for dynamic hostfxr lookup on Linux (avoiding hardcoded paths)
- Updated build artifacts and project files to target .NET 8.0 (from .NET 6.0, which is EOL)
- Platform-specific APIs for file operations, dynamic library loading, and path handling
Reviewed Changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Microsoft.SqlServer.CSharpExtensionTest.csproj | Updated target framework from net6.0 to net8.0 |
| Microsoft.SqlServer.CSharpExtension.csproj | Updated target framework from net6.0 to net8.0 |
| RegexSample.csproj | Updated target framework from net6.0 to net8.0 |
| Logger.cpp | Removed Windows-specific includes (stdio.h, windows.h) |
| Logger.h | Removed stdio.h include |
| DotnetEnvironment.cpp | Added platform-specific code for library loading, path handling, and hostfxr lookup using nethost |
| DotnetEnvironment.h | Added platform-specific macros and definitions for path separators and string types |
| nativecsharpextension.h | Guarded windows.h include with platform check |
| nethost.h | Added header file for nethost API |
| libnethost.a | Added static library for nethost (Linux) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #if defined(_WIN32) || defined(WINDOWS) | ||
| m_root_path(to_utf16_str(language_path)) | ||
| #else | ||
| m_root_path(language_path) | ||
| #endif |
There was a problem hiding this comment.
[nitpick] The conditional initialization of m_root_path in the constructor initializer list could be simplified. Consider using a helper function to convert the path conditionally, which would make the code cleaner and easier to maintain. For example, create a convert_path(const std::string& path) function that returns either the UTF-16 or UTF-8 version based on the platform.
| char buffer[4096]; | ||
| size_t buffer_size = sizeof(buffer); | ||
| if (get_hostfxr_path(buffer, &buffer_size, nullptr) != 0) { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
[nitpick] The hardcoded buffer size of 4096 bytes should be defined as a named constant (e.g., constexpr size_t HOSTFXR_PATH_BUFFER_SIZE = 4096;) to improve code maintainability and make it easier to adjust if needed.
| #include "DotnetEnvironment.h" | ||
| #include "Logger.h" | ||
|
|
||
| #if defined(_WIN32) || defined(WINDOWS) |
There was a problem hiding this comment.
[nitpick] The platform check uses both _WIN32 and WINDOWS macros. The _WIN32 macro is the standard Microsoft compiler define for Windows (both 32-bit and 64-bit). The WINDOWS macro appears to be custom. Consider using only _WIN32 for consistency with common practice, or document why both are needed if there's a specific reason.
|
@MarkpageBxl , have you ever met this error: Error: Could not find a part of the path |
SicongLiu2000
left a comment
There was a problem hiding this comment.
Code Review — PR #64: Add Linux support to .NET language extension
I tested this end-to-end in a Docker container (SQL Server 2022 + mssql-server-extensibility on Ubuntu) and confirmed the Linux path works — the regex sample returns correct results via sp_execute_external_script.
Overall this is a clean PR. The platform #ifdef guards, nethost integration for hostfxr discovery, and the Linux build scripts are well done. A few comments below.
Issues
1. STR/CH macros duplicated in both .h and .cpp
DotnetEnvironment.h and DotnetEnvironment.cpp both define STR(s) and CH(c) with the same #ifdef guards. They should be defined in only one place (the header) to avoid maintenance drift.
2. README link mismatch in Linux build section
The Linux build instructions reference build-dotnet-core-CSharp-extension.ps1 but the link text shows .cmd. Same for the archive script.
3. Pre-existing issues on main (not from this PR, but worth noting)
While testing, I found critical memory safety bugs in CSharpParamContainer.cs that already exist on main:
ReplaceNumericParam<T>: uses&value(dangling stack pointer) instead of the correctGCHandle.Alloc(array, Pinned)+AddrOfPinnedObject()pattern. This corrupts all numeric output parameters.ReplaceStringParam:fixedblock pointer escapes its scope while theGCHandleis not pinned. This corrupts string output parameters.GetStrLenNullMap/ReplaceParamfor DotNetChar: uses.Length(char count) instead ofEncoding.UTF8.GetByteCount()— wrong for multi-byte UTF-8.
These should be tracked as a separate issue/fix.
Positive
nethost/get_hostfxr_path()for Linux hostfxr discovery is the right approachPATH_SEPARATORmacro is clean- Build scripts (
.ps1) are well-structured with proper error handling net8.0target upgrade is appropriate (net6.0 is EOL)- End-to-end verified working on Linux
| #include <hostfxr.h> | ||
| #include <nethost.h> | ||
|
|
||
| #if defined(_WIN32) || defined(WINDOWS) |
There was a problem hiding this comment.
Nit: STR/CH macros are already defined identically in DotnetEnvironment.h (lines 18-23). Defining them in both the header and the .cpp is redundant and creates maintenance drift risk. Consider removing the duplicate here and relying on the header definitions.
| #include <hostfxr.h> | ||
|
|
||
| #if defined(_WIN32) || defined(WINDOWS) | ||
| #define STR(s) L ## s |
There was a problem hiding this comment.
The two adjacent #ifdef blocks for the same condition could be merged. Consider defining PATH_SEPARATOR alongside STR/CH in the block above rather than in a separate block.
| 2. Run [create-dotnet-core-CSharp-extension-zip.ps1](./build/windows/create-dotnet-core-CSharp-extension-zip.cmd) which will generate: \ | ||
| - PATH/TO/ENLISTMENT/build-output/dotnet-core-CSharp-extension/linux/release/packages/dotnet-core-CSharp-lang-extension.tar.gz | ||
| This tarball can be used in CREATE EXTERNAL LANGUAGE, as detailed in the tutorial in the Usage section below. | ||
|
|
There was a problem hiding this comment.
The link text says .cmd but the actual file is a .ps1 script, and the path points to ./build/windows/ rather than ./build/linux/. Should be:
[build-dotnet-core-CSharp-extension.ps1](./build/linux/build-dotnet-core-CSharp-extension.ps1)
This PR adds Linux support to the .NET language extension, which currently only supports Windows.
This involves the following:
hostfxrbetween Linux and Windows, using a hardcodedhostfxrlibrary path was a no go for portability (e.g. .NET packages on RHEL and Debian do not install .NET in the same base directories). Instead, we make use ofnethost(in the form of thelibnethost.astatic library provided by the .NET runtime) to first do the hostfxr lookup. This approach has the advantage of honoringDOTNET_ROOTandinstall_locationfiles if they exist, which hostfxr does not.Additionally, this bumps references to
net6.0up tonet8.0, since the former is EOL.At this point, this has been tested manually on SQL Server running on Ubuntu 22.04 LTS. A .NET 8.0 assembly was successfully executed.