Make class members that are static constexpr also be inline.

This is in prep for compiling with -std=c++14 and -Wno-c++17-extensions
when building with clang. Chrome has encountered problems with
third_party headers that are included both in Skia and other Chrome
sources that produce different code based on whether preprocessor macros
indicate a C++14 or C++17 compilation.

In C++17 they are already inline implicitly. When compiling with C++14
we can get linker errors unless they're explicitly inlined or defined
outside the class. With -Wno-c++17-extensions we can explicitly inline
them in the C++14 build because the warning that would be generated
about using a C++17 language extension is suppressed.

We cannot do this in public headers because we support compiling with
C++14 without suppressing the C++17 language extension warnings.

Bug: chromium:1257145
Change-Id: Iaf5f4c62a398f98dd4ca9b7dfb86f2d5cab21d66
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/457498
Reviewed-by: Ben Wagner <bungeman@google.com>
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/bench/BulkRectBench.cpp b/bench/BulkRectBench.cpp
index 359e48b..c2a124d 100644
--- a/bench/BulkRectBench.cpp
+++ b/bench/BulkRectBench.cpp
@@ -42,11 +42,11 @@
     static_assert(kImageMode == ImageMode::kNone || kDrawMode != DrawMode::kQuad,
                   "kQuad only supported for solid color draws");
 
-    static constexpr int kWidth      = 1024;
-    static constexpr int kHeight     = 1024;
+    inline static constexpr int kWidth      = 1024;
+    inline static constexpr int kHeight     = 1024;
 
     // There will either be 0 images, 1 image, or 1 image per rect
-    static constexpr int kImageCount = kImageMode == ImageMode::kShared ?
+    inline static constexpr int kImageCount = kImageMode == ImageMode::kShared ?
             1 : (kImageMode == ImageMode::kNone ? 0 : kRectCount);
 
     bool isSuitableFor(Backend backend) override {
diff --git a/bench/GrQuadBench.cpp b/bench/GrQuadBench.cpp
index 00d538a..21f9aad 100644
--- a/bench/GrQuadBench.cpp
+++ b/bench/GrQuadBench.cpp
@@ -22,7 +22,7 @@
     }
 
 protected:
-    static constexpr int kQuadCount = 1000;
+    inline static constexpr int kQuadCount = 1000;
 
     const char* onGetName() override {
         return fName.c_str();
diff --git a/bench/ImageCacheBudgetBench.cpp b/bench/ImageCacheBudgetBench.cpp
index 5aa1621..b39083c 100644
--- a/bench/ImageCacheBudgetBench.cpp
+++ b/bench/ImageCacheBudgetBench.cpp
@@ -143,8 +143,8 @@
     }
 
 private:
-    static constexpr int kImagesToDraw = 100;
-    static constexpr int kSimulatedFrames = 5;
+    inline static constexpr int kImagesToDraw = 100;
+    inline static constexpr int kSimulatedFrames = 5;
 
     int                         fBudgetSize;
     bool                        fShuffle;
@@ -251,10 +251,10 @@
     }
 
 private:
-    static constexpr int kImagesInBudget  = 25;
-    static constexpr int kMinImagesToDraw = 15;
-    static constexpr int kMaxImagesToDraw = 35;
-    static constexpr int kSimulatedFrames = 80;
+    inline static constexpr int kImagesInBudget  = 25;
+    inline static constexpr int kMinImagesToDraw = 15;
+    inline static constexpr int kMaxImagesToDraw = 35;
+    inline static constexpr int kSimulatedFrames = 80;
 
     Mode                        fMode;
     sk_sp<SkImage>              fImages[kMaxImagesToDraw];
diff --git a/bench/ImageCycleBench.cpp b/bench/ImageCycleBench.cpp
index 16322c0..8b69af7 100644
--- a/bench/ImageCycleBench.cpp
+++ b/bench/ImageCycleBench.cpp
@@ -84,8 +84,8 @@
 private:
     SkIPoint onGetSize() override { return {kDeviceSize.fWidth, kDeviceSize.fHeight}; }
 
-    static constexpr SkISize kImageSize{4, 4};
-    static constexpr SkISize kDeviceSize{64, 64};
+    inline static constexpr SkISize kImageSize{4, 4};
+    inline static constexpr SkISize kDeviceSize{64, 64};
 
     std::unique_ptr<sk_sp<SkImage>[]> fImages;
     SkString fName;
diff --git a/bench/RectanizerBench.cpp b/bench/RectanizerBench.cpp
index 275e036..843b26c 100644
--- a/bench/RectanizerBench.cpp
+++ b/bench/RectanizerBench.cpp
@@ -27,8 +27,8 @@
  */
 class RectanizerBench : public Benchmark {
 public:
-    static constexpr int kWidth = 1024;
-    static constexpr int kHeight = 1024;
+    inline static constexpr int kWidth = 1024;
+    inline static constexpr int kHeight = 1024;
 
     enum RectanizerType {
         kPow2_RectanizerType,
diff --git a/bench/TileBench.cpp b/bench/TileBench.cpp
index 1a5b3bf..b897ca7 100644
--- a/bench/TileBench.cpp
+++ b/bench/TileBench.cpp
@@ -102,8 +102,8 @@
     }
 
 private:
-    static constexpr int kWidth = 1;
-    static constexpr int kHeight = 300;
+    inline static constexpr int kWidth = 1;
+    inline static constexpr int kHeight = 300;
 
     const SkFilterMode fFilterMode;
     const SkTileMode fXTile,
diff --git a/client_utils/android/FrontBufferedStream.cpp b/client_utils/android/FrontBufferedStream.cpp
index a5e229f..d3d9d3d 100644
--- a/client_utils/android/FrontBufferedStream.cpp
+++ b/client_utils/android/FrontBufferedStream.cpp
@@ -36,19 +36,19 @@
 private:
     SkStreamRewindable* onDuplicate() const override { return nullptr; }
 
-    std::unique_ptr<SkStream> fStream;
-    const bool                fHasLength;
-    const size_t              fLength;
+    std::unique_ptr<SkStream>        fStream;
+    const bool                       fHasLength;
+    const size_t                     fLength;
     // Current offset into the stream. Always >= 0.
-    size_t                    fOffset;
+    size_t                           fOffset;
     // Amount that has been buffered by calls to read. Will always be less than
     // fBufferSize.
-    size_t                    fBufferedSoFar;
+    size_t                           fBufferedSoFar;
     // Total size of the buffer.
-    const size_t              fBufferSize;
-    char*                     fBuffer;
-    static constexpr size_t   kStorageSize = SkCodec::MinBufferedBytesNeeded();
-    char                      fStorage[kStorageSize];
+    const size_t                     fBufferSize;
+    char*                            fBuffer;
+    inline static constexpr size_t   kStorageSize = SkCodec::MinBufferedBytesNeeded();
+    char                             fStorage[kStorageSize];
 
     // Read up to size bytes from already buffered data, and copy to
     // dst, if non-nullptr. Updates fOffset. Assumes that fOffset is less
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index 2f0035f..4be400d 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -297,11 +297,11 @@
 
 private:
     // Generates a kTileCount x kTileCount filmstrip with evenly distributed frames.
-    static constexpr int      kTileCount = 5;
+    inline static constexpr int      kTileCount = 5;
 
     // Fit kTileCount x kTileCount frames to a 1000x1000 film strip.
-    static constexpr SkScalar kTargetSize = 1000;
-    static constexpr SkScalar kTileSize = kTargetSize / kTileCount;
+    inline static constexpr SkScalar kTargetSize = 1000;
+    inline static constexpr SkScalar kTileSize = kTargetSize / kTileCount;
 
     Path                      fPath;
 };
@@ -319,11 +319,11 @@
 
 private:
     // Generates a kTileCount x kTileCount filmstrip with evenly distributed frames.
-    static constexpr int      kTileCount  = 5;
+    inline static constexpr int      kTileCount  = 5;
 
     // Fit kTileCount x kTileCount frames to a 1000x1000 film strip.
-    static constexpr SkScalar kTargetSize = 1000;
-    static constexpr SkScalar kTileSize   = kTargetSize / kTileCount;
+    inline static constexpr SkScalar kTargetSize = 1000;
+    inline static constexpr SkScalar kTileSize   = kTargetSize / kTileCount;
 
     const Path fPath;
 };
diff --git a/experimental/graphite/src/RenderPipelineDesc.h b/experimental/graphite/src/RenderPipelineDesc.h
index 2f4d65a..8807248 100644
--- a/experimental/graphite/src/RenderPipelineDesc.h
+++ b/experimental/graphite/src/RenderPipelineDesc.h
@@ -39,7 +39,7 @@
 private:
     // Estimate of max expected key size
     // TODO: flesh this out
-    static constexpr int kPreAllocSize = 1;
+    inline static constexpr int kPreAllocSize = 1;
 
     SkSTArray<kPreAllocSize, uint32_t, true> fKey;
 };
diff --git a/experimental/graphite/src/geom/Shape.h b/experimental/graphite/src/geom/Shape.h
index 18e4565..8a6fbc9 100644
--- a/experimental/graphite/src/geom/Shape.h
+++ b/experimental/graphite/src/geom/Shape.h
@@ -28,7 +28,7 @@
     enum class Type : uint8_t {
         kEmpty, kRect, kRRect, kPath
     };
-    static constexpr int kTypeCount = static_cast<int>(Type::kPath) + 1;
+    inline static constexpr int kTypeCount = static_cast<int>(Type::kPath) + 1;
 
     Shape() {}
     Shape(const Shape& shape)            { *this = shape; }
diff --git a/gm/anisotropic.cpp b/gm/anisotropic.cpp
index 34813ef..60b62ff 100644
--- a/gm/anisotropic.cpp
+++ b/gm/anisotropic.cpp
@@ -106,9 +106,9 @@
     }
 
 private:
-    static constexpr int kImageSize     = 256;
-    static constexpr int kSpacer        = 10;
-    static constexpr int kNumVertImages = 5;
+    inline static constexpr int kImageSize     = 256;
+    inline static constexpr int kSpacer        = 10;
+    inline static constexpr int kNumVertImages = 5;
 
     sk_sp<SkImage>    fImage;
     SkSamplingOptions fSampling;
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index ee47b67..ebd5132 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -198,8 +198,8 @@
 
     SkMatrix fKLM;
 
-    static constexpr int kVertsPerCubic = 4;
-    static constexpr int kIndicesPerCubic = 6;
+    inline static constexpr int kVertsPerCubic = 4;
+    inline static constexpr int kIndicesPerCubic = 6;
 
     using INHERITED = BezierTestOp;
 };
@@ -405,8 +405,8 @@
 
     GrPathUtils::QuadUVMatrix fDevToUV;
 
-    static constexpr int kVertsPerCubic = 4;
-    static constexpr int kIndicesPerCubic = 6;
+    inline static constexpr int kVertsPerCubic = 4;
+    inline static constexpr int kIndicesPerCubic = 6;
 
     using INHERITED = BezierTestOp;
 };
diff --git a/gm/bigblurs.cpp b/gm/bigblurs.cpp
index e768850..143d82b 100644
--- a/gm/bigblurs.cpp
+++ b/gm/bigblurs.cpp
@@ -112,9 +112,9 @@
     }
 
 private:
-    static constexpr int kCloseUpSize = 64;
-    static constexpr int kWidth = 5 * kCloseUpSize;
-    static constexpr int kHeight = 2 * (kLastEnum_SkBlurStyle + 1) * kCloseUpSize;
+    inline static constexpr int kCloseUpSize = 64;
+    inline static constexpr int kWidth = 5 * kCloseUpSize;
+    inline static constexpr int kHeight = 2 * (kLastEnum_SkBlurStyle + 1) * kCloseUpSize;
 
     using INHERITED = GM;
 };
diff --git a/gm/bigrrectaaeffect.cpp b/gm/bigrrectaaeffect.cpp
index 5ea95a4..d506135 100644
--- a/gm/bigrrectaaeffect.cpp
+++ b/gm/bigrrectaaeffect.cpp
@@ -117,9 +117,9 @@
 
 private:
     // pad between test cases
-    static constexpr int kPad = 7;
+    inline static constexpr int kPad = 7;
     // gap between rect for each case that is rendered and exterior of rrect
-    static constexpr int kGap = 3;
+    inline static constexpr int kGap = 3;
 
     SkRRect fRRect;
     int fWidth;
diff --git a/gm/bigtileimagefilter.cpp b/gm/bigtileimagefilter.cpp
index 20c3c66..3688e7e 100644
--- a/gm/bigtileimagefilter.cpp
+++ b/gm/bigtileimagefilter.cpp
@@ -105,9 +105,9 @@
     }
 
 private:
-    static constexpr int kWidth = 512;
-    static constexpr int kHeight = 512;
-    static constexpr int kBitmapSize = 64;
+    inline static constexpr int kWidth = 512;
+    inline static constexpr int kHeight = 512;
+    inline static constexpr int kBitmapSize = 64;
 
     sk_sp<SkImage> fRedImage;
     sk_sp<SkImage> fGreenImage;
diff --git a/gm/bitmapimage.cpp b/gm/bitmapimage.cpp
index 409f13d2..c2c8dd5 100644
--- a/gm/bitmapimage.cpp
+++ b/gm/bitmapimage.cpp
@@ -75,7 +75,7 @@
     }
 
 private:
-    static constexpr int kSize = 512;
+    inline static constexpr int kSize = 512;
 
     using INHERITED = GM;
 };
diff --git a/gm/bleed.cpp b/gm/bleed.cpp
index 1c0d6e0..5a96acc 100644
--- a/gm/bleed.cpp
+++ b/gm/bleed.cpp
@@ -297,23 +297,23 @@
     }
 
 private:
-    static constexpr int kBlockSize = 70;
-    static constexpr int kBlockSpacing = 12;
+    inline static constexpr int kBlockSize = 70;
+    inline static constexpr int kBlockSpacing = 12;
 
-    static constexpr int kCol0X = kBlockSpacing;
-    static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
-    static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
-    static constexpr int kWidth = 4*kBlockSpacing + 3*kBlockSize;
+    inline static constexpr int kCol0X = kBlockSpacing;
+    inline static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
+    inline static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
+    inline static constexpr int kWidth = 4*kBlockSpacing + 3*kBlockSize;
 
-    static constexpr int kRow0Y = kBlockSpacing;
-    static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
-    static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
-    static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
-    static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
+    inline static constexpr int kRow0Y = kBlockSpacing;
+    inline static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
+    inline static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
+    inline static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
+    inline static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
 
-    static constexpr int kSmallSize = 6;
+    inline static constexpr int kSmallSize = 6;
     // This must be at least as large as the GM width and height so that a surface can be made.
-    static constexpr int kMaxTextureSize = 1000;
+    inline static constexpr int kMaxTextureSize = 1000;
 
     SkString fShortName;
     sk_sp<SkImage> fBigImage;
diff --git a/gm/blurcircles.cpp b/gm/blurcircles.cpp
index 449fc49..6dcf439 100644
--- a/gm/blurcircles.cpp
+++ b/gm/blurcircles.cpp
@@ -68,7 +68,7 @@
         }
     }
 private:
-    static constexpr int kNumBlurs = 4;
+    inline static constexpr int kNumBlurs = 4;
 
     sk_sp<SkMaskFilter> fBlurFilters[kNumBlurs];
 
diff --git a/gm/blurcircles2.cpp b/gm/blurcircles2.cpp
index c399d56..9665139 100644
--- a/gm/blurcircles2.cpp
+++ b/gm/blurcircles2.cpp
@@ -149,15 +149,15 @@
     }
 
 private:
-    static constexpr SkScalar kMinRadius = 15;
-    static constexpr SkScalar kMaxRadius = 45;
-    static constexpr SkScalar kRadiusPingPoingPeriod = 8;
-    static constexpr SkScalar kRadiusPingPoingShift = 3;
+    inline static constexpr SkScalar kMinRadius = 15;
+    inline static constexpr SkScalar kMaxRadius = 45;
+    inline static constexpr SkScalar kRadiusPingPoingPeriod = 8;
+    inline static constexpr SkScalar kRadiusPingPoingShift = 3;
 
-    static constexpr SkScalar kMinBlurRadius = 5;
-    static constexpr SkScalar kMaxBlurRadius = 45;
-    static constexpr SkScalar kBlurRadiusPingPoingPeriod = 3;
-    static constexpr SkScalar kBlurRadiusPingPoingShift = 1.5;
+    inline static constexpr SkScalar kMinBlurRadius = 5;
+    inline static constexpr SkScalar kMaxBlurRadius = 45;
+    inline static constexpr SkScalar kBlurRadiusPingPoingPeriod = 3;
+    inline static constexpr SkScalar kBlurRadiusPingPoingShift = 1.5;
 
     SkScalar    fAnimRadius;
     SkScalar    fAnimBlurRadius;
diff --git a/gm/blurignorexform.cpp b/gm/blurignorexform.cpp
index c8a40c9..58cdd38 100644
--- a/gm/blurignorexform.cpp
+++ b/gm/blurignorexform.cpp
@@ -119,7 +119,7 @@
     }
 
 private:
-    static constexpr int kNumBlurs = 2;
+    inline static constexpr int kNumBlurs = 2;
 
     static const struct BlurFlags {
         bool fRespectCTM;
diff --git a/gm/blurquickreject.cpp b/gm/blurquickreject.cpp
index 8b83920..42e6ff4 100644
--- a/gm/blurquickreject.cpp
+++ b/gm/blurquickreject.cpp
@@ -80,8 +80,8 @@
     }
 
 private:
-    static constexpr int kWidth = 300;
-    static constexpr int kHeight = 300;
+    inline static constexpr int kWidth = 300;
+    inline static constexpr int kHeight = 300;
 
     using INHERITED = GM;
 };
diff --git a/gm/blurrect.cpp b/gm/blurrect.cpp
index 0f15c49..2ff36ca 100644
--- a/gm/blurrect.cpp
+++ b/gm/blurrect.cpp
@@ -483,10 +483,10 @@
     // related to big blurs are fully visible.
     static int PadForSigma(float sigma) { return sk_float_ceil2int(4 * sigma); }
 
-    static constexpr int kSizes[] = {1, 2, 4, 8, 16, 32};
-    static constexpr float kSigmas[] = {0.5f, 1.2f, 2.3f, 3.9f, 7.4f};
-    static constexpr size_t kNumSizes = SK_ARRAY_COUNT(kSizes);
-    static constexpr size_t kNumSigmas = SK_ARRAY_COUNT(kSigmas);
+    inline static constexpr int kSizes[] = {1, 2, 4, 8, 16, 32};
+    inline static constexpr float kSigmas[] = {0.5f, 1.2f, 2.3f, 3.9f, 7.4f};
+    inline static constexpr size_t kNumSizes = SK_ARRAY_COUNT(kSizes);
+    inline static constexpr size_t kNumSigmas = SK_ARRAY_COUNT(kSigmas);
 
     sk_sp<SkImage> fReferenceMasks[kNumSigmas][kNumSizes][kNumSizes];
     sk_sp<SkImage> fActualMasks[kNumSigmas][kNumSizes][kNumSizes];
diff --git a/gm/blurredclippedcircle.cpp b/gm/blurredclippedcircle.cpp
index 0eb21fd..2754927 100644
--- a/gm/blurredclippedcircle.cpp
+++ b/gm/blurredclippedcircle.cpp
@@ -83,8 +83,8 @@
     }
 
 private:
-    static constexpr int kWidth = 1164;
-    static constexpr int kHeight = 802;
+    inline static constexpr int kWidth = 1164;
+    inline static constexpr int kHeight = 802;
 
     using INHERITED = GM;
 };
diff --git a/gm/colorfilters.cpp b/gm/colorfilters.cpp
index 0093d85..1e4dfd6 100644
--- a/gm/colorfilters.cpp
+++ b/gm/colorfilters.cpp
@@ -155,8 +155,8 @@
     }
 
 private:
-    static constexpr SkScalar kWheelSize  = 100;
-    static constexpr size_t   kSteps = 7;
+    inline static constexpr SkScalar kWheelSize  = 100;
+    inline static constexpr size_t   kSteps = 7;
 
     static sk_sp<SkColorFilter> make_filter(float h, float s, float l) {
         // These are roughly AE semantics.
diff --git a/gm/complexclip2.cpp b/gm/complexclip2.cpp
index cf2542d..3bb4947 100644
--- a/gm/complexclip2.cpp
+++ b/gm/complexclip2.cpp
@@ -104,10 +104,10 @@
         }
     }
 
