diff --git a/BUILD.gn b/BUILD.gn
index 4e97f10134..32758ba1d5 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -169,7 +169,7 @@ is_loong64 = current_cpu == "loong64"
 opts("hsw") {
   enabled = is_x86
   sources = skia_opts.hsw_sources
-  if (is_win) {
+  if (is_msvc) {
     cflags = [ "/arch:AVX2" ]
   } else {
     cflags = [ "-march=haswell" ]
@@ -179,7 +179,7 @@ opts("hsw") {
 opts("skx") {
   enabled = is_x86
   sources = skia_opts.skx_sources
-  if (is_win) {
+  if (is_msvc) {
     cflags = [ "/arch:AVX512" ]
   } else {
     cflags = [ "-march=skylake-avx512" ]
@@ -447,7 +447,7 @@ optional("fontmgr_win") {
   sources = skia_ports_windows_fonts_sources
   if (skia_dwritecore_sdk != "") {
     defines = [ "DWRITE_CORE" ]
-    if (is_win && is_clang) {
+    if (is_msvc && is_clang) {
       # Clang complains about these headers, so mark them as system. These
       # headers are hiding SDK headers of the same name, which are also
       # included as system headers, so these need to go first in the cflags
@@ -468,7 +468,7 @@ optional("fontmgr_win_gdi") {
   public_defines = [ "SK_FONTMGR_GDI_AVAILABLE" ]
   public = skia_ports_windows_fonts_public
   sources = skia_ports_fonthost_win_sources
-  libs = [ "Gdi32.lib" ]
+  libs = [ "gdi32" ]
 }
 
 if (skia_lex) {
@@ -994,7 +994,7 @@ optional("gpu") {
         "src/gpu/ganesh/gl/win/GrGLMakeWinInterface.cpp",
       ]
       if (target_cpu != "arm64") {
-        libs += [ "OpenGL32.lib" ]
+        libs += [ "opengl32" ]
       }
     } else {
       sources += [ "src/gpu/ganesh/gl/GrGLMakeNativeInterface_none.cpp" ]
@@ -1027,9 +1027,9 @@ optional("gpu") {
       public_defines += [ "SK_ENABLE_D3D_DEBUG_LAYER" ]
     }
     libs += [
-      "d3d12.lib",
-      "dxgi.lib",
-      "d3dcompiler.lib",
+      "d3d12",
+      "dxgi",
+      "d3dcompiler",
     ]
   }
 
@@ -1527,15 +1527,16 @@ skia_component("skia") {
                  "src/ports/SkImageGeneratorWIC.cpp",
                ]
     libs += [
-      "Ole32.lib",
-      "OleAut32.lib",
+      "ole32",
+      "oleaut32",
+      "uuid",
     ]
 
     if (!skia_enable_winuwp) {
       libs += [
-        "FontSub.lib",
-        "User32.lib",
-        "Usp10.lib",
+        "fontsub",
+        "user32",
+        "usp10",
       ]
     }
   } else {
@@ -1793,7 +1794,7 @@ if (skia_enable_tools) {
   }
 
   config("cpp17") {
-    if (is_win) {
+    if (is_msvc) {
       cflags_cc = [ "/std:c++17" ]
     } else {
       cflags_cc = [ "-std=c++17" ]
@@ -2002,9 +2003,9 @@ if (skia_enable_tools) {
           "tools/gpu/gl/win/SkWGL.h",
           "tools/gpu/gl/win/SkWGL_win.cpp",
         ]
-        libs += [ "Gdi32.lib" ]
+        libs += [ "gdi32" ]
         if (target_cpu != "arm64") {
-          libs += [ "OpenGL32.lib" ]
+          libs += [ "opengl32" ]
         }
       }
     }
@@ -2879,7 +2880,7 @@ if (skia_enable_tools) {
         "tools/fiddle/examples.cpp",
         "tools/fiddle/examples.h",
       ]
-      if (is_win) {
+      if (is_msvc) {
         cflags = [
           "/wd4756",  # Overflow in constant arithmetic
           "/wd4305",  # truncation from 'double' to 'float'
diff --git a/gn/BUILDCONFIG.gn b/gn/BUILDCONFIG.gn
index 146ad60b4b..a41321f766 100644
--- a/gn/BUILDCONFIG.gn
+++ b/gn/BUILDCONFIG.gn
@@ -71,6 +71,8 @@ is_linux = current_os == "linux"
 is_mac = current_os == "mac"
 is_wasm = current_os == "wasm"
 is_win = current_os == "win"
+is_mingw = is_win && (cxx == "g++" || cxx == "clang++")
+is_msvc = is_win && !is_mingw
 
 # This is just to make the Dawn build files happy. Skia itself uses target_os = "linux"
 # for ChromeOS, so this variable will not affect Skia proper.
@@ -126,7 +128,7 @@ if (is_android) {
   }
 }
 
-if (target_os == "win") {
+if (is_msvc) {
   # By default we look for 2017 (Enterprise, Pro, and Community), then 2015. If MSVC is installed in a
   # non-default location, you can set win_vc to inform us where it is.
 
@@ -137,7 +139,7 @@ if (target_os == "win") {
                         # directory.
 }
 
-if (target_os == "win") {
+if (is_msvc) {
   if (win_toolchain_version == "") {
     win_toolchain_version = exec_script("//gn/highest_version_dir.py",
                                         [
@@ -230,7 +232,7 @@ if (!is_official_build) {
       [ "//gn/skia:warnings_for_public_headers" ]
 }
 
-if (is_win) {
+if (is_msvc) {
   # Windows tool chain
   set_default_toolchain("//gn/toolchain:msvc")
   default_toolchain_name = "msvc"
diff --git a/gn/skia/BUILD.gn b/gn/skia/BUILD.gn
index 94632fa75c..17fefd5d12 100644
--- a/gn/skia/BUILD.gn
+++ b/gn/skia/BUILD.gn
@@ -62,12 +62,12 @@ config("default") {
   # Disable warnings about unknown attributes.
   # (These unknown attribute warnings are on by default, so we don't make
   # disabling them part of :warnings, as some targets remove :warnings.)
-  if (is_win && !is_clang) {
+  if (is_msvc && !is_clang) {
     cflags += [
       "/wd5030",
       "/wd5051",
     ]
-  } else {
+  } else if (!is_mingw) {
     cflags += [ "-Wno-attributes" ]
   }
 
@@ -97,7 +97,7 @@ config("default") {
     asmflags += [ target_triple ]
   }
 
-  if (is_win) {
+  if (is_msvc) {
     if (is_clang && current_cpu == "arm64") {
       cflags += [ "--target=arm64-windows" ]
     }
@@ -142,11 +142,31 @@ config("default") {
       "$win_vc/Tools/MSVC/$win_toolchain_version/lib/$current_cpu",
     ]
   } else {
-    cflags += [
-      "-fstrict-aliasing",
-      "-fPIC",
-      "-fvisibility=hidden",
-    ]
+    if (is_mingw) {
+      if (target_cpu == "arm64") {
+        cflags += [
+          "-march=armv8-a+simd+fp",
+        ]
+      } else {
+        cflags += [
+          "-mavx2",
+          "-mavx512f",
+          "-mf16c",
+          "-mfma",
+        ]
+      }
+      cflags += [
+        "-fpermissive",
+        "-fstrict-aliasing",
+        "-fvisibility=default",
+      ]
+    } else {
+      cflags += [
+        "-fstrict-aliasing",
+        "-fPIC",
+        "-fvisibility=hidden",
+      ]
+    }
     cflags_cc += [
       "-std=c++17",
       "-fvisibility-inlines-hidden",
@@ -184,6 +204,20 @@ config("default") {
     libs += [ malloc ]
   }
 
+  if (is_mingw) {
+    defines += [
+      "_CRT_SECURE_NO_WARNINGS",
+      "WIN32_LEAN_AND_MEAN",
+      "NOMINMAX",
+    ]
+    if (!is_clang) {
+      cflags += [
+        "-Wno-attributes",
+        "-Wno-stringop-overflow",
+      ]
+    }
+  }
+
   if (is_android) {
     cflags += [ "--sysroot=$ndk/toolchains/llvm/prebuilt/$ndk_host/sysroot" ]
     ldflags += [ "-static-libstdc++" ]
@@ -191,7 +225,7 @@ config("default") {
 
   if (show_includes) {
     assert(is_clang, "show_includes requires clang to build.")
-    if (is_win) {
+    if (is_msvc) {
       cflags += [
         "/clang:-H",
         "/clang:-fshow-skipped-includes",
@@ -367,7 +401,7 @@ config("default") {
       "-fsanitize-blacklist=$_suppressions",
     ]
 
-    if (is_win) {
+    if (is_msvc) {
       cflags += [
         # On Release builds, we get strange warnings about string literals.
         "/GF-",
@@ -406,7 +440,7 @@ config("recover_pointer_overflow") {
 
 config("no_exceptions") {
   # Exceptions are disabled by default on Windows.  (Use /EHsc to enable them.)
-  if (!is_win) {
+  if (!is_msvc) {
     cflags_cc = [ "-fno-exceptions" ]
     cflags_objcc = cflags_cc
   }
@@ -419,14 +453,14 @@ config("warnings") {
   cflags_objcc = []
 
   if (werror) {
-    if (is_win) {
+    if (is_msvc) {
       cflags += [ "/WX" ]
     } else {
       cflags += [ "-Werror" ]
     }
   }
 
-  if (is_win) {
+  if (is_msvc) {
     cflags += [
       "/W3",  # Turn on lots of warnings.
 
@@ -628,7 +662,7 @@ config("warnings") {
   }
 
   # !is_clang is a proxy for gcc.
-  if (!is_clang && !is_win) {
+  if (!is_clang && !is_msvc) {
     cflags += [
       "-Wno-unreachable-code",  # Causes false positives in old GCC; removed
                                 # from modern GCC entirely
@@ -672,7 +706,7 @@ config("debug_symbols") {
       "-gline-tables-only",
       "-funwind-tables",  # Helps make in-process backtraces fuller.
     ]
-  } else if (is_win) {
+  } else if (is_msvc) {
     cflags = [ "/Z7" ]
     if (is_clang) {
       cflags += [ "-gcodeview-ghash" ]
@@ -690,7 +724,7 @@ config("debug_symbols") {
 
 config("no_rtti") {
   if (sanitize != "ASAN") {  # -fsanitize=vptr requires RTTI
-    if (is_win) {
+    if (is_msvc) {
       cflags_cc = [ "/GR-" ]
     } else {
       cflags_cc = [ "-fno-rtti" ]
@@ -701,7 +735,7 @@ config("no_rtti") {
 
 config("optimize") {
   ldflags = []
-  if (is_win) {
+  if (is_msvc) {
     cflags = [
       "/O2",
       "/Zc:inline",
@@ -716,7 +750,7 @@ config("optimize") {
   } else {
     if (skia_enable_optimize_size) {
       cflags = [ "-Oz" ]
-      if (!is_android) {
+      if (!is_android && !is_mingw) {
         cflags += [
           # Clang 15 turns PIE (Position-indendendent Executable) on by default.
           "-fno-PIE",
@@ -762,7 +796,9 @@ config("executable") {
       "-rdynamic",
       "-Wl,-rpath,\$ORIGIN",
     ]
-  } else if (is_win) {
+  } else if (is_mingw) {
+    ldflags = [ "-mconsole" ]
+  } else if (is_msvc) {
     ldflags = [
       "/SUBSYSTEM:CONSOLE",  # Quiet "no subsystem specified; CONSOLE assumed".
       "/INCREMENTAL:NO",  # Quiet warnings about failing to incrementally link
diff --git a/gn/toolchain/BUILD.gn b/gn/toolchain/BUILD.gn
index 4d4abc952f..1c4c7ae412 100644
--- a/gn/toolchain/BUILD.gn
+++ b/gn/toolchain/BUILD.gn
@@ -56,7 +56,7 @@ declare_args() {
 }
 
 # For 'shell' see https://ninja-build.org/manual.html#ref_rule_command
-if (host_os == "win") {
+if (is_msvc) {
   shell = "cmd.exe /c "
   stamp = "$shell echo >"
 } else {
@@ -322,8 +322,7 @@ template("gcc_like_toolchain") {
       } else {
         rspfile = "{{output}}.rsp"
         rspfile_content = "{{inputs}}"
-        rm_py = rebase_path("../rm.py")
-        command = "$shell python3 \"$rm_py\" \"{{output}}\" && $ar rcs {{output}} @$rspfile"
+        command = "$ar rcs {{output}} @$rspfile"
       }
 
       outputs =
@@ -342,6 +341,8 @@ template("gcc_like_toolchain") {
       rpath = "-Wl,-soname,$soname"
       if (is_mac || is_ios) {
         rpath = "-Wl,-install_name,@rpath/$soname"
+      } else if (is_mingw) {
+        rpath = ""  # For PE/COFF the soname argument has no effect
       }
 
       rspfile = "{{output}}.rsp"
@@ -360,11 +361,18 @@ template("gcc_like_toolchain") {
         _end_group = ""
       }
 
-      command = "$link -shared {{ldflags}} $_start_group @$rspfile {{frameworks}} {{solibs}} $_end_group {{libs}} $rpath -o {{output}}"
+      soname_flags = ""
+      if (is_mingw) {
+        soname_flags = "-Wl,--out-implib=$soname.a"
+      }
+
+      command = "$link -shared $soname_flags {{ldflags}} $_start_group @$rspfile {{frameworks}} {{solibs}} {{libs}} $_end_group $rpath -o {{output}}"
       outputs = [ "{{root_out_dir}}/$soname" ]
       output_prefix = "lib"
       if (is_mac || is_ios) {
         default_output_extension = ".dylib"
+      } else if (is_mingw) {
+        default_output_extension = ".dll"
       } else {
         default_output_extension = ".so"
       }
diff --git a/modules/skcms/BUILD.gn b/modules/skcms/BUILD.gn
index 5d037a94c9..4385748ac3 100644
--- a/modules/skcms/BUILD.gn
+++ b/modules/skcms/BUILD.gn
@@ -33,7 +33,7 @@ template("arch") {
 arch("skcms_TransformHsw") {
   enabled = current_cpu == "x64" && target_os != "android"
   sources = skcms_TransformHsw
-  if (is_win) {
+  if (is_msvc) {
     if (is_clang) {
       cflags = [
         "/clang:-mavx2",
@@ -43,6 +43,8 @@ arch("skcms_TransformHsw") {
     } else {
       cflags = [ "/arch:AVX2" ]
     }
+  } else if (is_mingw) {
+    cflags = [ "-march=haswell" ]
   } else {
     cflags = [
       "-mavx2",
@@ -55,7 +57,7 @@ arch("skcms_TransformHsw") {
 arch("skcms_TransformSkx") {
   enabled = current_cpu == "x64" && target_os != "android"
   sources = skcms_TransformSkx
-  if (is_win) {
+  if (is_msvc) {
     if (is_clang) {
       cflags = [
         "/clang:-mavx512f",
@@ -68,6 +70,8 @@ arch("skcms_TransformSkx") {
     } else {
       cflags = [ "/arch:AVX512" ]
     }
+  } else if (is_mingw) {
+    cflags = [ "-march=skylake-avx512" ]
   } else {
     cflags = [
       "-mavx512f",
@@ -83,7 +87,7 @@ arch("skcms_TransformSkx") {
 static_library("skcms") {
   cflags = []
   if (!is_win || is_clang) {
-    cflags += [ "-std=c11" ]
+    cflags_c = [ "-std=c11" ]
   }
   if (target_cpu != "x64" || target_os == "android") {
     defines = [
diff --git a/third_party/third_party.gni b/third_party/third_party.gni
index cbcd16cf38..207380f7e1 100644
--- a/third_party/third_party.gni
+++ b/third_party/third_party.gni
@@ -13,7 +13,7 @@ template("third_party_config") {
     if (enabled) {
       forward_variables_from(invoker, "*", [ "include_dirs" ])
       cflags = []
-      if (is_win) {
+      if (is_msvc) {
         include_dirs = invoker.include_dirs
         if (is_clang) {
           foreach(dir, invoker.include_dirs) {
@@ -92,7 +92,7 @@ template("third_party") {
       if (!defined(cflags)) {
         cflags = []
       }
-      if (is_win) {
+      if (is_msvc) {
         cflags += [ "/w" ]
       } else {
         cflags += [ "-w" ]
