Bazel now can build dynamic library from cc_library

Working towards: https://github.com/bazelbuild/bazel/issues/3311

When building dynamic library on Windows, Bazel builds an import library
and a DLL.

Bazel provides a feature called windows_export_all_symbols, if this
feature is enabled(and no_windows_export_all_symbols is not) for a
cc_library, then Bazel parses object files of that cc_library to generate
a DEF file that will be used during linking time to export symbols from
DLL. This feature can be specified at crosstool, package, target and
command line level.

A few differences from Unix platforms:

1. We don't build the shared library on Windows by default, users have to
specifiy --output_groups=dynamic_library for building dynamic libraries.
This output group is also available on other platforms.

2. By default, cc_test is dynamically linked on Unix, but it will be
statically linked on Windows by default. (meaning the default value of
linkstatic in cc_test is 1 on Windows, and 0 on other platforms)

3. For global data symbols, __declspec(dllimport) must still be used in
source files.

Remaining issues:

1. Extensions for import library and DLL are not correct yet.
2. DLLs are not guaranteed to be available during runtime yet.
3. Diamond problem
If a cc_library A is specified as linkstatic=0, then no dynamic library
will be built for it, so if another cc_library B depends on it, A will
be statically linked into B, and if a cc_binary C depends on B, A will
also be statically linked into C and B will be dynamically linked to C.
This is wrong because A is duplicated in both B and C.
It is essentially a diamond problem describled in C++ Transitive Library.
(https://docs.google.com/document/d/1-tv0_79zGyBoDmaP_pYWaBVUwHUteLpAs90_rUl-VY8/edit?usp=sharing)
Hopefully, we can avoid this by using cc_shared_library rule in future.

Change-Id: I23640d4caf8afe65d60b1522af6368536d7a8408
PiperOrigin-RevId: 168829958
diff --git a/src/BUILD b/src/BUILD
index 039baeb..a8bda8a 100644
--- a/src/BUILD
+++ b/src/BUILD
@@ -161,6 +161,7 @@
         "//src/java_tools/junitrunner/java/com/google/testing/junit/runner:Runner_deploy.jar",
         "//src/java_tools/junitrunner/java/com/google/testing/junit/runner:ExperimentalRunner_deploy.jar",
         "//src/java_tools/junitrunner/java/com/google/testing/coverage:embedded_tools",
+        "//third_party/def_parser:srcs",
         "//third_party/ijar",
         "//third_party/ijar:embedded_tools",
         "//src/java_tools/buildjar/java/com/google/devtools/build/java/turbine:turbine_deploy.jar",
@@ -185,14 +186,17 @@
         ":windows": [
             "//src/java_tools/singlejar:SingleJar_deploy.jar",
             "//src/tools/launcher:launcher",
+            "//third_party/def_parser:def_parser",
         ],
         ":windows_msys": [
             "//src/java_tools/singlejar:SingleJar_deploy.jar",
             "//src/tools/launcher:launcher",
+            "//third_party/def_parser:def_parser",
         ],
         ":windows_msvc": [
             "//src/java_tools/singlejar:SingleJar_deploy.jar",
             "//src/tools/launcher:launcher",
+            "//third_party/def_parser:def_parser",
         ],
         ":arm": [
             "//src/java_tools/singlejar:SingleJar_deploy.jar",
diff --git a/src/create_embedded_tools.py b/src/create_embedded_tools.py
index 699edd0..17d747f 100644
--- a/src/create_embedded_tools.py
+++ b/src/create_embedded_tools.py
@@ -45,6 +45,7 @@
     ('*Runner_deploy.jar', lambda x: 'tools/jdk/TestRunner_deploy.jar'),
     ('*singlejar', lambda x: 'tools/jdk/singlejar/singlejar'),
     ('*launcher.exe', lambda x: 'tools/launcher/launcher.exe'),
+    ('*def_parser.exe', lambda x: 'tools/def_parser/def_parser.exe'),
     ('*ijar.exe', lambda x: 'tools/jdk/ijar/ijar.exe'),
     ('*ijar', lambda x: 'tools/jdk/ijar/ijar'),
     ('*zipper.exe', lambda x: 'tools/zip/zipper/zipper.exe'),
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index 922d542..21a5a31 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -355,37 +355,51 @@
         }
       };
 