-    static constexpr int kRows = 5;
-    static constexpr int kCols = 5;
-    static constexpr int kPadX = 20;
-    static constexpr int kPadY = 20;
+    inline static constexpr int kRows = 5;
+    inline static constexpr int kCols = 5;
+    inline static constexpr int kPadX = 20;
+    inline static constexpr int kPadY = 20;
 
     static const char* ClipStr(Clip clip) {
         switch (clip) {
diff --git a/gm/composeshader.cpp b/gm/composeshader.cpp
index 1303333..06122b0 100644
--- a/gm/composeshader.cpp
+++ b/gm/composeshader.cpp
@@ -231,7 +231,7 @@
      *  work in a release build.  You can change this parameter and then compile a release build
      *  to have this GM draw larger bitmaps for easier visual inspection.
      */
-    static constexpr int squareLength = 20;
+    inline static constexpr int squareLength = 20;
 
     const bool fUseLocalMatrix;
 
diff --git a/gm/constcolorprocessor.cpp b/gm/constcolorprocessor.cpp
index 4c9e7ec..d5602eb 100644
--- a/gm/constcolorprocessor.cpp
+++ b/gm/constcolorprocessor.cpp
@@ -212,10 +212,10 @@
     sk_sp<SkShader> fShader;
     TestMode        fMode;
 
-    static constexpr SkScalar       kPad = 10.f;
-    static constexpr SkScalar       kRectSize = 20.f;
-    static constexpr int            kWidth  = 820;
-    static constexpr int            kHeight = 500;
+    inline static constexpr SkScalar       kPad = 10.f;
+    inline static constexpr SkScalar       kRectSize = 20.f;
+    inline static constexpr int            kWidth  = 820;
+    inline static constexpr int            kHeight = 500;
 
     using INHERITED = GM;
 };
diff --git a/gm/convex_all_line_paths.cpp b/gm/convex_all_line_paths.cpp
index 1294325..f56c09e 100644
--- a/gm/convex_all_line_paths.cpp
+++ b/gm/convex_all_line_paths.cpp
@@ -397,11 +397,11 @@
     }
 
 private:
-    static constexpr int kStrokeWidth   = 10;
-    static constexpr int kNumPaths      = 20;
-    static constexpr int kMaxPathHeight = 100;
-    static constexpr int kGMWidth       = 512;
-    static constexpr int kGMHeight      = 512;
+    inline static constexpr int kStrokeWidth   = 10;
+    inline static constexpr int kNumPaths      = 20;
+    inline static constexpr int kMaxPathHeight = 100;
+    inline static constexpr int kGMWidth       = 512;
+    inline static constexpr int kGMHeight      = 512;
 
     bool fDoStrokeAndFill;
 
diff --git a/gm/drawatlascolor.cpp b/gm/drawatlascolor.cpp
index 83ec2ef..bc4bcdb 100644
--- a/gm/drawatlascolor.cpp
+++ b/gm/drawatlascolor.cpp
@@ -165,11 +165,11 @@
     }
 
 private:
-    static constexpr int kNumXferModes = 29;
-    static constexpr int kNumColors = 4;
-    static constexpr int kAtlasSize = 30;
-    static constexpr int kPad = 2;
-    static constexpr int kTextPad = 8;
+    inline static constexpr int kNumXferModes = 29;
+    inline static constexpr int kNumColors = 4;
+    inline static constexpr int kAtlasSize = 30;
+    inline static constexpr int kPad = 2;
+    inline static constexpr int kTextPad = 8;
 
     using INHERITED = GM;
 };
diff --git a/gm/drawimageset.cpp b/gm/drawimageset.cpp
index 5cff475..b6c0289 100644
--- a/gm/drawimageset.cpp
+++ b/gm/drawimageset.cpp
@@ -196,10 +196,10 @@
             canvas->translate(2 * d, 0);
         }
     }
-    static constexpr int kM = 4;
-    static constexpr int kN = 3;
-    static constexpr SkScalar kTileW = 30;
-    static constexpr SkScalar kTileH = 60;
+    inline static constexpr int kM = 4;
+    inline static constexpr int kN = 3;
+    inline static constexpr SkScalar kTileW = 30;
+    inline static constexpr SkScalar kTileH = 60;
     SkCanvas::ImageSetEntry fSet[kM * kN];
 };
 
@@ -282,10 +282,10 @@
             canvas->save();
         }
     }
-    static constexpr int kM = 2;
-    static constexpr int kN = 2;
-    static constexpr int kTileW = 40;
-    static constexpr int kTileH = 50;
+    inline static constexpr int kM = 2;
+    inline static constexpr int kN = 2;
+    inline static constexpr int kTileW = 40;
+    inline static constexpr int kTileH = 50;
     SkCanvas::ImageSetEntry fSet[kM * kN];
 };
 
@@ -344,10 +344,10 @@
         }
     }
 
-    static constexpr int kM = 4;
-    static constexpr int kN = 4;
-    static constexpr int kTileW = 50;
-    static constexpr int kTileH = 50;
+    inline static constexpr int kM = 4;
+    inline static constexpr int kN = 4;
+    inline static constexpr int kTileW = 50;
+    inline static constexpr int kTileH = 50;
     SkCanvas::ImageSetEntry fSet[kM * kN];
 };
 
diff --git a/gm/filterfastbounds.cpp b/gm/filterfastbounds.cpp
index c0de77e..89c39fe 100644
--- a/gm/filterfastbounds.cpp
+++ b/gm/filterfastbounds.cpp
@@ -157,10 +157,10 @@
     }
 
 protected:
-    static constexpr int kTileWidth = 100;
-    static constexpr int kTileHeight = 100;
-    static constexpr int kNumVertTiles = 7;
-    static constexpr int kNumXtraCols = 2;
+    inline static constexpr int kTileWidth = 100;
+    inline static constexpr int kTileHeight = 100;
+    inline static constexpr int kNumVertTiles = 7;
+    inline static constexpr int kNumXtraCols = 2;
 
     SkString onShortName() override { return SkString("filterfastbounds"); }
 
diff --git a/gm/fontcache.cpp b/gm/fontcache.cpp
index a2aa0c4..f65e31a 100644
--- a/gm/fontcache.cpp
+++ b/gm/fontcache.cpp
@@ -124,15 +124,13 @@
         } while (true);
     }
 
-    static constexpr SkScalar kSize = 1280;
+    inline static constexpr SkScalar kSize = 1280;
 
     GrContextOptions::Enable fAllowMultipleTextures;
     sk_sp<SkTypeface> fTypefaces[6];
     using INHERITED = GM;
 };
 
-constexpr SkScalar FontCacheGM::kSize;
-
 //////////////////////////////////////////////////////////////////////////////
 
 DEF_GM(return new FontCacheGM(GrContextOptions::Enable::kNo))
diff --git a/gm/fontregen.cpp b/gm/fontregen.cpp
index b9002e9..26c9b95 100644
--- a/gm/fontregen.cpp
+++ b/gm/fontregen.cpp
@@ -108,7 +108,7 @@
     }
 
 private:
-    static constexpr int kSize = 512;
+    inline static constexpr int kSize = 512;
 
     sk_sp<SkTextBlob> fBlobs[3];
     using INHERITED = GM;
@@ -152,7 +152,7 @@
     }
 
 private:
-    static constexpr int kSize = 512;
+    inline static constexpr int kSize = 512;
 
     sk_sp<SkTextBlob> fBlobs[3];
     using INHERITED = GM;
diff --git a/gm/fontscalerdistortable.cpp b/gm/fontscalerdistortable.cpp
index c0e4e15..e343753 100644
--- a/gm/fontscalerdistortable.cpp
+++ b/gm/fontscalerdistortable.cpp
@@ -44,8 +44,8 @@
         return SkISize::Make(550, 700);
     }
 
-    static constexpr int rows = 2;
-    static constexpr int cols = 5;
+    inline static constexpr int rows = 2;
+    inline static constexpr int cols = 5;
     sk_sp<SkTypeface> typeface[rows][cols];
     void onOnceBeforeDraw() override {
         sk_sp<SkFontMgr> fontMgr(SkFontMgr::RefDefault());
diff --git a/gm/fp_sample_chaining.cpp b/gm/fp_sample_chaining.cpp
index ea24a60..5361f62 100644
--- a/gm/fp_sample_chaining.cpp
+++ b/gm/fp_sample_chaining.cpp
@@ -24,7 +24,7 @@
 // Scales along Y
 class UniformMatrixEffect : public GrFragmentProcessor {
 public:
-    static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 4;
+    inline static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 4;
 
     UniformMatrixEffect(std::unique_ptr<GrFragmentProcessor> child)
             : GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) {
@@ -65,7 +65,7 @@
 // Translates along Y
 class ExplicitCoordEffect : public GrFragmentProcessor {
 public:
-    static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 6;
+    inline static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 6;
 
     ExplicitCoordEffect(std::unique_ptr<GrFragmentProcessor> child)
             : GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) {
@@ -96,7 +96,7 @@
 // Generates test pattern
 class TestPatternEffect : public GrFragmentProcessor {
 public:
-    static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 7;
+    inline static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 7;
 
     TestPatternEffect() : GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) {
         this->setUsesSampleCoordsDirectly();
diff --git a/gm/fpcoordinateoverride.cpp b/gm/fpcoordinateoverride.cpp
index dfec939..73f3c80 100644
--- a/gm/fpcoordinateoverride.cpp
+++ b/gm/fpcoordinateoverride.cpp
@@ -32,7 +32,7 @@
 
 class SampleCoordEffect : public GrFragmentProcessor {
 public:
-    static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 0;
+    inline static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 0;
 
     SampleCoordEffect(std::unique_ptr<GrFragmentProcessor> child)
         : INHERITED(CLASS_ID, kNone_OptimizationFlags) {
diff --git a/gm/gm.cpp b/gm/gm.cpp
index d815bbe..6609cc9 100644
--- a/gm/gm.cpp
+++ b/gm/gm.cpp
@@ -27,8 +27,6 @@
 
 using namespace skiagm;
 
-constexpr char GM::kErrorMsg_DrawSkippedGpuOnly[];
-
 static void draw_failure_message(SkCanvas* canvas, const char format[], ...)  {
     SkString failureMsg;
 
diff --git a/gm/gm.h b/gm/gm.h
index 371c8fb..53d4565 100644
--- a/gm/gm.h
+++ b/gm/gm.h
@@ -105,7 +105,8 @@
         void setMode(Mode mode) { fMode = mode; }
         Mode getMode() const { return fMode; }
 
-        static constexpr char kErrorMsg_DrawSkippedGpuOnly[] = "This test is for GPU configs only.";
+        inline static constexpr char kErrorMsg_DrawSkippedGpuOnly[] =
+                "This test is for GPU configs only.";
 
         DrawResult gpuSetup(GrDirectContext* context, SkCanvas* canvas) {
             SkString errorMsg;
diff --git a/gm/gradients.cpp b/gm/gradients.cpp
index 50d88e4..9a41368 100644
--- a/gm/gradients.cpp
+++ b/gm/gradients.cpp
@@ -713,7 +713,7 @@
 DEF_GM( return new LinearGradientGM(false); )
 
 class LinearGradientTinyGM : public skiagm::GM {
-    static constexpr uint32_t kFlags = 0;
+    inline static constexpr uint32_t kFlags = 0;
 
     SkString onShortName() override { return SkString("linear_gradient_tiny"); }
 
diff --git a/gm/imagefromyuvtextures.cpp b/gm/imagefromyuvtextures.cpp
index 882d4a7..8fd0811 100644
--- a/gm/imagefromyuvtextures.cpp
+++ b/gm/imagefromyuvtextures.cpp
@@ -266,11 +266,11 @@
     std::unique_ptr<sk_gpu_test::LazyYUVImage> fLazyYUVImage;
 
     // 3 draws x 3 scales x 4 filter qualities
-    static constexpr int kNumImages = 3 * 3 * 4;
+    inline static constexpr int kNumImages = 3 * 3 * 4;
     sk_sp<SkImage> fYUVAImages[kNumImages];
     sk_sp<SkImage> fReferenceImage;
 
-    static constexpr SkScalar kPad = 10.0f;
+    inline static constexpr SkScalar kPad = 10.0f;
 
     using INHERITED = GM;
 };
diff --git a/gm/imagescalealigned.cpp b/gm/imagescalealigned.cpp
index 7c181df..12020de 100644
--- a/gm/imagescalealigned.cpp
+++ b/gm/imagescalealigned.cpp
@@ -150,8 +150,8 @@
         return pt;
     }
 
-    static constexpr unsigned  kSegLen = 15;
-    static constexpr unsigned  kStretchFactor = 4;
+    inline static constexpr unsigned  kSegLen = 15;
+    inline static constexpr unsigned  kStretchFactor = 4;
     SkSTArray<2, ImageSet> fSets;
 
     using INHERITED = GM;
diff --git a/gm/imagesource2.cpp b/gm/imagesource2.cpp
index 21cea76..6f033da 100644
--- a/gm/imagesource2.cpp
+++ b/gm/imagesource2.cpp
@@ -84,7 +84,7 @@
     }
 
 private:
-    static constexpr int kImageSize = 503;
+    inline static constexpr int kImageSize = 503;
 
     SkString          fSuffix;
     SkSamplingOptions fSampling;
diff --git a/gm/lazytiling.cpp b/gm/lazytiling.cpp
index 5a5b55f..44a703d 100644
--- a/gm/lazytiling.cpp
+++ b/gm/lazytiling.cpp
@@ -247,18 +247,18 @@
     }
 
 private:
-    static constexpr int kLeftContentOffset = 8;
-    static constexpr int kTopContentOffset = 16;
-    static constexpr int kRightContentPadding = 24;
-    static constexpr int kBottomContentPadding = 80;
+    inline static constexpr int kLeftContentOffset = 8;
+    inline static constexpr int kTopContentOffset = 16;
+    inline static constexpr int kRightContentPadding = 24;
+    inline static constexpr int kBottomContentPadding = 80;
 
-    static constexpr int kPad = 4; // on-screen padding between cells
+    inline static constexpr int kPad = 4; // on-screen padding between cells
 
-    static constexpr int kContentSize = 32;
+    inline static constexpr int kContentSize = 32;
 
     // Each cell in this GM's grid is a square - 2*kContentSize on a side
-    static constexpr int kTotalWidth = (2*kContentSize+kPad) * kSkTileModeCount + kPad;
-    static constexpr int kTotalHeight = (2*kContentSize+kPad) * kSkTileModeCount + kPad;
+    inline static constexpr int kTotalWidth = (2*kContentSize+kPad) * kSkTileModeCount + kPad;
+    inline static constexpr int kTotalHeight = (2*kContentSize+kPad) * kSkTileModeCount + kPad;
 
     GrSurfaceOrigin    fOrigin;
     SkIRect            fContentRect;
diff --git a/gm/lighting.cpp b/gm/lighting.cpp
index 268842a..1d78234 100644
--- a/gm/lighting.cpp
+++ b/gm/lighting.cpp
@@ -180,7 +180,7 @@
     }
 
 private:
-    static constexpr int kStartAzimuth = 225;
+    inline static constexpr int kStartAzimuth = 225;
 
     SkBitmap fBitmap;
     SkScalar fAzimuth;
diff --git a/gm/mandoline.cpp b/gm/mandoline.cpp
index 9a0f6ca..bb2a3fd 100644
--- a/gm/mandoline.cpp
+++ b/gm/mandoline.cpp
@@ -25,7 +25,7 @@
 // Slices paths into sliver-size contours shaped like ice cream cones.
 class MandolineSlicer {
 public:
-    static constexpr int kDefaultSubdivisions = 10;
+    inline static constexpr int kDefaultSubdivisions = 10;
 
     MandolineSlicer(SkPoint anchorPt) {
         fPath.setFillType(SkPathFillType::kEvenOdd);
diff --git a/gm/mixedtextblobs.cpp b/gm/mixedtextblobs.cpp
index e7b6828..a84726e 100644
--- a/gm/mixedtextblobs.cpp
+++ b/gm/mixedtextblobs.cpp
@@ -157,8 +157,8 @@
     const char* fEmojiText;
     sk_sp<SkTextBlob> fBlob;
 
-    static constexpr int kWidth = 1250;
-    static constexpr int kHeight = 700;
+    inline static constexpr int kWidth = 1250;
+    inline static constexpr int kHeight = 700;
 
     using INHERITED = GM;
 };
diff --git a/gm/nested.cpp b/gm/nested.cpp
index 2f2386b..039f32c 100644
--- a/gm/nested.cpp
+++ b/gm/nested.cpp
@@ -131,8 +131,8 @@
     }
 
 private:
-    static constexpr int kImageWidth = 269;
-    static constexpr int kImageHeight = 134;
+    inline static constexpr int kImageWidth = 269;
+    inline static constexpr int kImageHeight = 134;
 
     bool fDoAA;
     bool fFlipped;
diff --git a/gm/pathcontourstart.cpp b/gm/pathcontourstart.cpp
index 8fcadaa..d79e09a 100644
--- a/gm/pathcontourstart.cpp
+++ b/gm/pathcontourstart.cpp
@@ -84,8 +84,8 @@
     }
 
 private:
-    static constexpr int kImageWidth = 1200;
-    static constexpr int kImageHeight = 600;
+    inline static constexpr int kImageWidth = 1200;
+    inline static constexpr int kImageHeight = 600;
 
     SkPaint fDashPaint, fPointsPaint;
     SkRect  fRect;
diff --git a/gm/perspimages.cpp b/gm/perspimages.cpp
index c8afc0d..a97a2c8 100644
--- a/gm/perspimages.cpp
+++ b/gm/perspimages.cpp
@@ -121,7 +121,7 @@
     }
 
 private:
-    static constexpr int kNumImages = 4;
+    inline static constexpr int kNumImages = 4;
     SkTArray<sk_sp<SkImage>> fImages;
 
     using INHERITED = GM;
diff --git a/gm/perspshaders.cpp b/gm/perspshaders.cpp
index 186b1ae..661b251 100644
--- a/gm/perspshaders.cpp
+++ b/gm/perspshaders.cpp
@@ -160,9 +160,9 @@
         canvas->translate(0, SkIntToScalar(kCellSize));
     }
 private:
-    static constexpr int kCellSize = 50;
-    static constexpr int kNumRows = 4;
-    static constexpr int kNumCols = 6;
+    inline static constexpr int kCellSize = 50;
+    inline static constexpr int kNumRows = 4;
+    inline static constexpr int kNumCols = 6;
 
     bool            fDoAA;
     SkPath          fPath;
diff --git a/gm/pixelsnap.cpp b/gm/pixelsnap.cpp
index 659f3f0..31136e6 100644
--- a/gm/pixelsnap.cpp
+++ b/gm/pixelsnap.cpp
@@ -28,15 +28,15 @@
 
 protected:
     // kTrans should be even or checkboards wont agree in different test cases.
-    static constexpr int kTrans = 14;
-    static constexpr int kLabelPad = 4;
+    inline static constexpr int kTrans = 14;
+    inline static constexpr int kLabelPad = 4;
     // The inverse of this value should be a perfect SkScalar.
-    static constexpr int kSubPixelSteps = 8;
-    static constexpr int kLabelTextSize = 9;
+    inline static constexpr int kSubPixelSteps = 8;
+    inline static constexpr int kLabelTextSize = 9;
 
     static_assert(kSubPixelSteps < 99, "label_offset_too_small");
-    static constexpr int kLabelOffsetX = 2 * kLabelTextSize + kLabelPad;
-    static constexpr int kLabelOffsetY = kLabelTextSize + kLabelPad;
+    inline static constexpr int kLabelOffsetX = 2 * kLabelTextSize + kLabelPad;
+    inline static constexpr int kLabelOffsetY = kLabelTextSize + kLabelPad;
 
     SkISize onISize() override {
         return SkISize::Make((kSubPixelSteps + 1) * kTrans + kLabelOffsetX + kLabelPad,
diff --git a/gm/polygonoffset.cpp b/gm/polygonoffset.cpp
index 96ccfb5..a7b1d3d 100644
--- a/gm/polygonoffset.cpp
+++ b/gm/polygonoffset.cpp
@@ -608,11 +608,11 @@
     }
 
 private:
-    static constexpr int kNumPaths = 20;
-    static constexpr int kMaxPathHeight = 100;
-    static constexpr int kMaxOutset = 16;
-    static constexpr int kGMWidth = 512;
-    static constexpr int kGMHeight = 512;
+    inline static constexpr int kNumPaths = 20;
+    inline static constexpr int kMaxPathHeight = 100;
+    inline static constexpr int kMaxOutset = 16;
+    inline static constexpr int kGMWidth = 512;
+    inline static constexpr int kGMHeight = 512;
 
     bool fConvexOnly;
 
diff --git a/gm/polygons.cpp b/gm/polygons.cpp
index 511391c..da515ce 100644
--- a/gm/polygons.cpp
+++ b/gm/polygons.cpp
@@ -160,11 +160,11 @@
     }
 
 private:
-    static constexpr int kNumPolygons = 8;
-    static constexpr int kCellSize = 100;
-    static constexpr int kNumExtraStyles = 2;
-    static constexpr int kNumStrokeWidths = 3;
-    static constexpr int kNumJoins = 3;
+    inline static constexpr int kNumPolygons = 8;
+    inline static constexpr int kCellSize = 100;
+    inline static constexpr int kNumExtraStyles = 2;
+    inline static constexpr int kNumStrokeWidths = 3;
+    inline static constexpr int kNumJoins = 3;
 
     SkTArray<SkPath> fPolygons;
     using INHERITED = GM;
diff --git a/gm/rrects.cpp b/gm/rrects.cpp
index e056b7a..337ad84 100644
--- a/gm/rrects.cpp
+++ b/gm/rrects.cpp
@@ -188,17 +188,18 @@
 private:
     Type fType;
 
-    static constexpr int kImageWidth = 640;
-    static constexpr int kImageHeight = 480;
+    inline static constexpr int kImageWidth = 640;
+    inline static constexpr int kImageHeight = 480;
 
-    static constexpr int kTileX = 80;
-    static constexpr int kTileY = 40;
+    inline static constexpr int kTileX = 80;
+    inline static constexpr int kTileY = 40;
 
-    static constexpr int kNumSimpleCases = 7;
-    static constexpr int kNumComplexCases = 35;
+    inline static constexpr int kNumSimpleCases = 7;
+    inline static constexpr int kNumComplexCases = 35;
+
     static const SkVector gRadii[kNumComplexCases][4];
 
-    static constexpr int kNumRRects = kNumSimpleCases + kNumComplexCases;
+    inline static constexpr int kNumRRects = kNumSimpleCases + kNumComplexCases;
     SkRRect fRRects[kNumRRects];
 
     using INHERITED = GM;
diff --git a/gm/rsxtext.cpp b/gm/rsxtext.cpp
index cfd0acd..9df73f1 100644
--- a/gm/rsxtext.cpp
+++ b/gm/rsxtext.cpp
@@ -100,9 +100,9 @@
                 ->makeWithLocalMatrix(outer_lm);
     }
 
