[GN]: support for loadable modules

+ Adds a new target type loadable_module and tool type solink_module. loadable_module will trigger the solink_module tool type in the toolchain.
+ Updates reference.md and editor configs.

BUG=369774

Review URL: https://codereview.chromium.org/1386783003

Cr-Original-Commit-Position: refs/heads/master@{#354077}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 027840da082368b8d51f06b9c310807540e50eea
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn
index b8e24cc..cc7f7e4 100644
--- a/tools/gn/BUILD.gn
+++ b/tools/gn/BUILD.gn
@@ -289,7 +289,6 @@
     "string_utils_unittest.cc",
     "substitution_pattern_unittest.cc",
     "substitution_writer_unittest.cc",
-    "target_generator_unittest.cc",
     "target_unittest.cc",
     "template_unittest.cc",
     "test_with_scope.cc",
diff --git a/tools/gn/commands.cc b/tools/gn/commands.cc
index ab22ebe..3778d5b 100644
--- a/tools/gn/commands.cc
+++ b/tools/gn/commands.cc
@@ -190,6 +190,10 @@
     *type = Target::SHARED_LIBRARY;
     return true;
   }
+  if (value == "loadable_module") {
+    *type = Target::LOADABLE_MODULE;
+    return true;
+  }
   if (value == "static_library") {
     *type = Target::STATIC_LIBRARY;
     return true;
diff --git a/tools/gn/commands.h b/tools/gn/commands.h
index 3d26dba..d294a89 100644
--- a/tools/gn/commands.h
+++ b/tools/gn/commands.h
@@ -156,8 +156,8 @@
     "          Prints the first output file for the target relative to the\n"\
     "          current directory.\n"
 #define TARGET_TYPE_FILTER_COMMAND_LINE_HELP \
-    "  --type=(action|copy|executable|group|shared_library|source_set|\n"\
-    "          static_library)\n"\
+    "  --type=(action|copy|executable|group|loadable_module|shared_library|\n"\
+    "          source_set|static_library)\n"\
     "      Restrict outputs to targets matching the given type. If\n"\
     "      unspecified, no filtering will be performed.\n"
 #define TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP \
diff --git a/tools/gn/docs/faq.md b/tools/gn/docs/faq.md
index 980c18b..cd32f6a 100644
--- a/tools/gn/docs/faq.md
+++ b/tools/gn/docs/faq.md
@@ -12,10 +12,7 @@
 ## What is unsupported in GN?
 
 The main features not supported in GN yet are:
-  * Mac bundles
-  * Loadable module (this only matters on Mac where shared library !=
-    lodable module)
-  * Precompiled headers
+  * Mac/iOS bundles
 
 ## Where is the GN documentation?
 
diff --git a/tools/gn/docs/language.md b/tools/gn/docs/language.md
index 35ef4ae..7fb68e0 100644
--- a/tools/gn/docs/language.md
+++ b/tools/gn/docs/language.md
@@ -93,8 +93,8 @@
 ```
 a = [ "first" ]
 a += [ "second" ]  # [ "first", "second" ]
-a += [ "third", "fourth" ]  # [ "first", "second", "third", "fourth" ] 
-b = a + [ "fifth" ]  # [ "first", "second", "third", "fourth", "fifth" ] 
+a += [ "third", "fourth" ]  # [ "first", "second", "third", "fourth" ]
+b = a + [ "fifth" ]  # [ "first", "second", "third", "fourth", "fifth" ]
 ```
 
 Appending a list to another list appends the items in the second list
@@ -160,7 +160,7 @@
     ...
   } else {
     ...
-  }  
+  }
 ```
 
 You can use them in most places, even around entire targets if the
@@ -376,10 +376,11 @@
   * `group`: A virtual dependency node that refers to one or more other
     targets.
   * `shared_library`: A .dll or .so.
+  * `loadable_module`: A .dll or .so loadable only at runtime.
   * `source_set`: A lightweight virtual static library (usually
     preferrable over a real static library since it will build faster).
   * `static_library`: A .lib or .a file (normally you'll want a
-    source\_set instead).
+    `source_set` instead).
 
 You can extend this to make custom target types using templates (see below).
 
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md
index 657796a..a3bb57b 100644
--- a/tools/gn/docs/reference.md
+++ b/tools/gn/docs/reference.md
@@ -455,8 +455,8 @@
       Tree output can not be used with the filtering or output flags:
       --as, --type, --testonly.
 
-  --type=(action|copy|executable|group|shared_library|source_set|
-          static_library)
+  --type=(action|copy|executable|group|loadable_module|shared_library|
+          source_set|static_library)
       Restrict outputs to targets matching the given type. If
       unspecified, no filtering will be performed.
 
@@ -594,8 +594,8 @@
       accordingly. When unspecified, the target's testonly flags are
       ignored.
 
-  --type=(action|copy|executable|group|shared_library|source_set|
-          static_library)
+  --type=(action|copy|executable|group|loadable_module|shared_library|
+          source_set|static_library)
       Restrict outputs to targets matching the given type. If
       unspecified, no filtering will be performed.
 
@@ -740,8 +740,8 @@
       Tree output can not be used with the filtering or output flags:
       --as, --type, --testonly.
 
-  --type=(action|copy|executable|group|shared_library|source_set|
-          static_library)
+  --type=(action|copy|executable|group|loadable_module|shared_library|
+          source_set|static_library)
       Restrict outputs to targets matching the given type. If
       unspecified, no filtering will be performed.
 
@@ -1025,7 +1025,7 @@
 ### **Variables valid in a config definition**:
 ```
   Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
