-
Notifications
You must be signed in to change notification settings - Fork 322
Document nuget package structure #3965
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| --- | ||
| applyTo: "**/nuspec,**/build.proj,**/ref/**" | ||
| --- | ||
| # NuGet Package Structure — Microsoft.Data.SqlClient | ||
|
|
||
| This document describes the folder layout of the generated `Microsoft.Data.SqlClient` NuGet package, what each folder holds, and how runtime resolution works. | ||
|
|
||
| ## Package Resolution Overview | ||
|
|
||
| - **`ref/`** — Used at **compile time only**. Thin assemblies with `throw null` bodies defining the public API surface. NuGet selects the best-matching TFM. | ||
| - **`runtimes/{rid}/lib/`** — Used at **runtime** when the host OS RID matches. Contains full implementations with OS-specific code. These **override** the corresponding `lib/` assemblies. | ||
| - **`lib/`** — Used at **runtime** as a **fallback** when no RID-specific match exists in `runtimes/`. For `net462` this is the real implementation. For `net8.0`/`net9.0` these are AnyOS stubs. For `netstandard2.0` this is the only runtime target. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add an explanation of what |
||
|
|
||
| ## Folder Structure | ||
|
|
||
| ``` | ||
| Microsoft.Data.SqlClient.nupkg | ||
| │ | ||
| ├── ref/ # Compile-time reference assemblies (throw null bodies, no real implementation) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| │ ├── net462/ # Built from netfx/ref, Windows_NT | ||
| │ │ ├── Microsoft.Data.SqlClient.dll # NetFx ref assembly — public API surface for .NET Framework | ||
| │ │ └── Microsoft.Data.SqlClient.xml # XML doc comments for IntelliSense | ||
| │ ├── net8.0/ # Built from netcore/ref, AnyOS | ||
| │ │ ├── Microsoft.Data.SqlClient.dll # NetCore ref assembly — public API surface for .NET 8 | ||
| │ │ └── Microsoft.Data.SqlClient.xml # XML doc comments for IntelliSense | ||
| │ ├── net9.0/ # Built from netcore/ref, AnyOS | ||
| │ │ ├── Microsoft.Data.SqlClient.dll # NetCore ref assembly — public API surface for .NET 9 | ||
| │ │ └── Microsoft.Data.SqlClient.xml # XML doc comments for IntelliSense | ||
| │ └── netstandard2.0/ # Built from netcore/ref, AnyOS | ||
| │ ├── Microsoft.Data.SqlClient.dll # NetStandard ref assembly — public API surface for netstandard2.0 | ||
| │ └── Microsoft.Data.SqlClient.xml # XML doc comments for IntelliSense | ||
| │ | ||
| ├── lib/ # Default runtime assemblies (used when no RID-specific match in runtimes/) | ||
| │ ├── net462/ # Built from netfx/src, Windows_NT | ||
| │ │ ├── Microsoft.Data.SqlClient.dll # Full .NET Framework implementation (Windows-only) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we have the full .NET Framework implementation in two places? Do we expect there to be .NET Framework runtimes whose RID doesn't match |
||
| │ │ ├── Microsoft.Data.SqlClient.pdb # Debug symbols | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're removing debug symbols from our |
||
| │ │ ├── Microsoft.Data.SqlClient.xml # XML doc comments | ||
| │ │ └── {locale}/ # cs, de, es, fr, it, ja, ko, pl, pt-BR, ru, tr, zh-Hans, zh-Hant | ||
| │ │ └── Microsoft.Data.SqlClient.resources.dll # Localized satellite resource DLLs | ||
| │ ├── net8.0/ # Built from netcore/src, OSGroup=AnyOS | ||
| │ │ ├── Microsoft.Data.SqlClient.dll # AnyOS stub — generated via GenAPI/NotSupported.targets | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are the circumstances that would cause this DLL to be used at runtime? What are we trying to accomplish here? |
||
| │ │ ├── Microsoft.Data.SqlClient.pdb # Debug symbols | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these symbols for the generated |
||
| │ │ ├── Microsoft.Data.SqlClient.xml # XML doc comments (from Windows build) | ||
| │ │ └── {locale}/ # Localized satellite resource DLLs (from Windows build) | ||
| │ │ └── Microsoft.Data.SqlClient.resources.dll | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these the real resources (that the AnyOS stub DLL doesn't use), or just the string "Not supported" in a bunch of languages? |
||
| │ ├── net9.0/ # Built from netcore/src, OSGroup=AnyOS | ||
| │ │ ├── Microsoft.Data.SqlClient.dll # AnyOS stub — same as net8.0 | ||
| │ │ ├── Microsoft.Data.SqlClient.pdb # Debug symbols | ||
| │ │ ├── Microsoft.Data.SqlClient.xml # XML doc comments (from Windows build) | ||
| │ │ └── {locale}/ # Localized satellite resource DLLs (from Windows build) | ||
| │ │ └── Microsoft.Data.SqlClient.resources.dll | ||
| │ └── netstandard2.0/ # Built from netcore/ref with BuildForLib=true, AnyOS | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we omit this and just provide the |
||
| │ ├── Microsoft.Data.SqlClient.dll # ⚠️ Currently a ref assembly (throw null bodies) — see known issue below | ||
| │ ├── Microsoft.Data.SqlClient.pdb # Debug symbols | ||
| │ └── Microsoft.Data.SqlClient.xml # XML doc comments | ||
| │ | ||
| └── runtimes/ # RID-specific runtime assemblies (override lib/ when RID matches) | ||
| ├── win/lib/ # Windows-specific implementations (native SNI) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fingers crossed we can eliminate the RID-specific DLLs soon. I haven't looked into it deeply, but I suspect we have |
||
| │ ├── net462/ | ||
| │ │ ├── Microsoft.Data.SqlClient.dll # Full .NET Framework impl (same as lib/net462) | ||
| │ │ └── Microsoft.Data.SqlClient.pdb # Debug symbols | ||
| │ ├── net8.0/ | ||
| │ │ ├── Microsoft.Data.SqlClient.dll # Full .NET 8 impl compiled for Windows_NT | ||
| │ │ └── Microsoft.Data.SqlClient.pdb # Debug symbols | ||
| │ └── net9.0/ | ||
| │ ├── Microsoft.Data.SqlClient.dll # Full .NET 9 impl compiled for Windows_NT | ||
| │ └── Microsoft.Data.SqlClient.pdb # Debug symbols | ||
| └── unix/lib/ # Unix/Linux/macOS implementations (managed SNI) | ||
| ├── net8.0/ | ||
| │ ├── Microsoft.Data.SqlClient.dll # Full .NET 8 impl compiled for Unix | ||
| │ └── Microsoft.Data.SqlClient.pdb # Debug symbols | ||
| └── net9.0/ | ||
| ├── Microsoft.Data.SqlClient.dll # Full .NET 9 impl compiled for Unix | ||
| └── Microsoft.Data.SqlClient.pdb # Debug symbols | ||
| ``` | ||
|
|
||
| ## Known Issue: `lib/netstandard2.0/` Assembly | ||
|
|
||
| The `lib/netstandard2.0/` DLL is intended to be a `PlatformNotSupportedException` stub for unsupported platforms. However, it is built by the `BuildNetStandard` target, which builds the **ref project** (`netcore/ref/`) with `BuildForLib=true` and `OSGroup=AnyOS`. | ||
|
|
||
| The `NotSupported.targets` file is imported, but its logic is gated on `GeneratePlatformNotSupportedAssemblyMessage` being set — a property that only the **src project** (`netcore/src/`) defines. Since the ref project never sets it, the `GenerateNotSupportedSource` target is inert, and the output is just the ref assembly with `throw null` bodies instead of a proper `PlatformNotSupportedException` stub. | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,78 @@ | ||||||||||||||||||||||||||
| # Plan: Auto-Generate Ref Assemblies from Unified Src Project | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Summary | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Enable `ProduceReferenceAssembly` in the unified src project so ref assemblies are compiler-generated during normal builds. Create a small dedicated project for `PlatformNotSupportedException` stubs. Use `Microsoft.DotNet.ApiCompat.Tool` to compare auto-generated ref assemblies against the checked-in ref sources as a baseline. Update the nuspec to consume artifacts from the new output paths. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Phase 1: Enable auto-generated ref assemblies | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 1. In `src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj`, add two properties: | ||||||||||||||||||||||||||
| - `<ProduceReferenceAssembly>true</ProduceReferenceAssembly>` (for all TFMs, including net462 which doesn't default to true) | ||||||||||||||||||||||||||
| - `<GenerateDocumentationFile>true</GenerateDocumentationFile>` (so XML docs are generated alongside the build) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 2. Add a post-build target in the unified csproj (or a new `.targets` file imported by it) that copies the ref assembly from `$(IntermediateOutputPath)ref/$(TargetFileName)` to `$(OutputPath)ref/$(TargetFileName)`. The SDK only places the ref DLL in the intermediate `obj/` directory — this copy step puts it alongside the main assembly output at a predictable location like `artifacts/Microsoft.Data.SqlClient/{Config}/{os}/{tfm}/ref/Microsoft.Data.SqlClient.dll`. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 3. Also copy the generated XML doc file (`$(OutputPath)$(AssemblyName).xml`) to `$(OutputPath)ref/$(AssemblyName).xml` so the ref assembly has companion IntelliSense XML in the same directory. | ||||||||||||||||||||||||||
|
Comment on lines
+13
to
+15
|
||||||||||||||||||||||||||
| 2. Add a post-build target in the unified csproj (or a new `.targets` file imported by it) that copies the ref assembly from `$(IntermediateOutputPath)ref/$(TargetFileName)` to `$(OutputPath)ref/$(TargetFileName)`. The SDK only places the ref DLL in the intermediate `obj/` directory — this copy step puts it alongside the main assembly output at a predictable location like `artifacts/Microsoft.Data.SqlClient/{Config}/{os}/{tfm}/ref/Microsoft.Data.SqlClient.dll`. | |
| 3. Also copy the generated XML doc file (`$(OutputPath)$(AssemblyName).xml`) to `$(OutputPath)ref/$(AssemblyName).xml` so the ref assembly has companion IntelliSense XML in the same directory. | |
| 2. Add a post-build target in the unified csproj (or a new `.targets` file imported by it) that copies the ref assembly from `$(IntermediateOutputPath)ref/$(TargetFileName)` to `$(TargetDir)ref/$(TargetFileName)`. The SDK only places the ref DLL in the intermediate `obj/` directory — this copy step puts it alongside the main assembly output at a predictable location like `artifacts/Microsoft.Data.SqlClient/{Config}/{os}/{TargetFramework}/ref/Microsoft.Data.SqlClient.dll`. | |
| 3. Also copy the generated XML doc file (`$(TargetDir)$(AssemblyName).xml`) to `$(TargetDir)ref/$(AssemblyName).xml` so the ref assembly has companion IntelliSense XML in the same directory. |
Copilot
AI
Feb 18, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Phase 1 step 3 references the generated XML doc file as $(OutputPath)$(AssemblyName).xml, but by default SDK projects emit it into the per-TFM output directory (e.g., $(TargetDir)$(AssemblyName).xml, or use $(DocumentationFile) if set). Using $(OutputPath) directly will likely point at the parent directory and miss the file for multi-target builds.
| 3. Also copy the generated XML doc file (`$(OutputPath)$(AssemblyName).xml`) to `$(OutputPath)ref/$(AssemblyName).xml` so the ref assembly has companion IntelliSense XML in the same directory. | |
| 3. Also copy the generated XML doc file (`$(DocumentationFile)`) to `$(OutputPath)ref/$(AssemblyName).xml` so the ref assembly has companion IntelliSense XML in the same directory. |
Copilot
AI
Feb 18, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Step 7 proposes adding ApiCompat to dotnet-tools.json, but there doesn’t appear to be any repo automation restoring/using that manifest today (no references to dotnet-tools.json or dotnet tool restore --tool-manifest in build/pipeline scripts). To avoid a plan that won’t work when followed, consider either (a) switching to the standard tool manifest location (.config/dotnet-tools.json) and documenting dotnet tool restore, or (b) explicitly adding the restore/invocation steps in the proposed ValidateApiCompat target/CI wiring.
| 7. Add `Microsoft.DotNet.ApiCompat.Tool` to `dotnet-tools.json` as a local dotnet tool. This provides the `dotnet apicompat` command. | |
| 8. Create a new MSBuild target (e.g., `ValidateApiCompat` in a `.targets` file or in `build.proj`) that: | |
| 7. Add `Microsoft.DotNet.ApiCompat.Tool` to the standard local tool manifest at `.config/dotnet-tools.json`. This provides the `dotnet apicompat` command when `dotnet tool restore` is run. | |
| 8. Create a new MSBuild target (e.g., `ValidateApiCompat` in a `.targets` file or in `build.proj`) that: | |
| - Ensures the ApiCompat tool is available by running `dotnet tool restore` (for local development) and by adding a corresponding `dotnet tool restore` step in CI before invoking this target |
Copilot
AI
Feb 18, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Phase 3 step 8 references a baseline ref project at src/Microsoft.Data.SqlClient/ref/Microsoft.Data.SqlClient.csproj, but that project doesn’t exist in the repo. The checked-in ref projects are src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj (net462) and src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj (net8.0/net9.0/netstandard2.0), with shared ref sources in src/Microsoft.Data.SqlClient/ref/. Updating the plan to point at the actual csproj(s) will make the build steps actionable.
| - Builds the existing checked-in ref project at `src/Microsoft.Data.SqlClient/ref/Microsoft.Data.SqlClient.csproj` to produce baseline ref DLLs (for net462, net8.0, net9.0) | |
| - Runs `dotnet apicompat` comparing the auto-generated ref assemblies (from Phase 1) against these baseline DLLs | |
| - Fails the build if breaking changes are detected (new APIs are allowed; removed/changed APIs are errors) | |
| - This target should run as part of CI but be opt-in for local development (e.g., gated on a property like `ValidateApi=true`) | |
| 9. The checked-in ref sources at `src/Microsoft.Data.SqlClient/ref/` remain in the repo as the API baseline. They are no longer used for packaging — only for compat validation. Later, these can be replaced with a baseline from the last published NuGet package. | |
| - Builds the existing checked-in ref projects at `src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj` (net462) and `src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj` (net8.0/net9.0/netstandard2.0) to produce baseline ref DLLs for each TFM | |
| - Runs `dotnet apicompat` comparing the auto-generated ref assemblies (from Phase 1) against these baseline DLLs | |
| - Fails the build if breaking changes are detected (new APIs are allowed; removed/changed APIs are errors) | |
| - This target should run as part of CI but be opt-in for local development (e.g., gated on a property like `ValidateApi=true`) | |
| 9. The checked-in ref sources under `src/Microsoft.Data.SqlClient/ref/` (consumed by the `netfx/ref` and `netcore/ref` projects) remain in the repo as the API baseline. They are no longer used for packaging — only for compat validation. Later, these can be replaced with a baseline from the last published NuGet package. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The front-matter
applyToglob includes**/nuspec, but the repo’s nuspec files are*.nuspec(e.g.,tools/specs/Microsoft.Data.SqlClient.nuspec). As written, this instruction likely won’t apply to nuspec edits. Consider changing it to something like**/*.nuspec(and keep the existing**/build.proj,**/ref/**as needed).