-  public static final RuleSet CPP_RULES =
-      new RuleSet() {
-        @Override
-        public void init(Builder builder) {
-          builder.addConfig(
-              CppOptions.class, new CppConfigurationLoader(Functions.<String>identity()));
+  /**
+   * Set the label for Windows DEF parser. In bazel, it should be
+   * @bazel_tools//tools/def_parser:def_parser, otherwise it should be null.
+   *
+   * <p>TODO(pcloudy): Remove this after Bazel rule definitions are not used internally anymore.
+   * Related bug b/63658220
+   */
+  public static final RuleSet CPP_RULES = cppRules("@bazel_tools//tools/def_parser:def_parser");
 
-          builder.addBuildInfoFactory(new CppBuildInfo());
-          builder.addDynamicTransitionMaps(CppRuleClasses.DYNAMIC_TRANSITIONS_MAP);
+  public static RuleSet cppRules() {
+    return cppRules(null);
+  }
 
-          builder.addRuleDefinition(new CcToolchainRule());
-          builder.addRuleDefinition(new CcToolchainSuiteRule());
-          builder.addRuleDefinition(new CcToolchainAlias.CcToolchainAliasRule());
-          builder.addRuleDefinition(new CcIncLibraryRule());
-          builder.addRuleDefinition(new BazelCppRuleClasses.CcLinkingRule());
-          builder.addRuleDefinition(new BazelCppRuleClasses.CcDeclRule());
-          builder.addRuleDefinition(new BazelCppRuleClasses.CcBaseRule());
-          builder.addRuleDefinition(new BazelCppRuleClasses.CcRule());
-          builder.addRuleDefinition(new BazelCppRuleClasses.CcBinaryBaseRule());
-          builder.addRuleDefinition(new BazelCcBinaryRule());
-          builder.addRuleDefinition(new BazelCcTestRule());
-          builder.addRuleDefinition(new BazelCppRuleClasses.CcLibraryBaseRule());
-          builder.addRuleDefinition(new BazelCcLibraryRule());
-          builder.addRuleDefinition(new BazelCcIncLibraryRule());
-        }
+  public static RuleSet cppRules(String defParserLabel) {
+    return new RuleSet() {
+      @Override
+      public void init(Builder builder) {
+        builder.addConfig(
+            CppOptions.class, new CppConfigurationLoader(Functions.<String>identity()));
 
-        @Override
-        public ImmutableList<RuleSet> requires() {
-          return ImmutableList.of(CoreRules.INSTANCE, PLATFORM_RULES);
-        }
-      };
+        builder.addBuildInfoFactory(new CppBuildInfo());
+        builder.addDynamicTransitionMaps(CppRuleClasses.DYNAMIC_TRANSITIONS_MAP);
+
+        builder.addRuleDefinition(new CcToolchainRule(defParserLabel));
+        builder.addRuleDefinition(new CcToolchainSuiteRule());
+        builder.addRuleDefinition(new CcToolchainAlias.CcToolchainAliasRule());
+        builder.addRuleDefinition(new CcIncLibraryRule());
+        builder.addRuleDefinition(new BazelCppRuleClasses.CcLinkingRule());
+        builder.addRuleDefinition(new BazelCppRuleClasses.CcDeclRule());
+        builder.addRuleDefinition(new BazelCppRuleClasses.CcBaseRule());
+        builder.addRuleDefinition(new BazelCppRuleClasses.CcRule());
+        builder.addRuleDefinition(new BazelCppRuleClasses.CcBinaryBaseRule());
+        builder.addRuleDefinition(new BazelCcBinaryRule());
+        builder.addRuleDefinition(new BazelCcTestRule());
+        builder.addRuleDefinition(new BazelCppRuleClasses.CcLibraryBaseRule());
+        builder.addRuleDefinition(new BazelCcLibraryRule());
+        builder.addRuleDefinition(new BazelCcIncLibraryRule());
+      }
+
+      @Override
+      public ImmutableList<RuleSet> requires() {
+        return ImmutableList.of(CoreRules.INSTANCE, PLATFORM_RULES);
+      }
+    };
+  }
 
   public static final RuleSet CPP_PROTO_RULES =
       new RuleSet() {
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcTestRule.java
index 72e9517..292bd9c 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcTestRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcTestRule.java
@@ -29,6 +29,7 @@
 import com.google.devtools.build.lib.packages.TriState;
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
 import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
+import com.google.devtools.build.lib.util.OS;
 
 /** Rule definition for cc_test rules. */
 public final class BazelCcTestRule implements RuleDefinition {
@@ -37,7 +38,11 @@
     return builder
         .requiresConfigurationFragments(CppConfiguration.class)
         .setImplicitOutputsFunction(CppRuleClasses.CC_BINARY_DEBUG_PACKAGE)
-        .override(attr("linkstatic", BOOLEAN).value(false))
+        // We don't want C++ tests to be dynamically linked by default on Windows,
+        // because windows_export_all_symbols is not enabled by default, and it cannot solve
+        // all symbols visibility issues, for example, users still have to use __declspec(dllimport)
+        // to decorate data symbols imported from DLL.
+        .override(attr("linkstatic", BOOLEAN).value(OS.getCurrent() == OS.WINDOWS))
         .override(attr("stamp", TRISTATE).value(TriState.NO))
         // Oh weary adventurer, endeavour not to remove this attribute, enticing as that may be,
         // given that no code referenceth it. Should ye be on the verge of yielding to the
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
index b846dfa..e90dda7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
@@ -187,11 +187,17 @@
     // doesn't support it, then register an action which complains when triggered,
     // which only happens when some rule explicitly depends on the dynamic library.
     if (!createDynamicLibrary && !supportsDynamicLinker) {
-      Artifact solibArtifact =
+      ImmutableList.Builder<Artifact> dynamicLibraries = ImmutableList.builder();
+      dynamicLibraries.add(
+        CppHelper.getLinuxLinkedArtifact(
+          ruleContext, ruleContext.getConfiguration(), LinkTargetType.DYNAMIC_LIBRARY));
+      if (ccToolchain.getCppConfiguration().useInterfaceSharedObjects()) {
+        dynamicLibraries.add(
           CppHelper.getLinuxLinkedArtifact(
-              ruleContext, ruleContext.getConfiguration(), LinkTargetType.DYNAMIC_LIBRARY);
+            ruleContext, ruleContext.getConfiguration(), LinkTargetType.INTERFACE_DYNAMIC_LIBRARY));
+      }
       ruleContext.registerAction(new FailAction(ruleContext.getActionOwner(),
-          ImmutableList.of(solibArtifact), "Toolchain does not support dynamic linking"));
+          dynamicLibraries.build(), "Toolchain does not support dynamic linking"));
     } else if (!createDynamicLibrary
         && ruleContext.attributes().isConfigurable("srcs")) {
       // If "srcs" is configurable, the .so output is always declared because the logic that
@@ -199,11 +205,17 @@
       // Here, where we *do* have the correct value, it may not contain any source files to
       // generate an .so with. If that's the case, register a fake generating action to prevent
       // a "no generating action for this artifact" error.
-      Artifact solibArtifact =
+      ImmutableList.Builder<Artifact> dynamicLibraries = ImmutableList.builder();
+      dynamicLibraries.add(
+        CppHelper.getLinuxLinkedArtifact(
+          ruleContext, ruleContext.getConfiguration(), LinkTargetType.DYNAMIC_LIBRARY));
+      if (ccToolchain.getCppConfiguration().useInterfaceSharedObjects()) {
+        dynamicLibraries.add(
           CppHelper.getLinuxLinkedArtifact(
-              ruleContext, ruleContext.getConfiguration(), LinkTargetType.DYNAMIC_LIBRARY);
+            ruleContext, ruleContext.getConfiguration(), LinkTargetType.INTERFACE_DYNAMIC_LIBRARY));
+      }
       ruleContext.registerAction(new FailAction(ruleContext.getActionOwner(),
-          ImmutableList.of(solibArtifact), "configurable \"srcs\" triggers an implicit .so output "
+          dynamicLibraries.build(), "configurable \"srcs\" triggers an implicit .so output "
           + "even though there are no sources to compile in this configuration"));
     }
 