-         defines, include_dirs, ldflags, lib_dirs, libs,
+         asmflags, defines, include_dirs, ldflags, lib_dirs, libs,
          precompiled_header, precompiled_source
 
 ```
@@ -1103,9 +1103,48 @@
 
   See also "gn help buildargs" for an overview.
 
+  The precise behavior of declare args is:
+
+   1. The declare_arg block executes. Any variables in the enclosing
+      scope are available for reading.
+
+   2. At the end of executing the block, any variables set within that
+      scope are saved globally as build arguments, with their current
+      values being saved as the "default value" for that argument.
+
+   3. User-defined overrides are applied. Anything set in "gn args"
+      now overrides any default values. The resulting set of variables
+      is promoted to be readable from the following code in the file.
+
+  This has some ramifications that may not be obvious:
+
+    - You should not perform difficult work inside a declare_args block
+      since this only sets a default value that may be discarded. In
+      particular, don't use the result of exec_script() to set the
+      default value. If you want to have a script-defined default, set
+      some default "undefined" value like [], "", or -1, and after
+      the declare_args block, call exec_script if the value is unset by
+      the user.
+
+    - Any code inside of the declare_args block will see the default
+      values of previous variables defined in the block rather than
+      the user-overridden value. This can be surprising because you will
+      be used to seeing the overridden value. If you need to make the
+      default value of one arg dependent on the possibly-overridden
+      value of another, write two separate declare_args blocks:
+
+        declare_args() {
+          enable_foo = true
+        }
+        declare_args() {
+          # Bar defaults to same user-overridden state as foo.
+          enable_bar = enable_foo
+        }
+
 ```
 
-### **Example**:
+### **Example**
+
 ```
   declare_args() {
     enable_teleporter = true
@@ -1223,7 +1262,7 @@
 
 ```
   Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
-         defines, include_dirs, ldflags, lib_dirs, libs,
+         asmflags, defines, include_dirs, ldflags, lib_dirs, libs,
          precompiled_header, precompiled_source
   Deps: data_deps, deps, public_deps
   Dependent configs: all_dependent_configs, public_configs
@@ -1582,7 +1621,7 @@
   specify configs that apply to their dependents.
 
   Depending on a group is exactly like depending directly on that
-  group's deps.
+  group's deps. 
 
 ```
 
@@ -1645,6 +1684,32 @@
 
 
 ```
+## **loadable_module**: Declare a loadable module target.
+
+```
+  This target type allows you to create an object file that is (and can
+  only be) loaded and unloaded at runtime.
+
+  A loadable module will be specified on the linker line for targets
+  listing the loadable module in its "deps". If you don't want this
+  (if you don't need to dynamically load the library at runtime), then
+  you should use a "shared_library" target type instead.
+
+```
+
+### **Variables**
+
+```
+  Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
+         asmflags, defines, include_dirs, ldflags, lib_dirs, libs,
+         precompiled_header, precompiled_source
+  Deps: data_deps, deps, public_deps
+  Dependent configs: all_dependent_configs, public_configs
+  General: check_includes, configs, data, inputs, output_name,
+           output_extension, public, sources, testonly, visibility
+
+
+```
 ## **print**: Prints to the console.
 
 ```
@@ -1988,7 +2053,8 @@
   A shared library will be specified on the linker line for targets
   listing the shared library in its "deps". If you don't want this
   (say you dynamically load the library at runtime), then you should
-  depend on the shared library via "data_deps" instead.
+  depend on the shared library via "data_deps" or, on Darwin
+  platforms, use a "loadable_module" target type instead.
 
 ```
 
@@ -1996,7 +2062,7 @@
 
 ```
   Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
-         defines, include_dirs, ldflags, lib_dirs, libs,
+         asmflags, defines, include_dirs, ldflags, lib_dirs, libs,
          precompiled_header, precompiled_source
   Deps: data_deps, deps, public_deps
   Dependent configs: all_dependent_configs, public_configs
@@ -2037,7 +2103,7 @@
 
 ```
   Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
-         defines, include_dirs, ldflags, lib_dirs, libs,
+         asmflags, defines, include_dirs, ldflags, lib_dirs, libs,
          precompiled_header, precompiled_source
   Deps: data_deps, deps, public_deps
   Dependent configs: all_dependent_configs, public_configs
