Repository: bazelbuild/bazel
Issue: Action_config for 'assemble' missing from Windows crosstool
Labels: type: bug
P3
platform: windows

Reported on [bazel-discuss](https://groups.google.com/d/msgid/bazel-discuss/f0bcc3e2-2e19-4d30-86ab-4eb37a923e1b%40googlegroups.com).

Yun, can cl.exe compile assembly?

Issue comments:
Yes, I am sure it can, will looking into this.

Pull request review comments:
We don't need --cpu=x64_windows_msvc anymore, please remove this.

Patch that resolved the issue:
diff --git a/tools/cpp/CROSSTOOL.tpl b/tools/cpp/CROSSTOOL.tpl
index af58b7ad182f2e..6b585fcaf49e41 100644
--- a/tools/cpp/CROSSTOOL.tpl
+++ b/tools/cpp/CROSSTOOL.tpl
@@ -132,6 +132,10 @@ toolchain {
     name: "ar"
     path: "%{msvc_lib_path}"
   }
+  tool_path {
+    name: "ml"
+    path: "%{msvc_ml_path}"
+  }
   tool_path {
     name: "cpp"
     path: "%{msvc_cl_path}"
@@ -264,6 +268,26 @@ toolchain {
     name: 'copy_dynamic_libraries_to_binary'
   }
 
+  action_config {
+    config_name: 'assemble'
+    action_name: 'assemble'
+    tool {
+      tool_path: '%{msvc_ml_path}'
+    }
+    flag_set {
+      expand_if_all_available: 'output_object_file'
+      flag_group {
+        flag: '/Fo%{output_object_file}'
+        flag: '/Zi'
+        flag: '/c'
+        flag: '%{source_file}'
+      }
+    }
+    implies: 'nologo'
+    implies: 'msvc_env'
+    implies: 'sysroot'
+  }
+
   action_config {
     config_name: 'c-compile'
     action_name: 'c-compile'
@@ -453,7 +477,6 @@ toolchain {
     name: 'legacy_compile_flags'
     flag_set {
       expand_if_all_available: 'legacy_compile_flags'
-      action: 'assemble'
       action: 'preprocess-assemble'
       action: 'c-compile'
       action: 'c++-compile'
@@ -523,6 +546,7 @@ toolchain {
   feature {
     name: 'include_paths'
     flag_set {
+      action: "assemble"
       action: 'preprocess-assemble'
       action: 'c-compile'
       action: 'c++-compile'
@@ -547,6 +571,7 @@ toolchain {
   feature {
     name: "preprocessor_defines"
     flag_set {
+      action: "assemble"
       action: "preprocess-assemble"
       action: "c-compile"
       action: "c++-compile"
@@ -564,7 +589,6 @@ toolchain {
   feature {
     name: 'parse_showincludes'
     flag_set {
-      action: 'assemble'
       action: 'preprocess-assemble'
       action: 'c-compile'
       action: 'c++-compile'
@@ -933,7 +957,6 @@ toolchain {
     name: 'user_compile_flags'
     flag_set {
       expand_if_all_available: 'user_compile_flags'
-      action: 'assemble'
       action: 'preprocess-assemble'
       action: 'c-compile'
       action: 'c++-compile'
@@ -973,7 +996,6 @@ toolchain {
     name: 'unfiltered_compile_flags'
     flag_set {
       expand_if_all_available: 'unfiltered_compile_flags'
-      action: 'assemble'
       action: 'preprocess-assemble'
       action: 'c-compile'
       action: 'c++-compile'
diff --git a/tools/cpp/unix_cc_configure.bzl b/tools/cpp/unix_cc_configure.bzl
index ed245fc943df39..aa46f5597840be 100644
--- a/tools/cpp/unix_cc_configure.bzl
+++ b/tools/cpp/unix_cc_configure.bzl
@@ -392,6 +392,7 @@ def configure_unix_toolchain(repository_ctx, cpu_value):
       "%{msvc_env_include}": "",
       "%{msvc_env_lib}": "",
       "%{msvc_cl_path}": "",
+      "%{msvc_ml_path}": "",
       "%{msvc_link_path}": "",
       "%{msvc_lib_path}": "",
       "%{compilation_mode_content}": "",
diff --git a/tools/cpp/windows_cc_configure.bzl b/tools/cpp/windows_cc_configure.bzl
index a78c8a9b79f875..594e82a8ea4bb3 100644
--- a/tools/cpp/windows_cc_configure.bzl
+++ b/tools/cpp/windows_cc_configure.bzl
@@ -295,6 +295,7 @@ def configure_windows_toolchain(repository_ctx):
   escaped_tmp_dir = escape_string(
       get_env_var(repository_ctx, "TMP", "C:\\Windows\\Temp").replace("\\", "\\\\"))
   msvc_cl_path = _find_msvc_tool(repository_ctx, vc_path, "cl.exe").replace("\\", "/")
+  msvc_ml_path = _find_msvc_tool(repository_ctx, vc_path, "ml64.exe").replace("\\", "/")
   msvc_link_path = _find_msvc_tool(repository_ctx, vc_path, "link.exe").replace("\\", "/")
   msvc_lib_path = _find_msvc_tool(repository_ctx, vc_path, "lib.exe").replace("\\", "/")
   escaped_cxx_include_directories = []
@@ -346,6 +347,7 @@ def configure_windows_toolchain(repository_ctx):
       "%{msvc_env_include}": escaped_include_paths,
       "%{msvc_env_lib}": escaped_lib_paths,
       "%{msvc_cl_path}": msvc_cl_path,
+      "%{msvc_ml_path}": msvc_ml_path,
       "%{msvc_link_path}": msvc_link_path,
       "%{msvc_lib_path}": msvc_lib_path,
       "%{compilation_mode_content}": compilation_mode_content,


Test patch:
diff --git a/src/test/py/bazel/bazel_windows_test.py b/src/test/py/bazel/bazel_windows_test.py
index 69ac921c56c5ed..931c240284b800 100644
--- a/src/test/py/bazel/bazel_windows_test.py
+++ b/src/test/py/bazel/bazel_windows_test.py
@@ -68,6 +68,50 @@ def testUseMSVCWrapperScript(self):
                 execution_root,
                 'external/local_config_cc/wrapper/bin/pydir/msvc_tools.py')))
 
+  def testWindowsCompilesAssembly(self):
+    self.ScratchFile('WORKSPACE')
+    exit_code, stdout, stderr = self.RunBazel(['info', 'bazel-bin'])
+    self.AssertExitCode(exit_code, 0, stderr)
+    bazel_bin = stdout[0]
+    self.ScratchFile('BUILD', [
+        'cc_binary(',
+        '    name="x",',
+        '    srcs=['
+        '        "x.asm",',
+        '        "y.cc",',
+        '    ],',
+        ')',
+    ])
+    self.ScratchFile('x.asm', [
+        '.code',
+        'PUBLIC increment',
+        'increment PROC x:WORD',
+        '  xchg rcx,rax',
+        '  inc rax',
+        '  ret',
+        'increment EndP',
+        'END',
+    ])
+    self.ScratchFile('y.cc', [
+        '#include <stdio.h>',
+        'extern "C" int increment(int);',
+        'int main(int, char**) {'
+        '  int x = 5;',
+        '  x = increment(x);',
+        '  printf("%d\\n", x);',
+        '  return 0;',
+        '}',
+    ])
+
+    exit_code, _, stderr = self.RunBazel(
+        [
+            'build',
+            '//:x',
+        ])
+
+    self.AssertExitCode(exit_code, 0, stderr)
+    self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'x.exe')))
+
 
 if __name__ == '__main__':
   unittest.main()