From a3abab0f9fd001a3917d302f69974d2d64b1e30d Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 11:33:00 -0500 Subject: [PATCH 01/20] Wrap the dotnet executable --- csharp/defs.bzl | 5 ++ csharp/private/BUILD | 7 +-- csharp/private/rules/main.cc | 93 ++++++++++++++++++++++++++++++++ csharp/private/rules/wrapper.bzl | 30 +++++++++++ csharp/private/runtime.BUILD | 41 ++++++++++++-- csharp/private/toolchains.bzl | 4 +- 6 files changed, 168 insertions(+), 12 deletions(-) create mode 100644 csharp/private/rules/main.cc create mode 100644 csharp/private/rules/wrapper.bzl diff --git a/csharp/defs.bzl b/csharp/defs.bzl index 600b1e2..d2c92b4 100644 --- a/csharp/defs.bzl +++ b/csharp/defs.bzl @@ -7,6 +7,10 @@ load( "//csharp/private:rules/binary.bzl", _csharp_binary = "csharp_binary", ) +load( + "//csharp/private:rules/wrapper.bzl", + _dotnet_wrapper = "dotnet_wrapper", +) load( "//csharp/private:rules/library.bzl", _csharp_library = "csharp_library", @@ -34,6 +38,7 @@ load( _setup_basic_nuget_package = "setup_basic_nuget_package", ) +dotnet_wrapper = _dotnet_wrapper csharp_binary = _csharp_binary csharp_library = _csharp_library csharp_library_set = _csharp_library_set diff --git a/csharp/private/BUILD b/csharp/private/BUILD index 7115c26..3ad2bda 100644 --- a/csharp/private/BUILD +++ b/csharp/private/BUILD @@ -1,13 +1,10 @@ load(":toolchains.bzl", "configure_toolchain") -exports_files(["nunit/shim.cs"]) +exports_files(["nunit/shim.cs", "rules/ResGen.csproj", "rules/main.cc"]) toolchain_type(name = "toolchain_type") -configure_toolchain( - "windows", - exe = "dotnet.exe", -) +configure_toolchain("windows") configure_toolchain("linux") diff --git a/csharp/private/rules/main.cc b/csharp/private/rules/main.cc new file mode 100644 index 0000000..8c300d6 --- /dev/null +++ b/csharp/private/rules/main.cc @@ -0,0 +1,93 @@ +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#else // not _WIN32 +#include +#include +#endif // _WIN32 + +#include "tools/cpp/runfiles/runfiles.h" + +using bazel::tools::cpp::runfiles::Runfiles; + +std::string evprintf(std::string name, std::string path) +{ + std::stringstream ss; + ss << name << "=" << path; + return ss.str(); +} + +int main(int argc, char **argv) +{ + std::string error; + + auto runfiles = Runfiles::Create(argv[0], &error); + + if (runfiles == nullptr) + { + std::cerr << "Couldn't load runfiles: " << error << std::endl; + return 101; + } + + auto dotnet = runfiles->Rlocation("{DotnetExe}"); + if (dotnet.empty()) + { + std::cerr << "Couldn't find the .NET runtime" << std::endl; + return 404; + } + + // Get the name of the directory containing dotnet.exe + auto dotnetDir = dotnet.substr(0, dotnet.find_last_of("/\\")); + + /* + dotnet and nuget require these environment variables to be set + without them we cannot build/run anything with dotnet. + + dotnet: HOME, DOTNET_CLI_HOME, APPDATA, PROGRAMFILES + nuget: TMP, TEMP, USERPROFILE + */ + std::vector envvars; + envvars.push_back(evprintf("HOME", dotnetDir)); + envvars.push_back(evprintf("DOTNET_CLI_HOME", dotnetDir)); + envvars.push_back(evprintf("APPDATA", dotnetDir)); + envvars.push_back(evprintf("PROGRAMFILES", dotnetDir)); + envvars.push_back(evprintf("TMP", dotnetDir)); + envvars.push_back(evprintf("TEMP", dotnetDir)); + envvars.push_back(evprintf("USERPROFILE", dotnetDir)); + envvars.push_back(evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1")); // disable telemetry + + std::vector envp{}; + for(auto& envvar : envvars) + envp.push_back(&envvar.front()); + envp.push_back(0); + + // dotnet wants this to either be dotnet or dotnet.exe but doesn't have a + // preference otherwise. + auto dotnet_argv = new char*[argc]; + dotnet_argv[0] = (char *)"dotnet"; + for (int i = 1; i < argc; i++) + { + dotnet_argv[i] = argv[i]; + } + dotnet_argv[argc] = 0; + + // run `dotnet.exe` and wait for it to complete + // the output from this cmd will be emitted to stdout +#ifdef _WIN32 + auto result = _spawnve(_P_WAIT, dotnet.c_str(), dotnet_argv, envp.data()); +#else // not _WIN32 + auto result = execve(dotnet.c_str(), dotnet_argv, envp.data()); +#endif // _WIN32 + if (result != 0) + { + std::cout << "dotnet failed: " << errno << std::endl; + return -1; + } + + return result; +} \ No newline at end of file diff --git a/csharp/private/rules/wrapper.bzl b/csharp/private/rules/wrapper.bzl new file mode 100644 index 0000000..62e6880 --- /dev/null +++ b/csharp/private/rules/wrapper.bzl @@ -0,0 +1,30 @@ +def _dotnet_wrapper_impl(ctx): + cc_file = ctx.actions.declare_file("%s.cc" % (ctx.attr.name)) + ctx.actions.expand_template( + template = ctx.file.src, + output = cc_file, + substitutions = { + "{DotnetExe}": ctx.files.target[0].short_path[3:], + }, + ) + + files = depset(direct = [cc_file]) + return [ + DefaultInfo( + files = files, + ), + ] + +dotnet_wrapper = rule( + implementation = _dotnet_wrapper_impl, + attrs = { + "src": attr.label( + mandatory = True, + allow_single_file = True + ), + "target": attr.label_list( + mandatory = True, + allow_files = True, + ), + }, +) \ No newline at end of file diff --git a/csharp/private/runtime.BUILD b/csharp/private/runtime.BUILD index 65e75d7..f9356c4 100644 --- a/csharp/private/runtime.BUILD +++ b/csharp/private/runtime.BUILD @@ -1,9 +1,16 @@ +load("@rules_cc//cc:defs.bzl", "cc_binary") +load("@d2l_rules_csharp//csharp:defs.bzl", "dotnet_wrapper") + +_WRAPPER_TEMPLATE = "@d2l_rules_csharp//csharp/private:rules/main.cc" + exports_files( - glob([ - "dotnet", - "dotnet.exe", # windows, yeesh - ], allow_empty = True) + - glob([ + glob( + [ + "dotnet", + "dotnet.exe", # windows, yeesh + ], + allow_empty = True, + ) + glob([ "host/**/*", "shared/**/*", ]) + @@ -13,3 +20,27 @@ exports_files( ]), visibility = ["//visibility:public"], ) + +cc_binary( + name = "dotnetw", + srcs = [":main-cc"], + data = glob( + [ + "dotnet", + "dotnet.exe", + ], + ), + visibility = ["//visibility:public"], + deps = ["@bazel_tools//tools/cpp/runfiles"], +) + +dotnet_wrapper( + name = "main-cc", + src = _WRAPPER_TEMPLATE, + target = glob( + [ + "dotnet", + "dotnet.exe", + ], + ), +) diff --git a/csharp/private/toolchains.bzl b/csharp/private/toolchains.bzl index 8378f79..41a2dd4 100644 --- a/csharp/private/toolchains.bzl +++ b/csharp/private/toolchains.bzl @@ -1,7 +1,7 @@ def _csharp_toolchain_impl(ctx): return [ platform_common.ToolchainInfo( - runtime = ctx.file.runtime, + runtime = ctx.attr.runtime.files_to_run, compiler = ctx.file.compiler, ), ] @@ -25,7 +25,7 @@ csharp_toolchain = rule( ) # This is called in BUILD -def configure_toolchain(os, exe = "dotnet"): +def configure_toolchain(os, exe = "dotnetw"): csharp_toolchain( name = "csharp_x86_64-" + os, runtime = "@netcore-sdk-%s//:%s" % (os, exe), From cb2b6432d56652278d6e138ddc998c1b346dce34 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 14:50:38 -0500 Subject: [PATCH 02/20] Resolve issue with character limits --- csharp/private/BUILD | 2 +- csharp/private/actions/assembly.bzl | 2 +- csharp/private/runtime.BUILD | 2 +- csharp/private/{rules/main.cc => wrappers/dotnet.cc} | 9 +++++---- 4 files changed, 8 insertions(+), 7 deletions(-) rename csharp/private/{rules/main.cc => wrappers/dotnet.cc} (94%) diff --git a/csharp/private/BUILD b/csharp/private/BUILD index 3ad2bda..b2f05e2 100644 --- a/csharp/private/BUILD +++ b/csharp/private/BUILD @@ -1,6 +1,6 @@ load(":toolchains.bzl", "configure_toolchain") -exports_files(["nunit/shim.cs", "rules/ResGen.csproj", "rules/main.cc"]) +exports_files(["nunit/shim.cs", "wrappers/dotnet.cc"]) toolchain_type(name = "toolchain_type") diff --git a/csharp/private/actions/assembly.bzl b/csharp/private/actions/assembly.bzl index 9c4a348..3267db4 100644 --- a/csharp/private/actions/assembly.bzl +++ b/csharp/private/actions/assembly.bzl @@ -153,7 +153,7 @@ def AssemblyAction( # spill to a "response file" when the argument list gets too big (Bazel # makes that call based on limitations of the OS). args.set_param_file_format("multiline") - args.use_param_file("@%s") + args.use_param_file("@%s", use_always=True) direct_inputs = srcs + resources + analyzer_assemblies + additionalfiles + [toolchain.compiler] direct_inputs += [keyfile] if keyfile else [] diff --git a/csharp/private/runtime.BUILD b/csharp/private/runtime.BUILD index f9356c4..649fa0e 100644 --- a/csharp/private/runtime.BUILD +++ b/csharp/private/runtime.BUILD @@ -1,7 +1,7 @@ load("@rules_cc//cc:defs.bzl", "cc_binary") load("@d2l_rules_csharp//csharp:defs.bzl", "dotnet_wrapper") -_WRAPPER_TEMPLATE = "@d2l_rules_csharp//csharp/private:rules/main.cc" +_WRAPPER_TEMPLATE = "@d2l_rules_csharp//csharp/private:wrappers/dotnet.cc" exports_files( glob( diff --git a/csharp/private/rules/main.cc b/csharp/private/wrappers/dotnet.cc similarity index 94% rename from csharp/private/rules/main.cc rename to csharp/private/wrappers/dotnet.cc index 8c300d6..e931c13 100644 --- a/csharp/private/rules/main.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -3,6 +3,7 @@ #include #ifdef _WIN32 +#include #include #include #include @@ -56,8 +57,8 @@ int main(int argc, char **argv) envvars.push_back(evprintf("DOTNET_CLI_HOME", dotnetDir)); envvars.push_back(evprintf("APPDATA", dotnetDir)); envvars.push_back(evprintf("PROGRAMFILES", dotnetDir)); - envvars.push_back(evprintf("TMP", dotnetDir)); - envvars.push_back(evprintf("TEMP", dotnetDir)); + // envvars.push_back(evprintf("TMP", dotnetDir)); + // envvars.push_back(evprintf("TEMP", dotnetDir)); envvars.push_back(evprintf("USERPROFILE", dotnetDir)); envvars.push_back(evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1")); // disable telemetry @@ -80,9 +81,9 @@ int main(int argc, char **argv) // the output from this cmd will be emitted to stdout #ifdef _WIN32 auto result = _spawnve(_P_WAIT, dotnet.c_str(), dotnet_argv, envp.data()); -#else // not _WIN32 +#else auto result = execve(dotnet.c_str(), dotnet_argv, envp.data()); -#endif // _WIN32 +#endif // _WIN32 if (result != 0) { std::cout << "dotnet failed: " << errno << std::endl; From f1fce1b218b74f0b65e1a00439e20f33bf85bcab Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 15:05:29 -0500 Subject: [PATCH 03/20] Environment vars have max amount --- csharp/private/wrappers/dotnet.cc | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index e931c13..9d61a1c 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -7,10 +7,10 @@ #include #include #include -#else // not _WIN32 +#else // not _WIN32 #include #include -#endif // _WIN32 +#endif // _WIN32 #include "tools/cpp/runfiles/runfiles.h" @@ -44,7 +44,7 @@ int main(int argc, char **argv) // Get the name of the directory containing dotnet.exe auto dotnetDir = dotnet.substr(0, dotnet.find_last_of("/\\")); - + /* dotnet and nuget require these environment variables to be set without them we cannot build/run anything with dotnet. @@ -57,19 +57,12 @@ int main(int argc, char **argv) envvars.push_back(evprintf("DOTNET_CLI_HOME", dotnetDir)); envvars.push_back(evprintf("APPDATA", dotnetDir)); envvars.push_back(evprintf("PROGRAMFILES", dotnetDir)); - // envvars.push_back(evprintf("TMP", dotnetDir)); - // envvars.push_back(evprintf("TEMP", dotnetDir)); envvars.push_back(evprintf("USERPROFILE", dotnetDir)); envvars.push_back(evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1")); // disable telemetry - - std::vector envp{}; - for(auto& envvar : envvars) - envp.push_back(&envvar.front()); - envp.push_back(0); // dotnet wants this to either be dotnet or dotnet.exe but doesn't have a // preference otherwise. - auto dotnet_argv = new char*[argc]; + auto dotnet_argv = new char *[argc]; dotnet_argv[0] = (char *)"dotnet"; for (int i = 1; i < argc; i++) { @@ -80,8 +73,17 @@ int main(int argc, char **argv) // run `dotnet.exe` and wait for it to complete // the output from this cmd will be emitted to stdout #ifdef _WIN32 - auto result = _spawnve(_P_WAIT, dotnet.c_str(), dotnet_argv, envp.data()); + for (int i = 1; i < envvars.size(); i++) + { + putenv(envvars[i].c_str()); + } + auto result = _spawnv(_P_WAIT, dotnet.c_str(), dotnet_argv); #else + std::vector envp{}; + for (auto &envvar : envvars) + envp.push_back(&envvar.front()); + envp.push_back(0); + auto result = execve(dotnet.c_str(), dotnet_argv, envp.data()); #endif // _WIN32 if (result != 0) From 25b3a32ea52aac4905e1bea378f49bd80a5c220c Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 15:08:42 -0500 Subject: [PATCH 04/20] Document about env vars --- csharp/private/wrappers/dotnet.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index 9d61a1c..707d438 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -70,13 +70,17 @@ int main(int argc, char **argv) } dotnet_argv[argc] = 0; - // run `dotnet.exe` and wait for it to complete - // the output from this cmd will be emitted to stdout #ifdef _WIN32 + // _spawnve has a limit on the size of the environment variables + // passed to the process. So here we will set the environment + // variables for this process, and the spawned instance will inherit them for (int i = 1; i < envvars.size(); i++) { putenv(envvars[i].c_str()); } + + // run `dotnet.exe` and wait for it to complete + // the output from this cmd will be emitted to stdout auto result = _spawnv(_P_WAIT, dotnet.c_str(), dotnet_argv); #else std::vector envp{}; @@ -84,6 +88,8 @@ int main(int argc, char **argv) envp.push_back(&envvar.front()); envp.push_back(0); + // run `dotnet.exe` and wait for it to complete + // the output from this cmd will be emitted to stdout auto result = execve(dotnet.c_str(), dotnet_argv, envp.data()); #endif // _WIN32 if (result != 0) From 462992aca37123d411f62eaa519f404162733576 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 15:24:37 -0500 Subject: [PATCH 05/20] Add sandbox debug to macOS --- .bazelci/presubmit.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 744b80d..bdbe31e 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -22,6 +22,8 @@ tasks: examples-macos: name: Examples on macOS platform: macos + build_flags: + - "--sandbox_debug" include_json_profile: - build - test From 4db9e3d2acc6eca1187bc545d0c8ec1800f43771 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 15:39:50 -0500 Subject: [PATCH 06/20] Test nullptr --- csharp/private/wrappers/dotnet.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index 707d438..90a6614 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -3,7 +3,6 @@ #include #ifdef _WIN32 -#include #include #include #include @@ -68,7 +67,7 @@ int main(int argc, char **argv) { dotnet_argv[i] = argv[i]; } - dotnet_argv[argc] = 0; + dotnet_argv[argc] = nullptr; #ifdef _WIN32 // _spawnve has a limit on the size of the environment variables @@ -84,9 +83,11 @@ int main(int argc, char **argv) auto result = _spawnv(_P_WAIT, dotnet.c_str(), dotnet_argv); #else std::vector envp{}; - for (auto &envvar : envvars) + envp.reserve(envvars.size()+1); + for (auto &envvar : envvars) { envp.push_back(&envvar.front()); - envp.push_back(0); + } + envp.push_back(nullptr); // run `dotnet.exe` and wait for it to complete // the output from this cmd will be emitted to stdout From 755779c72b8620dbd336f7efc74aa7deefd37f96 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 15:45:17 -0500 Subject: [PATCH 07/20] Replace vector with char* array --- csharp/private/wrappers/dotnet.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index 90a6614..8b67ab0 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -82,16 +82,18 @@ int main(int argc, char **argv) // the output from this cmd will be emitted to stdout auto result = _spawnv(_P_WAIT, dotnet.c_str(), dotnet_argv); #else - std::vector envp{}; - envp.reserve(envvars.size()+1); - for (auto &envvar : envvars) { - envp.push_back(&envvar.front()); + auto envc = envvars.size(); + auto envp = new char*[envc+1]; + for (uint i = 0; i < envc; i++) + { + // envp[i] = envvars[i].c_str(); + envp[i] = &envvars[i][0]; } - envp.push_back(nullptr); + envp[envc] = nullptr; // run `dotnet.exe` and wait for it to complete // the output from this cmd will be emitted to stdout - auto result = execve(dotnet.c_str(), dotnet_argv, envp.data()); + auto result = execve(dotnet.c_str(), dotnet_argv, envp); #endif // _WIN32 if (result != 0) { From 36bc198de2c2a83b2da8a8492fd0b3db684a8383 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 15:48:56 -0500 Subject: [PATCH 08/20] Try const char on args --- csharp/private/wrappers/dotnet.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index 8b67ab0..711ef61 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -93,7 +93,7 @@ int main(int argc, char **argv) // run `dotnet.exe` and wait for it to complete // the output from this cmd will be emitted to stdout - auto result = execve(dotnet.c_str(), dotnet_argv, envp); + auto result = execve(dotnet.c_str(), const_cast(dotnet_argv), envp); #endif // _WIN32 if (result != 0) { From a1c7528ad1fa348fbf4d38e4437434d1a346067a Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 15:51:22 -0500 Subject: [PATCH 09/20] Remove test with c_str --- csharp/private/wrappers/dotnet.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index 711ef61..1e86dcc 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -86,7 +86,6 @@ int main(int argc, char **argv) auto envp = new char*[envc+1]; for (uint i = 0; i < envc; i++) { - // envp[i] = envvars[i].c_str(); envp[i] = &envvars[i][0]; } envp[envc] = nullptr; From 155426d13f3496ac02864e91109a468e6657d890 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 16:24:18 -0500 Subject: [PATCH 10/20] Remove sandbox debugging --- .bazelci/presubmit.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index bdbe31e..744b80d 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -22,8 +22,6 @@ tasks: examples-macos: name: Examples on macOS platform: macos - build_flags: - - "--sandbox_debug" include_json_profile: - build - test From cb981c78d77bd79887c19e4fdab9bbece967778f Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Thu, 21 Nov 2019 16:24:27 -0500 Subject: [PATCH 11/20] Move template into rule --- csharp/private/rules/wrapper.bzl | 21 +++++++++++++++------ csharp/private/runtime.BUILD | 5 +---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/csharp/private/rules/wrapper.bzl b/csharp/private/rules/wrapper.bzl index 62e6880..6c9a235 100644 --- a/csharp/private/rules/wrapper.bzl +++ b/csharp/private/rules/wrapper.bzl @@ -1,10 +1,15 @@ +_TEMPLATE = "@d2l_rules_csharp//csharp/private:wrappers/dotnet.cc" + def _dotnet_wrapper_impl(ctx): cc_file = ctx.actions.declare_file("%s.cc" % (ctx.attr.name)) + if len(ctx.files.src) < 1: + fail("No dotnet executable found in the SDK") + ctx.actions.expand_template( - template = ctx.file.src, + template = ctx.file.template, output = cc_file, substitutions = { - "{DotnetExe}": ctx.files.target[0].short_path[3:], + "{DotnetExe}": ctx.files.src[0].short_path[3:], }, ) @@ -18,12 +23,16 @@ def _dotnet_wrapper_impl(ctx): dotnet_wrapper = rule( implementation = _dotnet_wrapper_impl, attrs = { - "src": attr.label( - mandatory = True, + "template": attr.label( + doc = """Path to the program that will wrap the dotnet executable. +This program will be compiled and used instead of directly calling the dotnet executable.""", + default = Label(_TEMPLATE), allow_single_file = True ), - "target": attr.label_list( - mandatory = True, + "src": attr.label_list( + doc = """The name of the dotnet executable. +On windows this should be 'dotnet.exe', and 'dotnet' on linux/macOS.""", + mandatory = True, allow_files = True, ), }, diff --git a/csharp/private/runtime.BUILD b/csharp/private/runtime.BUILD index 649fa0e..f28ce2f 100644 --- a/csharp/private/runtime.BUILD +++ b/csharp/private/runtime.BUILD @@ -1,8 +1,6 @@ load("@rules_cc//cc:defs.bzl", "cc_binary") load("@d2l_rules_csharp//csharp:defs.bzl", "dotnet_wrapper") -_WRAPPER_TEMPLATE = "@d2l_rules_csharp//csharp/private:wrappers/dotnet.cc" - exports_files( glob( [ @@ -36,8 +34,7 @@ cc_binary( dotnet_wrapper( name = "main-cc", - src = _WRAPPER_TEMPLATE, - target = glob( + src = glob( [ "dotnet", "dotnet.exe", From a79858990ef88708dae4a54126b74189d59a2fe2 Mon Sep 17 00:00:00 2001 From: Jonathan Beverly Date: Mon, 25 Nov 2019 09:53:48 -0500 Subject: [PATCH 12/20] Explain why we use param_file always Co-Authored-By: Jacob Parker --- csharp/private/actions/assembly.bzl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csharp/private/actions/assembly.bzl b/csharp/private/actions/assembly.bzl index 3267db4..b571837 100644 --- a/csharp/private/actions/assembly.bzl +++ b/csharp/private/actions/assembly.bzl @@ -153,6 +153,8 @@ def AssemblyAction( # spill to a "response file" when the argument list gets too big (Bazel # makes that call based on limitations of the OS). args.set_param_file_format("multiline") + # Our wrapper uses _spawnv to launch dotnet, and that has a command line limit + # of 1024 bytes, so always use a param file. args.use_param_file("@%s", use_always=True) direct_inputs = srcs + resources + analyzer_assemblies + additionalfiles + [toolchain.compiler] From c80b76e06e59fff7f393038a5fd915a1d2811265 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Mon, 25 Nov 2019 10:02:30 -0500 Subject: [PATCH 13/20] Allow empty for executable globs --- csharp/private/runtime.BUILD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csharp/private/runtime.BUILD b/csharp/private/runtime.BUILD index f28ce2f..62c7b12 100644 --- a/csharp/private/runtime.BUILD +++ b/csharp/private/runtime.BUILD @@ -27,6 +27,7 @@ cc_binary( "dotnet", "dotnet.exe", ], + allow_empty = True, ), visibility = ["//visibility:public"], deps = ["@bazel_tools//tools/cpp/runfiles"], @@ -39,5 +40,6 @@ dotnet_wrapper( "dotnet", "dotnet.exe", ], + allow_empty = True, ), ) From 8347cbeaafbbbfbb0b96632b2fde8b992ddfe5fe Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Mon, 25 Nov 2019 10:08:39 -0500 Subject: [PATCH 14/20] Add google style rules --- csharp/private/wrappers/.clang-format | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 csharp/private/wrappers/.clang-format diff --git a/csharp/private/wrappers/.clang-format b/csharp/private/wrappers/.clang-format new file mode 100644 index 0000000..aa86d87 --- /dev/null +++ b/csharp/private/wrappers/.clang-format @@ -0,0 +1,14 @@ +# Use the Google style in this project. +BasedOnStyle: Google + +DerivePointerAlignment: false +PointerAlignment: Left + +IncludeBlocks: Merge +IncludeCategories: +- Regex: '^\"' + Priority: 1000 +- Regex: '^<.*/.*' + Priority: 4000 +- Regex: '^<[^/]*>' + Priority: 5000 \ No newline at end of file From 56e04849fd7b607589c12295a8338daab6ba8b9a Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Mon, 25 Nov 2019 10:08:52 -0500 Subject: [PATCH 15/20] Run format on wrapper --- csharp/private/wrappers/dotnet.cc | 45 +++++++++++++------------------ 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index 1e86dcc..015260a 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -1,42 +1,38 @@ #include -#include #include +#include #ifdef _WIN32 -#include -#include #include -#else // not _WIN32 +#include +#include +#else // not _WIN32 #include #include -#endif // _WIN32 +#endif // _WIN32 #include "tools/cpp/runfiles/runfiles.h" using bazel::tools::cpp::runfiles::Runfiles; -std::string evprintf(std::string name, std::string path) -{ +std::string evprintf(std::string name, std::string path) { std::stringstream ss; ss << name << "=" << path; return ss.str(); } -int main(int argc, char **argv) -{ +int main(int argc, char** argv) { std::string error; auto runfiles = Runfiles::Create(argv[0], &error); - if (runfiles == nullptr) - { + if (runfiles == nullptr) { std::cerr << "Couldn't load runfiles: " << error << std::endl; return 101; } auto dotnet = runfiles->Rlocation("{DotnetExe}"); - if (dotnet.empty()) - { + if (dotnet.empty()) { std::cerr << "Couldn't find the .NET runtime" << std::endl; return 404; } @@ -57,14 +53,14 @@ int main(int argc, char **argv) envvars.push_back(evprintf("APPDATA", dotnetDir)); envvars.push_back(evprintf("PROGRAMFILES", dotnetDir)); envvars.push_back(evprintf("USERPROFILE", dotnetDir)); - envvars.push_back(evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1")); // disable telemetry + envvars.push_back( + evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1")); // disable telemetry // dotnet wants this to either be dotnet or dotnet.exe but doesn't have a // preference otherwise. - auto dotnet_argv = new char *[argc]; - dotnet_argv[0] = (char *)"dotnet"; - for (int i = 1; i < argc; i++) - { + auto dotnet_argv = new char*[argc]; + dotnet_argv[0] = (char*)"dotnet"; + for (int i = 1; i < argc; i++) { dotnet_argv[i] = argv[i]; } dotnet_argv[argc] = nullptr; @@ -73,8 +69,7 @@ int main(int argc, char **argv) // _spawnve has a limit on the size of the environment variables // passed to the process. So here we will set the environment // variables for this process, and the spawned instance will inherit them - for (int i = 1; i < envvars.size(); i++) - { + for (int i = 1; i < envvars.size(); i++) { putenv(envvars[i].c_str()); } @@ -83,9 +78,8 @@ int main(int argc, char **argv) auto result = _spawnv(_P_WAIT, dotnet.c_str(), dotnet_argv); #else auto envc = envvars.size(); - auto envp = new char*[envc+1]; - for (uint i = 0; i < envc; i++) - { + auto envp = new char*[envc + 1]; + for (uint i = 0; i < envc; i++) { envp[i] = &envvars[i][0]; } envp[envc] = nullptr; @@ -93,9 +87,8 @@ int main(int argc, char **argv) // run `dotnet.exe` and wait for it to complete // the output from this cmd will be emitted to stdout auto result = execve(dotnet.c_str(), const_cast(dotnet_argv), envp); -#endif // _WIN32 - if (result != 0) - { +#endif // _WIN32 + if (result != 0) { std::cout << "dotnet failed: " << errno << std::endl; return -1; } From 80e56d3d468ac767c98b22231df22891057d25aa Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Tue, 26 Nov 2019 16:52:50 -0500 Subject: [PATCH 16/20] Use static init for envvars --- csharp/private/wrappers/dotnet.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index 015260a..84761dd 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -47,14 +47,14 @@ int main(int argc, char** argv) { dotnet: HOME, DOTNET_CLI_HOME, APPDATA, PROGRAMFILES nuget: TMP, TEMP, USERPROFILE */ - std::vector envvars; - envvars.push_back(evprintf("HOME", dotnetDir)); - envvars.push_back(evprintf("DOTNET_CLI_HOME", dotnetDir)); - envvars.push_back(evprintf("APPDATA", dotnetDir)); - envvars.push_back(evprintf("PROGRAMFILES", dotnetDir)); - envvars.push_back(evprintf("USERPROFILE", dotnetDir)); - envvars.push_back( - evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1")); // disable telemetry + std::vector envvars = { + evprintf("HOME", dotnetDir), + evprintf("DOTNET_CLI_HOME", dotnetDir), + evprintf("APPDATA", dotnetDir), + evprintf("PROGRAMFILES", dotnetDir), + evprintf("USERPROFILE", dotnetDir), + evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1"), // disable telemetry + }; // dotnet wants this to either be dotnet or dotnet.exe but doesn't have a // preference otherwise. From 1e3a71f64a75e33907a9022110a3951c5638f410 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Tue, 26 Nov 2019 17:00:05 -0500 Subject: [PATCH 17/20] Revert "Use static init for envvars" This reverts commit 80e56d3d468ac767c98b22231df22891057d25aa. --- csharp/private/wrappers/dotnet.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index 84761dd..015260a 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -47,14 +47,14 @@ int main(int argc, char** argv) { dotnet: HOME, DOTNET_CLI_HOME, APPDATA, PROGRAMFILES nuget: TMP, TEMP, USERPROFILE */ - std::vector envvars = { - evprintf("HOME", dotnetDir), - evprintf("DOTNET_CLI_HOME", dotnetDir), - evprintf("APPDATA", dotnetDir), - evprintf("PROGRAMFILES", dotnetDir), - evprintf("USERPROFILE", dotnetDir), - evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1"), // disable telemetry - }; + std::vector envvars; + envvars.push_back(evprintf("HOME", dotnetDir)); + envvars.push_back(evprintf("DOTNET_CLI_HOME", dotnetDir)); + envvars.push_back(evprintf("APPDATA", dotnetDir)); + envvars.push_back(evprintf("PROGRAMFILES", dotnetDir)); + envvars.push_back(evprintf("USERPROFILE", dotnetDir)); + envvars.push_back( + evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1")); // disable telemetry // dotnet wants this to either be dotnet or dotnet.exe but doesn't have a // preference otherwise. From 8d0ef05ff1a94a3423fb18be05f1b1293367a8d2 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Wed, 27 Nov 2019 14:23:20 -0500 Subject: [PATCH 18/20] Use list init for envvars --- csharp/private/wrappers/dotnet.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index 015260a..3855c70 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -47,14 +47,14 @@ int main(int argc, char** argv) { dotnet: HOME, DOTNET_CLI_HOME, APPDATA, PROGRAMFILES nuget: TMP, TEMP, USERPROFILE */ - std::vector envvars; - envvars.push_back(evprintf("HOME", dotnetDir)); - envvars.push_back(evprintf("DOTNET_CLI_HOME", dotnetDir)); - envvars.push_back(evprintf("APPDATA", dotnetDir)); - envvars.push_back(evprintf("PROGRAMFILES", dotnetDir)); - envvars.push_back(evprintf("USERPROFILE", dotnetDir)); - envvars.push_back( - evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1")); // disable telemetry + std::vector envvars = { + evprintf("HOME", dotnetDir), + evprintf("DOTNET_CLI_HOME", dotnetDir), + evprintf("APPDATA", dotnetDir), + evprintf("PROGRAMFILES", dotnetDir), + evprintf("USERPROFILE", dotnetDir), + evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1"), // disable telemetry + }; // dotnet wants this to either be dotnet or dotnet.exe but doesn't have a // preference otherwise. @@ -80,7 +80,7 @@ int main(int argc, char** argv) { auto envc = envvars.size(); auto envp = new char*[envc + 1]; for (uint i = 0; i < envc; i++) { - envp[i] = &envvars[i][0]; + envp[i] = const_cast(&envvars[i][0]); } envp[envc] = nullptr; From 45c6e59a7f4398163c0a809d1224a39c3b8f81d6 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Wed, 27 Nov 2019 14:29:16 -0500 Subject: [PATCH 19/20] Remove resx specific envvars --- csharp/private/wrappers/dotnet.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index 3855c70..e508823 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -41,18 +41,13 @@ int main(int argc, char** argv) { auto dotnetDir = dotnet.substr(0, dotnet.find_last_of("/\\")); /* - dotnet and nuget require these environment variables to be set - without them we cannot build/run anything with dotnet. - - dotnet: HOME, DOTNET_CLI_HOME, APPDATA, PROGRAMFILES - nuget: TMP, TEMP, USERPROFILE + dotnet requires these environment variables to be set. */ std::vector envvars = { evprintf("HOME", dotnetDir), evprintf("DOTNET_CLI_HOME", dotnetDir), evprintf("APPDATA", dotnetDir), evprintf("PROGRAMFILES", dotnetDir), - evprintf("USERPROFILE", dotnetDir), evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1"), // disable telemetry }; From ad39050ba88f2ff0002f51be7ec2eb389b519fe6 Mon Sep 17 00:00:00 2001 From: jrbeverly Date: Wed, 27 Nov 2019 15:04:20 -0500 Subject: [PATCH 20/20] User profile is needed for MacOS --- csharp/private/wrappers/dotnet.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/csharp/private/wrappers/dotnet.cc b/csharp/private/wrappers/dotnet.cc index e508823..e28a87d 100644 --- a/csharp/private/wrappers/dotnet.cc +++ b/csharp/private/wrappers/dotnet.cc @@ -48,6 +48,7 @@ int main(int argc, char** argv) { evprintf("DOTNET_CLI_HOME", dotnetDir), evprintf("APPDATA", dotnetDir), evprintf("PROGRAMFILES", dotnetDir), + evprintf("USERPROFILE", dotnetDir), evprintf("DOTNET_CLI_TELEMETRY_OPTOUT", "1"), // disable telemetry };