@@ -2061,7 +2127,7 @@
 
 ```
   Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,
-         defines, include_dirs, ldflags, lib_dirs, libs,
+         asmflags, defines, include_dirs, ldflags, lib_dirs, libs,
          precompiled_header, precompiled_source
   Deps: data_deps, deps, public_deps
   Dependent configs: all_dependent_configs, public_configs
@@ -2394,7 +2460,7 @@
     depend_output  [string with substitutions]
         Valid for: "solink" only (optional)
 
-        These two files specify whch of the outputs from the solink
+        These two files specify which of the outputs from the solink
         tool should be used for linking and dependency tracking. These
         should match entries in the "outputs". If unspecified, the
         first item in the "outputs" array will be used for both. See
@@ -2511,6 +2577,7 @@
   along with a set of compiler-specific flags. The following expansions
   are available:
 
+    {{asmflags}}
     {{cflags}}
     {{cflags_c}}
     {{cflags_cc}}
@@ -3217,8 +3284,11 @@
   and Objective C++ compilers.
 
   To target one of these variants individually, use "cflags_c",
-  "cflags_cc", "cflags_objc", and "cflags_objcc", respectively.
-  These variant-specific versions will be appended to the "cflags".
+  "cflags_cc", "cflags_objc", and "cflags_objcc",
+  respectively.
+
+  These variant-specific versions of cflags* will be appended to the
+  "cflags".
 
 ```
 
@@ -3250,8 +3320,11 @@
   and Objective C++ compilers.
 
   To target one of these variants individually, use "cflags_c",
-  "cflags_cc", "cflags_objc", and "cflags_objcc", respectively.
-  These variant-specific versions will be appended to the "cflags".
+  "cflags_cc", "cflags_objc", and "cflags_objcc",
+  respectively.
+
+  These variant-specific versions of cflags* will be appended to the
+  "cflags".
 
 ```
 
@@ -3283,8 +3356,11 @@
   and Objective C++ compilers.
 
   To target one of these variants individually, use "cflags_c",
-  "cflags_cc", "cflags_objc", and "cflags_objcc", respectively.
-  These variant-specific versions will be appended to the "cflags".
+  "cflags_cc", "cflags_objc", and "cflags_objcc",
+  respectively.
+
+  These variant-specific versions of cflags* will be appended to the
+  "cflags".
 
 ```
 
@@ -3316,8 +3392,11 @@
   and Objective C++ compilers.
 
   To target one of these variants individually, use "cflags_c",
-  "cflags_cc", "cflags_objc", and "cflags_objcc", respectively.
-  These variant-specific versions will be appended to the "cflags".
+  "cflags_cc", "cflags_objc", and "cflags_objcc",
+  respectively.
+
+  These variant-specific versions of cflags* will be appended to the
+  "cflags".
 
 ```
 
@@ -3349,8 +3428,11 @@
   and Objective C++ compilers.
 
   To target one of these variants individually, use "cflags_c",
-  "cflags_cc", "cflags_objc", and "cflags_objcc", respectively.
-  These variant-specific versions will be appended to the "cflags".
+  "cflags_cc", "cflags_objc", and "cflags_objcc",
+  respectively.
+
+  These variant-specific versions of cflags* will be appended to the
+  "cflags".
 
 ```
 
@@ -3718,8 +3800,6 @@
 
 
 ```
-
-```
 ## **include_dirs**: Additional include directories.
 
 ```
@@ -4796,8 +4876,8 @@
 
   To a first approximation, the runtime dependencies of a target are
   the set of "data" files, data directories, and the shared libraries
-  from all transitive dependencies. Executables and shared libraries are
-  considered runtime dependencies of themselves.
+  from all transitive dependencies. Executables, shared libraries, and
+  loadable modules are considered runtime dependencies of themselves.
 
 ```
 
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc
index 298cac5..7068370 100644
--- a/tools/gn/function_toolchain.cc
+++ b/tools/gn/function_toolchain.cc
@@ -195,6 +195,7 @@
 bool IsLinkerTool(Toolchain::ToolType type) {
   return type == Toolchain::TYPE_ALINK ||
          type == Toolchain::TYPE_SOLINK ||
+         type == Toolchain::TYPE_SOLINK_MODULE ||
          type == Toolchain::TYPE_LINK;
 }
 
@@ -503,7 +504,7 @@
     "    depend_output  [string with substitutions]\n"
     "        Valid for: \"solink\" only (optional)\n"
     "\n"
-    "        These two files specify whch of the outputs from the solink\n"
+    "        These two files specify which of the outputs from the solink\n"
     "        tool should be used for linking and dependency tracking. These\n"
     "        should match entries in the \"outputs\". If unspecified, the\n"
     "        first item in the \"outputs\" array will be used for both. See\n"
