Path: blob/trunk/dotnet/private/executable_assembly.bzl
3227 views
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"], )