-    static constexpr float kSZ     = 300,
-                           kFontSZ = kSZ * 0.38,
-                           kScale  = 1.4f;
+    inline static constexpr float kSZ     = 300,
+                                  kFontSZ = kSZ * 0.38,
+                                  kScale  = 1.4f;
 
     sk_sp<SkTextBlob> fBlob;
 };
diff --git a/gm/texelsubset.cpp b/gm/texelsubset.cpp
index bf1f488..f0bc241 100644
--- a/gm/texelsubset.cpp
+++ b/gm/texelsubset.cpp
@@ -214,9 +214,9 @@
     }
 
 private:
-    static constexpr SkISize kImageSize = {128, 88};
-    static constexpr SkScalar kDrawPad = 10.f;
-    static constexpr SkScalar kTestPad = 10.f;
+    inline static constexpr SkISize kImageSize = {128, 88};
+    inline static constexpr SkScalar kDrawPad = 10.f;
+    inline static constexpr SkScalar kTestPad = 10.f;
     SkBitmap fBitmap;
     Filter fFilter;
     MipmapMode fMipmapMode;
diff --git a/gm/textblobblockreordering.cpp b/gm/textblobblockreordering.cpp
index 0cb5f82..2f93503 100644
--- a/gm/textblobblockreordering.cpp
+++ b/gm/textblobblockreordering.cpp
@@ -90,8 +90,8 @@
 private:
     sk_sp<SkTextBlob> fBlob;
 
-    static constexpr int kWidth = 275;
-    static constexpr int kHeight = 200;
+    inline static constexpr int kWidth = 275;
+    inline static constexpr int kHeight = 200;
 
     using INHERITED = GM;
 };
diff --git a/gm/textblobcolortrans.cpp b/gm/textblobcolortrans.cpp
index 1077160..1a189d2 100644
--- a/gm/textblobcolortrans.cpp
+++ b/gm/textblobcolortrans.cpp
@@ -94,8 +94,8 @@
 private:
     sk_sp<SkTextBlob> fBlob;
 
-    static constexpr int kWidth = 675;
-    static constexpr int kHeight = 1600;
+    inline static constexpr int kWidth = 675;
+    inline static constexpr int kHeight = 1600;
 
     using INHERITED = GM;
 };
diff --git a/gm/textblobgeometrychange.cpp b/gm/textblobgeometrychange.cpp
index 122133c..26c0b9d 100644
--- a/gm/textblobgeometrychange.cpp
+++ b/gm/textblobgeometrychange.cpp
@@ -69,8 +69,8 @@
     }
 
 private:
-    static constexpr int kWidth = 200;
-    static constexpr int kHeight = 200;
+    inline static constexpr int kWidth = 200;
+    inline static constexpr int kHeight = 200;
 
     using INHERITED = GM;
 };
diff --git a/gm/textblobrandomfont.cpp b/gm/textblobrandomfont.cpp
index 122d6fd..6d70559 100644
--- a/gm/textblobrandomfont.cpp
+++ b/gm/textblobrandomfont.cpp
@@ -166,8 +166,8 @@
 private:
     sk_sp<SkTextBlob> fBlob;
 
-    static constexpr int kWidth = 2000;
-    static constexpr int kHeight = 1600;
+    inline static constexpr int kWidth = 2000;
+    inline static constexpr int kHeight = 1600;
 
     using INHERITED = GM;
 };
diff --git a/gm/textblobtransforms.cpp b/gm/textblobtransforms.cpp
index bee808a..b5e9f83 100644
--- a/gm/textblobtransforms.cpp
+++ b/gm/textblobtransforms.cpp
@@ -167,8 +167,8 @@
 private:
     sk_sp<SkTextBlob> fBlob;
 
-    static constexpr int kWidth = 1000;
-    static constexpr int kHeight = 1200;
+    inline static constexpr int kWidth = 1000;
+    inline static constexpr int kHeight = 1200;
 
     using INHERITED = GM;
 };
diff --git a/gm/textblobuseaftergpufree.cpp b/gm/textblobuseaftergpufree.cpp
index 2154944..947f6bf 100644
--- a/gm/textblobuseaftergpufree.cpp
+++ b/gm/textblobuseaftergpufree.cpp
@@ -58,8 +58,8 @@
     }
 
 private:
-    static constexpr int kWidth = 200;
-    static constexpr int kHeight = 200;
+    inline static constexpr int kWidth = 200;
+    inline static constexpr int kHeight = 200;
 
     using INHERITED = GM;
 };
diff --git a/gm/variedtext.cpp b/gm/variedtext.cpp
index 002c2a8..47b680d 100644
--- a/gm/variedtext.cpp
+++ b/gm/variedtext.cpp
@@ -143,9 +143,9 @@
     bool runAsBench() const override { return true; }
 
 private:
-    static constexpr int kCnt = 30;
-    static constexpr int kMinLength = 15;
-    static constexpr int kMaxLength = 40;
+    inline static constexpr int kCnt = 30;
+    inline static constexpr int kMinLength = 15;
+    inline static constexpr int kMaxLength = 40;
 
     bool        fEffectiveClip;
     bool        fLCD;
diff --git a/gm/widebuttcaps.cpp b/gm/widebuttcaps.cpp
index 8f35d78..a8c2a9d 100644
--- a/gm/widebuttcaps.cpp
+++ b/gm/widebuttcaps.cpp
@@ -107,7 +107,7 @@
     //
     // - >=4 because the tessellator code will just assume we have enough to combine a miter join
     //   and line in a single patch. (Requires 4 segments. Spec required minimum is 64.)
-    static constexpr int kMaxTessellationSegmentsOverride = 5;
+    inline static constexpr int kMaxTessellationSegmentsOverride = 5;
 
     void modifyGrContextOptions(GrContextOptions* options) override {
         options->fMaxTessellationSegmentsOverride = kMaxTessellationSegmentsOverride;
diff --git a/gm/yuvtorgbsubset.cpp b/gm/yuvtorgbsubset.cpp
index a4c587d..df41aa1 100644
--- a/gm/yuvtorgbsubset.cpp
+++ b/gm/yuvtorgbsubset.cpp
@@ -168,7 +168,7 @@
     SkYUVAPixmaps fPixmaps;
     GrYUVATextureProxies fProxies;
 
-    static constexpr SkScalar kTestPad = 10.f;
+    inline static constexpr SkScalar kTestPad = 10.f;
 
     using INHERITED = GM;
 };
diff --git a/modules/canvaskit/skottie_bindings.cpp b/modules/canvaskit/skottie_bindings.cpp
index febf8b8..1de0331 100644
--- a/modules/canvaskit/skottie_bindings.cpp
+++ b/modules/canvaskit/skottie_bindings.cpp
@@ -140,8 +140,8 @@
         fLogger.call<void>(func, std::string(msg), std::string(json));
     }
 
-    static constexpr char kWrnFunc[] = "onWarning",
-                          kErrFunc[] = "onError";
+    inline static constexpr char kWrnFunc[] = "onWarning",
+                                 kErrFunc[] = "onError";
 
     const emscripten::val fLogger;
 };
diff --git a/modules/skottie/gm/ExternalProperties.cpp b/modules/skottie/gm/ExternalProperties.cpp
index 7a4422c..cac7767 100644
--- a/modules/skottie/gm/ExternalProperties.cpp
+++ b/modules/skottie/gm/ExternalProperties.cpp
@@ -126,7 +126,7 @@
         }
     }
 
-    static constexpr SkScalar kSize = 800;
+    inline static constexpr SkScalar kSize = 800;
 
     sk_sp<skottie::Animation>                             fAnimation;
     std::unique_ptr<skottie_utils::CustomPropertyManager> fPropManager;
diff --git a/modules/skottie/gm/SkottieGM.cpp b/modules/skottie/gm/SkottieGM.cpp
index 0f298b9..e0dab25 100644
--- a/modules/skottie/gm/SkottieGM.cpp
+++ b/modules/skottie/gm/SkottieGM.cpp
@@ -81,7 +81,7 @@
     }
 
 private:
-    static constexpr SkScalar kSize = 800;
+    inline static constexpr SkScalar kSize = 800;
 
     sk_sp<skottie::Animation> fAnimation;
 
@@ -164,7 +164,7 @@
     }
 
 private:
-    static constexpr SkScalar kSize = 800;
+    inline static constexpr SkScalar kSize = 800;
 
     const char*                                                fName;
     const char*                                                fResource;
@@ -232,7 +232,7 @@
         }
     };
 
-    static constexpr SkScalar kSize = 800;
+    inline static constexpr SkScalar kSize = 800;
 
     sk_sp<skottie::Animation> fAnimation;
 
diff --git a/modules/skottie/src/animator/KeyframeAnimator.h b/modules/skottie/src/animator/KeyframeAnimator.h
index 845eb08..90b4b3d 100644
--- a/modules/skottie/src/animator/KeyframeAnimator.h
+++ b/modules/skottie/src/animator/KeyframeAnimator.h
@@ -54,9 +54,9 @@
                       //   1 -> linear
                       //   n -> cubic: cubic_mappers[n-2]
 
-    static constexpr uint32_t kConstantMapping  = 0;
-    static constexpr uint32_t kLinearMapping    = 1;
-    static constexpr uint32_t kCubicIndexOffset = 2;
+    inline static constexpr uint32_t kConstantMapping  = 0;
+    inline static constexpr uint32_t kLinearMapping    = 1;
+    inline static constexpr uint32_t kCubicIndexOffset = 2;
 };
 
 class KeyframeAnimator : public Animator {
diff --git a/modules/skottie/src/text/SkottieShaper.cpp b/modules/skottie/src/text/SkottieShaper.cpp
index 4468cf9..69165a8 100644
--- a/modules/skottie/src/text/SkottieShaper.cpp
+++ b/modules/skottie/src/text/SkottieShaper.cpp
@@ -331,7 +331,7 @@
         return fDesc.fAscent ? fDesc.fAscent : fFirstLineAscent;
     }
 
-    static constexpr SkGlyphID kMissingGlyphID = 0;
+    inline static constexpr SkGlyphID kMissingGlyphID = 0;
 
     const Shaper::TextDesc&   fDesc;
     const SkRect&             fBox;
diff --git a/modules/svg/src/SkSVGTextPriv.h b/modules/svg/src/SkSVGTextPriv.h
index ab89825..67698a8 100644
--- a/modules/svg/src/SkSVGTextPriv.h
+++ b/modules/svg/src/SkSVGTextPriv.h
@@ -65,7 +65,7 @@
         bool isImplicitRotate() const { return fImplicitRotate; }
 
     private:
-        static constexpr auto kNone = std::numeric_limits<float>::infinity();
+        inline static constexpr auto kNone = std::numeric_limits<float>::infinity();
 
         float fStorage[5]     = { kNone, kNone, kNone, kNone, kNone };
         bool  fImplicitRotate = false;
diff --git a/samplecode/Sample3D.cpp b/samplecode/Sample3D.cpp
index 4ddc15d..d5c6bcf 100644
--- a/samplecode/Sample3D.cpp
+++ b/samplecode/Sample3D.cpp
@@ -176,8 +176,8 @@
     SkScalar    fAngleSpeed = 0,
                 fAngleSign = 1;
 