@@ -847,9 +848,10 @@
   // Validate that the link_output and depend_output refer to items in the
   // outputs and aren't defined for irrelevant tool types.
   if (!tool->link_output().empty()) {
-    if (tool_type != Toolchain::TYPE_SOLINK) {
+    if (tool_type != Toolchain::TYPE_SOLINK &&
+        tool_type != Toolchain::TYPE_SOLINK_MODULE) {
       *err = Err(function, "This tool specifies a link_output.",
-          "This is only valid for solink tools.");
+          "This is only valid for solink and solink_module tools.");
       return Value();
     }
     if (!IsPatternInOutputList(tool->outputs(), tool->link_output())) {
@@ -859,9 +861,10 @@
     }
   }
   if (!tool->depend_output().empty()) {
-    if (tool_type != Toolchain::TYPE_SOLINK) {
+    if (tool_type != Toolchain::TYPE_SOLINK &&
+        tool_type != Toolchain::TYPE_SOLINK_MODULE) {
       *err = Err(function, "This tool specifies a depend_output.",
-          "This is only valid for solink tools.");
+          "This is only valid for solink and solink_module tools.");
       return Value();
     }
     if (!IsPatternInOutputList(tool->outputs(), tool->depend_output())) {
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index 9413a7f..18fd0b3 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -800,6 +800,7 @@
     INSERT_FUNCTION(Copy, true)
     INSERT_FUNCTION(Executable, true)
     INSERT_FUNCTION(Group, true)
+    INSERT_FUNCTION(LoadableModule, true)
     INSERT_FUNCTION(SharedLibrary, true)
     INSERT_FUNCTION(SourceSet, true)
     INSERT_FUNCTION(StaticLibrary, true)
diff --git a/tools/gn/functions.h b/tools/gn/functions.h
index 262fc60..b746515 100644
--- a/tools/gn/functions.h
+++ b/tools/gn/functions.h
@@ -195,6 +195,15 @@
                 const std::vector<Value>& args,
                 Err* err);
 
+extern const char kLoadableModule[];
+extern const char kLoadableModule_HelpShort[];
+extern const char kLoadableModule_Help[];
+Value RunLoadableModule(Scope* scope,
+                        const FunctionCallNode* function,
+                        const std::vector<Value>& args,
+                        BlockNode* block,
+                        Err* err);
+
 extern const char kPrint[];
 extern const char kPrint_HelpShort[];
 extern const char kPrint_Help[];
diff --git a/tools/gn/functions_target.cc b/tools/gn/functions_target.cc
index fbac2d2..79af535 100644
--- a/tools/gn/functions_target.cc
+++ b/tools/gn/functions_target.cc
@@ -355,6 +355,38 @@
                               block, err);
 }
 
+// loadable_module -------------------------------------------------------------
+
+const char kLoadableModule[] = "loadable_module";
+const char kLoadableModule_HelpShort[] =
+    "loadable_module: Declare a loadable module target.";
+const char kLoadableModule_Help[] =
+    "loadable_module: Declare a loadable module target.\n"
+    "\n"
+    "  This target type allows you to create an object file that is (and can\n"
+    "  only be) loaded and unloaded at runtime.\n"
+    "\n"
+    "  A loadable module will be specified on the linker line for targets\n"
+    "  listing the loadable module in its \"deps\". If you don't want this\n"
+    "  (if you don't need to dynamically load the library at runtime), then\n"
+    "  you should use a \"shared_library\" target type instead.\n"
+    "\n"
+    "Variables\n"
+    "\n"
+    CONFIG_VALUES_VARS_HELP
+    DEPS_VARS
+    DEPENDENT_CONFIG_VARS
+    GENERAL_TARGET_VARS;
+
+Value RunLoadableModule(Scope* scope,
+                       const FunctionCallNode* function,
+                       const std::vector<Value>& args,
+                       BlockNode* block,
+                       Err* err) {
+  return ExecuteGenericTarget(functions::kLoadableModule, scope, function, args,
+                              block, err);
+}
+
 // shared_library --------------------------------------------------------------
 
 const char kSharedLibrary[] = "shared_library";
@@ -366,7 +398,8 @@
     "  A shared library will be specified on the linker line for targets\n"
     "  listing the shared library in its \"deps\". If you don't want this\n"
     "  (say you dynamically load the library at runtime), then you should\n"
-    "  depend on the shared library via \"data_deps\" instead.\n"
+    "  depend on the shared library via \"data_deps\" or, on Darwin\n"
+    "  platforms, use a \"loadable_module\" target type instead.\n"
     "\n"
     "Variables\n"
     "\n"
