[Reland] Switch pdfium target from a static library to a component

Reland reland fixes fuzzer issues and Windows startup failure in Debug
configuration.  Verified by Chromium's CQ:
https://chromium-review.googlesource.com/c/chromium/src/+/1592280

Reland fixes linker failures, verified by Chromium's CQ:
https://chromium-review.googlesource.com/c/chromium/src/+/1590226

Reduces size of build directory by 206 MiB (-1.0%) when building "all"
with gn args "use_goma=true is_component_build=true is_debug=false
enable_nacl=false symbol_level=1".  Build time also reduced from
426.111s to 405.252s, though I only took one sample.

Also added some missing dependencies that were causing linker failures
in component builds.

BUG=chromium:941663
R=thestig

Change-Id: I7f6786acad857ac62b4bbd8b5a5071147d91f505
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/53910
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 83fc631..f0a6fee 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -129,7 +129,7 @@
   public_configs = [ ":pdfium_public_config" ]
 }
 
-jumbo_static_library("pdfium") {
+jumbo_component("pdfium") {
   sources = [
     "fpdfsdk/fpdf_annot.cpp",
     "fpdfsdk/fpdf_attachment.cpp",
@@ -184,6 +184,8 @@
     "core/fxcrt",
   ]
 
+  defines = [ "FPDF_IMPLEMENTATION" ]
+
   if (pdf_enable_xfa) {
     deps += [
       "fpdfsdk/fpdfxfa",
@@ -212,6 +214,10 @@
     complete_static_lib = true
     configs -= [ "//build/config/compiler:thin_archive" ]
   }
+
+  if (is_component_build) {
+    deps += [ "testing/fuzzers:fuzzer_impls" ]
+  }
 }
 
 # Targets below this are only visible within this file (and to the
@@ -359,6 +365,7 @@
   ]
   deps = [
     ":pdfium",
+    "core/fxcrt",
     "testing/image_diff",
     "//build/win:default_exe_manifest",
   ]
diff --git a/core/fpdfapi/font/BUILD.gn b/core/fpdfapi/font/BUILD.gn
index 1e8c76e..c5ce882 100644
--- a/core/fpdfapi/font/BUILD.gn
+++ b/core/fpdfapi/font/BUILD.gn
@@ -48,6 +48,9 @@
     "../cmaps",
     "../parser",
   ]
+  if (is_mac) {
+    libs = [ "CoreFoundation.framework" ]
+  }
   allow_circular_includes_from = [
     "../../fxge",
     "../cmaps",
diff --git a/core/fxge/BUILD.gn b/core/fxge/BUILD.gn
index 6c9ed9a..83374cc 100644
--- a/core/fxge/BUILD.gn
+++ b/core/fxge/BUILD.gn
@@ -168,6 +168,7 @@
       "apple/fx_mac_imp.cpp",
       "apple/fx_quartz_device.cpp",
     ]
+    libs = [ "CoreGraphics.framework" ]
   }
 
   if (is_win) {
diff --git a/public/fpdfview.h b/public/fpdfview.h
index 8892da5..f521259 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -154,12 +154,29 @@
 // Dictionary value types.
 typedef int FPDF_OBJECT_TYPE;
 
-#if defined(_WIN32) && defined(FPDFSDK_EXPORTS)
-// On Windows system, functions are exported in a DLL
+#if defined(COMPONENT_BUILD)
+// FPDF_EXPORT should be consistent with |export| in the pdfium_fuzzer
+// template in testing/fuzzers/BUILD.gn.
+#if defined(WIN32)
+#if defined(FPDF_IMPLEMENTATION)
 #define FPDF_EXPORT __declspec(dllexport)
-#define FPDF_CALLCONV __stdcall
+#else
+#define FPDF_EXPORT __declspec(dllimport)
+#endif  // defined(FPDF_IMPLEMENTATION)
+#else
+#if defined(FPDF_IMPLEMENTATION)
+#define FPDF_EXPORT __attribute__((visibility("default")))
 #else
 #define FPDF_EXPORT
+#endif  // defined(FPDF_IMPLEMENTATION)
+#endif  // defined(WIN32)
+#else
+#define FPDF_EXPORT
+#endif  // defined(COMPONENT_BUILD)
+
+#if defined(WIN32) && defined(FPDFSDK_EXPORTS)
+#define FPDF_CALLCONV __stdcall
+#else
 #define FPDF_CALLCONV
 #endif
 
diff --git a/testing/fuzzers/BUILD.gn b/testing/fuzzers/BUILD.gn
index 0dbbccc..c2b501f 100644
--- a/testing/fuzzers/BUILD.gn
+++ b/testing/fuzzers/BUILD.gn
@@ -15,56 +15,74 @@
   include_dirs = [ "../.." ]
 }
 
+# "pdfium_fuzzer"s (which may depend on PDFium internals) should be added to
+# |fuzzer_list|.  "pdfium_public_fuzzer"s (which can only depend on PDFium's
+# public API) should be added to |public_fuzzer_list|.
+fuzzer_list = [
+  "pdf_cmap_fuzzer",
+  "pdf_codec_a85_fuzzer",
+  "pdf_codec_fax_fuzzer",
+  "pdf_codec_icc_fuzzer",
+  "pdf_codec_jbig2_fuzzer",
+  "pdf_codec_rle_fuzzer",
+  "pdf_font_fuzzer",
+  "pdf_hint_table_fuzzer",
+  "pdf_jpx_fuzzer",
+  "pdf_psengine_fuzzer",
+  "pdf_streamparser_fuzzer",
+  "pdf_xml_fuzzer",
+]
+public_fuzzer_list = [ "pdfium_fuzzer" ]
+if (pdf_enable_v8) {
+  fuzzer_list += [
+    "pdf_cjs_util_fuzzer",
+    "pdf_fx_date_helpers_fuzzer",
+  ]
+  if (pdf_enable_xfa) {
+    fuzzer_list += [
+      "pdf_bidi_fuzzer",
+      "pdf_cfgas_stringformatter_fuzzer",
+      "pdf_cfx_barcode_fuzzer",
+      "pdf_codec_jpeg_fuzzer",
+      "pdf_css_fuzzer",
+      "pdf_fm2js_fuzzer",
+      "pdf_formcalc_fuzzer",
+    ]
+    public_fuzzer_list += [
+      "pdf_formcalc_context_fuzzer",
+      "pdfium_xfa_fuzzer",
+    ]
+    if (pdf_enable_xfa_bmp) {
+      fuzzer_list += [ "pdf_codec_bmp_fuzzer" ]
+    }
+    if (pdf_enable_xfa_gif) {
+      fuzzer_list += [
+        "pdf_codec_gif_fuzzer",
+        "pdf_lzw_fuzzer",
+      ]
+    }
+    if (pdf_enable_xfa_png) {
+      fuzzer_list += [ "pdf_codec_png_fuzzer" ]
+    }
+    if (pdf_enable_xfa_tiff) {
+      fuzzer_list += [ "pdf_codec_tiff_fuzzer" ]
+    }
+  }
+}
+
 group("fuzzers") {
   testonly = true
-  deps = [
-    ":pdf_cmap_fuzzer_src",
-    ":pdf_codec_a85_fuzzer_src",
-    ":pdf_codec_fax_fuzzer_src",
-    ":pdf_codec_icc_fuzzer_src",
-    ":pdf_codec_jbig2_fuzzer_src",
-    ":pdf_codec_rle_fuzzer_src",
-    ":pdf_font_fuzzer_src",
-    ":pdf_hint_table_fuzzer_src",
-    ":pdf_jpx_fuzzer_src",
-    ":pdf_psengine_fuzzer_src",
-    ":pdf_streamparser_fuzzer_src",
-    ":pdf_xml_fuzzer_src",
-    ":pdfium_fuzzer_src",
-  ]
-  if (pdf_enable_v8) {
-    deps += [
-      ":pdf_cjs_util_fuzzer_src",
-      ":pdf_fx_date_helpers_fuzzer_src",
-    ]
+  deps = []
+  foreach(fuzzer, fuzzer_list + public_fuzzer_list) {
+    deps += [ ":${fuzzer}_src" ]
+  }
+}
 
-    if (pdf_enable_xfa) {
-      deps += [
-        ":pdf_bidi_fuzzer_src",
-        ":pdf_cfgas_stringformatter_fuzzer_src",
-        ":pdf_cfx_barcode_fuzzer_src",
-        ":pdf_codec_jpeg_fuzzer_src",
-        ":pdf_css_fuzzer_src",
-        ":pdf_fm2js_fuzzer_src",
-        ":pdf_formcalc_context_fuzzer_src",
-        ":pdf_formcalc_fuzzer_src",
-        ":pdfium_xfa_fuzzer_src",
-      ]
-      if (pdf_enable_xfa_bmp) {
-        deps += [ ":pdf_codec_bmp_fuzzer_src" ]
-      }
-      if (pdf_enable_xfa_gif) {
-        deps += [
-          ":pdf_codec_gif_fuzzer_src",
-          ":pdf_lzw_fuzzer_src",
-        ]
-      }
-      if (pdf_enable_xfa_png) {
-        deps += [ ":pdf_codec_png_fuzzer_src" ]
-      }
-      if (pdf_enable_xfa_tiff) {
-        deps += [ ":pdf_codec_tiff_fuzzer_src" ]
-      }
+if (is_component_build) {
+  group("fuzzer_impls") {
+    deps = []
+    foreach(fuzzer, fuzzer_list) {
+      deps += [ ":${fuzzer}_impl" ]
     }
   }
 }
@@ -75,12 +93,18 @@
     "pdfium_fuzzer_util.h",
   ]
 
-  testonly = true
   include_dirs = [ "../.." ]
+
+  # In component builds, the pdfium target (which is not testonly) depends on
+  # the fuzzer sources, which may depend on this target, so add testonly only in
+  # non-component builds.
+  if (!is_component_build) {
+    testonly = true
+  }
 }
 
 template("pdfium_public_fuzzer") {
-  jumbo_source_set(target_name) {
+  jumbo_source_set(target_name + "_src") {
     sources = invoker.sources + [
                 "pdfium_fuzzer_helper.cc",
                 "pdfium_fuzzer_helper.h",
@@ -109,15 +133,36 @@
 }
 
 template("pdfium_fuzzer") {
-  jumbo_source_set(target_name) {
-    sources = invoker.sources + [ "pdf_fuzzer_init.cc" ]
-    deps = [
-      "../../:pdfium",
-    ]
+  if (is_component_build) {
+    # In component builds, fuzzers are split into "_impl" and "_src" targets.
+    # The "_impl" target exports the fuzzer implementation and gets statically
+    # linked into the PDFium shared library.  The "_src" target is a thin
+    # wrapper that imports the fuzzer from PDFium; this gets linked into the
+    # real fuzzer executable.  In static builds, there's only a single "_src"
+    # target that contains the implementation and statically links in PDFium.
+    impl_name = target_name + "_impl"
+    template_target_name = target_name
+    jumbo_source_set("${target_name}_src") {
+      testonly = true
+      sources = [
+        "component_fuzzer_template.cc",
+        "pdf_fuzzer_init.cc",
+      ]
+      deps = [
+        "../../:pdfium",
+      ]
+      configs += [ ":fuzzer_config" ]
+      defines = [ "FUZZER_IMPL=${template_target_name}" ]
+    }
+  } else {
+    impl_name = target_name + "_src"
+  }
+  jumbo_source_set(impl_name) {
+    sources = invoker.sources
+    deps = []
     if (defined(invoker.deps)) {
       deps += invoker.deps
     }
-    testonly = true
     configs -= [ "//build/config/compiler:chromium_code" ]
     configs += [
       "//build/config/compiler:no_chromium_code",
@@ -126,11 +171,27 @@
     if (pdf_enable_v8) {
       configs += [ "//v8:external_startup_data" ]
     }
+    if (is_component_build) {
+      # |export| should be consistent with FPDF_EXPORT In public/fpdfview.h.
+      if (is_win) {
+        export = "__declspec(dllexport)"
+      } else {
+        export = "__attribute__((visibility(\"default\")))"
+      }
+      defines = [
+        "FPDF_IMPLEMENTATION",
+        "LLVMFuzzerTestOneInput=${export} ${template_target_name}",
+      ]
+    } else {
+      sources += [ "pdf_fuzzer_init.cc" ]
+      testonly = true
+      deps += [ "../../:pdfium" ]
+    }
   }
 }
 
 if (pdf_enable_v8) {
-  pdfium_fuzzer("pdf_cjs_util_fuzzer_src") {
+  pdfium_fuzzer("pdf_cjs_util_fuzzer") {
     sources = [
       "pdf_cjs_util_fuzzer.cc",
     ]
@@ -138,7 +199,7 @@
       "../../fxjs",
     ]
   }
-  pdfium_fuzzer("pdf_fx_date_helpers_fuzzer_src") {
+  pdfium_fuzzer("pdf_fx_date_helpers_fuzzer") {
     sources = [
       "pdf_fx_date_helpers_fuzzer.cc",
     ]
@@ -148,18 +209,20 @@
   }
 
   if (pdf_enable_xfa) {
-    pdfium_fuzzer("pdf_bidi_fuzzer_src") {
+    pdfium_fuzzer("pdf_bidi_fuzzer") {
       sources = [
         "pdf_bidi_fuzzer.cc",
       ]
       deps = [
+        "../../:freetype_common",
         "../../core/fxge",
         "../../xfa/fgas",
         "../../xfa/fgas/layout",
+        "//third_party/icu:icuuc",
       ]
     }
 
-    pdfium_fuzzer("pdf_cfgas_stringformatter_fuzzer_src") {
+    pdfium_fuzzer("pdf_cfgas_stringformatter_fuzzer") {
       sources = [
         "pdf_cfgas_stringformatter_fuzzer.cc",
       ]
@@ -169,23 +232,23 @@
       ]
     }
 
-    pdfium_fuzzer("pdf_cfx_barcode_fuzzer_src") {
+    pdfium_fuzzer("pdf_cfx_barcode_fuzzer") {
       sources = [
         "pdf_cfx_barcode_fuzzer.cc",
       ]
       deps = [
         "../../xfa/fwl",
+        "//third_party/icu:icuuc",
       ]
     }
 
     if (pdf_enable_xfa_bmp) {
-      pdfium_fuzzer("pdf_codec_bmp_fuzzer_src") {
+      pdfium_fuzzer("pdf_codec_bmp_fuzzer") {
         sources = [
           "pdf_codec_bmp_fuzzer.cc",
           "xfa_codec_fuzzer.h",
         ]
         deps = [
-          "../:test_support",
           "../../core/fxcodec",
           "../../core/fxge",
         ]
@@ -193,19 +256,18 @@
     }
 
     if (pdf_enable_xfa_gif) {
-      pdfium_fuzzer("pdf_codec_gif_fuzzer_src") {
+      pdfium_fuzzer("pdf_codec_gif_fuzzer") {
         sources = [
           "pdf_codec_gif_fuzzer.cc",
           "xfa_codec_fuzzer.h",
         ]
         deps = [
-          "../:test_support",
           "../../core/fxcodec",
           "../../core/fxge",
         ]
       }
 
-      pdfium_fuzzer("pdf_lzw_fuzzer_src") {
+      pdfium_fuzzer("pdf_lzw_fuzzer") {
         sources = [
           "pdf_lzw_fuzzer.cc",
         ]
@@ -215,26 +277,24 @@
       }
     }
 
-    pdfium_fuzzer("pdf_codec_jpeg_fuzzer_src") {
+    pdfium_fuzzer("pdf_codec_jpeg_fuzzer") {
       sources = [
         "pdf_codec_jpeg_fuzzer.cc",
         "xfa_codec_fuzzer.h",
       ]
       deps = [
-        "../:test_support",
         "../../core/fxcodec",
         "../../core/fxge",
       ]
     }
 
     if (pdf_enable_xfa_png) {
-      pdfium_fuzzer("pdf_codec_png_fuzzer_src") {
+      pdfium_fuzzer("pdf_codec_png_fuzzer") {
         sources = [
           "pdf_codec_png_fuzzer.cc",
           "xfa_codec_fuzzer.h",
         ]
         deps = [
-          "../:test_support",
           "../../core/fxcodec",
           "../../core/fxge",
         ]
@@ -242,20 +302,19 @@
     }
 
     if (pdf_enable_xfa_tiff) {
-      pdfium_fuzzer("pdf_codec_tiff_fuzzer_src") {
+      pdfium_fuzzer("pdf_codec_tiff_fuzzer") {
         sources = [
           "pdf_codec_tiff_fuzzer.cc",
           "xfa_codec_fuzzer.h",
         ]
         deps = [
-          "../:test_support",
           "../../core/fxcodec",
           "../../core/fxge",
         ]
       }
     }
 
-    pdfium_fuzzer("pdf_css_fuzzer_src") {
+    pdfium_fuzzer("pdf_css_fuzzer") {
       sources = [
         "pdf_css_fuzzer.cc",
       ]
@@ -264,7 +323,7 @@
       ]
     }
 
-    pdfium_fuzzer("pdf_fm2js_fuzzer_src") {
+    pdfium_fuzzer("pdf_fm2js_fuzzer") {
       sources = [
         "pdf_fm2js_fuzzer.cc",
       ]
@@ -273,18 +332,19 @@
       ]
     }
 
-    pdfium_public_fuzzer("pdf_formcalc_context_fuzzer_src") {
+    pdfium_public_fuzzer("pdf_formcalc_context_fuzzer") {
       sources = [
         "pdf_formcalc_context_fuzzer.cc",
       ]
       deps = [
+        "../../fpdfsdk",
         "../../fpdfsdk/fpdfxfa",
         "../../fxjs",
         "../../xfa/fxfa",
       ]
     }
 
-    pdfium_fuzzer("pdf_formcalc_fuzzer_src") {
+    pdfium_fuzzer("pdf_formcalc_fuzzer") {
       sources = [
         "pdf_formcalc_fuzzer.cc",
       ]
@@ -293,7 +353,7 @@
       ]
     }
 
-    pdfium_public_fuzzer("pdfium_xfa_fuzzer_src") {
+    pdfium_public_fuzzer("pdfium_xfa_fuzzer") {
       sources = [
         "pdfium_xfa_fuzzer.cc",
       ]
@@ -301,16 +361,17 @@
   }
 }
 
-pdfium_fuzzer("pdf_cmap_fuzzer_src") {
+pdfium_fuzzer("pdf_cmap_fuzzer") {
   sources = [
     "pdf_cmap_fuzzer.cc",
   ]
   deps = [
+    "../../:freetype_common",
     "../../core/fpdfapi/font",
   ]
 }
 
-pdfium_fuzzer("pdf_codec_a85_fuzzer_src") {
+pdfium_fuzzer("pdf_codec_a85_fuzzer") {
   sources = [
     "pdf_codec_a85_fuzzer.cc",
   ]
@@ -319,7 +380,7 @@
   ]
 }
 
-pdfium_fuzzer("pdf_codec_fax_fuzzer_src") {
+pdfium_fuzzer("pdf_codec_fax_fuzzer") {
   sources = [
     "pdf_codec_fax_fuzzer.cc",
   ]
@@ -329,7 +390,7 @@
   ]
 }
 
-pdfium_fuzzer("pdf_codec_icc_fuzzer_src") {
+pdfium_fuzzer("pdf_codec_icc_fuzzer") {
   sources = [
     "pdf_codec_icc_fuzzer.cc",
   ]
@@ -339,7 +400,7 @@
   ]
 }
 
-pdfium_fuzzer("pdf_codec_jbig2_fuzzer_src") {
+pdfium_fuzzer("pdf_codec_jbig2_fuzzer") {
   sources = [
     "pdf_codec_jbig2_fuzzer.cc",
   ]
@@ -351,7 +412,7 @@
   ]
 }
 
-pdfium_fuzzer("pdf_codec_rle_fuzzer_src") {
+pdfium_fuzzer("pdf_codec_rle_fuzzer") {
   sources = [
     "pdf_codec_rle_fuzzer.cc",
   ]
@@ -360,13 +421,13 @@
   ]
 }
 
-pdfium_fuzzer("pdf_font_fuzzer_src") {
+pdfium_fuzzer("pdf_font_fuzzer") {
   sources = [
     "pdf_font_fuzzer.cc",
   ]
 }
 
-pdfium_fuzzer("pdf_hint_table_fuzzer_src") {
+pdfium_fuzzer("pdf_hint_table_fuzzer") {
   sources = [
     "pdf_hint_table_fuzzer.cc",
   ]
@@ -375,7 +436,7 @@
   ]
 }
 
-pdfium_fuzzer("pdf_jpx_fuzzer_src") {
+pdfium_fuzzer("pdf_jpx_fuzzer") {
   sources = [
     "pdf_jpx_fuzzer.cc",
   ]
@@ -385,7 +446,7 @@
   ]
 }
 
-pdfium_fuzzer("pdf_psengine_fuzzer_src") {
+pdfium_fuzzer("pdf_psengine_fuzzer") {
   sources = [
     "pdf_psengine_fuzzer.cc",
   ]
@@ -394,7 +455,7 @@
   ]
 }
 
-pdfium_fuzzer("pdf_streamparser_fuzzer_src") {
+pdfium_fuzzer("pdf_streamparser_fuzzer") {
   sources = [
     "pdf_streamparser_fuzzer.cc",
   ]
@@ -404,13 +465,13 @@
   ]
 }
 
-pdfium_fuzzer("pdf_xml_fuzzer_src") {
+pdfium_fuzzer("pdf_xml_fuzzer") {
   sources = [
     "pdf_xml_fuzzer.cc",
   ]
 }
 
-pdfium_public_fuzzer("pdfium_fuzzer_src") {
+pdfium_public_fuzzer("pdfium_fuzzer") {
   sources = [
     "pdfium_fuzzer.cc",
   ]
diff --git a/testing/fuzzers/component_fuzzer_template.cc b/testing/fuzzers/component_fuzzer_template.cc
new file mode 100644
index 0000000..7106417
--- /dev/null
+++ b/testing/fuzzers/component_fuzzer_template.cc
@@ -0,0 +1,22 @@
+// Copyright 2019 The PDFium 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 <cstddef>
+#include <cstdint>
+
+// This template is used in component builds to forward to the real fuzzers
+// which are exported from the PDFium shared library.  FUZZER_IMPL is a macro
+// defined at build time that contains the name of the real fuzzer.
+
+#if defined(WIN32)
+#define IMPORT __declspec(dllimport)
+#else
+#define IMPORT
+#endif
+
+extern "C" IMPORT int FUZZER_IMPL(const uint8_t* data, size_t size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  return FUZZER_IMPL(data, size);
+}