aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Yun Peng <pcloudy@google.com>2016-10-25 13:49:28 +0000
committerGravatar John Cater <jcater@google.com>2016-10-25 20:18:38 +0000
commit81aede1f9bdddfe0e2327d6cf0ba9bd40fd62718 (patch)
tree9bccf6c64b547e03cfa336ffa4b1e7da144f9cab
parentca99bb71b8120e61a3bbde8e54f1a9488fa0478f (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-xsrc/test/shell/bazel/bazel_windows_example_test.sh42
-rw-r--r--tools/cpp/CROSSTOOL.tpl170
-rw-r--r--tools/cpp/cc_configure.bzl13
-rw-r--r--tools/cpp/wrapper/bin/pydir/msvc_link.py3
-rw-r--r--tools/cpp/wrapper/bin/pydir/msvc_tools.py.tpl31
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.