@@ -501,8 +534,7 @@
                 BlockNode* block,
                 Err* err) {
   if (args.size() != 2) {
-    *err = Err(function, "Expected two arguments.",
-               "Dude, try \"gn help target\".");
+    *err = Err(function, "Expected two arguments.", "Try \"gn help target\".");
     return Value();
   }
 
diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp
index 19bc57c..fbc2c37 100644
--- a/tools/gn/gn.gyp
+++ b/tools/gn/gn.gyp
@@ -249,7 +249,6 @@
         'string_utils_unittest.cc',
         'substitution_pattern_unittest.cc',
         'substitution_writer_unittest.cc',
-        'target_generator_unittest.cc',
         'target_unittest.cc',
         'template_unittest.cc',
         'test_with_scope.cc',
diff --git a/tools/gn/misc/emacs/gn-mode.el b/tools/gn/misc/emacs/gn-mode.el
index e61dec5..3cb7341 100644
--- a/tools/gn/misc/emacs/gn-mode.el
+++ b/tools/gn/misc/emacs/gn-mode.el
@@ -54,7 +54,7 @@
   :group 'gn-faces)
 
 (defvar gn-font-lock-target-declaration-keywords
-  '("action" "action_foreach" "copy" "executable" "group"
+  '("action" "action_foreach" "copy" "executable" "group" "loadable_module"
     "shared_library" "source_set" "static_library" "if" "else"))
 
 (defvar gn-font-lock-buildfile-fun-keywords
diff --git a/tools/gn/misc/tm/GN.tmLanguage b/tools/gn/misc/tm/GN.tmLanguage
index 5f39f01..6a80a36 100644
--- a/tools/gn/misc/tm/GN.tmLanguage
+++ b/tools/gn/misc/tm/GN.tmLanguage
@@ -65,7 +65,7 @@
       <key>comment</key>
       <string>targets</string>
       <key>match</key>
-      <string>\b(?:action|action_foreach|copy|executable|group|shared_library|source_set|static_library)\b</string>
+      <string>\b(?:action|action_foreach|copy|executable|group|loadable_module|shared_library|source_set|static_library)\b</string>
       <key>name</key>
       <string>entity.name.tag.gn</string>
     </dict>
diff --git a/tools/gn/misc/vim/syntax/gn.vim b/tools/gn/misc/vim/syntax/gn.vim
index b7cef23..55f1852 100644
--- a/tools/gn/misc/vim/syntax/gn.vim
+++ b/tools/gn/misc/vim/syntax/gn.vim
@@ -27,6 +27,7 @@
 " Target declarations
 syn keyword     gnTarget action action_foreach copy executable group
 syn keyword     gnTarget shared_library source_set static_library
+syn keyword     gnTarget loadable_module
 hi def link     gnTarget            Type
 
 " Buildfile functions
diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc
index ae46760..64bf042 100644
--- a/tools/gn/ninja_binary_target_writer.cc
+++ b/tools/gn/ninja_binary_target_writer.cc
@@ -962,7 +962,7 @@
 
   if (dep->output_type() == Target::SOURCE_SET) {
     // Source sets have their object files linked into final targets
-    // (shared libraries, executables, and complete static
+    // (shared libraries, executables, loadable modules, and complete static
     // libraries). Intermediate static libraries and other source sets
     // just forward the dependency, otherwise the files in the source
     // set can easily get linked more than once which will cause
diff --git a/tools/gn/ninja_binary_target_writer_unittest.cc b/tools/gn/ninja_binary_target_writer_unittest.cc
index 25d4782..3de68e8 100644
--- a/tools/gn/ninja_binary_target_writer_unittest.cc
+++ b/tools/gn/ninja_binary_target_writer_unittest.cc
@@ -365,6 +365,72 @@
   EXPECT_EQ(expected, out.str());
 }
 
+TEST(NinjaBinaryTargetWriter, LoadableModule) {
+  TestWithScope setup;
+  setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
+
+  Target loadable_module(setup.settings(), Label(SourceDir("//foo/"), "bar"));
+  loadable_module.set_output_type(Target::LOADABLE_MODULE);
+  loadable_module.visibility().SetPublic();
+  loadable_module.SetToolchain(setup.toolchain());
+  loadable_module.sources().push_back(SourceFile("//foo/sources.cc"));
+
+  Err err;
+  ASSERT_TRUE(loadable_module.OnResolved(&err)) << err.message();
+
+  std::ostringstream out;
+  NinjaBinaryTargetWriter writer(&loadable_module, out);
+  writer.Run();
+
+  const char loadable_expected[] =
+      "defines =\n"
+      "include_dirs =\n"
+      "cflags =\n"
+      "cflags_cc =\n"
+      "root_out_dir = .\n"
+      "target_out_dir = obj/foo\n"
+      "target_output_name = libbar\n"
+      "\n"
+      "build obj/foo/libbar.sources.o: cxx ../../foo/sources.cc\n"
+      "\n"
+      "build ./libbar.so: solink_module obj/foo/libbar.sources.o\n"
+      "  ldflags =\n"
+      "  libs =\n"
+      "  output_extension = .so\n";
+  EXPECT_EQ(loadable_expected, out.str());
+
+  // Final target.
+  Target exe(setup.settings(), Label(SourceDir("//foo/"), "exe"));
+  exe.set_output_type(Target::EXECUTABLE);
+  exe.public_deps().push_back(LabelTargetPair(&loadable_module));
+  exe.SetToolchain(setup.toolchain());
+  exe.sources().push_back(SourceFile("//foo/final.cc"));
+  ASSERT_TRUE(exe.OnResolved(&err)) << err.message();
+
+  std::ostringstream final_out;
+  NinjaBinaryTargetWriter final_writer(&exe, final_out);
+  final_writer.Run();
+
+  // The final output depends on the loadable module so should have an
+  // order-only dependency on the loadable modules's output file.
+  const char final_expected[] =
+      "defines =\n"
+      "include_dirs =\n"
+      "cflags =\n"
+      "cflags_cc =\n"
+      "root_out_dir = .\n"
+      "target_out_dir = obj/foo\n"
+      "target_output_name = exe\n"
+      "\n"
+      "build obj/foo/exe.final.o: cxx ../../foo/final.cc\n"
+      "\n"
+      "build ./exe: link obj/foo/exe.final.o || ./libbar.so\n"
+      "  ldflags =\n"
+      "  libs =\n"
+      "  output_extension = \n";
+  EXPECT_EQ(final_expected, final_out.str());
+}
+
 TEST(NinjaBinaryTargetWriter, WinPrecompiledHeaders) {
   Err err;
 
diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc
index 098a58c..7c168ea 100644
--- a/tools/gn/ninja_target_writer.cc
+++ b/tools/gn/ninja_target_writer.cc
@@ -68,13 +68,14 @@
     NinjaGroupTargetWriter writer(target, file);
     writer.Run();
   } else if (target->output_type() == Target::EXECUTABLE ||
+             target->output_type() == Target::LOADABLE_MODULE ||
              target->output_type() == Target::STATIC_LIBRARY ||
              target->output_type() == Target::SHARED_LIBRARY ||
              target->output_type() == Target::SOURCE_SET) {
     NinjaBinaryTargetWriter writer(target, file);
     writer.Run();
   } else {
-    CHECK(0);
+    CHECK(0) << "Output type of target not handled.";
   }
 
   std::string contents = file.str();
diff --git a/tools/gn/ninja_toolchain_writer.cc b/tools/gn/ninja_toolchain_writer.cc
index c22fb2c..e7459eb 100644
--- a/tools/gn/ninja_toolchain_writer.cc
+++ b/tools/gn/ninja_toolchain_writer.cc
@@ -109,8 +109,11 @@
 
   // The link pool applies to linker tools. Don't count TYPE_ALINK since
   // static libraries are not generally intensive to write.
-  if (type == Toolchain::TYPE_SOLINK || type == Toolchain::TYPE_LINK)
+  if (type == Toolchain::TYPE_SOLINK ||
+      type == Toolchain::TYPE_SOLINK_MODULE ||
+      type == Toolchain::TYPE_LINK) {
     out_ << kIndent << "pool = link_pool\n";
+  }
 
   if (tool->restat())
     out_ << kIndent << "restat = 1" << std::endl;
diff --git a/tools/gn/runtime_deps.cc b/tools/gn/runtime_deps.cc
index f6441e8..d828311 100644
--- a/tools/gn/runtime_deps.cc
+++ b/tools/gn/runtime_deps.cc
@@ -81,8 +81,10 @@
   }
   (*seen_targets)[target] = is_target_data_dep;
 
