| load("@d2l_rules_csharp//csharp/private:actions/assembly.bzl", "AssemblyAction") |
| load("@d2l_rules_csharp//csharp/private:actions/misc.bzl", "write_runtimeconfig") |
| load( |
| "@d2l_rules_csharp//csharp/private:common.bzl", |
| "fill_in_missing_frameworks", |
| "is_core_framework", |
| "is_debug", |
| "is_standard_framework", |
| ) |
| load("@d2l_rules_csharp//csharp/private:providers.bzl", "AnyTargetFrameworkInfo") |
| load("//dotnet/private:copy_files.bzl", "copy_files") |
| |
| def _generate_execution_script_file(ctx, target): |
| tfm = target.actual_tfm |
| assembly_file_name = target.out.basename |
| shell_file_extension = "sh" |
| execution_line = "$( cd \"$(dirname \"$BASH_SOURCE[0]}\")\" >/dev/null 2>&1 && pwd -P )/" + assembly_file_name + " $@" |
| if ctx.attr.is_windows: |
| shell_file_extension = "bat" |
| execution_line = "%~dp0" + assembly_file_name + " %*" |
| if is_core_framework(tfm) or tfm == "net5.0" or tfm == "net6.0": |
| execution_line = "dotnet " + execution_line |
| else: |
| execution_line = "mono " + execution_line |
| |
| toolchain = ctx.toolchains["@d2l_rules_csharp//csharp/private:toolchain_type"] |
| dotnet_sdk_location = toolchain.runtime.executable.dirname |
| environment = "" |
| if not ctx.attr.is_windows: |
| environment += "export DOTNET_CLI_HOME=%s\n" % dotnet_sdk_location |
| environment += "export APPDATA=%s\n" % dotnet_sdk_location |
| environment += "export PROGRAMFILES=%s\n" % dotnet_sdk_location |
| environment += "export USERPROFILE=%s\n" % dotnet_sdk_location |
| environment += "export DOTNET_CLI_TELEMETRY_OPTOUT=1\n" |
| else: |
| environment += "@echo off\n" |
| |
| shell_content = environment + execution_line |
| |
| shell_file_name = "bazelout/%s/%s.%s" % (tfm, assembly_file_name, shell_file_extension) |
| shell_file = ctx.actions.declare_file(shell_file_name) |
| ctx.actions.write( |
| output = shell_file, |
| content = shell_content, |
| is_executable = True, |
| ) |
| |
| return shell_file |
| |
| def _copy_dependency_files(ctx, provider_value): |
| src_list = provider_value.transitive_runfiles.to_list() |
| target_dir = "bazelout/%s/" % (provider_value.actual_tfm) |
| file_list = [] |
| for src_file in src_list: |
| file_list.append((src_file, src_file.basename)) |
| |
| return copy_files(ctx, file_list, target_dir, ctx.attr.is_windows) |
| |
| def create_executable_assembly(ctx, extra_srcs, extra_deps): |
| stdrefs = [ctx.attr._stdrefs] if ctx.attr.include_stdrefs else [] |
| |
| providers = {} |
| for tfm in ctx.attr.target_frameworks: |
| if is_standard_framework(tfm): |
| fail("It doesn't make sense to build an executable for " + tfm) |
| |
| providers[tfm] = AssemblyAction( |
| ctx.actions, |
| additionalfiles = ctx.files.additionalfiles, |
| analyzers = ctx.attr.analyzers, |
| debug = is_debug(ctx), |
| defines = ctx.attr.defines, |
| deps = ctx.attr.deps + extra_deps + stdrefs, |
| keyfile = ctx.file.keyfile, |
| internals_visible_to = None, |
| internals_visible_to_cs = None, |
| langversion = ctx.attr.langversion, |
| nullable = ctx.attr.nullable, |
| resources = ctx.files.resources, |
| srcs = ctx.files.srcs + extra_srcs, |
| out = ctx.attr.out, |
| target = "exe", |
| target_name = ctx.attr.name, |
| target_framework = tfm, |
| toolchain = ctx.toolchains["@d2l_rules_csharp//csharp/private:toolchain_type"], |
| ) |
| |
| fill_in_missing_frameworks(ctx.attr.out, providers) |
| |
| result = providers.values() |
| dependency_files_list = _copy_dependency_files(ctx, result[0]) |
| |
| runtimeconfig = write_runtimeconfig( |
| ctx.actions, |
| ctx.file.runtimeconfig_template, |
| result[0].out.basename.replace("." + result[0].out.extension, ""), |
| result[0].actual_tfm, |
| ) |
| |
| data_runfiles = [] if ctx.attr.data == None else [d.files for d in ctx.attr.data] |
| |
| shell_file = _generate_execution_script_file(ctx, result[0]) |
| |
| direct_runfiles = [result[0].out, result[0].pdb] |
| if runtimeconfig != None: |
| direct_runfiles.append(runtimeconfig) |
| |
| result.append(DefaultInfo( |
| executable = shell_file, |
| runfiles = ctx.runfiles( |
| files = direct_runfiles, |
| transitive_files = depset(dependency_files_list, transitive = data_runfiles), |
| ), |
| files = depset([result[0].out, result[0].prefout, result[0].pdb, shell_file]), |
| )) |
| |
| return result |
| |
| def _csharp_executable_impl(ctx): |
| extra_srcs = [] |
| extra_deps = [] |
| return create_executable_assembly(ctx, extra_srcs, extra_deps) |
| |
| csharp_executable = rule( |
| _csharp_executable_impl, |
| doc = "Create an executable C# exe", |
| attrs = { |
| "srcs": attr.label_list( |
| doc = "C# source files.", |
| allow_files = [".cs"], |
| ), |
| "additionalfiles": attr.label_list( |
| doc = "Extra files to configure analyzers.", |
| allow_files = True, |
| ), |
| "analyzers": attr.label_list( |
| doc = "A list of analyzer references.", |
| providers = AnyTargetFrameworkInfo, |
| ), |
| "keyfile": attr.label( |
| doc = "The key file used to sign the assembly with a strong name.", |
| allow_single_file = True, |
| ), |
| "langversion": attr.string( |
| doc = "The version string for the C# language.", |
| ), |
| "nullable": attr.string( |
| doc = "Enable nullable context, or nullable warnings.", |
| ), |
| "resources": attr.label_list( |
| doc = "A list of files to embed in the DLL as resources.", |
| allow_files = True, |
| ), |
| "out": attr.string( |
| doc = "File name, without extension, of the built assembly.", |
| ), |
| "target_frameworks": attr.string_list( |
| doc = "A list of target framework monikers to build" + |
| "See https://docs.microsoft.com/en-us/dotnet/standard/frameworks", |
| allow_empty = False, |
| ), |
| "defines": attr.string_list( |
| doc = "A list of preprocessor directive symbols to define.", |
| default = [], |
| allow_empty = True, |
| ), |
| "include_stdrefs": attr.bool( |
| doc = "Whether to reference @net//:StandardReferences (the default set of references that MSBuild adds to every project).", |
| default = True, |
| ), |
| "runtimeconfig_template": attr.label( |
| doc = "A template file to use for generating runtimeconfig.json", |
| default = "@d2l_rules_csharp//csharp/private:runtimeconfig.json.tpl", |
| allow_single_file = True, |
| ), |
| "_stdrefs": attr.label( |
| doc = "The standard set of assemblies to reference.", |
| default = "@net//:StandardReferences", |
| ), |
| "deps": attr.label_list( |
| doc = "Other C# libraries, binaries, or imported DLLs", |
| providers = AnyTargetFrameworkInfo, |
| ), |
| "data": attr.label_list( |
| doc = "Additional data files or targets that are required to run the executable.", |
| allow_files = True, |
| ), |
| "is_windows": attr.bool(default = False), |
| }, |
| executable = True, |
| toolchains = ["@d2l_rules_csharp//csharp/private:toolchain_type"], |
| ) |