diff options
author | Yun Peng <pcloudy@google.com> | 2016-10-25 13:49:28 +0000 |
---|---|---|
committer | John Cater <jcater@google.com> | 2016-10-25 20:18:38 +0000 |
commit | 81aede1f9bdddfe0e2327d6cf0ba9bd40fd62718 (patch) | |
tree | 9bccf6c64b547e03cfa336ffa4b1e7da144f9cab | |
parent | ca99bb71b8120e61a3bbde8e54f1a9488fa0478f (diff) |
Reimplement whole archive on Windows
Use wrapper script to get object files if /WHOLEARCHIVE is not supported.
fix https://github.com/bazelbuild/bazel/issues/1978
work towards https://github.com/bazelbuild/bazel/issues/1918
--
Change-Id: I675311478e65a1e1f3fa963187a5a8da531150d3
Reviewed-on: https://bazel-review.googlesource.com/#/c/6833
MOS_MIGRATED_REVID=137151817
-rwxr-xr-x | src/test/shell/bazel/bazel_windows_example_test.sh | 42 | ||||
-rw-r--r-- | tools/cpp/CROSSTOOL.tpl | 170 | ||||
-rw-r--r-- | tools/cpp/cc_configure.bzl | 13 | ||||
-rw-r--r-- | tools/cpp/wrapper/bin/pydir/msvc_link.py | 3 | ||||
-rw-r--r-- | tools/cpp/wrapper/bin/pydir/msvc_tools.py.tpl | 31 |
5 files changed, 259 insertions, 0 deletions
diff --git a/src/test/shell/bazel/bazel_windows_example_test.sh b/src/test/shell/bazel/bazel_windows_example_test.sh index 910d98f742..ec5b8f6f11 100755 --- a/src/test/shell/bazel/bazel_windows_example_test.sh +++ b/src/test/shell/bazel/bazel_windows_example_test.sh @@ -60,6 +60,48 @@ function test_cpp() { assert_test_fails "//examples/cpp:hello-fail_test" } +function test_cpp_alwayslink() { + mkdir -p cpp/main + cat >cpp/main/BUILD <<EOF +cc_library( + name = "lib", + srcs = ["lib.cc"], + alwayslink = 1, +) +cc_library( + name = "main", + srcs = ["main.cc"], +) +cc_binary( + name = "bin", + deps = [":main", ":lib"], +) +EOF + + cat >cpp/main/lib.cc <<EOF +extern int global_variable; +int init() { + ++global_variable; + return global_variable; +} +int x = init(); +int y = init(); +EOF + + cat >cpp/main/main.cc <<EOF +#include<stdio.h> +int global_variable = 0; +int main(void) { + printf("global : %d\n", global_variable); + return 0; +} +EOF + assert_build //cpp/main:bin + ./bazel-bin/cpp/main/bin >& $TEST_log \ + || fail "//cpp/main:bin execution failed" + expect_log "global : 2" +} + function test_java() { local java_pkg=examples/java-native/src/main/java/com/example/myproject diff --git a/tools/cpp/CROSSTOOL.tpl b/tools/cpp/CROSSTOOL.tpl index 295faa00fc..2ede35de28 100644 --- a/tools/cpp/CROSSTOOL.tpl +++ b/tools/cpp/CROSSTOOL.tpl @@ -293,6 +293,176 @@ toolchain { } } + action_config { + config_name: 'c++-link-executable' + action_name: 'c++-link-executable' + tool { + tool_path: 'wrapper/bin/msvc_link.bat' + } + implies: 'linkstamps' + implies: 'output_execpath_flags' + implies: 'input_param_flags' + implies: 'global_whole_archive' + } + + action_config { + config_name: 'c++-link-dynamic-library' + action_name: 'c++-link-dynamic-library' + tool { + tool_path: 'wrapper/bin/msvc_link.bat' + } + implies: 'shared_flag' + implies: 'linkstamps' + implies: 'output_execpath_flags' + implies: 'input_param_flags' + implies: 'global_whole_archive' + implies: 'has_configured_linker_path' + } + + action_config { + config_name: 'c++-link-static-library' + action_name: 'c++-link-static-library' + tool { + tool_path: 'wrapper/bin/msvc_link.bat' + } + implies: 'input_param_flags' + implies: 'global_whole_archive' + } + + action_config { + config_name: 'c++-link-alwayslink-static-library' + action_name: 'c++-link-alwayslink-static-library' + tool { + tool_path: 'wrapper/bin/msvc_link.bat' + } + implies: 'input_param_flags' + implies: 'global_whole_archive' + } + + # TODO(pcloudy): The following action_config is listed in MANDATORY_LINK_TARGET_TYPES. + # But do we really need them on Windows? + action_config { + config_name: 'c++-link-pic-static-library' + action_name: 'c++-link-pic-static-library' + tool { + tool_path: 'wrapper/bin/msvc_link.bat' + } + implies: 'input_param_flags' + implies: 'global_whole_archive' + } + + action_config { + config_name: 'c++-link-alwayslink-pic-static-library' + action_name: 'c++-link-alwayslink-pic-static-library' + tool { + tool_path: 'wrapper/bin/msvc_link.bat' + } + implies: 'input_param_flags' + implies: 'global_whole_archive' + } + + action_config { + config_name: 'c++-link-interface-dynamic-library' + action_name: 'c++-link-interface-dynamic-library' + tool { + tool_path: 'wrapper/bin/msvc_link.bat' + } + } + + feature { + name: 'has_configured_linker_path' + } + + feature { + name: 'shared_flag' + flag_set { + action: 'c++-link-dynamic-library' + flag_group { + flag: '/DLL' + } + } + } + + feature { + name: 'linkstamps' + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + expand_if_all_available: 'linkstamp_paths' + flag_group { + flag: '%{linkstamp_paths}' + } + } + } + + feature { + name: 'output_execpath_flags' + flag_set { + expand_if_all_available: 'output_execpath' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + flag_group { + flag: '/OUT:%{output_execpath}' + } + } + } + + feature { + name: 'input_param_flags' + flag_set { + expand_if_all_available: 'libopts' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: 'c++-link-static-library' + action: 'c++-link-alwayslink-static-library' + action: 'c++-link-pic-static-library' + action: 'c++-link-alwayslink-pic-static-library' + flag_group { + flag: '%{libopts}' + } + } + flag_set { + expand_if_all_available: 'whole_archive_linker_params' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: 'c++-link-static-library' + action: 'c++-link-alwayslink-static-library' + action: 'c++-link-pic-static-library' + action: 'c++-link-alwayslink-pic-static-library' + flag_group { + flag: '/WHOLEARCHIVE:%{whole_archive_linker_params}' + } + } + flag_set { + expand_if_all_available: 'linker_input_params' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: 'c++-link-static-library' + action: 'c++-link-alwayslink-static-library' + action: 'c++-link-pic-static-library' + action: 'c++-link-alwayslink-pic-static-library' + flag_group { + flag: '%{linker_input_params}' + } + } + } + + feature { + name: 'global_whole_archive' + flag_set { + expand_if_all_available: 'global_whole_archive' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: 'c++-link-static-library' + action: 'c++-link-alwayslink-static-library' + action: 'c++-link-pic-static-library' + action: 'c++-link-alwayslink-pic-static-library' + flag_group { + flag: '/WHOLEARCHIVE' + } + } +} + compilation_mode_flags { mode: DBG compiler_flag: "/DDEBUG=1" diff --git a/tools/cpp/cc_configure.bzl b/tools/cpp/cc_configure.bzl index 1ea3c3e7d9..329eb05fa4 100644 --- a/tools/cpp/cc_configure.bzl +++ b/tools/cpp/cc_configure.bzl @@ -428,6 +428,12 @@ def _find_env_vars(repository_ctx, vs_path): return env_map +def _is_support_whole_archive(repository_ctx, vs_dir): + """Run MSVC linker alone to see if it supports /WHOLEARCHIVE.""" + result = _execute(repository_ctx, [vs_dir + "/VC/BIN/amd64/link"]) + return result.find("/WHOLEARCHIVE") != -1 + + def _tpl(repository_ctx, tpl, substitutions={}, out=None): if not out: out = tpl @@ -476,12 +482,19 @@ def _impl(repository_ctx): python_dir = python_binary[0:-10].replace("\\", "\\\\") include_paths = env["INCLUDE"] + (python_dir + "include") lib_paths = env["LIB"] + (python_dir + "libs") + lib_tool = vs_path + "/VC/bin/amd64/lib.exe" + if _is_support_whole_archive(repository_ctx, vs_path): + support_whole_archive = "True" + else: + support_whole_archive = "False" tmp_dir = _get_env_var(repository_ctx, "TMP", "C:\\Windows\\Temp") _tpl(repository_ctx, "wrapper/bin/pydir/msvc_tools.py", { "%{tmp}": tmp_dir.replace("\\", "\\\\"), "%{path}": env["PATH"], "%{include}": include_paths, "%{lib}": lib_paths, + "%{lib_tool}": lib_tool, + "%{support_whole_archive}": support_whole_archive }) cxx_include_directories = [] diff --git a/tools/cpp/wrapper/bin/pydir/msvc_link.py b/tools/cpp/wrapper/bin/pydir/msvc_link.py index b9aa81abb7..98c1a0b5e7 100644 --- a/tools/cpp/wrapper/bin/pydir/msvc_link.py +++ b/tools/cpp/wrapper/bin/pydir/msvc_link.py @@ -68,6 +68,9 @@ class MsvcLinker(msvc_tools.WindowsRunner): # Build argument list. parser = msvc_tools.ArgParser(self, argv, LINKPATTERNS) + # Preprocessing arguments for linking whole archive libraries + parser.WholeArchivePreprocess() + # Find the output file name. name = '' for arg in parser.options: diff --git a/tools/cpp/wrapper/bin/pydir/msvc_tools.py.tpl b/tools/cpp/wrapper/bin/pydir/msvc_tools.py.tpl index 99b2e39c3e..813b07d6cf 100644 --- a/tools/cpp/wrapper/bin/pydir/msvc_tools.py.tpl +++ b/tools/cpp/wrapper/bin/pydir/msvc_tools.py.tpl @@ -31,6 +31,7 @@ TMP_PATH = '%{tmp}' PATH = "%{path}" INCLUDE = "%{include}" LIB = "%{lib}" +LIB_TOOL = "%{lib_tool}" class Error(Exception): """Base class for all script-specific errors.""" @@ -52,8 +53,38 @@ class ArgParser(object): self.deps_file = None self.output_file = None self.params_file = None + self.support_whole_archive = %{support_whole_archive} + self.need_global_whole_archive = None self._ParseArgs(argv) + def ReplaceLibrary(self, arg): + """Do the actual replacement if necessary.""" + if arg == "/WHOLEARCHIVE": + return [] + if arg.startswith("/OUT:") or os.path.splitext(arg)[1] not in ['.a', '.lo']: + return [arg] + if self.global_whole_archive or arg.startswith("/WHOLEARCHIVE:"): + if arg.startswith("/WHOLEARCHIVE:"): + arg = arg[len("/WHOLEARCHIVE:"):] + output = subprocess.check_output([LIB_TOOL, "/list", arg]).decode("utf-8") + object_files = [] + for line in output.split("\n"): + line = line.strip() + if line.endswith(".o"): + object_files.append(line) + return object_files + return [arg] + + def WholeArchivePreprocess(self): + """Replace library file with object files if /WHOLEARCHIVE is not supported.""" + if self.support_whole_archive: + return + options = [] + self.global_whole_archive = "/WHOLEARCHIVE" in self.options + for arg in self.options: + options.extend(self.ReplaceLibrary(arg)) + self.options = options + def _MatchOneArg(self, args): """Finds a pattern which matches the beginning elements of args. |