-  // Add the main output file for executables and shared libraries.
+  // Add the main output file for executables, shared libraries, and
+  // loadable modules.
   if (target->output_type() == Target::EXECUTABLE ||
+      target->output_type() == Target::LOADABLE_MODULE ||
       target->output_type() == Target::SHARED_LIBRARY)
     AddIfNew(GetMainOutput(target), target, deps, found_files);
 
@@ -149,8 +151,8 @@
     "\n"
     "  To a first approximation, the runtime dependencies of a target are\n"
     "  the set of \"data\" files, data directories, and the shared libraries\n"
-    "  from all transitive dependencies. Executables and shared libraries are\n"
-    "  considered runtime dependencies of themselves.\n"
+    "  from all transitive dependencies. Executables, shared libraries, and\n"
+    "  loadable modules are considered runtime dependencies of themselves.\n"
     "\n"
     "Executables\n"
     "\n"
diff --git a/tools/gn/runtime_deps_unittest.cc b/tools/gn/runtime_deps_unittest.cc
index a674e5b..3b3c880 100644
--- a/tools/gn/runtime_deps_unittest.cc
+++ b/tools/gn/runtime_deps_unittest.cc
@@ -43,9 +43,10 @@
   TestWithScope setup;
   Err err;
 
-  // Dependency hierarchy: main(exe) -> stat
-  //                                 -> shared
-  //                                 -> set
+  // Dependency hierarchy: main(exe) -> static library
+  //                                 -> shared library
+  //                                 -> loadable module
+  //                                 -> source set
 
   Target stat(setup.settings(), Label(SourceDir("//"), "stat"));
   InitTargetWithType(setup, &stat, Target::STATIC_LIBRARY);