@@ -258,9 +270,12 @@
     NestedSetBuilder<Artifact> filesBuilder = NestedSetBuilder.stableOrder();
     filesBuilder.addAll(LinkerInputs.toLibraryArtifacts(linkedLibraries.getStaticLibraries()));
     filesBuilder.addAll(LinkerInputs.toLibraryArtifacts(linkedLibraries.getPicStaticLibraries()));
-    filesBuilder.addAll(LinkerInputs.toNonSolibArtifacts(linkedLibraries.getDynamicLibraries()));
-    filesBuilder.addAll(
-        LinkerInputs.toNonSolibArtifacts(linkedLibraries.getExecutionDynamicLibraries()));
+
+    if (!featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
+      filesBuilder.addAll(LinkerInputs.toNonSolibArtifacts(linkedLibraries.getDynamicLibraries()));
+      filesBuilder.addAll(
+          LinkerInputs.toNonSolibArtifacts(linkedLibraries.getExecutionDynamicLibraries()));
+    }
 
     CcLinkingOutputs linkingOutputs = info.getCcLinkingOutputs();
     if (!featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_CODEGEN)) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
index 02c7c26..58d3f60 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
@@ -89,6 +89,12 @@
           + "hidden_header_tokens"
           + OutputGroupProvider.INTERNAL_SUFFIX;
 
+  /** A string constant for the name of archive library(.a, .lo) output group. */
+  public static final String ARCHIVE_LIBRARY_OUTPUT_GROUP_NAME = "cc_archive";
+
+  /** A string constant for the name of dynamic library output group. */
+  public static final String DYNAMIC_LIBRARY_OUTPUT_GROUP_NAME = "cc_dynamic_library";
+
   /**
    * A group of source file types and action names for builds controlled by CcLibraryHelper.
    * Determines what file types CcLibraryHelper considers sources and what action configs are
@@ -1137,10 +1143,20 @@
               configuration,
               Link.LinkTargetType.DYNAMIC_LIBRARY,
               linkedArtifactNameSuffix));
+
+      if (ccToolchain.getCppConfiguration().useInterfaceSharedObjects()
+          && emitInterfaceSharedObjects) {
+        dynamicLibrary.add(
+            CppHelper.getLinuxLinkedArtifact(
+                ruleContext,
+                configuration,
+                LinkTargetType.INTERFACE_DYNAMIC_LIBRARY,
+                linkedArtifactNameSuffix));
+      }
     }
 
-    outputGroups.put("archive", archiveFile.build());
-    outputGroups.put("dynamic_library", dynamicLibrary.build());
+    outputGroups.put(ARCHIVE_LIBRARY_OUTPUT_GROUP_NAME, archiveFile.build());
+    outputGroups.put(DYNAMIC_LIBRARY_OUTPUT_GROUP_NAME, dynamicLibrary.build());
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
index 48afc44..e44b32b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
@@ -392,6 +392,9 @@
             cppConfiguration.supportsInterfaceSharedObjects()
                 ? ruleContext.getPrerequisiteArtifact("$link_dynamic_library_tool", Mode.HOST)
                 : null,
+            ruleContext.attributes().has("$def_parser")
+                ? ruleContext.getPrerequisiteArtifact("$def_parser", Mode.HOST)
+                : null,
             getEnvironment(ruleContext),
             builtInIncludeDirectories,
             sysroot);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
index 8f85034..b79164b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
@@ -63,6 +63,7 @@
           ImmutableList.<Artifact>of(),
           NestedSetBuilder.<Pair<String, String>>emptySet(Order.COMPILE_ORDER),
           null,
+          null,
           ImmutableMap.<String, String>of(),
           ImmutableList.<PathFragment>of(),
           null);
@@ -90,6 +91,7 @@
   private final ImmutableList<Artifact> builtinIncludeFiles;
   private final NestedSet<Pair<String, String>> coverageEnvironment;
   @Nullable private final Artifact linkDynamicLibraryTool;
+  @Nullable private final Artifact defParser;
   private final ImmutableMap<String, String> environment;
   private final ImmutableList<PathFragment> builtInIncludeDirectories;
   @Nullable private final PathFragment sysroot;
@@ -118,6 +120,7 @@
       ImmutableList<Artifact> builtinIncludeFiles,
       NestedSet<Pair<String, String>> coverageEnvironment,
       Artifact linkDynamicLibraryTool,
+      Artifact defParser,
       ImmutableMap<String, String> environment,
       ImmutableList<PathFragment> builtInIncludeDirectories,
       @Nullable PathFragment sysroot) {
@@ -145,6 +148,7 @@
     this.builtinIncludeFiles = builtinIncludeFiles;
     this.coverageEnvironment = coverageEnvironment;
     this.linkDynamicLibraryTool = linkDynamicLibraryTool;
+    this.defParser = defParser;
     this.environment = environment;
     this.builtInIncludeDirectories = builtInIncludeDirectories;
     this.sysroot = sysroot;
@@ -330,6 +334,14 @@
   }
 
   /**
+   * Returns the tool which should be used to parser object files for generating DEF file on
+   * Windows. The label of this tool is //third_party/def_parser:def_parser.
+   */
+  public Artifact getDefParserTool() {
+    return defParser;
+  }
+
+  /**
    * Returns the tool that builds interface libraries from dynamic libraries.
    */
   public Artifact getInterfaceSoBuilder() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java
