rules_dotnet
rules_dotnet copied to clipboard
`ImplicitUsings` is not handled
Since rules_dotnet doesn't run MSBuild, the Using directives added by the Task files in the .NET SDK are not handled, causing the build to fail unless the auto-generated {Assembly}.GlobalUsings.g.cs is included in srcs.
For the time being, I'm hand-maintaining the following file:
// NOTE: Keep this file in sync with the following Using directives
// whenever the .NET SDK version is updated:
//
// https://github.com/dotnet/sdk/blob/release/8.0.2xx/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.CSharp.props#L26
// https://github.com/dotnet/sdk/blob/release/8.0.2xx/src/WebSdk/Web/Targets/Sdk.Server.props#L64
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;
global using global::System.Net.Http.Json;
global using global::Microsoft.AspNetCore.Builder;
global using global::Microsoft.AspNetCore.Hosting;
global using global::Microsoft.AspNetCore.Http;
global using global::Microsoft.AspNetCore.Routing;
global using global::Microsoft.Extensions.Configuration;
global using global::Microsoft.Extensions.DependencyInjection;
global using global::Microsoft.Extensions.Hosting;
global using global::Microsoft.Extensions.Logging;
But obviously this isn't very nice. Would there be anyway to generate this file through Bazel somehow?
I'm not sure how this list is generated so It's hard to tell if it would be worth the maintenance cost to add this feature to rules_dotnet. This can be worked around by the end user by using a bazel macro around the csharp_library/binary fairly easily.
If you have any further information on how this list is generated then that would help with making the decision.
I actually looked into it a little bit. The way it works is as follows:
ImplicitUsingsis set toenabledhere, which enables it for everyone usingMicrosoft.NET.Sdkand its children:
https://github.com/dotnet/sdk/blob/f48021c3202146e8ba6c8364fc619b31bef84d89/Directory.Build.props#L48
- In each SDK, there's a
.propsfile which contains a conditionalItemGroupthat adds theUsingstatements:
https://github.com/dotnet/sdk/blob/a9db5d8e5f90e64e28dff757c70a934a70ac73ef/src/WebSdk/Web/Targets/Sdk.Server.props#L64
- Finally, there's a custom task that gets executed during the build, which generates the
{AssemblyName}.GlobalUsings.g.csfile:
https://github.com/dotnet/sdk/blob/f48021c3202146e8ba6c8364fc619b31bef84d89/src/Tasks/Microsoft.NET.Build.Tasks/GenerateGlobalUsings.cs#L8 https://github.com/dotnet/sdk/blob/f48021c3202146e8ba6c8364fc619b31bef84d89/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateGlobalUsings.targets#L23
I might be incorrect, but from what I can understand, the only "proper" ways to get these Using targets is:
- Maintaining them as a catalog in
rules_dotnet, and updating them with new .NET releases - Parsing the XML files for the
<Using />tags (brittle) - Actually running MSBuild
I've just hit this too, my build is failing. I'm not quite sure what to do.
@peakschris You wrap the rules with your own macro where you provide a source file with the global imports. But I think I would also accept an contribution that adds the global imports in a maintainable way.
What I did at work for now:
- Create a folder called
GlobalUsingsat the top level, containing files likeMicrosoft.NET.SDK.cs. - Each file contains the
GlobalUsings.g.cscontents that would be generated for that SDK, along with a link to which.propsfile in https://github.com/dotnet/sdk they are generated from. - Each project within the solution contains a
GlobalUsingsfolder, and relatively symlinks the SDKs they use, i.e. a project using theMicrosoft.NET.SDK.WebSDK will symlink bothMicrosoft.NET.SDK.csandMicrosoft.NET.SDK.Web.cs.
(Make sure to add <ImplicitUsings>false</ImplicitUsings> to your csproj files to avoid duplicates in the MSBuild workflow, if you intend to have one.)
Want this feature to simplify the migration. Almost all of my projects used this feature.
It works fine to create an extra .GlobalUsings.g.cs file and add to the project that contains the using statements. This can be added explicitly or in a wrapped rule:
MyLibrary.GlobalUsings.g.cs:
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
But it would be far better if this file was auto-generated in the same way that msbuild does.
I know this issue is a little old, but the team I work with implemented support for this as suggested by @purkhusid - we intend to contribute it, but it needs some tidying to make it more generally manageable. In particular, we want to provide a better way to manage the namespaces across multiple SDKs and framework versions.
However it isn't super complicated to implement, so an outline for what we did might be helpful:
- We wrapped the rules_dotnet rules with our own macros
- Made a map (using the SDK as a key) of the implicit namespaces, based on the MS docs
- Used a genrule (see below) to create a cs file with a global using statement for each namespace
- Appended the generated source file to the list of srcs passed to rules_dotnet
We also added an attribute to allow other global usings to be supplied (like the <Using> msbuild element), simply adding them to the list of implicit namespaces.
The code for the genrule isn't especially complex either:
def _create_global_usings_file(filename, namespaces):
content = "\n".join(["global using global::%s;" % ns for ns in namespaces])
native.genrule(
name = filename.replace(".cs", ""),
outs = [filename],
cmd = "echo '" + content + "' > $@",
)