@@ -57,6 +58,11 @@
   shared.data().push_back("//shared.dat");
   ASSERT_TRUE(shared.OnResolved(&err));
 
+  Target loadable(setup.settings(), Label(SourceDir("//"), "loadable"));
+  InitTargetWithType(setup, &loadable, Target::LOADABLE_MODULE);
+  loadable.data().push_back("//loadable.dat");
+  ASSERT_TRUE(loadable.OnResolved(&err));
+
   Target set(setup.settings(), Label(SourceDir("//"), "set"));
   InitTargetWithType(setup, &set, Target::SOURCE_SET);
   set.data().push_back("//set.dat");
@@ -66,6 +72,7 @@
   InitTargetWithType(setup, &main, Target::EXECUTABLE);
   main.private_deps().push_back(LabelTargetPair(&stat));
   main.private_deps().push_back(LabelTargetPair(&shared));
+  main.private_deps().push_back(LabelTargetPair(&loadable));
   main.private_deps().push_back(LabelTargetPair(&set));
   main.data().push_back("//main.dat");
   ASSERT_TRUE(main.OnResolved(&err));
@@ -73,8 +80,9 @@
   std::vector<std::pair<OutputFile, const Target*>> result =
       ComputeRuntimeDeps(&main);
 
-  // The result should have deps of main, all 4 dat files, and libshared.so
-  ASSERT_EQ(6u, result.size()) << GetVectorDescription(result);
+  // The result should have deps of main, all 5 dat files, libshared.so, and
+  // libloadable.so.
+  ASSERT_EQ(8u, result.size()) << GetVectorDescription(result);
 
   // The first one should always be the main exe.
   EXPECT_TRUE(MakePair("./main", &main) == result[0]);
@@ -87,16 +95,22 @@
                         MakePair("../../shared.dat", &shared)) !=
               result.end()) << GetVectorDescription(result);
   EXPECT_TRUE(std::find(result.begin(), result.end(),
+                        MakePair("../../loadable.dat", &loadable)) !=
+              result.end()) << GetVectorDescription(result);
+  EXPECT_TRUE(std::find(result.begin(), result.end(),
                         MakePair("../../set.dat", &set)) !=
               result.end()) << GetVectorDescription(result);
   EXPECT_TRUE(std::find(result.begin(), result.end(),
                         MakePair("../../main.dat", &main)) !=
               result.end()) << GetVectorDescription(result);
 
-  // Check the static library
+  // Check the static library and loadable module.
   EXPECT_TRUE(std::find(result.begin(), result.end(),
                         MakePair("./libshared.so", &shared)) !=
               result.end()) << GetVectorDescription(result);
+  EXPECT_TRUE(std::find(result.begin(), result.end(),
+                        MakePair("./libloadable.so", &loadable)) !=
+              result.end()) << GetVectorDescription(result);
 }
 
 // Tests that executables that aren't listed as data deps aren't included in
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index a27a5c4..94cc2e0 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -125,6 +125,8 @@
       return "Group";
     case EXECUTABLE:
       return "Executable";
+    case LOADABLE_MODULE:
+      return "Loadable module";
     case SHARED_LIBRARY:
       return "Shared library";
     case STATIC_LIBRARY:
@@ -193,7 +195,9 @@
 }
 
 bool Target::IsFinal() const {
-  return output_type_ == EXECUTABLE || output_type_ == SHARED_LIBRARY ||
+  return output_type_ == EXECUTABLE ||
+         output_type_ == SHARED_LIBRARY ||
+         output_type_ == LOADABLE_MODULE ||
          (output_type_ == STATIC_LIBRARY && complete_static_lib_);
 }
 
@@ -350,8 +354,9 @@
       break;
     }
     case EXECUTABLE:
-      // Executables don't get linked to, but the first output is used for
-      // dependency management.
+    case LOADABLE_MODULE:
+      // Executables and loadable modules don't get linked to, but the first
+      // output is used for dependency management.
       CHECK_GE(tool->outputs().list().size(), 1u);
       check_tool_outputs = true;
       dependency_output_file_ =
diff --git a/tools/gn/target.h b/tools/gn/target.h
index fc752ac..383a2af 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -35,6 +35,7 @@
     GROUP,
     EXECUTABLE,
     SHARED_LIBRARY,