index c691d43..5f9f07a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java
@@ -41,6 +41,23 @@
 public final class CcToolchainRule implements RuleDefinition {
 
   /**
+   * The label points to the Windows object file parser. In bazel, it should be
+   * //tools/def_parser:def_parser, otherwise it should be null.
+   *
+   * <p>TODO(pcloudy): Remove this after Bazel rule definitions are not used internally anymore.
+   * Related bug b/63658220
+   */
+  private final String defParserLabel;
+
+  public CcToolchainRule(String defParser) {
+    this.defParserLabel = defParser;
+  }
+
+  public CcToolchainRule() {
+    this.defParserLabel = null;
+  }
+
+  /**
    * Determines if the given target is a cc_toolchain or one of its subclasses. New subclasses
    * should be added to this method.
    */
@@ -60,6 +77,13 @@
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
     final Label zipper = env.getToolsLabel("//tools/zip:zipper");
+    if (defParserLabel != null) {
+      builder.add(
+          attr("$def_parser", LABEL)
+              .cfg(HOST)
+              .singleArtifact()
+              .value(env.getLabel(defParserLabel)));
+    }
     return builder
         .setUndocumented()
         .requiresConfigurationFragments(CppConfiguration.class)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
index 2d47b74..7a21660 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
@@ -79,6 +79,8 @@
    */
   public static final String THINLTO_PARAM_FILE_VARIABLE = "thinlto_param_file";
 
+  public static final String DEF_FILE_PATH_VARIABLE = "def_file_path";
+
   /**
    * A build variable to let thinlto know where it should write linker flags when indexing.
    */
@@ -190,6 +192,7 @@
   private LinkStaticness linkStaticness = LinkStaticness.FULLY_STATIC;
   private String libraryIdentifier = null;
   private ImmutableMap<Artifact, Artifact> ltoBitcodeFiles;
+  private Artifact defFile;
 
   private boolean fake;
   private boolean isNativeDeps;
@@ -561,10 +564,13 @@
     }
 
     switch (linkType) {
-        // We currently can't split dynamic library links if they have interface outputs. That was
-        // probably an unintended side effect of the change that introduced interface outputs.
+        // On Unix, we currently can't split dynamic library links if they have interface outputs.
+        // That was probably an unintended side effect of the change that introduced interface
+        // outputs.
+        // On Windows, We can always split the command line when building DLL.
       case DYNAMIC_LIBRARY:
-        return interfaceOutput == null;
+        return (interfaceOutput == null
+            || featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS));
       case EXECUTABLE:
       case STATIC_LIBRARY:
       case PIC_STATIC_LIBRARY:
@@ -819,6 +825,9 @@
       dependencyInputsBuilder.addAll(linkstamps);
       dependencyInputsBuilder.addTransitive(compilationInputs.build());
     }
+    if (defFile != null) {
+      dependencyInputsBuilder.add(defFile);
+    }
 
     Iterable<Artifact> expandedInputs =
         LinkerInputs.toLibraryArtifacts(
@@ -1095,6 +1104,11 @@
     return this;
   }
 
+  public CppLinkActionBuilder setDefFile(Artifact defFile) {
+    this.defFile = defFile;
+    return this;
+  }
+
   /**
    * Adds a single object file to the set of inputs.
    */
@@ -1533,6 +1547,10 @@
           INTERFACE_LIBRARY_OUTPUT_VARIABLE,
           shouldGenerateInterfaceLibrary ? interfaceLibraryOutput.getExecPathString() : "ignored");
 
+      if (defFile != null) {
+        buildVariables.addStringVariable(DEF_FILE_PATH_VARIABLE, defFile.getExecPathString());
+      }
+
       // Variables arising from the toolchain
       buildVariables
           .addAllStringVariables(toolchain.getBuildVariables())
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
index 72b65a9..2fcd332 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
@@ -14,6 +14,8 @@
 
 package com.google.devtools.build.lib.rules.cpp;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.base.Supplier;
@@ -23,10 +25,14 @@
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.FailAction;
+import com.google.devtools.build.lib.actions.ParameterFile;
 import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.PerLabelOptions;
 import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector;
@@ -54,6 +60,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.annotation.Nullable;
 
 /**
  * Representation of a C/C++ compilation. Its purpose is to share the code that creates compilation
@@ -681,6 +688,60 @@
   }
 
   /**
+   * Create actions for parsing object files to generate a DEF file, should on be used on Windows.
+   *
+   * <p>The method only creates the actions when WINDOWS_EXPORT_ALL_SYMBOLS feature is enabled and
+   * NO_WINDOWS_EXPORT_ALL_SYMBOLS feature is not enabled.
+   *
+   * @param objectFiles A list of object files to parse
+   * @param dllName The DLL name to be written into the DEF file, it specifies which DLL is required
+   *     at runtime
+   * @return The DEF file artifact, null if actions are not created.
+   */
+  @Nullable
+  public Artifact createDefFileActions(ImmutableList<Artifact> objectFiles, String dllName) {
+    if (!featureConfiguration.isEnabled(CppRuleClasses.WINDOWS_EXPORT_ALL_SYMBOLS)
+        || featureConfiguration.isEnabled(CppRuleClasses.NO_WINDOWS_EXPORT_ALL_SYMBOLS)) {
+      return null;
+    }
+    Artifact defFile = ruleContext.getBinArtifact(ruleContext.getLabel().getName() + ".def");
+    CustomCommandLine.Builder argv = new CustomCommandLine.Builder();
+    for (Artifact objectFile : objectFiles) {
+      argv.addDynamicString(objectFile.getExecPathString());
+    }
+
+    Artifact paramFile =
+        ruleContext.getDerivedArtifact(
+            ParameterFile.derivePath(defFile.getRootRelativePath()), defFile.getRoot());
+
+    ruleContext.registerAction(
+        new ParameterFileWriteAction(
+            ruleContext.getActionOwner(),
+            paramFile,
+            argv.build(),
+            ParameterFile.ParameterFileType.SHELL_QUOTED,
+            UTF_8));
+
+    Artifact defParser = ccToolchain.getDefParserTool();
+    ruleContext.registerAction(
+        new SpawnAction.Builder()
+            .addInput(paramFile)
+            .addInputs(objectFiles)
+            .addOutput(defFile)
+            .setExecutable(defParser)
+            .useDefaultShellEnvironment()
+            .addCommandLine(
+                CustomCommandLine.builder()
+                    .addExecPath(defFile)
+                    .addDynamicString(dllName)
+                    .addPrefixedExecPath("@", paramFile)
+                    .build())
+            .setMnemonic("DefParser")
+            .build(ruleContext));
+    return defFile;
+  }
+
+  /**
    * Constructs the C++ compiler actions. It generally creates one action for every specified source
    * file. It takes into account LIPO, fake-ness, coverage, and PIC, in addition to using the
    * settings specified on the current object. This method should only be called once.
@@ -1417,11 +1478,14 @@
               configuration,
               LinkTargetType.INTERFACE_DYNAMIC_LIBRARY,
               linkedArtifactNameSuffix);
-      sonameLinkopts =
-          ImmutableList.of(
-              "-Wl,-soname="
-                  + SolibSymlinkAction.getDynamicLibrarySoname(
-                      soImpl.getRootRelativePath(), /* preserveName= */ false));
+      // TODO(b/28946988): Remove this hard-coded flag.
+      if (!featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
+        sonameLinkopts =
+            ImmutableList.of(
+                "-Wl,-soname="
+                    + SolibSymlinkAction.getDynamicLibrarySoname(
+                        soImpl.getRootRelativePath(), /* preserveName= */ false));
+      }
     }
 
     CppLinkActionBuilder dynamicLinkActionBuilder =
