Skip to content
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

ImplicitUsings is not handled #436

Open
sin-ack opened this issue Apr 24, 2024 · 8 comments
Open

ImplicitUsings is not handled #436

sin-ack opened this issue Apr 24, 2024 · 8 comments

Comments

@sin-ack
Copy link
Contributor

sin-ack commented Apr 24, 2024

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
Copy link
Collaborator

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
Copy link
Contributor Author

sin-ack commented Apr 24, 2024

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

  • ImplicitUsings is set to enabled here, which enables it for everyone using Microsoft.NET.Sdk and its children:

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

  • In each SDK, there's a .props file which contains a conditional ItemGroup that adds the Using statements:

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.cs file:

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

@peakschris
Copy link

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

@purkhusid
Copy link
Collaborator

@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
Copy link
Contributor Author

sin-ack commented Jul 3, 2024

What I did at work for now:

  • Create a folder called GlobalUsings at the top level, containing files like Microsoft.NET.SDK.cs.
  • Each file contains the GlobalUsings.g.cs contents that would be generated for that SDK, along with a link to which .props file in https://github.com/dotnet/sdk they are generated from.
  • Each project within the solution contains a GlobalUsings folder, and relatively symlinks the SDKs they use, i.e. a project using the Microsoft.NET.SDK.Web SDK will symlink both Microsoft.NET.SDK.cs and Microsoft.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.)

@hcoona
Copy link

hcoona commented Jul 4, 2024

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

@peakschris
Copy link

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
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants