diff --git a/gn/toolchain/BUILD.gn b/gn/toolchain/BUILD.gn
index 4517710946..f49d3b9b39 100644
--- a/gn/toolchain/BUILD.gn
+++ b/gn/toolchain/BUILD.gn
@@ -67,7 +67,7 @@ toolchain("msvc") {
   if (target_cpu == "x86") {
     # Toolchain asset includes a script that configures for x86 building.
     # We don't support x86 builds with local MSVC installations.
-    env_setup = "$shell $win_sdk/bin/SetEnv.cmd /x86 && "
+    # env_setup = "$shell $win_sdk/bin/SetEnv.cmd /x86 && "
   } else if (target_cpu == "arm64") {
     # ARM64 compiler is incomplete - it relies on DLLs located in the host toolchain directory.
     env_setup = "$shell set \"PATH=%PATH%;$win_vc\\Tools\\MSVC\\$win_toolchain_version\\bin\\HostX64\\x64\" && "
@@ -201,7 +201,7 @@ toolchain("msvc") {
 
   tool("copy") {
     cp_py = rebase_path("../cp.py")
-    command = "python \"$cp_py\" {{source}} {{output}}"
+    command = "$shell python \"$cp_py\" {{source}} {{output}}"
     description = "copy {{source}} {{output}}"
   }
 }
@@ -341,13 +341,13 @@ template("gcc_like_toolchain") {
 
     tool("copy") {
       cp_py = rebase_path("../cp.py")
-      command = "python \"$cp_py\" {{source}} {{output}}"
+      command = "$shell python \"$cp_py\" {{source}} {{output}}"
       description = "copy {{source}} {{output}}"
     }
 
     tool("copy_bundle_data") {
       cp_py = rebase_path("../cp.py")
-      command = "python \"$cp_py\" {{source}} {{output}}"
+      command = "$shell python \"$cp_py\" {{source}} {{output}}"
       description = "copy_bundle_data {{source}} {{output}}"
     }
 
diff --git a/include/core/SkM44.h b/include/core/SkM44.h
index 63b3ac140b..d32921d96e 100644
--- a/include/core/SkM44.h
+++ b/include/core/SkM44.h
@@ -405,7 +405,7 @@ private:
     friend class SkMatrixPriv;
 };
 
-SkM44 Sk3LookAt(const SkV3& eye, const SkV3& center, const SkV3& up);
-SkM44 Sk3Perspective(float near, float far, float angle);
+SK_API SkM44 Sk3LookAt(const SkV3& eye, const SkV3& center, const SkV3& up);
+SK_API SkM44 Sk3Perspective(float near, float far, float angle);
 
 #endif
diff --git a/include/core/SkString.h b/include/core/SkString.h
index 6f1d972da2..5bee2dc218 100644
--- a/include/core/SkString.h
+++ b/include/core/SkString.h
@@ -270,7 +270,7 @@ private:
 };
 
 /// Creates a new string and writes into it using a printf()-style format.
-SkString SkStringPrintf(const char* format, ...) SK_PRINTF_LIKE(1, 2);
+SK_API SkString SkStringPrintf(const char* format, ...) SK_PRINTF_LIKE(1, 2);
 /// This makes it easier to write a caller as a VAR_ARGS function where the format string is
 /// optional.
 static inline SkString SkStringPrintf() { return SkString(); }
diff --git a/include/private/SkPathRef.h b/include/private/SkPathRef.h
index f9533d7261..41de226110 100644
--- a/include/private/SkPathRef.h
+++ b/include/private/SkPathRef.h
@@ -21,6 +21,7 @@
 
 #include <atomic>
 #include <limits>
+#include <tuple>
 
 class SkRBuffer;
 class SkWBuffer;
diff --git a/include/private/SkThreadID.h b/include/private/SkThreadID.h
index 06b9be7317..ac3d29f825 100644
--- a/include/private/SkThreadID.h
+++ b/include/private/SkThreadID.h
@@ -12,7 +12,7 @@
 
 typedef int64_t SkThreadID;
 
-SkThreadID SkGetThreadID();
+SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID();
 
 const SkThreadID kIllegalThreadID = 0;
 
diff --git a/include/utils/SkCustomTypeface.h b/include/utils/SkCustomTypeface.h
index 61f32afed5..ffe3ad8d34 100644
--- a/include/utils/SkCustomTypeface.h
+++ b/include/utils/SkCustomTypeface.h
@@ -19,7 +19,7 @@
 
 class SkStream;
 
-class SkCustomTypefaceBuilder {
+class SK_API SkCustomTypefaceBuilder {
 public:
     SkCustomTypefaceBuilder();
 
diff --git a/modules/skottie/BUILD.gn b/modules/skottie/BUILD.gn
index dbba5122da..99ac6ab532 100644
--- a/modules/skottie/BUILD.gn
+++ b/modules/skottie/BUILD.gn
@@ -9,6 +9,9 @@ if (skia_enable_skottie) {
   config("public_config") {
     defines = [ "SK_ENABLE_SKOTTIE" ]
     include_dirs = [ "include" ]
+    if (is_component_build) {
+      defines += [ "SKOTTIE_DLL" ]
+    }
   }
 
   component("skottie") {
@@ -24,6 +27,7 @@ if (skia_enable_skottie) {
       "../sksg",
       "../skshaper",
     ]
+    defines = [ "SKOTTIE_IMPLEMENTATION=1" ]
   }
 
   if (defined(is_skia_standalone)) {
diff --git a/modules/skottie/include/ExternalLayer.h b/modules/skottie/include/ExternalLayer.h
index 4513fd5f48..f717b27f87 100644
--- a/modules/skottie/include/ExternalLayer.h
+++ b/modules/skottie/include/ExternalLayer.h
@@ -9,6 +9,7 @@
 #define SkottieExternalLayer_DEFINED
 
 #include "include/core/SkRefCnt.h"
+#include "modules/skottie/include/SkottieConfig.h"
 
 class SkCanvas;
 struct SkSize;
@@ -18,7 +19,7 @@ namespace skottie {
 /**
  * Interface for externally-rendered layers.
  */
-class ExternalLayer : public SkRefCnt {
+class SKOTTIE_API ExternalLayer : public SkRefCnt {
 public:
     /** Render layer content into the given canvas.
      *
@@ -34,7 +35,7 @@ public:
  * Embedders can register interceptors with animation builders, to substitute target layers
  * with arbitrary/externally-controlled content (see ExternalLayer above).
  */
-class PrecompInterceptor : public SkRefCnt {
+class SKOTTIE_API PrecompInterceptor : public SkRefCnt {
 public:
     /**
      * Invoked at animation build time, for each precomp layer.
diff --git a/modules/skottie/include/Skottie.h b/modules/skottie/include/Skottie.h
index c519068b43..f56dc4c3d5 100644
--- a/modules/skottie/include/Skottie.h
+++ b/modules/skottie/include/Skottie.h
@@ -13,6 +13,7 @@
 #include "include/core/SkSize.h"
 #include "include/core/SkString.h"
 #include "include/core/SkTypes.h"
+#include "modules/skottie/include/SkottieConfig.h"
 #include "modules/skottie/include/ExternalLayer.h"
 #include "modules/skottie/include/SkottieProperty.h"
 #include "modules/skresources/include/SkResources.h"
@@ -43,7 +44,7 @@ using ResourceProvider = skresources::ResourceProvider;
 /**
  * A Logger subclass can be used to receive Animation::Builder parsing errors and warnings.
  */
-class SK_API Logger : public SkRefCnt {
+class SKOTTIE_API Logger : public SkRefCnt {
 public:
     enum class Level {
         kWarning,
@@ -56,13 +57,13 @@ public:
 /**
  * Interface for receiving AE composition markers at Animation build time.
  */
-class SK_API MarkerObserver : public SkRefCnt {
+class SKOTTIE_API MarkerObserver : public SkRefCnt {
 public:
     // t0,t1 are in the Animation::seek() domain.
     virtual void onMarker(const char name[], float t0, float t1) = 0;
 };
 
-class SK_API Animation : public SkNVRefCnt<Animation> {
+class SKOTTIE_API Animation : public SkNVRefCnt<Animation> {
 public:
     class Builder final {
     public:
diff --git a/modules/skottie/include/SkottieConfig.h b/modules/skottie/include/SkottieConfig.h
new file mode 100644
index 0000000000..7743f1cd1f
--- /dev/null
+++ b/modules/skottie/include/SkottieConfig.h
@@ -0,0 +1,25 @@
+
+#ifndef SkottieConfig_DEFINED
+#define SkottieConfig_DEFINED
+
+#if !defined(SKOTTIE_IMPLEMENTATION)
+    #define SKOTTIE_IMPLEMENTATION 0
+#endif
+
+#if !defined(SKOTTIE_API)
+    #if defined(SKOTTIE_DLL)
+        #if defined(_MSC_VER)
+            #if SKOTTIE_IMPLEMENTATION
+                #define SKOTTIE_API __declspec(dllexport)
+            #else
+                #define SKOTTIE_API __declspec(dllimport)
+            #endif
+        #else
+            #define SKOTTIE_API __attribute__((visibility("default")))
+        #endif
+    #else
+        #define SKOTTIE_API
+    #endif
+#endif
+
+#endif
diff --git a/modules/skottie/include/SkottieProperty.h b/modules/skottie/include/SkottieProperty.h
index 2355984b86..62fa24da7c 100644
--- a/modules/skottie/include/SkottieProperty.h
+++ b/modules/skottie/include/SkottieProperty.h
@@ -13,6 +13,8 @@
 #include "include/core/SkRefCnt.h"
 #include "include/core/SkTypeface.h"
 #include "include/utils/SkTextUtils.h"
+
+#include "modules/skottie/include/SkottieConfig.h"
 #include "modules/skottie/src/text/SkottieShaper.h"
 
 #include <functional>
@@ -31,7 +33,7 @@ namespace skottie {
 using ColorPropertyValue   = SkColor;
 using OpacityPropertyValue = float;
 
-struct TextPropertyValue {
+struct SKOTTIE_API TextPropertyValue {
     sk_sp<SkTypeface>    fTypeface;
     SkString             fText;
     float                fTextSize    = 0,
@@ -51,7 +53,7 @@ struct TextPropertyValue {
     bool operator!=(const TextPropertyValue& other) const;
 };
 
-struct TransformPropertyValue {
+struct SKOTTIE_API TransformPropertyValue {
     SkPoint  fAnchorPoint,
              fPosition;
     SkVector fScale;
@@ -70,7 +72,7 @@ namespace internal { class AnimationBuilder; }
  * and the internal scene-graph representation.
  */
 template <typename ValueT, typename NodeT>
-class SK_API PropertyHandle final {
+class PropertyHandle final {
 public:
     explicit PropertyHandle(sk_sp<NodeT> node) : fNode(std::move(node)) {}
     ~PropertyHandle();
@@ -106,7 +108,7 @@ using TransformPropertyHandle = PropertyHandle<TransformPropertyValue,
  * various properties of layer and shape nodes.  The |node_name| argument corresponds to the
  * name ("nm") node property.
  */
-class SK_API PropertyObserver : public SkRefCnt {
+class SKOTTIE_API PropertyObserver : public SkRefCnt {
 public:
     template <typename T>
     using LazyHandle = std::function<std::unique_ptr<T>()>;
diff --git a/modules/skottie/skottie.gni b/modules/skottie/skottie.gni
index 3b64e1dac6..685998e4a7 100644
--- a/modules/skottie/skottie.gni
+++ b/modules/skottie/skottie.gni
@@ -8,6 +8,7 @@ _src = get_path_info("src", "abspath")
 _include = get_path_info("include", "abspath")
 
 skia_skottie_public = [
+  "$_include/SkottieConfig.h",
   "$_include/Skottie.h",
   "$_include/ExternalLayer.h",
   "$_include/SkottieProperty.h",
diff --git a/modules/skparagraph/BUILD.gn b/modules/skparagraph/BUILD.gn
index 48e09296c8..6b3bdc17d9 100644
--- a/modules/skparagraph/BUILD.gn
+++ b/modules/skparagraph/BUILD.gn
@@ -15,6 +15,9 @@ if (skia_enable_skparagraph) {
       "include",
       "utils",
     ]
+    if (is_component_build) {
+      defines = [ "SKPARAGRAPH_DLL" ]
+    }
   }
 
   component("skparagraph") {
@@ -32,6 +35,7 @@ if (skia_enable_skparagraph) {
       "../skshaper",
       "//third_party/icu",
     ]
+    defines = [ "SKPARAGRAPH_IMPLEMENTATION=1" ]
   }
 
   config("utils_config") {
diff --git a/modules/skparagraph/include/DartTypes.h b/modules/skparagraph/include/DartTypes.h
index 415d5dfa72..efe3ee93e9 100644
--- a/modules/skparagraph/include/DartTypes.h
+++ b/modules/skparagraph/include/DartTypes.h
@@ -5,6 +5,7 @@
 
 #include "include/core/SkRect.h"
 #include "include/core/SkTypes.h"
+#include "modules/skparagraph/include/SkParagraphConfig.h"
 
 #include <iterator>
 #include <limits>
diff --git a/modules/skparagraph/include/FontCollection.h b/modules/skparagraph/include/FontCollection.h
index f7336286a8..cc1a56569e 100644
--- a/modules/skparagraph/include/FontCollection.h
+++ b/modules/skparagraph/include/FontCollection.h
@@ -7,6 +7,7 @@
 #include "include/core/SkFontMgr.h"
 #include "include/core/SkRefCnt.h"
 #include "include/private/SkTHash.h"
+#include "modules/skparagraph/include/SkParagraphConfig.h"
 #include "modules/skparagraph/include/ParagraphCache.h"
 #include "modules/skparagraph/include/TextStyle.h"
 
@@ -15,7 +16,7 @@ namespace textlayout {
 
 class TextStyle;
 class Paragraph;
-class FontCollection : public SkRefCnt {
+class SKPARAGRAPH_API FontCollection : public SkRefCnt {
 public:
     FontCollection();
 
diff --git a/modules/skparagraph/include/Metrics.h b/modules/skparagraph/include/Metrics.h
index 49e944437f..e1c58a6e54 100644
--- a/modules/skparagraph/include/Metrics.h
+++ b/modules/skparagraph/include/Metrics.h
@@ -3,6 +3,7 @@
 #define Metrics_DEFINED
 
 #include <map>
+#include "modules/skparagraph/include/SkParagraphConfig.h"
 #include "modules/skparagraph/include/TextStyle.h"
 
 namespace skia {
diff --git a/modules/skparagraph/include/Paragraph.h b/modules/skparagraph/include/Paragraph.h
index 4e99931830..124ba45cf2 100644
--- a/modules/skparagraph/include/Paragraph.h
+++ b/modules/skparagraph/include/Paragraph.h
@@ -2,6 +2,7 @@
 #ifndef Paragraph_DEFINED
 #define Paragraph_DEFINED
 
+#include "modules/skparagraph/include/SkParagraphConfig.h"
 #include "modules/skparagraph/include/FontCollection.h"
 #include "modules/skparagraph/include/Metrics.h"
 #include "modules/skparagraph/include/ParagraphStyle.h"
@@ -12,7 +13,7 @@ class SkCanvas;
 namespace skia {
 namespace textlayout {
 
-class Paragraph {
+class SKPARAGRAPH_API Paragraph {
 
 public:
     Paragraph(ParagraphStyle style, sk_sp<FontCollection> fonts);
diff --git a/modules/skparagraph/include/ParagraphBuilder.h b/modules/skparagraph/include/ParagraphBuilder.h
index 29c061da7c..f4f614b974 100644
--- a/modules/skparagraph/include/ParagraphBuilder.h
+++ b/modules/skparagraph/include/ParagraphBuilder.h
@@ -6,6 +6,7 @@
 #include <stack>
 #include <string>
 #include <tuple>
+#include "modules/skparagraph/include/SkParagraphConfig.h"
 #include "modules/skparagraph/include/FontCollection.h"
 #include "modules/skparagraph/include/Paragraph.h"
 #include "modules/skparagraph/include/ParagraphStyle.h"
diff --git a/modules/skparagraph/include/ParagraphCache.h b/modules/skparagraph/include/ParagraphCache.h
index 1d477a1b13..6ad9ab2bc7 100644
--- a/modules/skparagraph/include/ParagraphCache.h
+++ b/modules/skparagraph/include/ParagraphCache.h
@@ -3,6 +3,7 @@
 #define ParagraphCache_DEFINED
 
 #include "include/private/SkMutex.h"
+#include "modules/skparagraph/include/SkParagraphConfig.h"
 #include "src/core/SkLRUCache.h"
 #include <functional>  // std::function
 
@@ -27,7 +28,7 @@ class ParagraphCacheValue;
 
 bool operator==(const ParagraphCacheKey& a, const ParagraphCacheKey& b);
 
-class ParagraphCache {
+class SKPARAGRAPH_API ParagraphCache {
 public:
     ParagraphCache();
     ~ParagraphCache();
diff --git a/modules/skparagraph/include/ParagraphStyle.h b/modules/skparagraph/include/ParagraphStyle.h
index 682bae07d0..43ae5b77c0 100644
--- a/modules/skparagraph/include/ParagraphStyle.h
+++ b/modules/skparagraph/include/ParagraphStyle.h
@@ -5,6 +5,7 @@
 #include "include/core/SkFontStyle.h"
 #include "include/core/SkScalar.h"
 #include "include/core/SkString.h"
+#include "modules/skparagraph/include/SkParagraphConfig.h"
 #include "modules/skparagraph/include/DartTypes.h"
 #include "modules/skparagraph/include/TextStyle.h"
 
@@ -18,7 +19,7 @@
 namespace skia {
 namespace textlayout {
 
-struct StrutStyle {
+struct SKPARAGRAPH_API StrutStyle {
     StrutStyle();
 
     const std::vector<SkString>& getFontFamilies() const { return fFontFamilies; }
@@ -68,7 +69,7 @@ private:
     bool fHeightOverride;
 };
 
-struct ParagraphStyle {
+struct SKPARAGRAPH_API ParagraphStyle {
     ParagraphStyle();
 
     bool operator==(const ParagraphStyle& rhs) const {
diff --git a/modules/skparagraph/include/SkParagraphConfig.h b/modules/skparagraph/include/SkParagraphConfig.h
new file mode 100644
index 0000000000..a079bd9d6e
--- /dev/null
+++ b/modules/skparagraph/include/SkParagraphConfig.h
@@ -0,0 +1,25 @@
+
+#ifndef SkParagraphConfig_DEFINED
+#define SkParagraphConfig_DEFINED
+
+#if !defined(SKPARAGRAPH_IMPLEMENTATION)
+    #define SKPARAGRAPH_IMPLEMENTATION 0
+#endif
+
+#if !defined(SKPARAGRAPH_API)
+    #if defined(SKPARAGRAPH_DLL)
+        #if defined(_MSC_VER)
+            #if SKPARAGRAPH_IMPLEMENTATION
+                #define SKPARAGRAPH_API __declspec(dllexport)
+            #else
+                #define SKPARAGRAPH_API __declspec(dllimport)
+            #endif
+        #else
+            #define SKPARAGRAPH_API __attribute__((visibility("default")))
+        #endif
+    #else
+        #define SKPARAGRAPH_API
+    #endif
+#endif
+
+#endif
diff --git a/modules/skparagraph/include/TextShadow.h b/modules/skparagraph/include/TextShadow.h
index a580b9c370..77e0a23510 100644
--- a/modules/skparagraph/include/TextShadow.h
+++ b/modules/skparagraph/include/TextShadow.h
@@ -4,11 +4,12 @@
 
 #include "include/core/SkColor.h"
 #include "include/core/SkPoint.h"
+#include "modules/skparagraph/include/SkParagraphConfig.h"
 
 namespace skia {
 namespace textlayout {
 
-class TextShadow {
+class SKPARAGRAPH_API TextShadow {
 public:
     SkColor fColor = SK_ColorBLACK;
     SkPoint fOffset;
diff --git a/modules/skparagraph/include/TextStyle.h b/modules/skparagraph/include/TextStyle.h
index b1feaa4d60..44df43363b 100644
--- a/modules/skparagraph/include/TextStyle.h
+++ b/modules/skparagraph/include/TextStyle.h
@@ -9,6 +9,7 @@
 #include "include/core/SkFontStyle.h"
 #include "include/core/SkPaint.h"
 #include "include/core/SkScalar.h"
+#include "modules/skparagraph/include/SkParagraphConfig.h"
 #include "modules/skparagraph/include/DartTypes.h"
 #include "modules/skparagraph/include/TextShadow.h"
 
@@ -151,7 +152,7 @@ struct PlaceholderStyle {
     SkScalar fBaselineOffset;
 };
 
-class TextStyle {
+class SKPARAGRAPH_API TextStyle {
 public:
     TextStyle();
     TextStyle(const TextStyle& other, bool placeholder);
diff --git a/modules/skparagraph/include/TypefaceFontProvider.h b/modules/skparagraph/include/TypefaceFontProvider.h
index 727659d85d..15e9c9407a 100644
--- a/modules/skparagraph/include/TypefaceFontProvider.h
+++ b/modules/skparagraph/include/TypefaceFontProvider.h
@@ -10,11 +10,13 @@
 #include "include/core/SkFontMgr.h"
 #include "include/core/SkStream.h"
 #include "include/core/SkString.h"
+#include "modules/skparagraph/include/SkParagraphConfig.h"
+#include "modules/skparagraph/include/Paragraph.h"
 
 namespace skia {
 namespace textlayout {
 
-class TypefaceFontStyleSet : public SkFontStyleSet {
+class SKPARAGRAPH_API TypefaceFontStyleSet : public SkFontStyleSet {
 public:
     explicit TypefaceFontStyleSet(const SkString& familyName);
 
@@ -33,7 +35,7 @@ private:
     SkString fAlias;
 };
 
-class TypefaceFontProvider : public SkFontMgr {
+class SKPARAGRAPH_API TypefaceFontProvider : public SkFontMgr {
 public:
     size_t registerTypeface(sk_sp<SkTypeface> typeface);
     size_t registerTypeface(sk_sp<SkTypeface> typeface, const SkString& alias);
diff --git a/modules/skparagraph/skparagraph.gni b/modules/skparagraph/skparagraph.gni
index 0221d78680..ed4594fc55 100644
--- a/modules/skparagraph/skparagraph.gni
+++ b/modules/skparagraph/skparagraph.gni
@@ -6,6 +6,7 @@ _include = get_path_info("include", "abspath")
 _utils = get_path_info("utils", "abspath")
 
 skparagraph_public = [
+  "$_include/SkParagraphConfig.h",
   "$_include/ParagraphStyle.h",
   "$_include/TextStyle.h",
   "$_include/TextShadow.h",
diff --git a/modules/skresources/include/SkResources.h b/modules/skresources/include/SkResources.h
index c5bdb81dfa..af6b2baa36 100644
--- a/modules/skresources/include/SkResources.h
+++ b/modules/skresources/include/SkResources.h
@@ -26,7 +26,7 @@ namespace skresources {
 /**
  * Image asset proxy interface.
  */
-class SK_API ImageAsset : public SkRefCnt {
+class ImageAsset : public SkRefCnt {
 public:
     /**
      * Returns true if the image asset is animated.
@@ -75,7 +75,7 @@ private:
  * ResourceProvider is an interface that lets rich-content modules defer loading of external
  * resources (images, fonts, etc.) to embedding clients.
  */
-class SK_API ResourceProvider : public SkRefCnt {
+class ResourceProvider : public SkRefCnt {
 public:
     /**
      * Load a generic resource (currently only nested animations) specified by |path| + |name|,
diff --git a/modules/sksg/BUILD.gn b/modules/sksg/BUILD.gn
index 3bf998b173..0ca969729a 100644
--- a/modules/sksg/BUILD.gn
+++ b/modules/sksg/BUILD.gn
@@ -7,6 +7,9 @@ import("../../gn/skia.gni")
 
 config("public_config") {
   include_dirs = [ "include" ]
+  if (is_component_build) {
+    defines = [ "SKSG_DLL" ]
+  }
 }
 
 component("sksg") {
@@ -16,6 +19,7 @@ component("sksg") {
   sources = skia_sksg_sources
   configs += [ "../../:skia_private" ]
   deps = [ "../..:skia" ]
+  defines = [ "SKSG_IMPLEMENTATION=1" ]
 }
 
 if (defined(is_skia_standalone) && skia_enable_tools) {
diff --git a/modules/sksg/include/SkSGClipEffect.h b/modules/sksg/include/SkSGClipEffect.h
index 6614c6a404..203165b64d 100644
--- a/modules/sksg/include/SkSGClipEffect.h
+++ b/modules/sksg/include/SkSGClipEffect.h
@@ -18,7 +18,7 @@ class GeometryNode;
  * Concrete Effect node, applying a clip to its descendants.
  *
  */
-class ClipEffect final : public EffectNode {
+class SKSG_API ClipEffect final : public EffectNode {
 public:
     static sk_sp<ClipEffect> Make(sk_sp<RenderNode> child, sk_sp<GeometryNode> clip,
                                   bool aa = false) {
diff --git a/modules/sksg/include/SkSGColorFilter.h b/modules/sksg/include/SkSGColorFilter.h
index a10882127a..4fa3af0296 100644
--- a/modules/sksg/include/SkSGColorFilter.h
+++ b/modules/sksg/include/SkSGColorFilter.h
@@ -23,7 +23,7 @@ class Color;
 /**
  * Base class for nodes which apply a color filter when rendering their descendants.
  */
-class ColorFilter : public EffectNode {
+class SKSG_API ColorFilter : public EffectNode {
 protected:
     explicit ColorFilter(sk_sp<RenderNode>);
 
@@ -45,7 +45,7 @@ private:
  *
  * Allows attaching non-sksg color filters to the render tree.
  */
-class ExternalColorFilter final : public EffectNode {
+class SKSG_API ExternalColorFilter final : public EffectNode {
 public:
     static sk_sp<ExternalColorFilter> Make(sk_sp<RenderNode> child);
 
@@ -67,7 +67,7 @@ private:
 /**
  * Concrete SkModeColorFilter Effect node.
  */
-class ModeColorFilter final : public ColorFilter {
+class SKSG_API ModeColorFilter final : public ColorFilter {
 public:
     ~ModeColorFilter() override;
 
@@ -92,7 +92,7 @@ private:
  * based on input luminance (where the colors are evenly distributed across the luminance domain),
  * then mixes with the input based on weight.  Leaves alpha unchanged.
  */
-class GradientColorFilter final : public ColorFilter {
+class SKSG_API GradientColorFilter final : public ColorFilter {
 public:
     ~GradientColorFilter() override;
 
diff --git a/modules/sksg/include/SkSGDashEffect.h b/modules/sksg/include/SkSGDashEffect.h
index 341e71e5fb..b781a271ce 100644
--- a/modules/sksg/include/SkSGDashEffect.h
+++ b/modules/sksg/include/SkSGDashEffect.h
@@ -22,7 +22,7 @@ namespace  sksg {
  * intervals is odd, they are repeated once more to attain an even sequence (same as SVG
  * stroke-dasharray: https://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty).
  */
-class DashEffect final : public GeometryNode {
+class SKSG_API DashEffect final : public GeometryNode {
 public:
     static sk_sp<DashEffect> Make(sk_sp<GeometryNode> child) {
         return child ? sk_sp<DashEffect>(new DashEffect(std::move(child))) : nullptr;
diff --git a/modules/sksg/include/SkSGDraw.h b/modules/sksg/include/SkSGDraw.h
index 0889ebfde7..4e6bed337f 100644
--- a/modules/sksg/include/SkSGDraw.h
+++ b/modules/sksg/include/SkSGDraw.h
@@ -21,7 +21,7 @@ namespace sksg {
  *
  * Think Skia SkCanvas::drawFoo(foo, paint) calls.
  */
-class Draw : public RenderNode {
+class SKSG_API Draw : public RenderNode {
 public:
     static sk_sp<Draw> Make(sk_sp<GeometryNode> geo, sk_sp<PaintNode> paint) {
         return (geo && paint) ? sk_sp<Draw>(new Draw(std::move(geo), std::move(paint))) : nullptr;
diff --git a/modules/sksg/include/SkSGEffectNode.h b/modules/sksg/include/SkSGEffectNode.h
index 005a99c9ea..c6af119a1b 100644
--- a/modules/sksg/include/SkSGEffectNode.h
+++ b/modules/sksg/include/SkSGEffectNode.h
@@ -18,7 +18,7 @@ namespace sksg {
  *
  * This includes transforms, clipping, filters, etc.
  */
-class EffectNode : public RenderNode {
+class SKSG_API EffectNode : public RenderNode {
 protected:
     explicit EffectNode(sk_sp<RenderNode>, uint32_t inval_traits = 0);
     ~EffectNode() override;
diff --git a/modules/sksg/include/SkSGGeometryNode.h b/modules/sksg/include/SkSGGeometryNode.h
index d9d4e8ddec..88da3b657d 100644
--- a/modules/sksg/include/SkSGGeometryNode.h
+++ b/modules/sksg/include/SkSGGeometryNode.h
@@ -22,7 +22,7 @@ namespace sksg {
  *
  * Think SkRect, SkPath, etc.
  */
-class GeometryNode : public Node {
+class SKSG_API GeometryNode : public Node {
 public:
     void clip(SkCanvas*, bool antiAlias) const;
     void draw(SkCanvas*, const SkPaint&) const;
diff --git a/modules/sksg/include/SkSGGeometryTransform.h b/modules/sksg/include/SkSGGeometryTransform.h
index 400ab8a069..b7d8ddfe6e 100644
--- a/modules/sksg/include/SkSGGeometryTransform.h
+++ b/modules/sksg/include/SkSGGeometryTransform.h
@@ -21,7 +21,7 @@ class Transform;
 /**
  * Concrete Effect node, binding a Matrix to a GeometryNode.
  */
-class GeometryTransform final : public GeometryNode {
+class SKSG_API GeometryTransform final : public GeometryNode {
 public:
     static sk_sp<GeometryTransform> Make(sk_sp<GeometryNode> child, sk_sp<Transform> transform) {
         return child && transform
diff --git a/modules/sksg/include/SkSGGradient.h b/modules/sksg/include/SkSGGradient.h
index f76c7b836d..e0130007b4 100644
--- a/modules/sksg/include/SkSGGradient.h
+++ b/modules/sksg/include/SkSGGradient.h
@@ -22,7 +22,7 @@ namespace sksg {
 /**
  * Gradient base class.
  */
-class Gradient : public Shader {
+class SKSG_API Gradient : public Shader {
 public:
     struct ColorStop {
         SkScalar  fPosition;
@@ -52,7 +52,7 @@ private:
     using INHERITED = Shader;
 };
 
-class LinearGradient final : public Gradient {
+class SKSG_API LinearGradient final : public Gradient {
 public:
     static sk_sp<LinearGradient> Make() {
         return sk_sp<LinearGradient>(new LinearGradient());
@@ -74,7 +74,7 @@ private:
     using INHERITED = Gradient;
 };
 
-class RadialGradient final : public Gradient {
+class SKSG_API RadialGradient final : public Gradient {
 public:
     static sk_sp<RadialGradient> Make() {
         return sk_sp<RadialGradient>(new RadialGradient());
diff --git a/modules/sksg/include/SkSGGroup.h b/modules/sksg/include/SkSGGroup.h
index 085f7a66ab..1a612bb69d 100644
--- a/modules/sksg/include/SkSGGroup.h
+++ b/modules/sksg/include/SkSGGroup.h
@@ -17,7 +17,7 @@ namespace sksg {
 /**
  * Concrete node, grouping together multiple descendants.
  */
-class Group : public RenderNode {
+class SKSG_API Group : public RenderNode {
 public:
     static sk_sp<Group> Make() {
         return sk_sp<Group>(new Group(std::vector<sk_sp<RenderNode>>()));
diff --git a/modules/sksg/include/SkSGImage.h b/modules/sksg/include/SkSGImage.h
index 178662a0c5..8e841bb49a 100644
--- a/modules/sksg/include/SkSGImage.h
+++ b/modules/sksg/include/SkSGImage.h
@@ -20,7 +20,7 @@ namespace sksg {
  * Concrete rendering node, wrapping an SkImage.
  *
  */
-class Image final : public RenderNode {
+class SKSG_API Image final : public RenderNode {
 public:
     static sk_sp<Image> Make(sk_sp<SkImage> image) {
         return sk_sp<Image>(new Image(std::move(image)));
diff --git a/modules/sksg/include/SkSGInvalidationController.h b/modules/sksg/include/SkSGInvalidationController.h
index df496ba68a..1269fcf42d 100644
--- a/modules/sksg/include/SkSGInvalidationController.h
+++ b/modules/sksg/include/SkSGInvalidationController.h
@@ -10,6 +10,7 @@
 
 #include "include/core/SkMatrix.h"
 #include "include/core/SkTypes.h"
+#include "modules/sksg/include/SkSGNode.h"
 
 #include <vector>
 
@@ -22,7 +23,7 @@ namespace sksg {
  *
  * Tracks dirty regions for repaint.
  */
-class InvalidationController {
+class SKSG_API InvalidationController {
 public:
     InvalidationController();
     InvalidationController(const InvalidationController&) = delete;
diff --git a/modules/sksg/include/SkSGMaskEffect.h b/modules/sksg/include/SkSGMaskEffect.h
index 4497297f21..0ddabe8370 100644
--- a/modules/sksg/include/SkSGMaskEffect.h
+++ b/modules/sksg/include/SkSGMaskEffect.h
@@ -16,7 +16,7 @@ namespace sksg {
  * Concrete Effect node, applying a mask to its descendants.
  *
  */
-class MaskEffect final : public EffectNode {
+class SKSG_API MaskEffect final : public EffectNode {
 public:
     enum class Mode : uint32_t {
         kAlphaNormal,
diff --git a/modules/sksg/include/SkSGMerge.h b/modules/sksg/include/SkSGMerge.h
index 95993605df..2e5a2c62a7 100644
--- a/modules/sksg/include/SkSGMerge.h
+++ b/modules/sksg/include/SkSGMerge.h
@@ -22,7 +22,7 @@ namespace sksg {
 /**
  * Concrete Geometry node, combining other geometries based on Mode.
  */
-class Merge final : public GeometryNode {
+class SKSG_API Merge final : public GeometryNode {
 public:
     enum class Mode {
         // Append path mode.
diff --git a/modules/sksg/include/SkSGNode.h b/modules/sksg/include/SkSGNode.h
index 271aa39daf..15c202463b 100644
--- a/modules/sksg/include/SkSGNode.h
+++ b/modules/sksg/include/SkSGNode.h
@@ -13,6 +13,26 @@
 
 #include <vector>
 
+#if !defined(SKSG_IMPLEMENTATION)
+    #define SKSG_IMPLEMENTATION 0
+#endif
+
+#if !defined(SKSG_API)
+    #if defined(SKSG_DLL)
+        #if defined(_MSC_VER)
+            #if SKSG_IMPLEMENTATION
+                #define SKSG_API __declspec(dllexport)
+            #else
+                #define SKSG_API __declspec(dllimport)
+            #endif
+        #else
+            #define SKSG_API __attribute__((visibility("default")))
+        #endif
+    #else
+        #define SKSG_API
+    #endif
+#endif
+
 class SkCanvas;
 class SkMatrix;
 
@@ -29,7 +49,7 @@ class InvalidationController;
  * Note: egress edges are only implemented/supported in container subclasses
  * (e.g. Group, Effect, Draw).
  */
-class Node : public SkRefCnt {
+class SKSG_API Node : public SkRefCnt {
 public:
     // Traverse the DAG and revalidate any dependant/invalidated nodes.
     // Returns the bounding box for the DAG fragment.
diff --git a/modules/sksg/include/SkSGOpacityEffect.h b/modules/sksg/include/SkSGOpacityEffect.h
index 126ed3fa0b..09144c7d46 100644
--- a/modules/sksg/include/SkSGOpacityEffect.h
+++ b/modules/sksg/include/SkSGOpacityEffect.h
@@ -16,7 +16,7 @@ namespace sksg {
  * Concrete Effect node, applying opacity to its descendants.
  *
  */
-class OpacityEffect final : public EffectNode {
+class SKSG_API OpacityEffect final : public EffectNode {
 public:
     static sk_sp<OpacityEffect> Make(sk_sp<RenderNode> child, float opacity = 1) {
         return child ? sk_sp<OpacityEffect>(new OpacityEffect(std::move(child), opacity)) : nullptr;
diff --git a/modules/sksg/include/SkSGPaint.h b/modules/sksg/include/SkSGPaint.h
index 59c0de56ba..eb66fba6c9 100644
--- a/modules/sksg/include/SkSGPaint.h
+++ b/modules/sksg/include/SkSGPaint.h
@@ -23,7 +23,7 @@ class Shader;
  *
  * Roughly equivalent to Skia's SkPaint.
  */
-class PaintNode : public Node {
+class SKSG_API PaintNode : public Node {
 public:
     SkPaint makePaint() const;
 
@@ -57,7 +57,7 @@ private:
 /**
  * Concrete Paint node, wrapping an SkColor.
  */
-class Color : public PaintNode {
+class SKSG_API Color : public PaintNode {
 public:
     static sk_sp<Color> Make(SkColor c);
 
@@ -77,7 +77,7 @@ private:
 /**
  * Shader-based paint.
  */
-class ShaderPaint final : public PaintNode {
+class SKSG_API ShaderPaint final : public PaintNode {
 public:
     ~ShaderPaint() override;
 
diff --git a/modules/sksg/include/SkSGPath.h b/modules/sksg/include/SkSGPath.h
index 167fea1b0d..be59140015 100644
--- a/modules/sksg/include/SkSGPath.h
+++ b/modules/sksg/include/SkSGPath.h
@@ -20,7 +20,7 @@ namespace sksg {
 /**
  * Concrete Geometry node, wrapping an SkPath.
  */
-class Path : public GeometryNode {
+class SKSG_API Path : public GeometryNode {
 public:
     static sk_sp<Path> Make()                { return sk_sp<Path>(new Path(SkPath())); }
     static sk_sp<Path> Make(const SkPath& r) { return sk_sp<Path>(new Path(r)); }
diff --git a/modules/sksg/include/SkSGPlane.h b/modules/sksg/include/SkSGPlane.h
index 994ed6b3e6..5dd016720a 100644
--- a/modules/sksg/include/SkSGPlane.h
+++ b/modules/sksg/include/SkSGPlane.h
@@ -18,7 +18,7 @@ namespace sksg {
 /**
  * Concrete Geometry node, representing the whole canvas.
  */
-class Plane final : public GeometryNode {
+class SKSG_API Plane final : public GeometryNode {
 public:
     static sk_sp<Plane> Make() { return sk_sp<Plane>(new Plane()); }
 
diff --git a/modules/sksg/include/SkSGRect.h b/modules/sksg/include/SkSGRect.h
index fa39a8fe02..a2a6a091d8 100644
--- a/modules/sksg/include/SkSGRect.h
+++ b/modules/sksg/include/SkSGRect.h
@@ -22,7 +22,7 @@ namespace sksg {
 /**
  * Concrete Geometry node, wrapping an SkRect.
  */
-class Rect final : public GeometryNode {
+class SKSG_API Rect final : public GeometryNode {
 public:
     static sk_sp<Rect> Make()                { return sk_sp<Rect>(new Rect(SkRect::MakeEmpty())); }
     static sk_sp<Rect> Make(const SkRect& r) { return sk_sp<Rect>(new Rect(r)); }
@@ -68,7 +68,7 @@ private:
 /**
  * Concrete Geometry node, wrapping an SkRRect.
  */
-class RRect final : public GeometryNode {
+class SKSG_API RRect final : public GeometryNode {
 public:
     static sk_sp<RRect> Make()                  { return sk_sp<RRect>(new RRect(SkRRect())); }
     static sk_sp<RRect> Make(const SkRRect& rr) { return sk_sp<RRect>(new RRect(rr)); }
diff --git a/modules/sksg/include/SkSGRenderEffect.h b/modules/sksg/include/SkSGRenderEffect.h
index 1c0f93b006..f6ed0f0ef2 100644
--- a/modules/sksg/include/SkSGRenderEffect.h
+++ b/modules/sksg/include/SkSGRenderEffect.h
@@ -28,7 +28,7 @@ namespace sksg {
 /**
  * Shader base class.
  */
-class Shader : public Node {
+class SKSG_API Shader : public Node {
 public:
     ~Shader() override;
 
@@ -53,7 +53,7 @@ private:
 /**
  * Attaches a shader to the render DAG.
  */
-class ShaderEffect final : public EffectNode {
+class SKSG_API ShaderEffect final : public EffectNode {
 public:
     ~ShaderEffect() override;
 
@@ -77,7 +77,7 @@ private:
 /**
  * Attaches a mask shader to the render DAG.
  */
-class MaskShaderEffect final : public EffectNode {
+class SKSG_API MaskShaderEffect final : public EffectNode {
 public:
     static sk_sp<MaskShaderEffect> Make(sk_sp<RenderNode>, sk_sp<SkShader> = nullptr);
 
@@ -97,7 +97,7 @@ private:
 /**
  * ImageFilter base class.
  */
-class ImageFilter : public Node {
+class SKSG_API ImageFilter : public Node {
 public:
     ~ImageFilter() override;
 
@@ -129,7 +129,7 @@ private:
 /**
  * Attaches an ImageFilter (chain) to the render DAG.
  */
-class ImageFilterEffect final : public EffectNode {
+class SKSG_API ImageFilterEffect final : public EffectNode {
 public:
     ~ImageFilterEffect() override;
 
@@ -152,7 +152,7 @@ private:
 /**
  * Wrapper for externally-managed SkImageFilters.
  */
-class ExternalImageFilter final : public ImageFilter {
+class SKSG_API ExternalImageFilter final : public ImageFilter {
 public:
     ~ExternalImageFilter() override;
 
@@ -173,7 +173,7 @@ private:
 /**
  * SkDropShadowImageFilter node.
  */
-class DropShadowImageFilter final : public ImageFilter {
+class SKSG_API DropShadowImageFilter final : public ImageFilter {
 public:
     ~DropShadowImageFilter() override;
 
@@ -203,7 +203,7 @@ private:
 /**
  * SkBlurImageFilter node.
  */
-class BlurImageFilter final : public ImageFilter {
+class SKSG_API BlurImageFilter final : public ImageFilter {
 public:
     ~BlurImageFilter() override;
 
@@ -227,7 +227,7 @@ private:
 /**
  * Applies a SkBlendMode to descendant render nodes.
  */
-class BlendModeEffect final : public EffectNode {
+class SKSG_API BlendModeEffect final : public EffectNode {
 public:
     ~BlendModeEffect() override;
 
diff --git a/modules/sksg/include/SkSGRenderNode.h b/modules/sksg/include/SkSGRenderNode.h
index db01d49096..8de17d1031 100644
--- a/modules/sksg/include/SkSGRenderNode.h
+++ b/modules/sksg/include/SkSGRenderNode.h
@@ -23,7 +23,7 @@ namespace sksg {
 /**
  * Base class for nodes which can render to a canvas.
  */
-class RenderNode : public Node {
+class SKSG_API RenderNode : public Node {
 protected:
     struct RenderContext;
 
@@ -49,7 +49,7 @@ protected:
     // Paint property overrides.
     // These are deferred until we can determine whether they can be applied to the individual
     // draw paints, or whether they require content isolation (applied to a layer).
-    struct RenderContext {
+    struct SKSG_API RenderContext {
         sk_sp<SkColorFilter> fColorFilter;
         sk_sp<SkShader>      fShader;
         sk_sp<SkShader>      fMaskShader;
@@ -64,7 +64,7 @@ protected:
         void modulatePaint(const SkMatrix& ctm, SkPaint*, bool is_layer_paint = false) const;
     };
 
-    class ScopedRenderContext final {
+    class SKSG_API ScopedRenderContext final {
     public:
         ScopedRenderContext(SkCanvas*, const RenderContext*);
         ~ScopedRenderContext();
@@ -129,7 +129,7 @@ private:
  * should derive from this class instead of RenderNode.  It handles
  * various book-keeping, and provides a controlled extension point.
  */
-class CustomRenderNode : public RenderNode {
+class SKSG_API CustomRenderNode : public RenderNode {
 protected:
     explicit CustomRenderNode(std::vector<sk_sp<RenderNode>>&& children);
     ~CustomRenderNode() override;
diff --git a/modules/sksg/include/SkSGRoundEffect.h b/modules/sksg/include/SkSGRoundEffect.h
index 20a02d0468..cd57f8a8f5 100644
--- a/modules/sksg/include/SkSGRoundEffect.h
+++ b/modules/sksg/include/SkSGRoundEffect.h
@@ -17,7 +17,7 @@ namespace sksg {
 /**
  * Concrete Geometry node, applying a rounded-corner effect to its child.
  */
-class RoundEffect final : public GeometryNode {
+class SKSG_API RoundEffect final : public GeometryNode {
 public:
     static sk_sp<RoundEffect> Make(sk_sp<GeometryNode> child) {
         return child ? sk_sp<RoundEffect>(new RoundEffect(std::move(child))) : nullptr;
diff --git a/modules/sksg/include/SkSGScene.h b/modules/sksg/include/SkSGScene.h
index 8ad19a2193..f619a29660 100644
--- a/modules/sksg/include/SkSGScene.h
+++ b/modules/sksg/include/SkSGScene.h
@@ -8,6 +8,8 @@
 #ifndef SkSGScene_DEFINED
 #define SkSGScene_DEFINED
 
+#include "modules/sksg/include/SkSGNode.h"
+
 #include "include/core/SkRefCnt.h"
 #include "include/core/SkTypes.h"
 
@@ -26,7 +28,7 @@ class RenderNode;
  * Holds a scene root.  Provides high-level methods for rendering.
  *
  */
-class Scene final {
+class SKSG_API Scene final {
 public:
     static std::unique_ptr<Scene> Make(sk_sp<RenderNode> root);
     ~Scene();
diff --git a/modules/sksg/include/SkSGText.h b/modules/sksg/include/SkSGText.h
index 10ac04c70a..4515e46c23 100644
--- a/modules/sksg/include/SkSGText.h
+++ b/modules/sksg/include/SkSGText.h
@@ -25,7 +25,7 @@ namespace sksg {
 /**
  * Concrete Geometry node, wrapping a (shaped) SkTextBlob.
  */
-class Text final : public GeometryNode {
+class SKSG_API Text final : public GeometryNode {
 public:
     static sk_sp<Text> Make(sk_sp<SkTypeface> tf, const SkString& text);
     ~Text() override;
@@ -73,7 +73,7 @@ private:
 /**
  * Concrete Geometry node, wrapping an external SkTextBlob.
  */
-class TextBlob final : public GeometryNode {
+class SKSG_API TextBlob final : public GeometryNode {
 public:
     static sk_sp<TextBlob> Make(sk_sp<SkTextBlob> = nullptr);
     ~TextBlob() override;
diff --git a/modules/sksg/include/SkSGTransform.h b/modules/sksg/include/SkSGTransform.h
index 3c1c013086..37ddd5b7a1 100644
--- a/modules/sksg/include/SkSGTransform.h
+++ b/modules/sksg/include/SkSGTransform.h
@@ -8,6 +8,7 @@
 #ifndef SkSGTransform_DEFINED
 #define SkSGTransform_DEFINED
 
+#include "include/core/SkM44.h"
 #include "modules/sksg/include/SkSGEffectNode.h"
 
 class SkM44;
@@ -18,7 +19,7 @@ namespace sksg {
 /**
  * Transformations base class.
  */
-class Transform : public Node {
+class SKSG_API Transform : public Node {
 public:
     // Compose T' = A x B
     static sk_sp<Transform> MakeConcat(sk_sp<Transform> a, sk_sp<Transform> b);
@@ -79,10 +80,22 @@ private:
     using INHERITED = Transform;
 };
 
+template <>
+inline SkMatrix Matrix<SkMatrix>::asMatrix() const { return fMatrix; }
+
+template <>
+inline SkM44 Matrix<SkMatrix>::asM44() const { return SkM44(fMatrix); }
+
+template <>
+inline SkMatrix Matrix<SkM44>::asMatrix() const { return fMatrix.asM33(); }
+
+template <>
+inline SkM44 Matrix<SkM44>::asM44() const { return fMatrix; }
+
 /**
  * Concrete Effect node, binding a Transform to a RenderNode.
  */
-class TransformEffect final : public EffectNode {
+class SKSG_API TransformEffect final : public EffectNode {
 public:
     static sk_sp<TransformEffect> Make(sk_sp<RenderNode> child, sk_sp<Transform> transform) {
         return child && transform
diff --git a/modules/sksg/include/SkSGTrimEffect.h b/modules/sksg/include/SkSGTrimEffect.h
index 804f028d80..79991a8a0e 100644
--- a/modules/sksg/include/SkSGTrimEffect.h
+++ b/modules/sksg/include/SkSGTrimEffect.h
@@ -21,7 +21,7 @@ namespace sksg {
 /**
  * Concrete Geometry node, applying a trim effect to its child.
  */
-class TrimEffect final : public GeometryNode {
+class SKSG_API TrimEffect final : public GeometryNode {
 public:
     static sk_sp<TrimEffect> Make(sk_sp<GeometryNode> child) {
         return child ? sk_sp<TrimEffect>(new TrimEffect(std::move(child))) : nullptr;
diff --git a/modules/sksg/src/SkSGTransform.cpp b/modules/sksg/src/SkSGTransform.cpp
index 7f317527b2..e8e08a5676 100644
--- a/modules/sksg/src/SkSGTransform.cpp
+++ b/modules/sksg/src/SkSGTransform.cpp
@@ -128,18 +128,6 @@ private:
 
 } // namespace
 
-template <>
-SkMatrix Matrix<SkMatrix>::asMatrix() const { return fMatrix; }
-
-template <>
-SkM44 Matrix<SkMatrix>::asM44() const { return SkM44(fMatrix); }
-
-template <>
-SkMatrix Matrix<SkM44>::asMatrix() const { return fMatrix.asM33(); }
-
-template <>
-SkM44 Matrix<SkM44>::asM44() const { return fMatrix; }
-
 // Transform nodes don't generate damage on their own, but via ancestor TransformEffects.
 Transform::Transform() : INHERITED(kBubbleDamage_Trait) {}
 
diff --git a/src/core/SkTextBlobPriv.h b/src/core/SkTextBlobPriv.h
index 5394b50d5d..2fa56a9cab 100644
--- a/src/core/SkTextBlobPriv.h
+++ b/src/core/SkTextBlobPriv.h
@@ -199,7 +199,7 @@ private:
  *         .....
  *    }
  */
-class SkTextBlobRunIterator {
+class SK_API SkTextBlobRunIterator {
 public:
     SkTextBlobRunIterator(const SkTextBlob* blob);
 
diff --git a/src/utils/SkJSON.h b/src/utils/SkJSON.h
index d3f0b1d48f..970d64cd5b 100644
--- a/src/utils/SkJSON.h
+++ b/src/utils/SkJSON.h
@@ -53,7 +53,7 @@ namespace skjson {
  *         }
  *     }
  */
-class alignas(8) Value {
+class SK_API alignas(8) Value {
 public:
     enum class Type {
         kNull,
@@ -209,7 +209,7 @@ private:
 #endif
 };
 
-class NullValue final : public Value {
+class SK_API NullValue final : public Value {
 public:
     static constexpr Type kType = Type::kNull;
 
@@ -321,7 +321,7 @@ struct Member {
           Value fValue;
 };
 
-class ObjectValue final : public VectorValue<Member, Value::Type::kObject> {
+class SK_API ObjectValue final : public VectorValue<Member, Value::Type::kObject> {
 public:
     ObjectValue(const Member* src, size_t size, SkArenaAlloc& alloc);
 
@@ -332,7 +332,7 @@ public:
     }
 };
 
-class DOM final : public SkNoncopyable {
+class SK_API DOM final : public SkNoncopyable {
 public:
     DOM(const char*, size_t);