bazel-contrib / rules_dotnet

.NET rules for Bazel
Apache License 2.0
190 stars 83 forks source link

`ImplicitUsings` is not handled #436

Open sin-ack opened 5 months ago

sin-ack commented 5 months ago

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?

purkhusid commented 5 months ago

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.

sin-ack commented 5 months ago

I actually looked into it a little bit. The way it works is as follows:

https://github.com/dotnet/sdk/blob/f48021c3202146e8ba6c8364fc619b31bef84d89/Directory.Build.props#L48

https://github.com/dotnet/sdk/blob/a9db5d8e5f90e64e28dff757c70a934a70ac73ef/src/WebSdk/Web/Targets/Sdk.Server.props#L64

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:

peakschris commented 3 months ago

I've just hit this too, my build is failing. I'm not quite sure what to do.

purkhusid commented 3 months ago

@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.

sin-ack commented 3 months ago

What I did at work for now:

(Make sure to add <ImplicitUsings>false</ImplicitUsings> to your csproj files to avoid duplicates in the MSBuild workflow, if you intend to have one.)

hcoona commented 3 months ago

Want this feature to simplify the migration. Almost all of my projects used this feature.

peakschris commented 3 months ago

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.

matthewkenny commented 1 month ago

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 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 + "' > $@",
    )