@@ -1442,6 +1506,24 @@
                 ccToolchain.getDynamicRuntimeLinkInputs())
             .addVariablesExtensions(variablesExtensions);
 
+    Artifact defFile =
+        createDefFileActions(
+            ccOutputs.getObjectFiles(false),
+            SolibSymlinkAction.getDynamicLibrarySoname(soImpl.getRootRelativePath(), true));
+    if (defFile != null) {
+      dynamicLinkActionBuilder.setDefFile(defFile);
+    }
+
+    // On Windows, we cannot build a shared library with symbols unresolved, so here we dynamically
+    // link to all it's dependencies.
+    if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
+      CcLinkParams.Builder ccLinkParamsbuilder =
+          CcLinkParams.builder(/* linkingStatically= */ false, /* linkShared= */ true);
+      ccLinkParamsbuilder.addCcLibrary(
+          ruleContext, false, ImmutableList.of(), CcLinkingOutputs.EMPTY);
+      dynamicLinkActionBuilder.addLinkParams(ccLinkParamsbuilder.build(), ruleContext);
+    }
+
     if (!ccOutputs.getLtoBitcodeFiles().isEmpty()
         && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) {
       dynamicLinkActionBuilder.setLtoIndexing(true);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
index 275c717..4e8139e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
@@ -311,6 +311,22 @@
   public static final String GENERATE_PDB_FILE = "generate_pdb_file";
 
   /**
+   * A string constant for a feature that automatically exporting symbols on Windows. Bazel
+   * generates a DEF file for object files of a cc_library, then use it at linking time. This
+   * feature should only be used for toolchains targeting Windows, and the toolchain should support
+   * using DEF files for exporting symbols.
+   */
+  public static final String WINDOWS_EXPORT_ALL_SYMBOLS = "windows_export_all_symbols";
+
+  /** A string constant for a feature to disable WINDOWS_EXPORT_ALL_SYMBOLS. */
+  public static final String NO_WINDOWS_EXPORT_ALL_SYMBOLS = "no_windows_export_all_symbols";
+
+  /**
+   * A string constant for a feature that indicates we are using a toolchain building for Windows.
+   */
+  public static final String TARGETS_WINDOWS = "targets_windows";
+
+  /**
    * A string constant for no_stripping feature, if it's specified, then no strip action config is
    * needed, instead the stripped binary will simply be a symlink (or a copy on Windows) of the
    * original binary.
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
index f3525b3..ca99496 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
@@ -165,6 +165,11 @@
         "cc_binary(name='launcher', srcs=['launcher_main.cc'])");
 
     config.create(
+        "/bazel_tools_workspace/tools/def_parser/BUILD",
+        "package(default_visibility=['//visibility:public'])",
+        "filegroup(name='def_parser', srcs=['def_parser.exe'])");
+
+    config.create(
         "/bazel_tools_workspace/objcproto/BUILD",
         "package(default_visibility=['//visibility:public'])",
         "objc_library(",
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
index adf4d3d..51a46cc 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
@@ -189,7 +189,8 @@
             "archive_in_srcs_test",
             "cc_test(name = 'archive_in_srcs_test',",
             "           srcs = ['archive_in_srcs_test.cc'],",
-            "           deps = [':archive_in_srcs_lib'])",
+            "           deps = [':archive_in_srcs_lib'],",
+            "           linkstatic = 0,)",
             "cc_library(name = 'archive_in_srcs_lib',",
             "           srcs = ['libstatic.a', 'libboth.a', 'libboth.so'])");
     List<String> artifactNames = baseArtifactNames(getLinkerInputs(archiveInSrcsTest));
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProviderTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProviderTest.java
index 9b8b814..20891db 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProviderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProviderTest.java
@@ -33,61 +33,65 @@
 public class CcToolchainProviderTest {
   @Test
   public void equalityIsObjectIdentity() throws Exception {
-    CcToolchainProvider a = new CcToolchainProvider(
-        null,
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        null,
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        null,
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        null,
-        PathFragment.EMPTY_FRAGMENT,
-        CppCompilationContext.EMPTY,
-        false,
-        false,
-        ImmutableMap.<String, String>of(),
-        ImmutableList.<Artifact>of(),
-        NestedSetBuilder.<Pair<String, String>>emptySet(Order.COMPILE_ORDER),
-        null,
-        ImmutableMap.<String, String>of(),
-        ImmutableList.<PathFragment>of(),
-        null);
+    CcToolchainProvider a =
+        new CcToolchainProvider(
+            null,
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            null,
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            null,
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            null,
+            PathFragment.EMPTY_FRAGMENT,
+            CppCompilationContext.EMPTY,
+            false,
+            false,
+            ImmutableMap.<String, String>of(),
+            ImmutableList.<Artifact>of(),
+            NestedSetBuilder.<Pair<String, String>>emptySet(Order.COMPILE_ORDER),
+            null,
+            null,
+            ImmutableMap.<String, String>of(),
+            ImmutableList.<PathFragment>of(),
+            null);
 
-    CcToolchainProvider b = new CcToolchainProvider(
-        null,
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        null,
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        null,
-        NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
-        null,
-        PathFragment.EMPTY_FRAGMENT,
-        CppCompilationContext.EMPTY,
-        false,
-        false,
-        ImmutableMap.<String, String>of(),
-        ImmutableList.<Artifact>of(),
-        NestedSetBuilder.<Pair<String, String>>emptySet(Order.COMPILE_ORDER),
-        null,
-        ImmutableMap.<String, String>of(),
-        ImmutableList.<PathFragment>of(),
-        null);
+    CcToolchainProvider b =
+        new CcToolchainProvider(
+            null,
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            null,
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            null,
+            NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+            null,
+            PathFragment.EMPTY_FRAGMENT,
+            CppCompilationContext.EMPTY,
+            false,
+            false,
+            ImmutableMap.<String, String>of(),
+            ImmutableList.<Artifact>of(),
+            NestedSetBuilder.<Pair<String, String>>emptySet(Order.COMPILE_ORDER),
+            null,
+            null,
+            ImmutableMap.<String, String>of(),
+            ImmutableList.<PathFragment>of(),
+            null);
 
     new EqualsTester()
         .addEqualityGroup(a)
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CppOutputGroupsTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CppOutputGroupsTest.java
index 5110bdd..9d8e537 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CppOutputGroupsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CppOutputGroupsTest.java
@@ -19,7 +19,6 @@
 import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -34,8 +33,8 @@
     scratch.file(
         "a/BUILD",
         "cc_library(name='lib', srcs=['src.cc'], linkstatic=1, alwayslink=0)",
-        "filegroup(name='group_archive', srcs=[':lib'], output_group = 'archive')",
-        "filegroup(name='group_dynamic', srcs=[':lib'], output_group = 'dynamic_library')");
+        "filegroup(name='group_archive', srcs=[':lib'], output_group = 'cc_archive')",
+        "filegroup(name='group_dynamic', srcs=[':lib'], output_group = 'cc_dynamic_library')");
 
     ConfiguredTarget groupArchive = getConfiguredTarget("//a:group_archive");
     ConfiguredTarget groupDynamic = getConfiguredTarget("//a:group_dynamic");
@@ -51,8 +50,8 @@
     scratch.file(
         "a/BUILD",
         "cc_library(name='lib', srcs=['src.cc'], linkstatic=1, alwayslink=1)",
-        "filegroup(name='group_archive', srcs=[':lib'], output_group = 'archive')",
-        "filegroup(name='group_dynamic', srcs=[':lib'], output_group = 'dynamic_library')");
+        "filegroup(name='group_archive', srcs=[':lib'], output_group = 'cc_archive')",
+        "filegroup(name='group_dynamic', srcs=[':lib'], output_group = 'cc_dynamic_library')");
 
     ConfiguredTarget groupArchive = getConfiguredTarget("//a:group_archive");
     ConfiguredTarget groupDynamic = getConfiguredTarget("//a:group_dynamic");
@@ -68,16 +67,18 @@
     scratch.file(
         "a/BUILD",
         "cc_library(name='lib', srcs=['src.cc'], linkstatic=0, alwayslink=0)",
-        "filegroup(name='group_archive', srcs=[':lib'], output_group = 'archive')",
-        "filegroup(name='group_dynamic', srcs=[':lib'], output_group = 'dynamic_library')");
+        "filegroup(name='group_archive', srcs=[':lib'], output_group = 'cc_archive')",
+        "filegroup(name='group_dynamic', srcs=[':lib'], output_group = 'cc_dynamic_library')");
 
     ConfiguredTarget groupArchive = getConfiguredTarget("//a:group_archive");
     ConfiguredTarget groupDynamic = getConfiguredTarget("//a:group_dynamic");
 
     assertThat(ActionsTestUtil.prettyArtifactNames(getFilesToBuild(groupArchive)))
         .containsExactly("a/liblib.a");
+    // If supports_interface_shared_objects is true, .ifso could also be generated.
+    // So we here use contains instead containsExactly.
     assertThat(ActionsTestUtil.prettyArtifactNames(getFilesToBuild(groupDynamic)))
-        .containsExactly("a/liblib.so");
+        .contains("a/liblib.so");
   }
 
   @Test
@@ -86,15 +87,17 @@
     scratch.file(
         "a/BUILD",
         "cc_library(name='lib', srcs=['src.cc'], linkstatic=0, alwayslink=1)",
-        "filegroup(name='group_archive', srcs=[':lib'], output_group = 'archive')",
-        "filegroup(name='group_dynamic', srcs=[':lib'], output_group = 'dynamic_library')");
+        "filegroup(name='group_archive', srcs=[':lib'], output_group = 'cc_archive')",
+        "filegroup(name='group_dynamic', srcs=[':lib'], output_group = 'cc_dynamic_library')");
 
     ConfiguredTarget groupArchive = getConfiguredTarget("//a:group_archive");
     ConfiguredTarget groupDynamic = getConfiguredTarget("//a:group_dynamic");
 
     assertThat(ActionsTestUtil.prettyArtifactNames(getFilesToBuild(groupArchive)))
         .containsExactly("a/liblib.lo");
+    // If supports_interface_shared_objects is true, .ifso could also be generated.
+    // So we here use contains instead containsExactly.
     assertThat(ActionsTestUtil.prettyArtifactNames(getFilesToBuild(groupDynamic)))
-        .containsExactly("a/liblib.so");
+        .contains("a/liblib.so");
   }
 }
diff --git a/src/test/py/bazel/BUILD b/src/test/py/bazel/BUILD
index f93093b..221d1dc 100644
--- a/src/test/py/bazel/BUILD
+++ b/src/test/py/bazel/BUILD
@@ -75,3 +75,26 @@
     srcs = ["launcher_test.py"],
     deps = [":test_base"],
 )
+
+py_test(
+    name = "bazel_windows_dynamic_link_test",
+    size = "medium",
+    srcs = select({
+        "//src:windows": ["bazel_windows_dynamic_link_test.py"],
+        "//src:windows_msvc": ["bazel_windows_dynamic_link_test.py"],
+        "//src:windows_msys": ["bazel_windows_dynamic_link_test.py"],
+        "//conditions:default": ["empty_test.py"],
+    }),
+    main = select({
+        "//src:windows": "bazel_windows_dynamic_link_test.py",
+        "//src:windows_msvc": "bazel_windows_dynamic_link_test.py",
+        "//src:windows_msys": "bazel_windows_dynamic_link_test.py",
+        "//conditions:default": "empty_test.py",
+    }),
+    deps = select({
+        "//src:windows": [":test_base"],
+        "//src:windows_msvc": [":test_base"],
+        "//src:windows_msys": [":test_base"],
+        "//conditions:default": [],
+    }),
+)
diff --git a/src/test/py/bazel/bazel_windows_dynamic_link_test.py b/src/test/py/bazel/bazel_windows_dynamic_link_test.py
new file mode 100644
index 0000000..33440cd
--- /dev/null
+++ b/src/test/py/bazel/bazel_windows_dynamic_link_test.py
@@ -0,0 +1,193 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import unittest
+from src.test.py.bazel import test_base
+
+
+class BazelWindowsDynamicLinkTest(test_base.TestBase):
+
+  def createProjectFiles(self):
+    self.ScratchFile('WORKSPACE')
+    self.ScratchFile('BUILD', [
+        'package(',
+        '  features=["windows_export_all_symbols"]',
+        ')',
+        '',
+        'cc_library(',
+        '  name = "A",',
+        '  srcs = ["a.cc"],',
+        '  hdrs = ["a.h"],',
+        '  copts = ["/DCOMPILING_A_DLL"],',
+        '  features = ["no_windows_export_all_symbols"],',
+        ')',
+        '',
+        'cc_library(',
+        '  name = "B",',
+        '  srcs = ["b.cc"],',
+        '  hdrs = ["b.h"],',
+        '  deps = [":A"],',
+        '  copts = ["/DNO_DLLEXPORT"],',
+        ')',
+        '',
+        'cc_binary(',
+        '  name = "C",',
+        '  srcs = ["c.cc"],',
+        '  deps = [":A", ":B" ],',
+        '  linkstatic = 0,',
+        ')',
+    ])
+    self.ScratchFile('a.cc', [
+        '#include <stdio.h>',
+        '#include "a.h"',
+        'int a = 0;',
+        'void hello_A() {',
+        '  a++;',
+        '  printf("Hello A, %d\\n", a);',
+        '}',
+    ])
+    self.ScratchFile('b.cc', [
+        '#include <stdio.h>',
+        '#include "a.h"',
+        '#include "b.h"',
+        'void hello_B() {',
+        '  hello_A();',
+        '  printf("Hello B\\n");',
+        '}',
+    ])
+    header_temp = [
+        '#ifndef %{name}_H',
+        '#define %{name}_H',
+        '',
+        '#if NO_DLLEXPORT',
+        '  #define DLLEXPORT',
+        '#elif COMPILING_%{name}_DLL',
+        '  #define DLLEXPORT __declspec(dllexport)',
+        '#else',
+        '  #define DLLEXPORT __declspec(dllimport)',
+        '#endif',
+        '',
+        'DLLEXPORT void hello_%{name}();',
+        '',
+        '#endif',
+    ]
+    self.ScratchFile('a.h',
+                     [line.replace('%{name}', 'A') for line in header_temp])
+    self.ScratchFile('b.h',
+                     [line.replace('%{name}', 'B') for line in header_temp])
+
+    self.ScratchFile('c.cc', [
+        '#include <stdio.h>',
+        '#include "a.h"',
+        '#include "b.h"',
+        '',
+        'void hello_C() {',
+        '  hello_A();',
+        '  hello_B();',
+        '  printf("Hello C\\n");',
+        '}',
+        '',
+        'int main() {',
+        '  hello_C();',
+        '  return 0;',
+        '}',
+    ])
+
+  def getBazelInfo(self, info_key):
+    exit_code, stdout, stderr = self.RunBazel(['info', info_key])
+    self.AssertExitCode(exit_code, 0, stderr)
+    return stdout[0]
+
+  def testBuildDynamicLibraryWithUserExportedSymbol(self):
+    self.createProjectFiles()
+    bazel_bin = self.getBazelInfo('bazel-bin')
+
+    # //:A export symbols by itself using __declspec(dllexport), so it doesn't
+    # need Bazel to export symbols using DEF file.
+    exit_code, _, stderr = self.RunBazel(
+        ['build', '//:A', '--output_groups=cc_dynamic_library'])
+    self.AssertExitCode(exit_code, 0, stderr)
+
+    # TODO(pcloudy): change suffixes to .lib and .dll after making DLL
+    # extensions correct on
+    # Windows.
+    import_library = os.path.join(bazel_bin, 'libA.ifso')
+    shared_library = os.path.join(bazel_bin, 'libA.so')
+    def_file = os.path.join(bazel_bin, 'A.def')
+    self.assertTrue(os.path.exists(import_library))
+    self.assertTrue(os.path.exists(shared_library))
+    # DEF file shouldn't be generated for //:A
+    self.assertFalse(os.path.exists(def_file))
+
+  def testBuildDynamicLibraryWithExportSymbolFeature(self):
+    self.createProjectFiles()
+    bazel_bin = self.getBazelInfo('bazel-bin')
+
+    # //:B doesn't export symbols by itself, so it need Bazel to export symbols
+    # using DEF file.
+    exit_code, _, stderr = self.RunBazel(
+        ['build', '//:B', '--output_groups=cc_dynamic_library'])
+    self.AssertExitCode(exit_code, 0, stderr)
+
+    # TODO(pcloudy): change suffixes to .lib and .dll after making DLL
+    # extensions correct on
+    # Windows.
+    import_library = os.path.join(bazel_bin, 'libB.ifso')
+    shared_library = os.path.join(bazel_bin, 'libB.so')
+    def_file = os.path.join(bazel_bin, 'B.def')
+    self.assertTrue(os.path.exists(import_library))
+    self.assertTrue(os.path.exists(shared_library))
+    # DEF file should be generated for //:B
+    self.assertTrue(os.path.exists(def_file))
+
+    # Test build //:B if windows_export_all_symbols feature is disabled by
+    # no_windows_export_all_symbols.
+    exit_code, _, stderr = self.RunBazel([
+        'build', '//:B', '--output_groups=cc_dynamic_library',
+        '--features=no_windows_export_all_symbols'
+    ])
+    self.AssertExitCode(exit_code, 1, stderr)
+    self.assertIn('output \'libB.ifso\' was not created', ''.join(stderr))
+
+  def testBuildCcBinaryWithDependenciesDynamicallyLinked(self):
+    self.createProjectFiles()
+    bazel_bin = self.getBazelInfo('bazel-bin')
+
+    # Since linkstatic=0 is specified for //:C, it's dependencies should be
+    # dynamically linked.
+    exit_code, _, stderr = self.RunBazel(['build', '//:C'])
+    self.AssertExitCode(exit_code, 0, stderr)
+
+    # TODO(pcloudy): change suffixes to .lib and .dll after making DLL
+    # extensions correct on
+    # Windows.
+    # a_import_library
+    self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'libA.ifso')))
+    # a_shared_library
+    self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'libA.so')))
+    # a_def_file
+    self.assertFalse(os.path.exists(os.path.join(bazel_bin, 'A.def')))
+    # b_import_library
+    self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'libB.ifso')))
+    # b_shared_library
+    self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'libB.so')))
+    # b_def_file
+    self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'B.def')))
+    # c_exe
+    self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'C.exe')))
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/BUILD b/tools/BUILD
index 3270fcb..a6d6ac3 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -19,6 +19,7 @@
         "//tools/coverage:srcs",
         "//tools/jdk:srcs",
         "//tools/launcher:srcs",
+        "//tools/def_parser:srcs",
         "//tools/platforms:srcs",
         "//tools/genrule:srcs",
         "//tools/cpp:srcs",
@@ -50,6 +51,7 @@
         "//tools/jdk:package-srcs",
         "//tools/jdk:srcs",
         "//tools/launcher:srcs",
+        "//tools/def_parser:srcs",
         "//tools/platforms:srcs",
         "//tools/objc:srcs",
         "//tools/python:srcs",
diff --git a/tools/cpp/CROSSTOOL.tpl b/tools/cpp/CROSSTOOL.tpl
index 08a3d80..2b220f7 100644
--- a/tools/cpp/CROSSTOOL.tpl
+++ b/tools/cpp/CROSSTOOL.tpl
@@ -166,7 +166,7 @@
   }
   supports_gold_linker: false
   supports_start_end_lib: false
-  supports_interface_shared_objects: false
+  supports_interface_shared_objects: true
   supports_incremental_linker: false
   supports_normalizing_ar: true
   needsPic: false
@@ -238,11 +238,21 @@
     }
   }
 
+  feature {
+    name: 'has_configured_linker_path'
+  }
+
   # This feature indicates strip is not supported, building stripped binary will just result a copy of orignial binary
   feature {
     name: 'no_stripping'
   }
 
+  # This feature indicates this is a toolchain targeting Windows.
+  feature {
+    name: 'targets_windows'
+    enabled: true
+  }
+
   action_config {
     config_name: 'c-compile'
     action_name: 'c-compile'
@@ -358,6 +368,7 @@
     implies: 'msvc_env'
     implies: 'use_linker'
     implies: 'no_stripping'
+    implies: 'has_configured_linker_path'
   }
 
   action_config {
@@ -618,12 +629,11 @@
   feature {
     name: 'input_param_flags'
     flag_set {
-      expand_if_all_available: 'library_search_directories'
+      expand_if_all_available: 'interface_library_output_path'
       action: 'c++-link-executable'
       action: 'c++-link-dynamic-library'
       flag_group {
-        iterate_over: 'library_search_directories'
-        flag: "-L%{library_search_directories}"
+        flag: "/IMPLIB:%{interface_library_output_path}"
       }
     }
     flag_set {
@@ -933,6 +943,27 @@
     }
   }
 
+  feature {
+    name: 'windows_export_all_symbols'
+    flag_set {
+      expand_if_all_available: 'def_file_path'
+      action: 'c++-link-executable'
+      action: 'c++-link-dynamic-library'
+      flag_group {
+        flag: "/DEF:%{def_file_path}"
+        # We can specify a different DLL name in DEF file, /ignore:4070 suppresses
+        # the warning message about DLL name doesn't match the default one.
+        # See https://msdn.microsoft.com/en-us/library/sfkk2fz7.aspx
+        flag: "/ignore:4070"
+      }
+    }
+  }
+
+  feature {
+    name: 'no_windows_export_all_symbols'
+  }
+
+  linking_mode_flags { mode: DYNAMIC }
 
 %{compilation_mode_content}
 
diff --git a/tools/def_parser/BUILD b/tools/def_parser/BUILD
new file mode 100644
index 0000000..7070beb
--- /dev/null
+++ b/tools/def_parser/BUILD
@@ -0,0 +1,18 @@
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+    name = "srcs",
+    srcs = glob(["**"]),
+)
+
+# cc_toolchain now implicitly depends on @bazel_tools//tools/def_parser:def_parser
+# We need to make sure @bazel_tools//tools/def_parser:def_parser is not
+# a cc_binary, because otherwise, we'll introduce a cycle in dependency graph:
+# .-> @bazel_tools//tools/def_parser:def_parser (cc_binary)
+# |   cc_toolchain
+# `-- @bazel_tools//tools/def_parser:def_parser (cc_binary)
+
+filegroup(
+    name = "def_parser",
+    srcs = ["no_op.bat"],
+)
diff --git a/tools/def_parser/BUILD.tools b/tools/def_parser/BUILD.tools
new file mode 100644
index 0000000..bd1b891
--- /dev/null
+++ b/tools/def_parser/BUILD.tools
@@ -0,0 +1,13 @@
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+    name = "def_parser",
+    srcs = select({
+      "//src:host_windows": ["def_parser.exe"],
+      "//src:host_windows_msvc": ["def_parser.exe"],
+      "//src:host_windows_msys": ["def_parser.exe"],
+      "//conditions:default": [
+        "no_op.bat",
+      ],
+    }),
+)
diff --git a/tools/def_parser/no_op.bat b/tools/def_parser/no_op.bat
new file mode 100644
index 0000000..b422585
--- /dev/null
+++ b/tools/def_parser/no_op.bat
@@ -0,0 +1,17 @@
+:: Copyright 2016 The Bazel Authors. All rights reserved.
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::    http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+
+:: Invoke the python script under pydir with the same basename
+@echo OFF
+echo IGNORING: %0 %*