-    static constexpr double kSlowDown = 4;
-    static constexpr SkScalar kMaxSpeed = 16;
+    inline static constexpr double kSlowDown = 4;
+    inline static constexpr SkScalar kMaxSpeed = 16;
 
 public:
     void update(SkV3 axis, SkScalar angle) {
diff --git a/samplecode/SampleChart.cpp b/samplecode/SampleChart.cpp
index 46e4dec..37b9d06 100644
--- a/samplecode/SampleChart.cpp
+++ b/samplecode/SampleChart.cpp
@@ -79,9 +79,9 @@
 // A set of scrolling line plots with the area between each plot filled. Stresses out GPU path
 // filling
 class ChartView : public Sample {
-    static constexpr int kNumGraphs = 5;
-    static constexpr int kPixelsPerTick = 3;
-    static constexpr int kShiftPerFrame = 1;
+    inline static constexpr int kNumGraphs = 5;
+    inline static constexpr int kPixelsPerTick = 3;
+    inline static constexpr int kShiftPerFrame = 1;
     int                 fShift = 0;
     SkISize             fSize = {-1, -1};
     SkTDArray<SkScalar> fData[kNumGraphs];
diff --git a/samplecode/SampleChineseFling.cpp b/samplecode/SampleChineseFling.cpp
index 081433c..0e62725 100644
--- a/samplecode/SampleChineseFling.cpp
+++ b/samplecode/SampleChineseFling.cpp
@@ -38,8 +38,8 @@
 }
 
 class ChineseFlingView : public Sample {
-    static constexpr int kNumBlobs = 200;
-    static constexpr int kWordLength = 16;
+    inline static constexpr int kNumBlobs = 200;
+    inline static constexpr int kWordLength = 16;
 
     sk_sp<SkTypeface>    fTypeface;
     SkFontMetrics        fMetrics;
@@ -103,8 +103,8 @@
 };
 
 class ChineseZoomView : public Sample {
-    static constexpr int kNumBlobs = 8;
-    static constexpr int kParagraphLength = 175;
+    inline static constexpr int kNumBlobs = 8;
+    inline static constexpr int kParagraphLength = 175;
 
     bool                 fAfterFirstFrame = false;
     sk_sp<SkTypeface>    fTypeface;
diff --git a/samplecode/SampleCowboy.cpp b/samplecode/SampleCowboy.cpp
index 9c9a20a..2ed47cb 100644
--- a/samplecode/SampleCowboy.cpp
+++ b/samplecode/SampleCowboy.cpp
@@ -22,7 +22,7 @@
 
 namespace {
 class AnimatedSVGSample : public Sample {
-    static constexpr auto kAnimationIterations = 5;
+    inline static constexpr auto kAnimationIterations = 5;
     enum State {
         kZoomIn,
         kScroll,
diff --git a/samplecode/SampleFlutterAnimate.cpp b/samplecode/SampleFlutterAnimate.cpp
index c823722..48198bf 100644
--- a/samplecode/SampleFlutterAnimate.cpp
+++ b/samplecode/SampleFlutterAnimate.cpp
@@ -74,7 +74,7 @@
         }
     }
 
-    static constexpr double kDuration = 5.0;
+    inline static constexpr double kDuration = 5.0;
     double fCurrTime;
     double fResetTime;
     SkRandom fRand;
@@ -86,7 +86,7 @@
         SkScalar fEndRotation;
     };
     sk_sp<SkTypeface> fTypeface;
-    static constexpr int kNumChars = 40;
+    inline static constexpr int kNumChars = 40;
     AnimatedChar fChars[kNumChars];
 
     using INHERITED = Sample;
diff --git a/samplecode/SampleSimpleStroker.cpp b/samplecode/SampleSimpleStroker.cpp
index 999b084..651d2ed 100644
--- a/samplecode/SampleSimpleStroker.cpp
+++ b/samplecode/SampleSimpleStroker.cpp
@@ -352,7 +352,7 @@
     float fWidth = 175;
     SkPaint fPtsPaint, fStrokePaint, fMirrorStrokePaint, fNewFillPaint, fHiddenPaint,
             fSkeletonPaint;
-    static constexpr int kN = 3;
+    inline static constexpr int kN = 3;
 
 public:
     SkPoint fPts[kN];
diff --git a/samplecode/SampleTextureUpload.cpp b/samplecode/SampleTextureUpload.cpp
index 4f0757e..933748c 100644
--- a/samplecode/SampleTextureUpload.cpp
+++ b/samplecode/SampleTextureUpload.cpp
@@ -17,9 +17,9 @@
  * This sample exercises heavy texture updates and uploads.
  */
 class TextureUploadSample : public Sample {
-    static constexpr int kMinTileSize = 128;
-    static constexpr int kMaxTileSize = 2048;
-    static constexpr float kGridScale = 0.25f;
+    inline static constexpr int kMinTileSize = 128;
+    inline static constexpr int kMaxTileSize = 2048;
+    inline static constexpr float kGridScale = 0.25f;
 
     bool fDrawTexturesToScreen = true;
     int fTileSize = 256;
diff --git a/samplecode/SampleThinAA.cpp b/samplecode/SampleThinAA.cpp
index 452548d..5989deb 100644
--- a/samplecode/SampleThinAA.cpp
+++ b/samplecode/SampleThinAA.cpp
@@ -18,8 +18,8 @@
 
 class ShapeRenderer : public SkRefCntBase {
 public:
-    static constexpr SkScalar kTileWidth = 20.f;
-    static constexpr SkScalar kTileHeight = 20.f;
+    inline static constexpr SkScalar kTileWidth = 20.f;
+    inline static constexpr SkScalar kTileHeight = 20.f;
 
     // Draw the shape, limited to kTileWidth x kTileHeight. It must apply the local subpixel (tx,
     // ty) translation and rotation by angle. Prior to these transform adjustments, the SkCanvas
diff --git a/samplecode/SampleTiming.cpp b/samplecode/SampleTiming.cpp
index 9e237a0..d8e3216 100644
--- a/samplecode/SampleTiming.cpp
+++ b/samplecode/SampleTiming.cpp
@@ -12,8 +12,8 @@
 #include <chrono>
 
 struct TimingSample : public Sample {
-    static constexpr int W = 24,
-                         H = 16;
+    inline static constexpr int W = 24,
+                                H = 16;
     sk_sp<SkImage> fImg;
 
     SkString name() override { return SkString("Timing"); }
diff --git a/samplecode/SampleVariableWidthStroker.cpp b/samplecode/SampleVariableWidthStroker.cpp
index 7d9a352..65efa11 100644
--- a/samplecode/SampleVariableWidthStroker.cpp
+++ b/samplecode/SampleVariableWidthStroker.cpp
@@ -52,7 +52,7 @@
  */
 class ScalarBezCurve {
 public:
-    static constexpr int kDegreeInvalid = -1;
+    inline static constexpr int kDegreeInvalid = -1;
 
     /** Creates an empty curve with invalid degree. */
     ScalarBezCurve() : fDegree(kDegreeInvalid) {}
@@ -1374,7 +1374,7 @@
     float fWidth = 175;
     SkPaint fPtsPaint, fStrokePaint, fNewFillPaint, fHiddenPaint, fSkeletonPaint,
             fStrokePointsPaint;
-    static constexpr int kNPts = 5;
+    inline static constexpr int kNPts = 5;
     std::array<SkPoint, kNPts> fPathPts;
     SkSize fWinSize;
     SkVarWidthStroker::LengthMetric fLengthMetric;
diff --git a/src/codec/SkBmpCodec.h b/src/codec/SkBmpCodec.h
index 385a031..c150692 100644
--- a/src/codec/SkBmpCodec.h
+++ b/src/codec/SkBmpCodec.h
@@ -102,8 +102,8 @@
      * BMPs are typically encoded as BGRA/BGR so this is a more efficient choice
      * than RGBA.
      */
-    static constexpr SkColorType kXformSrcColorType = kBGRA_8888_SkColorType;
-    static constexpr auto kXformSrcColorFormat = skcms_PixelFormat_BGRA_8888;
+    inline static constexpr SkColorType kXformSrcColorType = kBGRA_8888_SkColorType;
+    inline static constexpr auto kXformSrcColorFormat = skcms_PixelFormat_BGRA_8888;
 
 private:
 
diff --git a/src/codec/SkBmpRLECodec.h b/src/codec/SkBmpRLECodec.h
index ae9c5a3..b920115 100644
--- a/src/codec/SkBmpRLECodec.h
+++ b/src/codec/SkBmpRLECodec.h
@@ -95,25 +95,25 @@
 
     SkSampler* getSampler(bool createIfNecessary) override;
 
-    sk_sp<SkColorTable>        fColorTable;
+    sk_sp<SkColorTable>               fColorTable;
     // fNumColors is the number specified in the header, or 0 if not present in the header.
-    const uint32_t             fNumColors;
-    const uint32_t             fBytesPerColor;
-    const uint32_t             fOffset;
+    const uint32_t                    fNumColors;
+    const uint32_t                    fBytesPerColor;
+    const uint32_t                    fOffset;
 
-    static constexpr size_t    kBufferSize = 4096;
-    uint8_t                    fStreamBuffer[kBufferSize];
-    size_t                     fBytesBuffered;
+    inline static constexpr size_t    kBufferSize = 4096;
+    uint8_t                           fStreamBuffer[kBufferSize];
+    size_t                            fBytesBuffered;
 
-    uint32_t                   fCurrRLEByte;
-    int                        fSampleX;
-    std::unique_ptr<SkSampler> fSampler;
+    uint32_t                          fCurrRLEByte;
+    int                               fSampleX;
+    std::unique_ptr<SkSampler>        fSampler;
 
     // Scanline decodes allow the client to ask for a single scanline at a time.
     // This can be tricky when the RLE encoding instructs the decoder to jump down
     // multiple lines.  This field keeps track of lines that need to be skipped
     // on subsequent calls to decodeRows().
-    int                        fLinesToSkip;
+    int                               fLinesToSkip;
 
     using INHERITED = SkBmpCodec;
 };
diff --git a/src/codec/SkFrameHolder.h b/src/codec/SkFrameHolder.h
index 7b4031e..44cb314 100644
--- a/src/codec/SkFrameHolder.h
+++ b/src/codec/SkFrameHolder.h
@@ -151,7 +151,7 @@
     virtual SkEncodedInfo::Alpha onReportedAlpha() const = 0;
 
 private:
-    static constexpr int kUninitialized = -2;
+    inline static constexpr int kUninitialized = -2;
 
     const int                           fId;
     bool                                fHasAlpha;
diff --git a/src/codec/SkStreamBuffer.h b/src/codec/SkStreamBuffer.h
index 465d2f5..6aae5fe 100644
--- a/src/codec/SkStreamBuffer.h
+++ b/src/codec/SkStreamBuffer.h
@@ -87,7 +87,7 @@
     sk_sp<SkData> getDataAtPosition(size_t position, size_t length);
 
 private:
-    static constexpr size_t kMaxSize = 256 * 3;
+    inline static constexpr size_t kMaxSize = 256 * 3;
 
     std::unique_ptr<SkStream>   fStream;
     size_t                      fPosition;
diff --git a/src/core/SkBlockAllocator.h b/src/core/SkBlockAllocator.h
index c147558..56609bd 100644
--- a/src/core/SkBlockAllocator.h
+++ b/src/core/SkBlockAllocator.h
@@ -49,7 +49,7 @@
 public:
     // Largest size that can be requested from allocate(), chosen because it's the largest pow-2
     // that is less than int32_t::max()/2.
-    static constexpr int kMaxAllocationSize = 1 << 29;
+    inline static constexpr int kMaxAllocationSize = 1 << 29;
 
     enum class GrowthPolicy : int {
         kFixed,       // Next block size = N
@@ -58,7 +58,7 @@
         kExponential, //   = 2^#blocks * N
         kLast = kExponential
     };
-    static constexpr int kGrowthPolicyCount = static_cast<int>(GrowthPolicy::kLast) + 1;
+    inline static constexpr int kGrowthPolicyCount = static_cast<int>(GrowthPolicy::kLast) + 1;
 
     class Block;
 
@@ -398,8 +398,8 @@
     inline BlockIter<false, true> rblocks() const;
 
 #ifdef SK_DEBUG
-    static constexpr int kAssignedMarker = 0xBEEFFACE;
-    static constexpr int kFreedMarker    = 0xCAFEBABE;
+    inline static constexpr int kAssignedMarker = 0xBEEFFACE;
+    inline static constexpr int kFreedMarker    = 0xCAFEBABE;
 
     void validate() const;
 #endif
@@ -408,7 +408,7 @@
     friend class BlockAllocatorTestAccess;
     friend class TBlockListTestAccess;
 
-    static constexpr int kDataStart = sizeof(Block);
+    inline static constexpr int kDataStart = sizeof(Block);
     #ifdef SK_FORCE_8_BYTE_ALIGNMENT
         // This is an issue for WASM builds using emscripten, which had std::max_align_t = 16, but
         // was returning pointers only aligned to 8 bytes.
@@ -417,11 +417,11 @@
         // Setting this to 8 will let SkBlockAllocator properly correct for the pointer address if
         // a 16-byte aligned allocation is requested in wasm (unlikely since we don't use long
         // doubles).
-        static constexpr size_t kAddressAlign = 8;
+        inline static constexpr size_t kAddressAlign = 8;
     #else
         // The alignment Block addresses will be at when created using operator new
         // (spec-compliant is pointers are aligned to max_align_t).
-        static constexpr size_t kAddressAlign = alignof(std::max_align_t);
+        inline static constexpr size_t kAddressAlign = alignof(std::max_align_t);
     #endif
 
     // Calculates the size of a new Block required to store a kMaxAllocationSize request for the
diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp
index 2efcf06..7e92a23 100644
--- a/src/core/SkColorSpace.cpp
+++ b/src/core/SkColorSpace.cpp
@@ -245,9 +245,9 @@
 
 struct ColorSpaceHeader {
     // Flag values, only used by old (k0_Version) serialization
-    static constexpr uint8_t kMatrix_Flag     = 1 << 0;
-    static constexpr uint8_t kICC_Flag        = 1 << 1;
-    static constexpr uint8_t kTransferFn_Flag = 1 << 3;
+    inline static constexpr uint8_t kMatrix_Flag     = 1 << 0;
+    inline static constexpr uint8_t kICC_Flag        = 1 << 1;
+    inline static constexpr uint8_t kTransferFn_Flag = 1 << 3;
 
     uint8_t fVersion = kCurrent_Version;
 
diff --git a/src/core/SkFontPriv.h b/src/core/SkFontPriv.h
index 922bd91..28ef438 100644
--- a/src/core/SkFontPriv.h
+++ b/src/core/SkFontPriv.h
@@ -32,7 +32,7 @@
      *  constraints, but since we ask for unhinted paths, the two values
      *  need not match per-se.
      */
-    static constexpr int kCanonicalTextSizeForPaths  = 64;
+    inline static constexpr int kCanonicalTextSizeForPaths  = 64;
 
     /**
      *  Return a matrix that applies the paint's text values: size, scale, skew
diff --git a/src/core/SkGaussFilter.h b/src/core/SkGaussFilter.h
index 1cf6eee..11ff4a8 100644
--- a/src/core/SkGaussFilter.h
+++ b/src/core/SkGaussFilter.h
@@ -14,7 +14,7 @@
 // Produces values as defined in "Scale-Space for Discrete Signals" by Tony Lindeberg.
 class SkGaussFilter {
 public:
-    static constexpr int kGaussArrayMax = 6;
+    inline static constexpr int kGaussArrayMax = 6;
 
     explicit SkGaussFilter(double sigma);
 
diff --git a/src/core/SkGlyph.cpp b/src/core/SkGlyph.cpp
index ae2b284..28f9cd5 100644
--- a/src/core/SkGlyph.cpp
+++ b/src/core/SkGlyph.cpp
@@ -12,8 +12,6 @@
 #include "src/pathops/SkPathOpsCubic.h"
 #include "src/pathops/SkPathOpsQuad.h"
 
-constexpr SkIPoint SkPackedGlyphID::kXYFieldMask;
-
 SkMask SkGlyph::mask() const {
     SkMask mask;
     mask.fImage = (uint8_t*)fImage;
diff --git a/src/core/SkGlyph.h b/src/core/SkGlyph.h
index 5c3911f..c9f9e90 100644
--- a/src/core/SkGlyph.h
+++ b/src/core/SkGlyph.h
@@ -22,7 +22,7 @@
 
 // A combination of SkGlyphID and sub-pixel position information.
 struct SkPackedGlyphID {
-    static constexpr uint32_t kImpossibleID = ~0u;
+    inline static constexpr uint32_t kImpossibleID = ~0u;
     enum {
         // Lengths
         kGlyphIDLen     = 16u,
@@ -44,10 +44,11 @@
         kFixedPointSubPixelPosBits = kFixedPointBinaryPointPos - kSubPixelPosLen,
     };
 
-    static constexpr SkScalar kSubpixelRound = 1.f / (1u << (SkPackedGlyphID::kSubPixelPosLen + 1));
+    inline static constexpr SkScalar kSubpixelRound =
+            1.f / (1u << (SkPackedGlyphID::kSubPixelPosLen + 1));
 
-    static constexpr SkIPoint kXYFieldMask{kSubPixelPosMask << kSubPixelX,
-                                           kSubPixelPosMask << kSubPixelY};
+    inline static constexpr SkIPoint kXYFieldMask{kSubPixelPosMask << kSubPixelX,
+                                                  kSubPixelPosMask << kSubPixelY};
 
     constexpr explicit SkPackedGlyphID(SkGlyphID glyphID)
             : fID{(uint32_t)glyphID << kGlyphID} { }
@@ -353,7 +354,7 @@
     friend class TestSVGTypeface;
     friend class TestTypeface;
 
-    static constexpr uint16_t kMaxGlyphWidth = 1u << 13u;
+    inline static constexpr uint16_t kMaxGlyphWidth = 1u << 13u;
 
     // Support horizontal and vertical skipping strike-through / underlines.
     // The caller walks the linked list looking for a match. For a horizontal underline,
diff --git a/src/core/SkGlyphRunPainter.h b/src/core/SkGlyphRunPainter.h
index 59adbb1..2e1433f 100644
--- a/src/core/SkGlyphRunPainter.h
+++ b/src/core/SkGlyphRunPainter.h
@@ -47,7 +47,7 @@
 public:
     // An atlas consists of plots, and plots hold glyphs. The minimum a plot can be is 256x256.
     // This means that the maximum size a glyph can be is 256x256.
-    static constexpr uint16_t kSkSideTooBigForAtlas = 256;
+    inline static constexpr uint16_t kSkSideTooBigForAtlas = 256;
 };
 
 class SkGlyphRunListPainter {
diff --git a/src/core/SkMaskBlurFilter.cpp b/src/core/SkMaskBlurFilter.cpp
index e9673fa..ed79f70 100644
--- a/src/core/SkMaskBlurFilter.cpp
+++ b/src/core/SkMaskBlurFilter.cpp
@@ -196,7 +196,7 @@
         }
 
     private:
-        static constexpr uint64_t kHalf = static_cast<uint64_t>(1) << 31;
+        inline static constexpr uint64_t kHalf = static_cast<uint64_t>(1) << 31;
 
         uint8_t finalScale(uint32_t sum) const {
             return SkTo<uint8_t>((fWeight * sum + kHalf) >> 32);
diff --git a/src/core/SkPathPriv.h b/src/core/SkPathPriv.h
index 3c4172a..149329b 100644
--- a/src/core/SkPathPriv.h
+++ b/src/core/SkPathPriv.h
@@ -26,7 +26,7 @@
 
     // skbug.com/9906: Not a perfect solution for W plane clipping, but 1/16384 is a
     // reasonable limit (roughly 5e-5)
-    static constexpr SkScalar kW0PlaneDistance = 1.f / (1 << 14);
+    inline static constexpr SkScalar kW0PlaneDistance = 1.f / (1 << 14);
 
     static SkPathFirstDirection AsFirstDirection(SkPathDirection dir) {
         // since we agree numerically for the values in Direction, we can just cast.
diff --git a/src/core/SkRegionPriv.h b/src/core/SkRegionPriv.h
index 2d0559c..402547b 100644
--- a/src/core/SkRegionPriv.h
+++ b/src/core/SkRegionPriv.h
@@ -16,7 +16,7 @@
 
 class SkRegionPriv {
 public:
-    static constexpr int kRunTypeSentinel = 0x7FFFFFFF;
+    inline static constexpr int kRunTypeSentinel = 0x7FFFFFFF;
     typedef SkRegion::RunType RunType;
     typedef SkRegion::RunHead RunHead;
 
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp
index 9c2e7bb..beaefed 100644
--- a/src/core/SkRemoteGlyphCache.cpp
+++ b/src/core/SkRemoteGlyphCache.cpp
@@ -222,8 +222,8 @@
     using GID = SkPackedGlyphID;
     static_assert(GID::kSubPixelX < GID::kGlyphID && GID::kGlyphID < GID::kSubPixelY,
             "SkPackedGlyphID must be organized: sub-y | glyph id | sub-x");
-    static constexpr int kMaxGlyphID = 128;
-    static constexpr int kMaxIndex = kMaxGlyphID * (1u << GID::kSubPixelPosLen);
+    inline static constexpr int kMaxGlyphID = 128;
+    inline static constexpr int kMaxIndex = kMaxGlyphID * (1u << GID::kSubPixelPosLen);
     std::bitset<kMaxIndex> fBits;
 };
 
@@ -603,7 +603,7 @@
     size_t remoteStrikeMapSizeForTesting() const;
 
 private:
-    static constexpr size_t kMaxEntriesInDescriptorMap = 2000u;
+    inline static constexpr size_t kMaxEntriesInDescriptorMap = 2000u;
 
     void checkForDeletedEntries();
 
diff --git a/src/core/SkScalerCache.h b/src/core/SkScalerCache.h
index 5a5123d..def2167 100644
--- a/src/core/SkScalerCache.h
+++ b/src/core/SkScalerCache.h
@@ -156,9 +156,9 @@
     std::vector<SkGlyph*> fGlyphForIndex SK_GUARDED_BY(fMu);
 
     // so we don't grow our arrays a lot
-    static constexpr size_t kMinGlyphCount = 8;
-    static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
-    static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
+    inline static constexpr size_t kMinGlyphCount = 8;
+    inline static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
+    inline static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
 
     SkArenaAlloc            fAlloc SK_GUARDED_BY(fMu) {kMinAllocAmount};
 };
diff --git a/src/core/SkStrikeSpec.h b/src/core/SkStrikeSpec.h
index 84ee87c..07966ba 100644
--- a/src/core/SkStrikeSpec.h
+++ b/src/core/SkStrikeSpec.h
@@ -114,7 +114,7 @@
     const SkGlyph* glyph(SkGlyphID glyphID);
 
 private:
-    static constexpr int kTypicalGlyphCount = 20;
+    inline static constexpr int kTypicalGlyphCount = 20;
     SkAutoSTArray<kTypicalGlyphCount, const SkGlyph*> fGlyphs;
     sk_sp<SkStrike> fStrike;
 };
@@ -129,7 +129,7 @@
                         const SkGlyph* glyph, SkScalar* array, int* count);
 
 private:
-    static constexpr int kTypicalGlyphCount = 20;
+    inline static constexpr int kTypicalGlyphCount = 20;
     SkAutoSTArray<kTypicalGlyphCount, const SkGlyph*> fGlyphs;
     sk_sp<SkStrike> fStrike;
 };
@@ -143,7 +143,7 @@
     const SkDescriptor& descriptor() const;
 
 private:
-    static constexpr int kTypicalGlyphCount = 64;
+    inline static constexpr int kTypicalGlyphCount = 64;
     SkAutoSTArray<kTypicalGlyphCount, const SkGlyph*> fGlyphs;
     sk_sp<SkStrike> fStrike;
 };
diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp
index bd12f5b..19cfe1a 100644
--- a/src/core/SkStroke.cpp
+++ b/src/core/SkStroke.cpp
@@ -63,7 +63,7 @@
 #if DEBUG_CUBIC_RECURSION_DEPTHS
     /* Prints a histogram of recursion depths at process termination. */
     static struct DepthHistogram {
-        static constexpr int kMaxDepth = 75;
+        inline static constexpr int kMaxDepth = 75;
         int fCubicDepths[kMaxDepth + 1];
 
         DepthHistogram() { memset(fCubicDepths, 0, sizeof(fCubicDepths)); }
diff --git a/src/core/SkTBlockList.h b/src/core/SkTBlockList.h
index 0959d25..860366f 100644
--- a/src/core/SkTBlockList.h
+++ b/src/core/SkTBlockList.h
@@ -229,7 +229,7 @@
     template<typename S, int N> friend class SkTBlockList;
     friend class TBlockListTestAccess;  // for fAllocator
 
-    static constexpr size_t StartingSize =
+    inline static constexpr size_t StartingSize =
             SkBlockAllocator::Overhead<alignof(T)>() + StartingItems * sizeof(T);
 
     static T& GetItem(SkBlockAllocator::Block* block, int index) {
diff --git a/src/core/SkVMBlitter.cpp b/src/core/SkVMBlitter.cpp
index 5218e8a..3389a7e 100644
--- a/src/core/SkVMBlitter.cpp
+++ b/src/core/SkVMBlitter.cpp
@@ -33,7 +33,7 @@
         int       y;      // Device y coordinate.
     };
     static_assert(SkIsAlign4(sizeof(BlitterUniforms)), "");
-    static constexpr int kBlitterUniformsCount = sizeof(BlitterUniforms) / 4;
+    inline static constexpr int kBlitterUniformsCount = sizeof(BlitterUniforms) / 4;
 
     static skvm::Coord device_coord(skvm::Builder* p, skvm::Uniforms* uniforms) {
         skvm::I32 dx = p->uniform32(uniforms->base, offsetof(BlitterUniforms, right))
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index e0e1cb8..eb7d9f0 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -124,8 +124,8 @@
         return std::unique_ptr<GrFragmentProcessor>(new ColorTableEffect(*this));
     }
 
-    static constexpr int kTexEffectFPIndex = 0;
-    static constexpr int kInputFPIndex = 1;
+    inline static constexpr int kTexEffectFPIndex = 0;
+    inline static constexpr int kInputFPIndex = 1;
 
 private:
     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
diff --git a/src/gpu/GrBufferAllocPool.cpp b/src/gpu/GrBufferAllocPool.cpp
index a8e2625..4ec84c1 100644
--- a/src/gpu/GrBufferAllocPool.cpp
+++ b/src/gpu/GrBufferAllocPool.cpp
@@ -85,8 +85,6 @@
         static_cast<GrGpuBuffer*>(block.fBuffer.get())->unmap();                     \
     } while (false)
 
-constexpr size_t GrBufferAllocPool::kDefaultBufferSize;
-
 GrBufferAllocPool::GrBufferAllocPool(GrGpu* gpu, GrGpuBufferType bufferType,
                                      sk_sp<CpuBufferCache> cpuBufferCache)
         : fBlocks(8)
diff --git a/src/gpu/GrBufferAllocPool.h b/src/gpu/GrBufferAllocPool.h
index ad57668..ecb9006 100644
--- a/src/gpu/GrBufferAllocPool.h
+++ b/src/gpu/GrBufferAllocPool.h
@@ -33,7 +33,7 @@
  */
 class GrBufferAllocPool : SkNoncopyable {
 public:
-    static constexpr size_t kDefaultBufferSize = 1 << 15;
+    inline static constexpr size_t kDefaultBufferSize = 1 << 15;
 
     /**
      * A cache object that can be shared by multiple GrBufferAllocPool instances. It caches
diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp
index 253043e..2900287 100644
--- a/src/gpu/GrDrawOpAtlas.cpp
+++ b/src/gpu/GrDrawOpAtlas.cpp
@@ -697,5 +697,3 @@
         return { 256, 256 };
     }
 }
-
-constexpr int GrDrawOpAtlasConfig::kMaxAtlasDim;
diff --git a/src/gpu/GrDrawOpAtlas.h b/src/gpu/GrDrawOpAtlas.h
index 9552bd0..4f4f3e9 100644
--- a/src/gpu/GrDrawOpAtlas.h
+++ b/src/gpu/GrDrawOpAtlas.h
@@ -58,8 +58,8 @@
     // These are both restricted by the space they occupy in the PlotLocator.
     // maxPages is also limited by being crammed into the glyph uvs.
     // maxPlots is also limited by the fPlotAlreadyUpdated bitfield in BulkUseTokenUpdater
-    static constexpr auto kMaxMultitexturePages = 4;
-    static constexpr int kMaxPlots = 32;
+    inline static constexpr auto kMaxMultitexturePages = 4;
+    inline static constexpr int kMaxPlots = 32;
 
     /**
      * A PlotLocator specifies the plot and is analogous to a directory path:
@@ -195,7 +195,7 @@
      */
     class GenerationCounter {
     public:
-        static constexpr uint64_t kInvalidGeneration = 0;
+        inline static constexpr uint64_t kInvalidGeneration = 0;
         uint64_t next() {
             return fGeneration++;
         }
@@ -332,7 +332,7 @@
             fPlotsToUpdate.push_back(PlotData(pageIdx, index));
         }
 
-        static constexpr int kMinItems = 4;
+        inline static constexpr int kMinItems = 4;
         SkSTArray<kMinItems, PlotData, true> fPlotsToUpdate;
         uint32_t fPlotAlreadyUpdated[kMaxMultitexturePages]; // TODO: increase this to uint64_t
                                                              //       to allow more plots per page
@@ -547,7 +547,7 @@
     // which limits the largest atlas dimensions to 2048x2048.
     // For simplicity we'll use this constraint for all of our atlas textures.
     // This can be revisited later if we need larger atlases.
-    static constexpr int kMaxAtlasDim = 2048;
+    inline static constexpr int kMaxAtlasDim = 2048;
 
     SkISize fARGBDimensions;
     int     fMaxTextureSize;
diff --git a/src/gpu/GrDynamicAtlas.h b/src/gpu/GrDynamicAtlas.h
index 50538c2..2b076a2 100644
--- a/src/gpu/GrDynamicAtlas.h
+++ b/src/gpu/GrDynamicAtlas.h
@@ -24,8 +24,9 @@
 class GrDynamicAtlas {
 public:
     // As long as GrSurfaceOrigin exists, we just have to decide on one for the atlas texture.
-    static constexpr GrSurfaceOrigin kTextureOrigin = kTopLeft_GrSurfaceOrigin;
-    static constexpr int kPadding = 1;  // Amount of padding below and to the right of each path.
+    inline static constexpr GrSurfaceOrigin kTextureOrigin = kTopLeft_GrSurfaceOrigin;
+    inline static constexpr int kPadding = 1;  // Amount of padding below and to the right of each
+                                               // path.
 
     using LazyAtlasDesc = GrSurfaceProxy::LazySurfaceDesc;
     using LazyInstantiateAtlasCallback = GrSurfaceProxy::LazyInstantiateCallback;
diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h
index 31667b4..c9c2af4 100644
--- a/src/gpu/GrGeometryProcessor.h
+++ b/src/gpu/GrGeometryProcessor.h
@@ -191,7 +191,7 @@
      */
     static uint32_t ComputeCoordTransformsKey(const GrFragmentProcessor& fp);
 
-    static constexpr int kCoordTransformKeyBits = 4;
+    inline static constexpr int kCoordTransformKeyBits = 4;
 
     /**
      * Adds a key on the GrProcessorKeyBuilder that reflects any variety in the code that the
@@ -393,7 +393,7 @@
         return (flags << (2 * kMatrixKeyBits)) |
                ComputeMatrixKeys(shaderCaps, viewMatrix, localMatrix);
     }
-    static constexpr int kMatrixKeyBits = 2;
+    inline static constexpr int kMatrixKeyBits = 2;
 
 protected:
     void setupUniformColor(GrGLSLFPFragmentBuilder* fragBuilder,
diff --git a/src/gpu/GrMemoryPool.h b/src/gpu/GrMemoryPool.h
index 962e591..089fca1 100644
--- a/src/gpu/GrMemoryPool.h
+++ b/src/gpu/GrMemoryPool.h
@@ -28,14 +28,14 @@
     // https://github.com/emscripten-core/emscripten/issues/10072
     // Since Skia does not use "long double" (16 bytes), we should be ok to force it back to 8 bytes
     // until emscripten is fixed.
-    static constexpr size_t kAlignment = 8;
+    inline static constexpr size_t kAlignment = 8;
 #else
     // Guaranteed alignment of pointer returned by allocate().
-    static constexpr size_t kAlignment = alignof(std::max_align_t);
+    inline static constexpr size_t kAlignment = alignof(std::max_align_t);
 #endif
 
     // Smallest block size allocated on the heap (not the smallest reservation via allocate()).
-    static constexpr size_t kMinAllocationSize = 1 << 10;
+    inline static constexpr size_t kMinAllocationSize = 1 << 10;
 
     /**
      * Prealloc size is the amount of space to allocate at pool creation
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index 0e70679..93ea95e 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -200,7 +200,8 @@
                                GrGLSLBuiltinUniformHandles* fBuiltinUniformHandles) const;
 
 private:
-    static constexpr uint8_t kLastInputFlag = (uint8_t)InputFlags::kSnapVerticesToPixelCenters;
+    inline static constexpr uint8_t kLastInputFlag =
+            (uint8_t)InputFlags::kSnapVerticesToPixelCenters;
 
     /** This is a continuation of the public "InputFlags" enum. */
     enum class Flags : uint8_t {
diff --git a/src/gpu/GrSamplerState.h b/src/gpu/GrSamplerState.h
index b9e84ae..8f65507 100644
--- a/src/gpu/GrSamplerState.h
+++ b/src/gpu/GrSamplerState.h
@@ -28,8 +28,8 @@
         kLast = kClampToBorder
     };
 
-    static constexpr int kFilterCount = static_cast<int>(Filter::kLast) + 1;
-    static constexpr int kWrapModeCount = static_cast<int>(WrapMode::kLast) + 1;
+    inline static constexpr int kFilterCount = static_cast<int>(Filter::kLast) + 1;
+    inline static constexpr int kWrapModeCount = static_cast<int>(WrapMode::kLast) + 1;
 
     constexpr GrSamplerState() = default;
 
@@ -108,10 +108,10 @@
         return static_cast<uint8_t>(result);
     }
 
-    static constexpr int kNumUniqueSamplers = (static_cast<int>(WrapMode::kLast  ) + 1)
-                                            * (static_cast<int>(WrapMode::kLast  ) + 1)
-                                            * (static_cast<int>(Filter::kLast    ) + 1)
-                                            * (static_cast<int>(MipmapMode::kLast) + 1);
+    inline static constexpr int kNumUniqueSamplers = (static_cast<int>(WrapMode::kLast  ) + 1)
+                                                   * (static_cast<int>(WrapMode::kLast  ) + 1)
+                                                   * (static_cast<int>(Filter::kLast    ) + 1)
+                                                   * (static_cast<int>(MipmapMode::kLast) + 1);
 private:
     WrapMode fWrapModes[2] = {WrapMode::kClamp, WrapMode::kClamp};
     Filter fFilter = GrSamplerState::Filter::kNearest;
diff --git a/src/gpu/GrStagingBufferManager.h b/src/gpu/GrStagingBufferManager.h
index d2d78ed..ead9014 100644
--- a/src/gpu/GrStagingBufferManager.h
+++ b/src/gpu/GrStagingBufferManager.h
@@ -46,7 +46,7 @@
     }
 
 private:
-    static constexpr size_t kMinStagingBufferSize = 64 * 1024;
+    inline static constexpr size_t kMinStagingBufferSize = 64 * 1024;
 
     struct StagingBuffer {
         StagingBuffer(sk_sp<GrGpuBuffer> buffer, void* mapPtr)
diff --git a/src/gpu/GrStencilSettings.h b/src/gpu/GrStencilSettings.h
index cfaa516..e7b475b 100644
--- a/src/gpu/GrStencilSettings.h
+++ b/src/gpu/GrStencilSettings.h
@@ -106,7 +106,7 @@
     // NOTE: This value is outside the declared range of GrStencilFlags, but since that type is
     // explicitly backed by 'int', it can still represent this constant. clang 11 complains about
     // mixing enum types in bit operations, so this works around that.
-    static constexpr GrStencilFlags kInvalid_PrivateFlag =
+    inline static constexpr GrStencilFlags kInvalid_PrivateFlag =
             static_cast<GrStencilFlags>(kLast_StencilFlag << 1);
 
     uint32_t   fFlags;
diff --git a/src/gpu/GrSubRunAllocator.h b/src/gpu/GrSubRunAllocator.h
index e330666..f82f3ef 100644
--- a/src/gpu/GrSubRunAllocator.h
+++ b/src/gpu/GrSubRunAllocator.h
@@ -87,20 +87,20 @@
 private:
     // The maximum alignment supported by GrBagOfBytes. 16 seems to be a good number for alignment.
     // If a use case for larger alignments is found, we can turn this into a template parameter.
-    static constexpr int kMaxAlignment = std::max(16, (int)alignof(std::max_align_t));
+    inline static constexpr int kMaxAlignment = std::max(16, (int)alignof(std::max_align_t));
     // The largest size that can be allocated. In larger sizes, the block is rounded up to 4K
     // chunks. Leave a 4K of slop.
-    static constexpr int k4K = (1 << 12);
+    inline static constexpr int k4K = (1 << 12);
     // This should never overflow with the calculations done on the code.
-    static constexpr int kMaxByteSize = std::numeric_limits<int>::max() - k4K;
+    inline static constexpr int kMaxByteSize = std::numeric_limits<int>::max() - k4K;
     // The assumed alignment of new char[] given the platform.
     // There is a bug in Emscripten's allocator that make alignment different than max_align_t.
     // kAllocationAlignment accounts for this difference. For more information see:
     // https://github.com/emscripten-core/emscripten/issues/10072
     #if !defined(SK_FORCE_8_BYTE_ALIGNMENT)
-        static constexpr int kAllocationAlignment = alignof(std::max_align_t);
+        inline static constexpr int kAllocationAlignment = alignof(std::max_align_t);
     #else
-        static constexpr int kAllocationAlignment = 8;
+        inline static constexpr int kAllocationAlignment = 8;
     #endif
 
     // The Block starts at the location pointed to by fEndByte.
diff --git a/src/gpu/GrVertexWriter.h b/src/gpu/GrVertexWriter.h
index a4c13a3..495a6e7 100644
--- a/src/gpu/GrVertexWriter.h
+++ b/src/gpu/GrVertexWriter.h
@@ -23,7 +23,7 @@
  * thereof.
  */
 struct GrVertexWriter {
-    constexpr static uint32_t kIEEE_32_infinity = 0x7f800000;
+    inline constexpr static uint32_t kIEEE_32_infinity = 0x7f800000;
 
     void* fPtr;
 
diff --git a/src/gpu/d3d/GrD3DDescriptorTableManager.h b/src/gpu/d3d/GrD3DDescriptorTableManager.h
index fe54a1b..65d792c 100644
--- a/src/gpu/d3d/GrD3DDescriptorTableManager.h
+++ b/src/gpu/d3d/GrD3DDescriptorTableManager.h
@@ -108,7 +108,7 @@
         void prepForSubmit(GrD3DGpu* gpu);
 
     private:
-        static constexpr int kInitialHeapDescriptorCount = 256;
+        inline static constexpr int kInitialHeapDescriptorCount = 256;
 
         std::vector<sk_sp<Heap>> fDescriptorHeaps;
         D3D12_DESCRIPTOR_HEAP_TYPE fHeapType;
diff --git a/src/gpu/d3d/GrD3DResourceProvider.h b/src/gpu/d3d/GrD3DResourceProvider.h
index f9ed87c..64e127b 100644
--- a/src/gpu/d3d/GrD3DResourceProvider.h
+++ b/src/gpu/d3d/GrD3DResourceProvider.h
@@ -149,7 +149,7 @@
             }
         };
         SkLRUCache<DescTableKey, DescTableValue, DescTableHash> fMap;
-        static constexpr int kRangeSizesCount = 8;
+        inline static constexpr int kRangeSizesCount = 8;
         unsigned int fRangeSizes[kRangeSizesCount];
     };
 
diff --git a/src/gpu/d3d/GrD3DRootSignature.h b/src/gpu/d3d/GrD3DRootSignature.h
index 0bc99f4..a56f8b5 100644
--- a/src/gpu/d3d/GrD3DRootSignature.h
+++ b/src/gpu/d3d/GrD3DRootSignature.h
@@ -24,7 +24,7 @@
 
         kLast = kSamplerDescriptorTable
     };
-    static constexpr unsigned int kParamIndexCount = (unsigned int)(ParamIndex::kLast) + 1;
+    inline static constexpr unsigned int kParamIndexCount = (unsigned int)(ParamIndex::kLast) + 1;
 
     bool isCompatible(int numTextureSamplers, int numUAVs) const;
 
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 7648aff..088dc11 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -149,8 +149,6 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-constexpr GrGeometryProcessor::Attribute GrConicEffect::kAttributes[];
-
 GrConicEffect::~GrConicEffect() = default;
 
 void GrConicEffect::addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
@@ -304,8 +302,6 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-constexpr GrGeometryProcessor::Attribute GrQuadEffect::kAttributes[];
-
 GrQuadEffect::~GrQuadEffect() = default;
 
 void GrQuadEffect::addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
diff --git a/src/gpu/effects/GrBezierEffect.h b/src/gpu/effects/GrBezierEffect.h
index eb10d04..f33d803 100644
--- a/src/gpu/effects/GrBezierEffect.h
+++ b/src/gpu/effects/GrBezierEffect.h
@@ -97,7 +97,7 @@
     SkMatrix            fLocalMatrix;
     bool                fUsesLocalCoords;
     uint8_t             fCoverageScale;
-    static constexpr Attribute kAttributes[] = {
+    inline static constexpr Attribute kAttributes[] = {
         {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType},
         {"inConicCoeffs", kFloat4_GrVertexAttribType, kHalf4_GrSLType}
     };
@@ -160,7 +160,7 @@
     bool fUsesLocalCoords;
     uint8_t fCoverageScale;
 
-    static constexpr Attribute kAttributes[] = {
+    inline static constexpr Attribute kAttributes[] = {
         {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType},
         {"inHairQuadEdge", kFloat4_GrVertexAttribType, kHalf4_GrSLType}
     };
diff --git a/src/gpu/effects/GrBicubicEffect.h b/src/gpu/effects/GrBicubicEffect.h
index c193300..f002a6f 100644
--- a/src/gpu/effects/GrBicubicEffect.h
+++ b/src/gpu/effects/GrBicubicEffect.h
@@ -19,8 +19,8 @@
                              // surrounding texels are needed by the kernel in x and y.
     };
 
-    static constexpr SkImage::CubicResampler gMitchell = { 1.0f/3, 1.0f/3 };
-    static constexpr SkImage::CubicResampler gCatmullRom = {    0, 1.0f/2 };
+    inline static constexpr SkImage::CubicResampler gMitchell = { 1.0f/3, 1.0f/3 };
+    inline static constexpr SkImage::CubicResampler gCatmullRom = {    0, 1.0f/2 };
 
     enum class Direction {
         /** Apply bicubic kernel in local coord x, nearest neighbor in y. */
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h
index ab25463..682b890 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.h
+++ b/src/gpu/effects/GrBitmapTextGeoProc.h
@@ -23,7 +23,7 @@
  */
 class GrBitmapTextGeoProc : public GrGeometryProcessor {
 public:
-    static constexpr int kMaxTextures = 4;
+    inline static constexpr int kMaxTextures = 4;
 
     static GrGeometryProcessor* Make(SkArenaAlloc* arena,
                                      const GrShaderCaps& caps,
diff --git a/src/gpu/effects/GrConvexPolyEffect.h b/src/gpu/effects/GrConvexPolyEffect.h
index e2bcc94..de19e6f 100644
--- a/src/gpu/effects/GrConvexPolyEffect.h
+++ b/src/gpu/effects/GrConvexPolyEffect.h
@@ -23,7 +23,7 @@
  */
 class GrConvexPolyEffect : public GrFragmentProcessor {
 public:
-    static constexpr int kMaxEdges = 8;
+    inline static constexpr int kMaxEdges = 8;
 
     /**
      * edges is a set of n edge equations where n is limited to kMaxEdges. It contains 3*n values.
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h
index 634048f..0cbcdf0 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.h
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.h
@@ -54,7 +54,7 @@
  */
 class GrDistanceFieldA8TextGeoProc : public GrGeometryProcessor {
 public:
-    static constexpr int kMaxTextures = 4;
+    inline static constexpr int kMaxTextures = 4;
 
     /** The local matrix should be identity if local coords are not required by the GrPipeline. */
 #ifdef SK_GAMMA_APPLY_TO_A8
@@ -135,7 +135,7 @@
  */
 class GrDistanceFieldPathGeoProc : public GrGeometryProcessor {
 public:
-    static constexpr int kMaxTextures = 4;
+    inline static constexpr int kMaxTextures = 4;
 
     /** The local matrix should be identity if local coords are not required by the GrPipeline. */
     static GrGeometryProcessor* Make(SkArenaAlloc* arena, const GrShaderCaps& caps,
@@ -192,7 +192,7 @@
  */
 class GrDistanceFieldLCDTextGeoProc : public GrGeometryProcessor {
 public:
-    static constexpr int kMaxTextures = 4;
+    inline static constexpr int kMaxTextures = 4;
 
     struct DistanceAdjust {
         SkScalar fR, fG, fB;
diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h
index 8bb67b2..a0f87f5 100644
--- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h
+++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h
@@ -49,7 +49,7 @@
     // samples per fragment program run in DX9SM2 (32). A sigma param of 4.0
     // on a blur filter gives a kernel width of 25 while a sigma of 5.0
     // would exceed a 32 wide kernel.
-    static constexpr int kMaxKernelRadius = 12;
+    inline static constexpr int kMaxKernelRadius = 12;
 
 private:
     class Impl;
@@ -76,7 +76,7 @@
 
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
 
-    static constexpr int kMaxKernelWidth = kMaxKernelRadius + 1;
+    inline static constexpr int kMaxKernelWidth = kMaxKernelRadius + 1;
 
     // The array size must be a multiple of 4 because we pass it as an array of float4 uniform
     // values.
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.h b/src/gpu/effects/GrMatrixConvolutionEffect.h
index eb09746..024fa3f 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.h
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.h
@@ -17,7 +17,7 @@
     // A little bit less than the minimum # uniforms required by DX9SM2 (32).
     // Allows for a 5x5 kernel (or 28x1, for that matter).
     // Must be a multiple of 4, since we upload these in vec4s.
-    static constexpr int kMaxUniformSize = 28;
+    inline static constexpr int kMaxUniformSize = 28;
 
     static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext*,
                                                      GrSurfaceProxyView srcView,
diff --git a/src/gpu/effects/GrTextureEffect.h b/src/gpu/effects/GrTextureEffect.h
index 71c8040..d7bbc3a 100644
--- a/src/gpu/effects/GrTextureEffect.h
+++ b/src/gpu/effects/GrTextureEffect.h
@@ -16,7 +16,7 @@
 
 class GrTextureEffect : public GrFragmentProcessor {
 public:
-    static constexpr float kDefaultBorder[4] = {0};
+    inline static constexpr float kDefaultBorder[4] = {0};
 
     /** Make from a filter. The sampler will be configured with clamp mode. */
     static std::unique_ptr<GrFragmentProcessor> Make(
diff --git a/src/gpu/geometry/GrQuadBuffer.h b/src/gpu/geometry/GrQuadBuffer.h
index c7309d4..15f2216 100644
--- a/src/gpu/geometry/GrQuadBuffer.h
+++ b/src/gpu/geometry/GrQuadBuffer.h
@@ -149,10 +149,10 @@
     };
     static_assert(sizeof(Header) == sizeof(int32_t), "Header should be 4 bytes");
 
-    static constexpr unsigned kSentinel = 0xbaffe;
-    static constexpr int kMetaSize = sizeof(Header) + sizeof(T);
-    static constexpr int k2DQuadFloats = 8;
-    static constexpr int k3DQuadFloats = 12;
+    inline static constexpr unsigned kSentinel = 0xbaffe;
+    inline static constexpr int kMetaSize = sizeof(Header) + sizeof(T);
+    inline static constexpr int k2DQuadFloats = 8;
+    inline static constexpr int k3DQuadFloats = 12;
 
     // Each logical entry in the buffer is a variable length tuple storing device coordinates,
     // optional local coordinates, and metadata. An entry always has a header that defines the
diff --git a/src/gpu/geometry/GrShape.h b/src/gpu/geometry/GrShape.h
index 9dd8976..4d58346 100644
--- a/src/gpu/geometry/GrShape.h
+++ b/src/gpu/geometry/GrShape.h
@@ -52,14 +52,14 @@
     enum class Type : uint8_t {
         kEmpty, kPoint, kRect, kRRect, kPath, kArc, kLine
     };
-    static constexpr int kTypeCount = static_cast<int>(Type::kLine) + 1;
+    inline static constexpr int kTypeCount = static_cast<int>(Type::kLine) + 1;
 
     // The direction and start index used when a shape does not have a representable winding,
     // or when that information was discarded during simplification (kIgnoreWinding_Flag).
-    static constexpr SkPathDirection kDefaultDir   = SkPathDirection::kCW;
-    static constexpr unsigned        kDefaultStart = 0;
+    inline static constexpr SkPathDirection kDefaultDir   = SkPathDirection::kCW;
+    inline static constexpr unsigned        kDefaultStart = 0;
     // The fill rule that is used by asPath() for shapes that aren't already a path.
-    static constexpr SkPathFillType  kDefaultFillType = SkPathFillType::kEvenOdd;
+    inline static constexpr SkPathFillType  kDefaultFillType = SkPathFillType::kEvenOdd;
 
     GrShape() {}
     explicit GrShape(const SkPoint& point) { this->setPoint(point); }
diff --git a/src/gpu/geometry/GrStyledShape.h b/src/gpu/geometry/GrStyledShape.h
index 54e05d3..b7f8445 100644
--- a/src/gpu/geometry/GrStyledShape.h
+++ b/src/gpu/geometry/GrStyledShape.h
@@ -40,7 +40,7 @@
 public:
     // Keys for paths may be extracted from the path data for small paths. Clients aren't supposed
     // to have to worry about this. This value is exposed for unit tests.
-    static constexpr int kMaxKeyFromDataVerbCnt = 10;
+    inline static constexpr int kMaxKeyFromDataVerbCnt = 10;
 
     GrStyledShape() {}
 
diff --git a/src/gpu/gl/GrGLVertexArray.h b/src/gpu/gl/GrGLVertexArray.h
index be72068..7c95eac 100644
--- a/src/gpu/gl/GrGLVertexArray.h
+++ b/src/gpu/gl/GrGLVertexArray.h
@@ -66,7 +66,7 @@
     int count() const { return fAttribArrayStates.count(); }
 
 private:
-    static constexpr int kInvalidDivisor = -1;
+    inline static constexpr int kInvalidDivisor = -1;
 
     /**
      * Tracks the state of glVertexAttribArray for an attribute index.
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
index aff0bc5..aaa0671 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
@@ -120,7 +120,7 @@
 
     void onFinalize() override;
 
-    static constexpr const char kDstColorName[] = "_dstColor";
+    inline static constexpr const char kDstColorName[] = "_dstColor";
 
     GrShaderVar* fCustomColorOutput = nullptr;
 
diff --git a/src/gpu/gradients/GrGradientShader.h b/src/gpu/gradients/GrGradientShader.h
index e08f46c..19948a6 100644
--- a/src/gpu/gradients/GrGradientShader.h
+++ b/src/gpu/gradients/GrGradientShader.h
@@ -41,11 +41,11 @@
         the gradient factory. (The constructor may decide not to use stops, in which case fStops
         will be nullptr). */
     struct RandomParams {
-        static constexpr int kMaxRandomGradientColors = 5;
+        inline static constexpr int kMaxRandomGradientColors = 5;
 
         // Should be of similar magnitude to the draw area of the tests so that the gradient
         // sampling is done at an appropriate scale.
-        static constexpr SkScalar kGradientScale = 256.0f;
+        inline static constexpr SkScalar kGradientScale = 256.0f;
 
         RandomParams(SkRandom* r);
 
diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h
index fc51b76..aea9738 100644
--- a/src/gpu/mtl/GrMtlCaps.h
+++ b/src/gpu/mtl/GrMtlCaps.h
@@ -165,9 +165,9 @@
         int fColorTypeInfoCount = 0;
     };
 #ifdef SK_BUILD_FOR_IOS
-    static constexpr size_t kNumMtlFormats = 17;
+    inline static constexpr size_t kNumMtlFormats = 17;
 #else
-    static constexpr size_t kNumMtlFormats = 16;
+    inline static constexpr size_t kNumMtlFormats = 16;
 #endif
     static size_t GetFormatIndex(MTLPixelFormat);
     FormatInfo fFormatTable[kNumMtlFormats];
diff --git a/src/gpu/mtl/GrMtlRenderTarget.h b/src/gpu/mtl/GrMtlRenderTarget.h
index 30c94d6..0576094 100644
--- a/src/gpu/mtl/GrMtlRenderTarget.h
+++ b/src/gpu/mtl/GrMtlRenderTarget.h
@@ -89,7 +89,7 @@
     // both of these being completely orthogonal. Thus we have a total of 4 types of render passes.
     // We then cache a framebuffer for each type of these render passes.
     // TODO: add support for other flags if needed
-    static constexpr int kNumCachedFramebuffers = 4;
+    inline static constexpr int kNumCachedFramebuffers = 4;
 
     sk_sp<const GrMtlFramebuffer> fCachedFramebuffers[kNumCachedFramebuffers];
 
diff --git a/src/gpu/ops/AtlasTextOp.h b/src/gpu/ops/AtlasTextOp.h
index 5f9fc83..68db35e 100644
--- a/src/gpu/ops/AtlasTextOp.h
+++ b/src/gpu/ops/AtlasTextOp.h
@@ -105,7 +105,7 @@
 
         kLast = kLCDBGRDistanceField
     };
-    static constexpr int kMaskTypeCount = static_cast<int>(MaskType::kLast) + 1;
+    inline static constexpr int kMaskTypeCount = static_cast<int>(MaskType::kLast) + 1;
 
 #if GR_TEST_UTILS && SK_GPU_V1
     static GrOp::Owner CreateOpTestingOnly(skgpu::v1::SurfaceDrawContext*,
diff --git a/src/gpu/ops/FillRRectOp.cpp b/src/gpu/ops/FillRRectOp.cpp
index 4411f74..e2aaaaa 100644
--- a/src/gpu/ops/FillRRectOp.cpp
+++ b/src/gpu/ops/FillRRectOp.cpp
@@ -367,7 +367,7 @@
         this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count());
     }
 
-    static constexpr Attribute kVertexAttribs[] = {
+    inline static constexpr Attribute kVertexAttribs[] = {
             {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
             {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
             // Coverage only.
@@ -380,8 +380,6 @@
     const Attribute* fColorAttrib;
 };
 
-constexpr GrGeometryProcessor::Attribute FillRRectOpImpl::Processor::kVertexAttribs[];
-
 // Our coverage geometry consists of an inset octagon with solid coverage, surrounded by linear
 // coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal
 // edges. The Vertex struct tells the shader where to place its vertex within a normalized
diff --git a/src/gpu/tessellate/shaders/GrTessellationShader.h b/src/gpu/tessellate/shaders/GrTessellationShader.h
index 23f9c51..0912640 100644
--- a/src/gpu/tessellate/shaders/GrTessellationShader.h
+++ b/src/gpu/tessellate/shaders/GrTessellationShader.h
@@ -41,9 +41,9 @@
     // A conic curve is written out with p3=[w,Infinity], but GPUs that don't support infinity can't
     // detect this. On these platforms we also write out an extra float with each patch that
     // explicitly tells the shader what type of curve it is.
-    constexpr static float kCubicCurveType = 0;
-    constexpr static float kConicCurveType = 1;
-    constexpr static float kTriangularConicCurveType = 2;  // Conic curve with w=Infinity.
+    inline constexpr static float kCubicCurveType = 0;
+    inline constexpr static float kConicCurveType = 1;
+    inline constexpr static float kTriangularConicCurveType = 2;  // Conic curve with w=Infinity.
 
     // Fills in a 4-point patch in such a way that the shader will recognize it as a conic.
     static void WriteConicPatch(const SkPoint pts[3], float w, GrVertexWriter* writer) {
diff --git a/src/gpu/text/GrTextBlob.h b/src/gpu/text/GrTextBlob.h
index c21d2af..245770c 100644
--- a/src/gpu/text/GrTextBlob.h
+++ b/src/gpu/text/GrTextBlob.h
@@ -58,7 +58,7 @@
 using GrAtlasSubRunOwner = std::unique_ptr<GrAtlasSubRun, GrSubRunAllocator::Destroyer>;
 class GrAtlasSubRun  {
 public:
-    static constexpr int kVerticesPerGlyph = 4;
+    inline static constexpr int kVerticesPerGlyph = 4;
 
     virtual ~GrAtlasSubRun() = default;
 
diff --git a/src/pdf/SkPDFGraphicStackState.h b/src/pdf/SkPDFGraphicStackState.h
index 593e9b1..97cc969 100644
--- a/src/pdf/SkPDFGraphicStackState.h
+++ b/src/pdf/SkPDFGraphicStackState.h
@@ -22,7 +22,7 @@
         int fGraphicStateIndex = -1;
     };
     // Must use stack for matrix, and for clip, plus one for no matrix or clip.
-    static constexpr int kMaxStackDepth = 2;
+    inline static constexpr int kMaxStackDepth = 2;
     Entry fEntries[kMaxStackDepth + 1];
     int fStackDepth = 0;
     SkDynamicMemoryWStream* fContentStream;
diff --git a/src/ports/SkFontConfigInterface_direct.cpp b/src/ports/SkFontConfigInterface_direct.cpp
index 555dd75..0cfc932 100644
--- a/src/ports/SkFontConfigInterface_direct.cpp
+++ b/src/ports/SkFontConfigInterface_direct.cpp
@@ -34,7 +34,7 @@
 }
 
 struct FCLocker {
-    static constexpr int FontConfigThreadSafeVersion = 21393;
+    inline static constexpr int FontConfigThreadSafeVersion = 21393;
 
     // Assume FcGetVersion() has always been thread safe.
     FCLocker() {
diff --git a/src/ports/SkFontHost_FreeType_common.cpp b/src/ports/SkFontHost_FreeType_common.cpp
index e0ab472..f1d7374 100644
--- a/src/ports/SkFontHost_FreeType_common.cpp
+++ b/src/ports/SkFontHost_FreeType_common.cpp
@@ -1557,7 +1557,7 @@
 public:
     SkFTGeometrySink(SkPath* path) : fPath{path}, fStarted{false}, fCurrent{0,0} {}
 
-    static constexpr const FT_Outline_Funcs Funcs{
+    inline static constexpr const FT_Outline_Funcs Funcs{
         /*move_to =*/ SkFTGeometrySink::Move,
         /*line_to =*/ SkFTGeometrySink::Line,
         /*conic_to =*/ SkFTGeometrySink::Quad,
diff --git a/src/ports/SkFontMgr_fontconfig.cpp b/src/ports/SkFontMgr_fontconfig.cpp
index 9e4e047..1a14168 100644
--- a/src/ports/SkFontMgr_fontconfig.cpp
+++ b/src/ports/SkFontMgr_fontconfig.cpp
@@ -66,7 +66,7 @@
 }
 
 class FCLocker {
-    static constexpr int FontConfigThreadSafeVersion = 21393;
+    inline static constexpr int FontConfigThreadSafeVersion = 21393;
 
     // Assume FcGetVersion() has always been thread safe.
     static void lock() SK_NO_THREAD_SAFETY_ANALYSIS {
diff --git a/src/sfnt/SkOTTable_OS_2.h b/src/sfnt/SkOTTable_OS_2.h
index 92619c4..cb5312f 100644
--- a/src/sfnt/SkOTTable_OS_2.h
+++ b/src/sfnt/SkOTTable_OS_2.h
@@ -18,11 +18,11 @@
 #pragma pack(push, 1)
 
 struct SkOTTableOS2 {
-    static constexpr SK_OT_CHAR TAG0 = 'O';
-    static constexpr SK_OT_CHAR TAG1 = 'S';
-    static constexpr SK_OT_CHAR TAG2 = '/';
-    static constexpr SK_OT_CHAR TAG3 = '2';
-    static constexpr SK_OT_ULONG TAG = SkOTTableTAG<SkOTTableOS2>::value;
+    inline static constexpr SK_OT_CHAR TAG0 = 'O';
+    inline static constexpr SK_OT_CHAR TAG1 = 'S';
+    inline static constexpr SK_OT_CHAR TAG2 = '/';
+    inline static constexpr SK_OT_CHAR TAG3 = '2';
+    inline static constexpr SK_OT_ULONG TAG = SkOTTableTAG<SkOTTableOS2>::value;
 
     union Version {
         SK_OT_USHORT version;
diff --git a/src/shaders/gradients/SkGradientShaderPriv.h b/src/shaders/gradients/SkGradientShaderPriv.h
index 07bb261..0c12384 100644
--- a/src/shaders/gradients/SkGradientShaderPriv.h
+++ b/src/shaders/gradients/SkGradientShaderPriv.h
@@ -133,8 +133,8 @@
 
 private:
     // Reserve inline space for up to 4 stops.
-    static constexpr size_t kInlineStopCount   = 4;
-    static constexpr size_t kInlineStorageSize = (sizeof(SkColor4f) + sizeof(SkScalar))
+    inline static constexpr size_t kInlineStopCount   = 4;
+    inline static constexpr size_t kInlineStorageSize = (sizeof(SkColor4f) + sizeof(SkScalar))
                                                * kInlineStopCount;
     SkAutoSTMalloc<kInlineStorageSize, uint8_t> fStorage;
 
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index 4cdec81..dbf6175 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -64,10 +64,10 @@
  */
 class SK_API Compiler {
 public:
-    static constexpr const char FRAGCOLOR_NAME[] = "sk_FragColor";
-    static constexpr const char RTADJUST_NAME[]  = "sk_RTAdjust";
-    static constexpr const char PERVERTEX_NAME[] = "sk_PerVertex";
-    static constexpr const char POISON_TAG[]     = "<POISON>";
+    inline static constexpr const char FRAGCOLOR_NAME[] = "sk_FragColor";
+    inline static constexpr const char RTADJUST_NAME[]  = "sk_RTAdjust";
+    inline static constexpr const char PERVERTEX_NAME[] = "sk_PerVertex";
+    inline static constexpr const char POISON_TAG[]     = "<POISON>";
 
     /**
      * Gets a float4 that adjusts the position from Skia device coords to normalized device coords,
diff --git a/src/sksl/codegen/SkSLMetalCodeGenerator.h b/src/sksl/codegen/SkSLMetalCodeGenerator.h
index 1668e69..4a2f539 100644
--- a/src/sksl/codegen/SkSLMetalCodeGenerator.h
+++ b/src/sksl/codegen/SkSLMetalCodeGenerator.h
@@ -53,8 +53,8 @@
  */
 class MetalCodeGenerator : public CodeGenerator {
 public:
-    static constexpr const char* SAMPLER_SUFFIX = "Smplr";
-    static constexpr const char* PACKED_PREFIX = "packed_";
+    inline static constexpr const char* SAMPLER_SUFFIX = "Smplr";
+    inline static constexpr const char* PACKED_PREFIX = "packed_";
 
     MetalCodeGenerator(const Context* context, const Program* program, OutputStream* out)
     : INHERITED(context, program, out)
@@ -67,12 +67,12 @@
     using Precedence = Operator::Precedence;
 
     typedef int Requirements;
-    static constexpr Requirements kNo_Requirements       = 0;
-    static constexpr Requirements kInputs_Requirement    = 1 << 0;
-    static constexpr Requirements kOutputs_Requirement   = 1 << 1;
-    static constexpr Requirements kUniforms_Requirement  = 1 << 2;
-    static constexpr Requirements kGlobals_Requirement   = 1 << 3;
-    static constexpr Requirements kFragCoord_Requirement = 1 << 4;
+    inline static constexpr Requirements kNo_Requirements       = 0;
+    inline static constexpr Requirements kInputs_Requirement    = 1 << 0;
+    inline static constexpr Requirements kOutputs_Requirement   = 1 << 1;
+    inline static constexpr Requirements kUniforms_Requirement  = 1 << 2;
+    inline static constexpr Requirements kGlobals_Requirement   = 1 << 3;
+    inline static constexpr Requirements kFragCoord_Requirement = 1 << 4;
 
     static const char* OperatorName(Operator op);
 
diff --git a/src/sksl/ir/SkSLBinaryExpression.h b/src/sksl/ir/SkSLBinaryExpression.h
index b79798a..e691f30 100644
--- a/src/sksl/ir/SkSLBinaryExpression.h
+++ b/src/sksl/ir/SkSLBinaryExpression.h
@@ -26,7 +26,7 @@
  */
 class BinaryExpression final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kBinary;
+    inline static constexpr Kind kExpressionKind = Kind::kBinary;
 
     BinaryExpression(int line, std::unique_ptr<Expression> left, Operator op,
                      std::unique_ptr<Expression> right, const Type* type)
diff --git a/src/sksl/ir/SkSLBlock.h b/src/sksl/ir/SkSLBlock.h
index 45922f6..02711c2 100644
--- a/src/sksl/ir/SkSLBlock.h
+++ b/src/sksl/ir/SkSLBlock.h
@@ -18,7 +18,7 @@
  */
 class Block final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kBlock;
+    inline static constexpr Kind kStatementKind = Kind::kBlock;
 
     Block(int line, StatementArray statements,
           const std::shared_ptr<SymbolTable> symbols = nullptr, bool isScope = true)
diff --git a/src/sksl/ir/SkSLBreakStatement.h b/src/sksl/ir/SkSLBreakStatement.h
index 457d514..80a13f1 100644
--- a/src/sksl/ir/SkSLBreakStatement.h
+++ b/src/sksl/ir/SkSLBreakStatement.h
@@ -18,7 +18,7 @@
  */
 class BreakStatement final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kBreak;
+    inline static constexpr Kind kStatementKind = Kind::kBreak;
 
     BreakStatement(int line)
     : INHERITED(line, kStatementKind) {}
diff --git a/src/sksl/ir/SkSLChildCall.h b/src/sksl/ir/SkSLChildCall.h
index be7e8d6..cabfd7d 100644
--- a/src/sksl/ir/SkSLChildCall.h
+++ b/src/sksl/ir/SkSLChildCall.h
@@ -19,7 +19,7 @@
  */
 class ChildCall final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kChildCall;
+    inline static constexpr Kind kExpressionKind = Kind::kChildCall;
 
     ChildCall(int line, const Type* type, const Variable* child, ExpressionArray arguments)
             : INHERITED(line, kExpressionKind, type)
diff --git a/src/sksl/ir/SkSLCodeStringExpression.h b/src/sksl/ir/SkSLCodeStringExpression.h
index b5573a5..c82d043 100644
--- a/src/sksl/ir/SkSLCodeStringExpression.h
+++ b/src/sksl/ir/SkSLCodeStringExpression.h
@@ -20,7 +20,7 @@
  */
 class CodeStringExpression final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kCodeString;
+    inline static constexpr Kind kExpressionKind = Kind::kCodeString;
 
     CodeStringExpression(String code, const Type* type)
         : INHERITED(/*line=*/-1, kExpressionKind, type)
diff --git a/src/sksl/ir/SkSLConstructorArray.h b/src/sksl/ir/SkSLConstructorArray.h
index 3d8cb00..99f274d 100644
--- a/src/sksl/ir/SkSLConstructorArray.h
+++ b/src/sksl/ir/SkSLConstructorArray.h
@@ -17,7 +17,7 @@
  */
 class ConstructorArray final : public MultiArgumentConstructor {
 public:
-    static constexpr Kind kExpressionKind = Kind::kConstructorArray;
+    inline static constexpr Kind kExpressionKind = Kind::kConstructorArray;
 
     ConstructorArray(int line, const Type& type, ExpressionArray arguments)
         : INHERITED(line, kExpressionKind, &type, std::move(arguments)) {}
diff --git a/src/sksl/ir/SkSLConstructorArrayCast.h b/src/sksl/ir/SkSLConstructorArrayCast.h
index eed87fe..a68e7fb 100644
--- a/src/sksl/ir/SkSLConstructorArrayCast.h
+++ b/src/sksl/ir/SkSLConstructorArrayCast.h
@@ -26,7 +26,7 @@
  */
 class ConstructorArrayCast final : public SingleArgumentConstructor {
 public:
-    static constexpr Kind kExpressionKind = Kind::kConstructorArrayCast;
+    inline static constexpr Kind kExpressionKind = Kind::kConstructorArrayCast;
 
     ConstructorArrayCast(int line, const Type& type, std::unique_ptr<Expression> arg)
         : INHERITED(line, kExpressionKind, &type, std::move(arg)) {}
diff --git a/src/sksl/ir/SkSLConstructorCompound.h b/src/sksl/ir/SkSLConstructorCompound.h
index d5276ce..59086b9 100644
--- a/src/sksl/ir/SkSLConstructorCompound.h
+++ b/src/sksl/ir/SkSLConstructorCompound.h
@@ -26,7 +26,7 @@
  */
 class ConstructorCompound final : public MultiArgumentConstructor {
 public:
-    static constexpr Kind kExpressionKind = Kind::kConstructorCompound;
+    inline static constexpr Kind kExpressionKind = Kind::kConstructorCompound;
 
     ConstructorCompound(int line, const Type& type, ExpressionArray args)
             : INHERITED(line, kExpressionKind, &type, std::move(args)) {}
diff --git a/src/sksl/ir/SkSLConstructorCompoundCast.h b/src/sksl/ir/SkSLConstructorCompoundCast.h
index 07c1f1e..e4597bd 100644
--- a/src/sksl/ir/SkSLConstructorCompoundCast.h
+++ b/src/sksl/ir/SkSLConstructorCompoundCast.h
@@ -24,7 +24,7 @@
  */
 class ConstructorCompoundCast final : public SingleArgumentConstructor {
 public:
-    static constexpr Kind kExpressionKind = Kind::kConstructorCompoundCast;
+    inline static constexpr Kind kExpressionKind = Kind::kConstructorCompoundCast;
 
     ConstructorCompoundCast(int line, const Type& type, std::unique_ptr<Expression> arg)
         : INHERITED(line, kExpressionKind, &type, std::move(arg)) {}
diff --git a/src/sksl/ir/SkSLConstructorDiagonalMatrix.h b/src/sksl/ir/SkSLConstructorDiagonalMatrix.h
index ec226d2..39cc414 100644
--- a/src/sksl/ir/SkSLConstructorDiagonalMatrix.h
+++ b/src/sksl/ir/SkSLConstructorDiagonalMatrix.h
@@ -24,7 +24,7 @@
  */
 class ConstructorDiagonalMatrix final : public SingleArgumentConstructor {
 public:
-    static constexpr Kind kExpressionKind = Kind::kConstructorDiagonalMatrix;
+    inline static constexpr Kind kExpressionKind = Kind::kConstructorDiagonalMatrix;
 
     ConstructorDiagonalMatrix(int line, const Type& type, std::unique_ptr<Expression> arg)
         : INHERITED(line, kExpressionKind, &type, std::move(arg))
diff --git a/src/sksl/ir/SkSLConstructorMatrixResize.h b/src/sksl/ir/SkSLConstructorMatrixResize.h
index ad47bd2..33cb938 100644
--- a/src/sksl/ir/SkSLConstructorMatrixResize.h
+++ b/src/sksl/ir/SkSLConstructorMatrixResize.h
@@ -25,7 +25,7 @@
  */
 class ConstructorMatrixResize final : public SingleArgumentConstructor {
 public:
-    static constexpr Kind kExpressionKind = Kind::kConstructorMatrixResize;
+    inline static constexpr Kind kExpressionKind = Kind::kConstructorMatrixResize;
 
     ConstructorMatrixResize(int line, const Type& type, std::unique_ptr<Expression> arg)
             : INHERITED(line, kExpressionKind, &type, std::move(arg))
diff --git a/src/sksl/ir/SkSLConstructorScalarCast.h b/src/sksl/ir/SkSLConstructorScalarCast.h
index bf4dce7..f272485 100644
--- a/src/sksl/ir/SkSLConstructorScalarCast.h
+++ b/src/sksl/ir/SkSLConstructorScalarCast.h
@@ -24,7 +24,7 @@
  */
 class ConstructorScalarCast final : public SingleArgumentConstructor {
 public:
-    static constexpr Kind kExpressionKind = Kind::kConstructorScalarCast;
+    inline static constexpr Kind kExpressionKind = Kind::kConstructorScalarCast;
 
     ConstructorScalarCast(int line, const Type& type, std::unique_ptr<Expression> arg)
         : INHERITED(line, kExpressionKind, &type, std::move(arg)) {}
diff --git a/src/sksl/ir/SkSLConstructorSplat.h b/src/sksl/ir/SkSLConstructorSplat.h
index eb9cd59..064bf8c 100644
--- a/src/sksl/ir/SkSLConstructorSplat.h
+++ b/src/sksl/ir/SkSLConstructorSplat.h
@@ -23,7 +23,7 @@
  */
 class ConstructorSplat final : public SingleArgumentConstructor {
 public:
-    static constexpr Kind kExpressionKind = Kind::kConstructorSplat;
+    inline static constexpr Kind kExpressionKind = Kind::kConstructorSplat;
 
     ConstructorSplat(int line, const Type& type, std::unique_ptr<Expression> arg)
         : INHERITED(line, kExpressionKind, &type, std::move(arg)) {}
diff --git a/src/sksl/ir/SkSLConstructorStruct.h b/src/sksl/ir/SkSLConstructorStruct.h
index 154545d..6987fee 100644
--- a/src/sksl/ir/SkSLConstructorStruct.h
+++ b/src/sksl/ir/SkSLConstructorStruct.h
@@ -17,7 +17,7 @@
  */
 class ConstructorStruct final : public MultiArgumentConstructor {
 public:
-    static constexpr Kind kExpressionKind = Kind::kConstructorStruct;
+    inline static constexpr Kind kExpressionKind = Kind::kConstructorStruct;
 
     ConstructorStruct(int line, const Type& type, ExpressionArray arguments)
         : INHERITED(line, kExpressionKind, &type, std::move(arguments)) {}
diff --git a/src/sksl/ir/SkSLContinueStatement.h b/src/sksl/ir/SkSLContinueStatement.h
index 2ab951d..8e03a31 100644
--- a/src/sksl/ir/SkSLContinueStatement.h
+++ b/src/sksl/ir/SkSLContinueStatement.h
@@ -18,7 +18,7 @@
  */
 class ContinueStatement final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kContinue;
+    inline static constexpr Kind kStatementKind = Kind::kContinue;
 
     ContinueStatement(int line)
     : INHERITED(line, kStatementKind) {}
diff --git a/src/sksl/ir/SkSLDiscardStatement.h b/src/sksl/ir/SkSLDiscardStatement.h
index 643cb38..adcf014 100644
--- a/src/sksl/ir/SkSLDiscardStatement.h
+++ b/src/sksl/ir/SkSLDiscardStatement.h
@@ -18,7 +18,7 @@
  */
 class DiscardStatement final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kDiscard;
+    inline static constexpr Kind kStatementKind = Kind::kDiscard;
 
     DiscardStatement(int line)
     : INHERITED(line, kStatementKind) {}
diff --git a/src/sksl/ir/SkSLDoStatement.h b/src/sksl/ir/SkSLDoStatement.h
index d3d9162..f33c182 100644
--- a/src/sksl/ir/SkSLDoStatement.h
+++ b/src/sksl/ir/SkSLDoStatement.h
@@ -18,7 +18,7 @@
  */
 class DoStatement final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kDo;
+    inline static constexpr Kind kStatementKind = Kind::kDo;
 
     DoStatement(int line, std::unique_ptr<Statement> statement, std::unique_ptr<Expression> test)
         : INHERITED(line, kStatementKind)
diff --git a/src/sksl/ir/SkSLExpressionStatement.h b/src/sksl/ir/SkSLExpressionStatement.h
index f7177b2..86606da 100644
--- a/src/sksl/ir/SkSLExpressionStatement.h
+++ b/src/sksl/ir/SkSLExpressionStatement.h
@@ -18,7 +18,7 @@
  */
 class ExpressionStatement final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kExpression;
+    inline static constexpr Kind kStatementKind = Kind::kExpression;
 
     ExpressionStatement(std::unique_ptr<Expression> expression)
         : INHERITED(expression->fLine, kStatementKind)
diff --git a/src/sksl/ir/SkSLExtension.h b/src/sksl/ir/SkSLExtension.h
index 28cf6ff..afa2119 100644
--- a/src/sksl/ir/SkSLExtension.h
+++ b/src/sksl/ir/SkSLExtension.h
@@ -17,7 +17,7 @@
  */
 class Extension final : public ProgramElement {
 public:
-    static constexpr Kind kProgramElementKind = Kind::kExtension;
+    inline static constexpr Kind kProgramElementKind = Kind::kExtension;
 
     Extension(int line, skstd::string_view name)
         : INHERITED(line, kProgramElementKind)
diff --git a/src/sksl/ir/SkSLExternalFunction.h b/src/sksl/ir/SkSLExternalFunction.h
index 0adffd4..373a78a 100644
--- a/src/sksl/ir/SkSLExternalFunction.h
+++ b/src/sksl/ir/SkSLExternalFunction.h
@@ -18,7 +18,7 @@
 
 class ExternalFunction : public Symbol {
 public:
-    static constexpr Kind kSymbolKind = Kind::kExternal;
+    inline static constexpr Kind kSymbolKind = Kind::kExternal;
 
     ExternalFunction(const char* name, const Type& type)
         : INHERITED(-1, kSymbolKind, name, &type) {}
diff --git a/src/sksl/ir/SkSLExternalFunctionCall.h b/src/sksl/ir/SkSLExternalFunctionCall.h
index 35958fd..e351909 100644
--- a/src/sksl/ir/SkSLExternalFunctionCall.h
+++ b/src/sksl/ir/SkSLExternalFunctionCall.h
@@ -20,7 +20,7 @@
  */
 class ExternalFunctionCall final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kExternalFunctionCall;
+    inline static constexpr Kind kExpressionKind = Kind::kExternalFunctionCall;
 
     ExternalFunctionCall(int line, const ExternalFunction* function, ExpressionArray arguments)
         : INHERITED(line, kExpressionKind, &function->type())
diff --git a/src/sksl/ir/SkSLExternalFunctionReference.h b/src/sksl/ir/SkSLExternalFunctionReference.h
index c63a890..84c6f86 100644
--- a/src/sksl/ir/SkSLExternalFunctionReference.h
+++ b/src/sksl/ir/SkSLExternalFunctionReference.h
@@ -20,7 +20,7 @@
  */
 class ExternalFunctionReference final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kExternalFunctionReference;
+    inline static constexpr Kind kExpressionKind = Kind::kExternalFunctionReference;
 
     ExternalFunctionReference(int line, const ExternalFunction* ef)
         : INHERITED(line, kExpressionKind, &ef->type())
diff --git a/src/sksl/ir/SkSLField.h b/src/sksl/ir/SkSLField.h
index 09275f4..b6d9e7b 100644
--- a/src/sksl/ir/SkSLField.h
+++ b/src/sksl/ir/SkSLField.h
@@ -22,7 +22,7 @@
  */
 class Field final : public Symbol {
 public:
-    static constexpr Kind kSymbolKind = Kind::kField;
+    inline static constexpr Kind kSymbolKind = Kind::kField;
 
     Field(int line, const Variable* owner, int fieldIndex)
         : INHERITED(line, kSymbolKind, owner->type().fields()[fieldIndex].fName,
diff --git a/src/sksl/ir/SkSLFieldAccess.h b/src/sksl/ir/SkSLFieldAccess.h
index f1df7cb..a30bf41 100644
--- a/src/sksl/ir/SkSLFieldAccess.h
+++ b/src/sksl/ir/SkSLFieldAccess.h
@@ -27,7 +27,7 @@
 public:
     using OwnerKind = FieldAccessOwnerKind;
 
-    static constexpr Kind kExpressionKind = Kind::kFieldAccess;
+    inline static constexpr Kind kExpressionKind = Kind::kFieldAccess;
 
     FieldAccess(std::unique_ptr<Expression> base, int fieldIndex,
                 OwnerKind ownerKind = OwnerKind::kDefault)
diff --git a/src/sksl/ir/SkSLForStatement.h b/src/sksl/ir/SkSLForStatement.h
index 0aa1a4e..562066a 100644
--- a/src/sksl/ir/SkSLForStatement.h
+++ b/src/sksl/ir/SkSLForStatement.h
@@ -29,7 +29,7 @@
  */
 class ForStatement final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kFor;
+    inline static constexpr Kind kStatementKind = Kind::kFor;
 
     ForStatement(int line,
                  std::unique_ptr<Statement> initializer,
diff --git a/src/sksl/ir/SkSLFunctionCall.h b/src/sksl/ir/SkSLFunctionCall.h
index 4ebc8bc..2b619c4 100644
--- a/src/sksl/ir/SkSLFunctionCall.h
+++ b/src/sksl/ir/SkSLFunctionCall.h
@@ -19,7 +19,7 @@
  */
 class FunctionCall final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kFunctionCall;
+    inline static constexpr Kind kExpressionKind = Kind::kFunctionCall;
 
     FunctionCall(int line, const Type* type, const FunctionDeclaration* function,
                  ExpressionArray arguments)
diff --git a/src/sksl/ir/SkSLFunctionDeclaration.h b/src/sksl/ir/SkSLFunctionDeclaration.h
index 0792328..860c6c6 100644
--- a/src/sksl/ir/SkSLFunctionDeclaration.h
+++ b/src/sksl/ir/SkSLFunctionDeclaration.h
@@ -35,7 +35,7 @@
  */
 class FunctionDeclaration final : public Symbol {
 public:
-    static constexpr Kind kSymbolKind = Kind::kFunctionDeclaration;
+    inline static constexpr Kind kSymbolKind = Kind::kFunctionDeclaration;
 
     FunctionDeclaration(int line,
                         const Modifiers* modifiers,
diff --git a/src/sksl/ir/SkSLFunctionDefinition.h b/src/sksl/ir/SkSLFunctionDefinition.h
index d0f38e3..442f41c 100644
--- a/src/sksl/ir/SkSLFunctionDefinition.h
+++ b/src/sksl/ir/SkSLFunctionDefinition.h
@@ -21,7 +21,7 @@
  */
 class FunctionDefinition final : public ProgramElement {
 public:
-    static constexpr Kind kProgramElementKind = Kind::kFunction;
+    inline static constexpr Kind kProgramElementKind = Kind::kFunction;
 
     using IntrinsicSet = std::unordered_set<const FunctionDeclaration*>;
 
diff --git a/src/sksl/ir/SkSLFunctionPrototype.h b/src/sksl/ir/SkSLFunctionPrototype.h
index 0b4a16f..92ff5e2 100644
--- a/src/sksl/ir/SkSLFunctionPrototype.h
+++ b/src/sksl/ir/SkSLFunctionPrototype.h
@@ -21,7 +21,7 @@
  */
 class FunctionPrototype final : public ProgramElement {
 public:
-    static constexpr Kind kProgramElementKind = Kind::kFunctionPrototype;
+    inline static constexpr Kind kProgramElementKind = Kind::kFunctionPrototype;
 
     FunctionPrototype(int line, const FunctionDeclaration* declaration, bool builtin)
             : INHERITED(line, kProgramElementKind)
diff --git a/src/sksl/ir/SkSLFunctionReference.h b/src/sksl/ir/SkSLFunctionReference.h
index fd492f8..cbcd02b 100644
--- a/src/sksl/ir/SkSLFunctionReference.h
+++ b/src/sksl/ir/SkSLFunctionReference.h
@@ -20,7 +20,7 @@
  */
 class FunctionReference final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kFunctionReference;
+    inline static constexpr Kind kExpressionKind = Kind::kFunctionReference;
 
     FunctionReference(const Context& context, int line,
                       std::vector<const FunctionDeclaration*> functions)
diff --git a/src/sksl/ir/SkSLIfStatement.h b/src/sksl/ir/SkSLIfStatement.h
index 3b0ec5d..06e4e5d 100644
--- a/src/sksl/ir/SkSLIfStatement.h
+++ b/src/sksl/ir/SkSLIfStatement.h
@@ -20,7 +20,7 @@
  */
 class IfStatement final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kIf;
+    inline static constexpr Kind kStatementKind = Kind::kIf;
 
     IfStatement(int line, bool isStatic, std::unique_ptr<Expression> test,
                 std::unique_ptr<Statement> ifTrue, std::unique_ptr<Statement> ifFalse)
diff --git a/src/sksl/ir/SkSLIndexExpression.h b/src/sksl/ir/SkSLIndexExpression.h
index ab888d5..287c0d0 100644
--- a/src/sksl/ir/SkSLIndexExpression.h
+++ b/src/sksl/ir/SkSLIndexExpression.h
@@ -18,7 +18,7 @@
  * An expression which extracts a value from an array or matrix, as in 'm[2]'.
  */
 struct IndexExpression final : public Expression {
-    static constexpr Kind kExpressionKind = Kind::kIndex;
+    inline static constexpr Kind kExpressionKind = Kind::kIndex;
 
     IndexExpression(const Context& context, std::unique_ptr<Expression> base,
                     std::unique_ptr<Expression> index)
diff --git a/src/sksl/ir/SkSLInlineMarker.h b/src/sksl/ir/SkSLInlineMarker.h
index 62d63ee..f43a3ce 100644
--- a/src/sksl/ir/SkSLInlineMarker.h
+++ b/src/sksl/ir/SkSLInlineMarker.h
@@ -20,7 +20,7 @@
  */
 class InlineMarker final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kInlineMarker;
+    inline static constexpr Kind kStatementKind = Kind::kInlineMarker;
 
     InlineMarker(const FunctionDeclaration* function)
             : INHERITED(/*line=*/-1, kStatementKind)
diff --git a/src/sksl/ir/SkSLInterfaceBlock.h b/src/sksl/ir/SkSLInterfaceBlock.h
index cbe7af6..53eb1fc 100644
--- a/src/sksl/ir/SkSLInterfaceBlock.h
+++ b/src/sksl/ir/SkSLInterfaceBlock.h
@@ -29,7 +29,7 @@
  */
 class InterfaceBlock final : public ProgramElement {
 public:
-    static constexpr Kind kProgramElementKind = Kind::kInterfaceBlock;
+    inline static constexpr Kind kProgramElementKind = Kind::kInterfaceBlock;
 
     InterfaceBlock(int line, const Variable& var, skstd::string_view typeName,
                    skstd::string_view instanceName, int arraySize,
diff --git a/src/sksl/ir/SkSLLiteral.h b/src/sksl/ir/SkSLLiteral.h
index fb80347..5cdbd18 100644
--- a/src/sksl/ir/SkSLLiteral.h
+++ b/src/sksl/ir/SkSLLiteral.h
@@ -19,7 +19,7 @@
 
 class Literal : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kLiteral;
+    inline static constexpr Kind kExpressionKind = Kind::kLiteral;
 
     Literal(int line, double value, const Type* type)
         : INHERITED(line, kExpressionKind, type)
diff --git a/src/sksl/ir/SkSLMethodReference.h b/src/sksl/ir/SkSLMethodReference.h
index 028fffa..0776043 100644
--- a/src/sksl/ir/SkSLMethodReference.h
+++ b/src/sksl/ir/SkSLMethodReference.h
@@ -29,7 +29,7 @@
  */
 class MethodReference final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kMethodReference;
+    inline static constexpr Kind kExpressionKind = Kind::kMethodReference;
 
     MethodReference(const Context& context,
                     int line,
diff --git a/src/sksl/ir/SkSLModifiersDeclaration.h b/src/sksl/ir/SkSLModifiersDeclaration.h
index 6729c62..0905d33 100644
--- a/src/sksl/ir/SkSLModifiersDeclaration.h
+++ b/src/sksl/ir/SkSLModifiersDeclaration.h
@@ -20,7 +20,7 @@
  */
 class ModifiersDeclaration final : public ProgramElement {
 public:
-    static constexpr Kind kProgramElementKind = Kind::kModifiers;
+    inline static constexpr Kind kProgramElementKind = Kind::kModifiers;
 
     ModifiersDeclaration(const Modifiers* modifiers)
         : INHERITED(-1, kProgramElementKind)
diff --git a/src/sksl/ir/SkSLNop.h b/src/sksl/ir/SkSLNop.h
index 9a24516..2da8533 100644
--- a/src/sksl/ir/SkSLNop.h
+++ b/src/sksl/ir/SkSLNop.h
@@ -18,7 +18,7 @@
  */
 class Nop final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kNop;
+    inline static constexpr Kind kStatementKind = Kind::kNop;
 
     Nop()
     : INHERITED(/*line=*/-1, kStatementKind) {}
diff --git a/src/sksl/ir/SkSLPoison.h b/src/sksl/ir/SkSLPoison.h
index 16dd355..9a18909 100644
--- a/src/sksl/ir/SkSLPoison.h
+++ b/src/sksl/ir/SkSLPoison.h
@@ -12,7 +12,7 @@
 
 class Poison : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kPoison;
+    inline static constexpr Kind kExpressionKind = Kind::kPoison;
 
     static std::unique_ptr<Expression> Make(int line, const Context& context) {
         return std::make_unique<Poison>(line, context.fTypes.fPoison.get());
diff --git a/src/sksl/ir/SkSLPostfixExpression.h b/src/sksl/ir/SkSLPostfixExpression.h
index 870e970..244043a 100644
--- a/src/sksl/ir/SkSLPostfixExpression.h
+++ b/src/sksl/ir/SkSLPostfixExpression.h
@@ -19,7 +19,7 @@
  */
 class PostfixExpression final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kPostfix;
+    inline static constexpr Kind kExpressionKind = Kind::kPostfix;
 
     PostfixExpression(std::unique_ptr<Expression> operand, Operator op)
         : INHERITED(operand->fLine, kExpressionKind, &operand->type())
diff --git a/src/sksl/ir/SkSLPrefixExpression.h b/src/sksl/ir/SkSLPrefixExpression.h
index 7476624..5b43214 100644
--- a/src/sksl/ir/SkSLPrefixExpression.h
+++ b/src/sksl/ir/SkSLPrefixExpression.h
@@ -22,7 +22,7 @@
  */
 class PrefixExpression final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kPrefix;
+    inline static constexpr Kind kExpressionKind = Kind::kPrefix;
 
     // Use PrefixExpression::Make to automatically simplify various prefix expression types.
     PrefixExpression(Operator op, std::unique_ptr<Expression> operand)
diff --git a/src/sksl/ir/SkSLReturnStatement.h b/src/sksl/ir/SkSLReturnStatement.h
index 70488ce..5cdf1e1 100644
--- a/src/sksl/ir/SkSLReturnStatement.h
+++ b/src/sksl/ir/SkSLReturnStatement.h
@@ -18,7 +18,7 @@
  */
 class ReturnStatement final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kReturn;
+    inline static constexpr Kind kStatementKind = Kind::kReturn;
 
     ReturnStatement(int line, std::unique_ptr<Expression> expression)
         : INHERITED(line, kStatementKind)
diff --git a/src/sksl/ir/SkSLSetting.h b/src/sksl/ir/SkSLSetting.h
index e003cfc..cf0b242 100644
--- a/src/sksl/ir/SkSLSetting.h
+++ b/src/sksl/ir/SkSLSetting.h
@@ -20,7 +20,7 @@
  */
 class Setting final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kSetting;
+    inline static constexpr Kind kExpressionKind = Kind::kSetting;
 
     Setting(int line, skstd::string_view name, const Type* type)
         : INHERITED(line, kExpressionKind, type)
diff --git a/src/sksl/ir/SkSLStructDefinition.h b/src/sksl/ir/SkSLStructDefinition.h
index 8ed4e2f..02ad797 100644
--- a/src/sksl/ir/SkSLStructDefinition.h
+++ b/src/sksl/ir/SkSLStructDefinition.h
@@ -26,7 +26,7 @@
  */
 class StructDefinition final : public ProgramElement {
 public:
-    static constexpr Kind kProgramElementKind = Kind::kStructDefinition;
+    inline static constexpr Kind kProgramElementKind = Kind::kStructDefinition;
 
     StructDefinition(int line, const Type& type)
     : INHERITED(line, kProgramElementKind)
diff --git a/src/sksl/ir/SkSLSwitchCase.h b/src/sksl/ir/SkSLSwitchCase.h
index 35125a8..5d443ed 100644
--- a/src/sksl/ir/SkSLSwitchCase.h
+++ b/src/sksl/ir/SkSLSwitchCase.h
@@ -18,7 +18,7 @@
  */
 class SwitchCase final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kSwitchCase;
+    inline static constexpr Kind kStatementKind = Kind::kSwitchCase;
 
     // null value implies "default" case
     SwitchCase(int line, std::unique_ptr<Expression> value, std::unique_ptr<Statement> statement)
diff --git a/src/sksl/ir/SkSLSwitchStatement.h b/src/sksl/ir/SkSLSwitchStatement.h
index f1f3190..fbca56d 100644
--- a/src/sksl/ir/SkSLSwitchStatement.h
+++ b/src/sksl/ir/SkSLSwitchStatement.h
@@ -24,7 +24,7 @@
  */
 class SwitchStatement final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kSwitch;
+    inline static constexpr Kind kStatementKind = Kind::kSwitch;
 
     SwitchStatement(int line, bool isStatic, std::unique_ptr<Expression> value,
                     StatementArray cases, std::shared_ptr<SymbolTable> symbols)
diff --git a/src/sksl/ir/SkSLSwizzle.h b/src/sksl/ir/SkSLSwizzle.h
index a187a61..d488b57 100644
--- a/src/sksl/ir/SkSLSwizzle.h
+++ b/src/sksl/ir/SkSLSwizzle.h
@@ -21,7 +21,7 @@
  * Represents a vector swizzle operation such as 'float3(1, 2, 3).zyx'.
  */
 struct Swizzle final : public Expression {
-    static constexpr Kind kExpressionKind = Kind::kSwizzle;
+    inline static constexpr Kind kExpressionKind = Kind::kSwizzle;
 
     Swizzle(const Context& context, std::unique_ptr<Expression> base,
             const ComponentArray& components)
diff --git a/src/sksl/ir/SkSLSymbolAlias.h b/src/sksl/ir/SkSLSymbolAlias.h
index 21e139b..7438bea 100644
--- a/src/sksl/ir/SkSLSymbolAlias.h
+++ b/src/sksl/ir/SkSLSymbolAlias.h
@@ -17,7 +17,7 @@
  */
 class SymbolAlias final : public Symbol {
 public:
-    static constexpr Kind kSymbolKind = Kind::kSymbolAlias;
+    inline static constexpr Kind kSymbolKind = Kind::kSymbolAlias;
 
     SymbolAlias(int line, skstd::string_view name, const Symbol* origSymbol)
         : INHERITED(line, kSymbolKind, name)
diff --git a/src/sksl/ir/SkSLTernaryExpression.h b/src/sksl/ir/SkSLTernaryExpression.h
index 4988705..c7096a3 100644
--- a/src/sksl/ir/SkSLTernaryExpression.h
+++ b/src/sksl/ir/SkSLTernaryExpression.h
@@ -17,7 +17,7 @@
  */
 class TernaryExpression final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kTernary;
+    inline static constexpr Kind kExpressionKind = Kind::kTernary;
 
     TernaryExpression(int line, std::unique_ptr<Expression> test,
                       std::unique_ptr<Expression> ifTrue, std::unique_ptr<Expression> ifFalse)
diff --git a/src/sksl/ir/SkSLType.cpp b/src/sksl/ir/SkSLType.cpp
index ec19d4e..fba2c24 100644
--- a/src/sksl/ir/SkSLType.cpp
+++ b/src/sksl/ir/SkSLType.cpp
@@ -25,7 +25,7 @@
 
 class ArrayType final : public Type {
 public:
-    static constexpr TypeKind kTypeKind = TypeKind::kArray;
+    inline static constexpr TypeKind kTypeKind = TypeKind::kArray;
 
     ArrayType(skstd::string_view name, const char* abbrev, const Type& componentType, int count)
         : INHERITED(name, abbrev, kTypeKind)
@@ -70,7 +70,7 @@
 
 class GenericType final : public Type {
 public:
-    static constexpr TypeKind kTypeKind = TypeKind::kGeneric;
+    inline static constexpr TypeKind kTypeKind = TypeKind::kGeneric;
 
     GenericType(const char* name, std::vector<const Type*> coercibleTypes)
         : INHERITED(name, "G", kTypeKind)
@@ -88,7 +88,7 @@
 
 class LiteralType : public Type {
 public:
-    static constexpr TypeKind kTypeKind = TypeKind::kLiteral;
+    inline static constexpr TypeKind kTypeKind = TypeKind::kLiteral;
 
     LiteralType(const char* name, const Type& scalarType, int8_t priority)
         : INHERITED(name, "L", kTypeKind)
@@ -137,7 +137,7 @@
 
 class ScalarType final : public Type {
 public:
-    static constexpr TypeKind kTypeKind = TypeKind::kScalar;
+    inline static constexpr TypeKind kTypeKind = TypeKind::kScalar;
 
     ScalarType(skstd::string_view name, const char* abbrev, NumberKind numberKind, int8_t priority,
                int8_t bitWidth)
@@ -184,7 +184,7 @@
 
 class MatrixType final : public Type {
 public:
-    static constexpr TypeKind kTypeKind = TypeKind::kMatrix;
+    inline static constexpr TypeKind kTypeKind = TypeKind::kMatrix;
 
     MatrixType(skstd::string_view name, const char* abbrev, const Type& componentType,
                int8_t columns, int8_t rows)
@@ -230,7 +230,7 @@
 
 class TextureType final : public Type {
 public:
-    static constexpr TypeKind kTypeKind = TypeKind::kTexture;
+    inline static constexpr TypeKind kTypeKind = TypeKind::kTexture;
 
     TextureType(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed,
                 bool isMultisampled, bool isSampled)
@@ -273,7 +273,7 @@
 
 class SamplerType final : public Type {
 public:
-    static constexpr TypeKind kTypeKind = TypeKind::kSampler;
+    inline static constexpr TypeKind kTypeKind = TypeKind::kSampler;
 
     SamplerType(const char* name, const Type& textureType)
         : INHERITED(name, "Z", kTypeKind)
@@ -311,7 +311,7 @@
 
 class StructType final : public Type {
 public:
-    static constexpr TypeKind kTypeKind = TypeKind::kStruct;
+    inline static constexpr TypeKind kTypeKind = TypeKind::kStruct;
 
     StructType(int line, skstd::string_view name, std::vector<Field> fields)
         : INHERITED(std::move(name), "S", kTypeKind, line)
@@ -345,7 +345,7 @@
 
 class VectorType final : public Type {
 public:
-    static constexpr TypeKind kTypeKind = TypeKind::kVector;
+    inline static constexpr TypeKind kTypeKind = TypeKind::kVector;
 
     VectorType(skstd::string_view name, const char* abbrev, const Type& componentType,
                int8_t columns)
diff --git a/src/sksl/ir/SkSLType.h b/src/sksl/ir/SkSLType.h
index 3c0b1c1..a20144f 100644
--- a/src/sksl/ir/SkSLType.h
+++ b/src/sksl/ir/SkSLType.h
@@ -56,8 +56,8 @@
  */
 class Type : public Symbol {
 public:
-    static constexpr Kind kSymbolKind = Kind::kType;
-    static constexpr int kMaxAbbrevLength = 3;
+    inline static constexpr Kind kSymbolKind = Kind::kType;
+    inline static constexpr int kMaxAbbrevLength = 3;
 
     struct Field {
         Field(Modifiers modifiers, skstd::string_view name, const Type* type)
diff --git a/src/sksl/ir/SkSLTypeReference.h b/src/sksl/ir/SkSLTypeReference.h
index 38b6ff4..8d9644b 100644
--- a/src/sksl/ir/SkSLTypeReference.h
+++ b/src/sksl/ir/SkSLTypeReference.h
@@ -19,7 +19,7 @@
  */
 class TypeReference final : public Expression {
 public:
-    static constexpr Kind kExpressionKind = Kind::kTypeReference;
+    inline static constexpr Kind kExpressionKind = Kind::kTypeReference;
 
     TypeReference(const Context& context, int line, const Type* value)
         : TypeReference(line, value, context.fTypes.fInvalid.get()) {}
diff --git a/src/sksl/ir/SkSLUnresolvedFunction.h b/src/sksl/ir/SkSLUnresolvedFunction.h
index 8bda69b..42b9b71 100644
--- a/src/sksl/ir/SkSLUnresolvedFunction.h
+++ b/src/sksl/ir/SkSLUnresolvedFunction.h
@@ -17,7 +17,7 @@
  */
 class UnresolvedFunction final : public Symbol {
 public:
-    static constexpr Kind kSymbolKind = Kind::kUnresolvedFunction;
+    inline static constexpr Kind kSymbolKind = Kind::kUnresolvedFunction;
 
     UnresolvedFunction(std::vector<const FunctionDeclaration*> funcs)
     : INHERITED(-1, kSymbolKind, funcs[0]->name())
diff --git a/src/sksl/ir/SkSLVarDeclarations.h b/src/sksl/ir/SkSLVarDeclarations.h
index 8c32e57..e93bf87 100644
--- a/src/sksl/ir/SkSLVarDeclarations.h
+++ b/src/sksl/ir/SkSLVarDeclarations.h
@@ -26,7 +26,7 @@
  */
 class VarDeclaration final : public Statement {
 public:
-    static constexpr Kind kStatementKind = Kind::kVarDeclaration;
+    inline static constexpr Kind kStatementKind = Kind::kVarDeclaration;
 
     VarDeclaration(const Variable* var,
                    const Type* baseType,
@@ -103,7 +103,7 @@
  */
 class GlobalVarDeclaration final : public ProgramElement {
 public:
-    static constexpr Kind kProgramElementKind = Kind::kGlobalVar;
+    inline static constexpr Kind kProgramElementKind = Kind::kGlobalVar;
 
     GlobalVarDeclaration(std::unique_ptr<Statement> decl)
             : INHERITED(decl->fLine, kProgramElementKind)
diff --git a/src/sksl/ir/SkSLVariable.h b/src/sksl/ir/SkSLVariable.h
index bb84719..1a01b6e 100644
--- a/src/sksl/ir/SkSLVariable.h
+++ b/src/sksl/ir/SkSLVariable.h
@@ -40,7 +40,7 @@
 public:
     using Storage = VariableStorage;
 
-    static constexpr Kind kSymbolKind = Kind::kVariable;
+    inline static constexpr Kind kSymbolKind = Kind::kVariable;
 
     Variable(int line, const Modifiers* modifiers, skstd::string_view name, const Type* type,
              bool builtin, Storage storage)
diff --git a/src/sksl/ir/SkSLVariableReference.h b/src/sksl/ir/SkSLVariableReference.h
index a88ea96..faf4bde 100644
--- a/src/sksl/ir/SkSLVariableReference.h
+++ b/src/sksl/ir/SkSLVariableReference.h
@@ -35,7 +35,7 @@
 public:
     using RefKind = VariableRefKind;
 
-    static constexpr Kind kExpressionKind = Kind::kVariableReference;
+    inline static constexpr Kind kExpressionKind = Kind::kVariableReference;
 
     VariableReference(int line, const Variable* variable, RefKind refKind);
 
diff --git a/src/sksl/lex/NFAtoDFA.h b/src/sksl/lex/NFAtoDFA.h
index e2fc54e..5331042 100644
--- a/src/sksl/lex/NFAtoDFA.h
+++ b/src/sksl/lex/NFAtoDFA.h
@@ -31,8 +31,8 @@
  */
 class NFAtoDFA {
 public:
-    static constexpr char START_CHAR = 9;
-    static constexpr char END_CHAR = 126;
+    inline static constexpr char START_CHAR = 9;
+    inline static constexpr char END_CHAR = 126;
 
     NFAtoDFA(NFA* nfa)
     : fNFA(*nfa) {}
diff --git a/src/sksl/lex/RegexParser.h b/src/sksl/lex/RegexParser.h
index c1753de..b8f4f1f 100644
--- a/src/sksl/lex/RegexParser.h
+++ b/src/sksl/lex/RegexParser.h
@@ -23,7 +23,7 @@
     RegexNode parse(std::string source);
 
 private:
-    static constexpr char END = '\0';
+    inline static constexpr char END = '\0';
 
     char peek();
 
diff --git a/src/utils/SkBitSet.h b/src/utils/SkBitSet.h
index cc904f2..8fadfa3 100644
--- a/src/utils/SkBitSet.h
+++ b/src/utils/SkBitSet.h
@@ -128,7 +128,7 @@
 
     using Chunk = uint32_t;
     static_assert(std::numeric_limits<Chunk>::radix == 2);
-    static constexpr size_t kChunkBits = std::numeric_limits<Chunk>::digits;
+    inline static constexpr size_t kChunkBits = std::numeric_limits<Chunk>::digits;
     static_assert(kChunkBits == sizeof(Chunk)*CHAR_BIT, "SkBitSet must use every bit in a Chunk");
     std::unique_ptr<Chunk, SkFunctionWrapper<void(void*), sk_free>> fChunks;
 
diff --git a/src/utils/SkJSON.cpp b/src/utils/SkJSON.cpp
index 91d8863..6888f7d 100644
--- a/src/utils/SkJSON.cpp
+++ b/src/utils/SkJSON.cpp
@@ -137,7 +137,7 @@
 
 private:
     // first byte reserved for tagging, \0 terminator => 6 usable chars
-    static constexpr size_t kMaxInlineStringSize = sizeof(Value) - 2;
+    inline static constexpr size_t kMaxInlineStringSize = sizeof(Value) - 2;
 
     void initLongString(const char* src, size_t size, SkArenaAlloc& alloc) {
         SkASSERT(size > kMaxInlineStringSize);
@@ -468,11 +468,11 @@
     SkArenaAlloc&         fAlloc;
 
     // Pending values stack.
-    static constexpr size_t kValueStackReserve = 256;
+    inline static constexpr size_t kValueStackReserve = 256;
     std::vector<Value>    fValueStack;
 
     // String unescape buffer.
-    static constexpr size_t kUnescapeBufferReserve = 512;
+    inline static constexpr size_t kUnescapeBufferReserve = 512;
     std::vector<char>     fUnescapeBuffer;
 
     // Tracks the current object/array scope, as an index into fStack:
diff --git a/src/utils/SkJSON.h b/src/utils/SkJSON.h
index d3f0b1d..a0d7762 100644
--- a/src/utils/SkJSON.h
+++ b/src/utils/SkJSON.h
@@ -132,7 +132,7 @@
         kArray                        = 0b00000110,  // ptr to external storage
         kObject                       = 0b00000111,  // ptr to external storage
     };
-    static constexpr uint8_t kTagMask = 0b00000111;
+    inline static constexpr uint8_t kTagMask = 0b00000111;
 
     void init_tagged(Tag);
     void init_tagged_pointer(Tag, void*);
@@ -199,7 +199,7 @@
     }
 
 private:
-    static constexpr size_t kValueSize = 8;
+    inline static constexpr size_t kValueSize = 8;
 
     uint8_t fData8[kValueSize];
 
@@ -211,14 +211,14 @@
 
 class NullValue final : public Value {
 public:
-    static constexpr Type kType = Type::kNull;
+    inline static constexpr Type kType = Type::kNull;
 
     NullValue();
 };
 
 class BoolValue final : public Value {
 public:
-    static constexpr Type kType = Type::kBool;
+    inline static constexpr Type kType = Type::kBool;
 
     explicit BoolValue(bool);
 
@@ -230,7 +230,7 @@
 
 class NumberValue final : public Value {
 public:
-    static constexpr Type kType = Type::kNumber;
+    inline static constexpr Type kType = Type::kNumber;
 
     explicit NumberValue(int32_t);
     explicit NumberValue(float);
@@ -249,7 +249,7 @@
 class VectorValue : public Value {
 public:
     using ValueT = T;
-    static constexpr Type kType = vtype;
+    inline static constexpr Type kType = vtype;
 
     size_t size() const {
         SkASSERT(this->getType() == kType);
@@ -283,7 +283,7 @@
 
 class StringValue final : public Value {
 public:
-    static constexpr Type kType = Type::kString;
+    inline static constexpr Type kType = Type::kString;
 
     StringValue();
     StringValue(const char* src, size_t size, SkArenaAlloc& alloc);
diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp
index 9baa29c..24a1b4f 100644
--- a/src/utils/SkShadowTessellator.cpp
+++ b/src/utils/SkShadowTessellator.cpp
@@ -39,9 +39,9 @@
     }
 
 protected:
-    static constexpr auto kMinHeight = 0.1f;
-    static constexpr auto kPenumbraColor = SK_ColorTRANSPARENT;
-    static constexpr auto kUmbraColor = SK_ColorBLACK;
+    inline static constexpr auto kMinHeight = 0.1f;
+    inline static constexpr auto kPenumbraColor = SK_ColorTRANSPARENT;
+    inline static constexpr auto kUmbraColor = SK_ColorBLACK;
 
     int vertexCount() const { return fPositions.count(); }
     int indexCount() const { return fIndices.count(); }
@@ -125,10 +125,6 @@
     SkPoint             fPrevPoint;
 };
 
-// make external linkage happy
-constexpr SkColor SkBaseShadowTessellator::kUmbraColor;
-constexpr SkColor SkBaseShadowTessellator::kPenumbraColor;
-
 static bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar dir,
                            SkVector* newNormal) {
     SkVector normal;
diff --git a/tests/GrPipelineDynamicStateTest.cpp b/tests/GrPipelineDynamicStateTest.cpp
index 3c06464..fbc952a 100644
--- a/tests/GrPipelineDynamicStateTest.cpp
+++ b/tests/GrPipelineDynamicStateTest.cpp
@@ -78,7 +78,7 @@
     const Attribute& inVertex() const { return kAttributes[0]; }
     const Attribute& inColor() const { return kAttributes[1]; }
 
-    static constexpr Attribute kAttributes[] = {
+    inline static constexpr Attribute kAttributes[] = {
             {"vertex", kFloat2_GrVertexAttribType, kHalf2_GrSLType},
             {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType},
     };
diff --git a/tools/gpu/gl/GLTestContext.cpp b/tools/gpu/gl/GLTestContext.cpp
index 9862a29..ffada97 100644
--- a/tools/gpu/gl/GLTestContext.cpp
+++ b/tools/gpu/gl/GLTestContext.cpp
@@ -30,10 +30,10 @@
     sk_gpu_test::PlatformTimerQuery onQueueTimerStart() const override;
     void onQueueTimerStop(sk_gpu_test::PlatformTimerQuery) const override;
 
-    static constexpr GrGLenum GL_QUERY_RESULT            = 0x8866;
-    static constexpr GrGLenum GL_QUERY_RESULT_AVAILABLE  = 0x8867;
-    static constexpr GrGLenum GL_TIME_ELAPSED            = 0x88bf;
-    static constexpr GrGLenum GL_GPU_DISJOINT            = 0x8fbb;
+    inline static constexpr GrGLenum GL_QUERY_RESULT            = 0x8866;
+    inline static constexpr GrGLenum GL_QUERY_RESULT_AVAILABLE  = 0x8867;
+    inline static constexpr GrGLenum GL_TIME_ELAPSED            = 0x88bf;
+    inline static constexpr GrGLenum GL_GPU_DISJOINT            = 0x8fbb;
 
     typedef void (GR_GL_FUNCTION_TYPE* GLGetIntegervProc) (GrGLenum, GrGLint*);
     typedef void (GR_GL_FUNCTION_TYPE* GLGenQueriesProc) (GrGLsizei, GrGLuint*);
diff --git a/tools/sk_app/win/D3D12WindowContext_win.cpp b/tools/sk_app/win/D3D12WindowContext_win.cpp
index 573b7cc..b818682 100644
--- a/tools/sk_app/win/D3D12WindowContext_win.cpp
+++ b/tools/sk_app/win/D3D12WindowContext_win.cpp
@@ -49,7 +49,7 @@
     void resize(int width, int height) override;
     void setDisplayParams(const DisplayParams& params) override;
 private:
-    static constexpr int kNumFrames = 2;
+    inline static constexpr int kNumFrames = 2;
 
     HWND fWindow;
     gr_cp<ID3D12Device> fDevice;