+    LOADABLE_MODULE,
     STATIC_LIBRARY,
     SOURCE_SET,
     COPY_FILES,
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc
index 366210c..dd83639 100644
--- a/tools/gn/target_generator.cc
+++ b/tools/gn/target_generator.cc
@@ -100,6 +100,10 @@
   } else if (output_type == functions::kGroup) {
     GroupTargetGenerator generator(target.get(), scope, function_call, err);
     generator.Run();
+  } else if (output_type == functions::kLoadableModule) {
+    BinaryTargetGenerator generator(target.get(), scope, function_call,
+                                    Target::LOADABLE_MODULE, err);
+    generator.Run();
   } else if (output_type == functions::kSharedLibrary) {
     BinaryTargetGenerator generator(target.get(), scope, function_call,
                                     Target::SHARED_LIBRARY, err);
diff --git a/tools/gn/target_generator_unittest.cc b/tools/gn/target_generator_unittest.cc
deleted file mode 100644
index feef6a9..0000000
--- a/tools/gn/target_generator_unittest.cc
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "tools/gn/filesystem_utils.h"
-#include "tools/gn/target_generator.h"
-
diff --git a/tools/gn/test_with_scope.cc b/tools/gn/test_with_scope.cc
index 20551f1..4793f39 100644
--- a/tools/gn/test_with_scope.cc
+++ b/tools/gn/test_with_scope.cc
@@ -99,6 +99,16 @@
       "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"));
   toolchain->SetTool(Toolchain::TYPE_SOLINK, solink_tool.Pass());
 
+  // SOLINK_MODULE
+  scoped_ptr<Tool> solink_module_tool(new Tool);
+  SetCommandForTool("ld -bundle -o {{target_output_name}}.so {{inputs}} "
+      "{{ldflags}} {{libs}}", solink_module_tool.get());
+  solink_module_tool->set_output_prefix("lib");
+  solink_module_tool->set_default_output_extension(".so");
+  solink_module_tool->set_outputs(SubstitutionList::MakeForTest(
+      "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"));
+  toolchain->SetTool(Toolchain::TYPE_SOLINK_MODULE, solink_module_tool.Pass());
+
   // LINK
   scoped_ptr<Tool> link_tool(new Tool);
   SetCommandForTool("ld -o {{target_output_name}} {{source}} "
diff --git a/tools/gn/toolchain.cc b/tools/gn/toolchain.cc
index cdd70c0..826c875 100644
--- a/tools/gn/toolchain.cc
+++ b/tools/gn/toolchain.cc
@@ -18,6 +18,7 @@
 const char* Toolchain::kToolAsm = "asm";
 const char* Toolchain::kToolAlink = "alink";
 const char* Toolchain::kToolSolink = "solink";
+const char* Toolchain::kToolSolinkModule = "solink_module";
 const char* Toolchain::kToolLink = "link";
 const char* Toolchain::kToolStamp = "stamp";
 const char* Toolchain::kToolCopy = "copy";
@@ -49,6 +50,7 @@
   if (str == kToolAsm) return TYPE_ASM;
   if (str == kToolAlink) return TYPE_ALINK;
   if (str == kToolSolink) return TYPE_SOLINK;
+  if (str == kToolSolinkModule) return TYPE_SOLINK_MODULE;
   if (str == kToolLink) return TYPE_LINK;
   if (str == kToolStamp) return TYPE_STAMP;
   if (str == kToolCopy) return TYPE_COPY;
@@ -66,6 +68,7 @@
     case TYPE_ASM: return kToolAsm;
     case TYPE_ALINK: return kToolAlink;
     case TYPE_SOLINK: return kToolSolink;
+    case TYPE_SOLINK_MODULE: return kToolSolinkModule;
     case TYPE_LINK: return kToolLink;
     case TYPE_STAMP: return kToolStamp;
     case TYPE_COPY: return kToolCopy;
@@ -140,6 +143,8 @@
       return Toolchain::TYPE_LINK;
     case Target::SHARED_LIBRARY:
       return Toolchain::TYPE_SOLINK;
+    case Target::LOADABLE_MODULE:
+      return Toolchain::TYPE_SOLINK_MODULE;
     case Target::STATIC_LIBRARY:
       return Toolchain::TYPE_ALINK;
     case Target::SOURCE_SET:
diff --git a/tools/gn/toolchain.h b/tools/gn/toolchain.h
index c94d8ed..b49153b 100644
--- a/tools/gn/toolchain.h
+++ b/tools/gn/toolchain.h
@@ -40,6 +40,7 @@
     TYPE_ASM,
     TYPE_ALINK,
     TYPE_SOLINK,
+    TYPE_SOLINK_MODULE,
     TYPE_LINK,
     TYPE_STAMP,
     TYPE_COPY,
@@ -55,6 +56,7 @@
   static const char* kToolAsm;
   static const char* kToolAlink;
   static const char* kToolSolink;
+  static const char* kToolSolinkModule;
   static const char* kToolLink;
   static const char* kToolStamp;
   static const char* kToolCopy;