Add Linux support to .NET language extension#64
Add Linux support to .NET language extension#64MarkpageBxl wants to merge 14 commits intomicrosoft:mainfrom
Conversation
|
@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?
There was a problem hiding this comment.
If PowerShell is acceptable, then it would indeed probably make sense to harmonize this on Windows and Linux. I would suggest creating a distinct separate work item for this.
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
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).
04be02e to
86d15ea
Compare
|
I have rebased on main, and made an additional fallout fix re the use of the |
|
I also assume we should probably upgrade to |
- Replace PowerShell build scripts with bash (build, archive, restore) - Remove checked-in libnethost.a; fetch at build time via restore-packages.sh - Add libnethost.a existence guard in build script - Use vswhere.exe for VS detection in Windows build scripts - Add convert_string() abstraction in DotnetEnvironment - Conditional nethost.h include (Linux only), HOSTFXR_PATH_BUFFER_SIZE constant - Add LOG_ERROR on hostfxr lookup failure - Fix load_hostfxr comment (was incorrectly named get_export) - Add Linux test build/run scripts and CMake platform support - Add -fshort-wchar and fix wstring ABI issues in test code - Add platform-conditional HintPath in test csproj - Add Linux dlopen/dlsym equivalents in test API code - Add Dockerfile for Linux build/test CI
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.