diff --git a/config/BUILD.gn b/config/BUILD.gn
index 56ca3ca73..4b0b33318 100644
--- a/config/BUILD.gn
+++ b/config/BUILD.gn
@@ -157,25 +157,25 @@ config("default_libs") {
     # instead the targets that use the less common ones (e.g. wininet or
     # winspool) should include those explicitly.
     libs = [
-      "advapi32.lib",
-      "comdlg32.lib",
-      "dbghelp.lib",
-      "dnsapi.lib",
-      "gdi32.lib",
-      "msimg32.lib",
-      "odbc32.lib",
-      "odbccp32.lib",
-      "oleaut32.lib",
-      "shell32.lib",
-      "shlwapi.lib",
-      "user32.lib",
-      "usp10.lib",
-      "uuid.lib",
-      "version.lib",
-      "wininet.lib",
-      "winmm.lib",
-      "winspool.lib",
-      "ws2_32.lib",
+      "advapi32",
+      "comdlg32",
+      "dbghelp",
+      "dnsapi",
+      "gdi32",
+      "msimg32",
+      "odbc32",
+      "odbccp32",
+      "oleaut32",
+      "shell32",
+      "shlwapi",
+      "user32",
+      "usp10",
+      "uuid",
+      "version",
+      "wininet",
+      "winmm",
+      "winspool",
+      "ws2_32",
 
       # Please don't add more stuff here. We should actually be making this
       # list smaller, since all common things should be covered. If you need
@@ -191,9 +191,9 @@ config("default_libs") {
     } else {
       # These libraries are not compatible with Windows UWP (i.e. store apps.)
       libs += [
-        "delayimp.lib",
-        "kernel32.lib",
-        "ole32.lib",
+        "delayimp",
+        "kernel32",
+        "ole32",
       ]
     }
   } else if (is_android) {
@@ -253,7 +253,7 @@ group("common_deps_without_libcxx") {
     }
   }
 
-  if (is_win) {
+  if (is_msvc) {
     if (build_with_chromium && is_component_build) {
       # To enable allocator_shim for the windows component built chrome,
       # need to make all shared libraries and also executable(i.e.chrome.exe)
@@ -405,7 +405,7 @@ config("shared_library_config") {
 # Recommend precompiled headers for targets with more than 50 .cc files.
 config("precompiled_headers") {
   if (enable_precompiled_headers) {
-    if (is_win) {
+    if (is_msvc) {
       # This is a string rather than a file GN knows about. It has to match
       # exactly what's in the /FI flag below, and what might appear in the
       # source code in quotes for an #include directive.
@@ -418,7 +418,7 @@ config("precompiled_headers") {
 
       # Force include the header.
       cflags = [ "/FI$precompiled_header" ]
-    } else if (is_mac || is_linux) {
+    } else if (is_mac || is_linux || is_mingw) {
       precompiled_source = "//build/precompile.h"
     }
   }
diff --git a/config/BUILDCONFIG.gn b/config/BUILDCONFIG.gn
index 147226d72..07b31bfc5 100644
--- a/config/BUILDCONFIG.gn
+++ b/config/BUILDCONFIG.gn
@@ -135,6 +135,9 @@ declare_args() {
   # set "is_official_build" to true for any build intended to ship to end-users.
   is_official_build = false
 
+  # Set to true when compiling with the MinGW GCC compiler on the MSYS2 environment.
+  is_mingw = current_os == "win" && (getenv("CXX") == "g++" || getenv("CXX") == "clang++")
+
   # Set to true when compiling with the Clang compiler.
   is_clang = current_os != "linux" ||
              (current_cpu != "s390x" && current_cpu != "s390" &&
@@ -227,16 +230,20 @@ if (host_toolchain == "") {
     # On Windows always use the target CPU for host builds for x86/x64. On the
     # configurations we support this will always work and it saves build steps.
     # Windows ARM64 targets require an x64 host for cross build.
-    if (target_cpu == "x86" || target_cpu == "x64") {
-      if (is_clang) {
-        host_toolchain = "//build/toolchain/win:win_clang_$target_cpu"
+    if (is_mingw) {
+      host_toolchain = "//build/toolchain/win:mingw_$target_cpu"
+    } else {
+      if (target_cpu == "x86" || target_cpu == "x64") {
+        if (is_clang) {
+          host_toolchain = "//build/toolchain/win:win_clang_$target_cpu"
+        } else {
+          host_toolchain = "//build/toolchain/win:$target_cpu"
+        }
+      } else if (is_clang) {
+        host_toolchain = "//build/toolchain/win:win_clang_$host_cpu"
       } else {
-        host_toolchain = "//build/toolchain/win:$target_cpu"
+        host_toolchain = "//build/toolchain/win:$host_cpu"
       }
-    } else if (is_clang) {
-      host_toolchain = "//build/toolchain/win:win_clang_$host_cpu"
-    } else {
-      host_toolchain = "//build/toolchain/win:$host_cpu"
     }
   } else if (host_os == "aix") {
     host_toolchain = "//build/toolchain/aix:$host_cpu"
@@ -271,10 +278,14 @@ if (target_os == "android") {
 } else if (target_os == "win") {
   # On Windows, we use the same toolchain for host and target by default.
   # Beware, win cross builds have some caveats, see docs/win_cross.md
-  if (is_clang) {
-    _default_toolchain = "//build/toolchain/win:win_clang_$target_cpu"
+  if (is_mingw) {
+    _default_toolchain = "//build/toolchain/win:mingw_$target_cpu"
   } else {
-    _default_toolchain = "//build/toolchain/win:$target_cpu"
+    if (is_clang) {
+      _default_toolchain = "//build/toolchain/win:win_clang_$target_cpu"
+    } else {
+      _default_toolchain = "//build/toolchain/win:$target_cpu"
+    }
   }
 } else if (target_os == "winuwp") {
   # Only target WinUWP on for a Windows store application and only
@@ -339,6 +350,7 @@ is_win = current_os == "win" || current_os == "winuwp"
 
 is_apple = is_ios || is_mac || is_watchos
 is_posix = !is_win && !is_fuchsia
+is_msvc = is_win && !is_mingw
 
 # =============================================================================
 # TARGET DEFAULTS
@@ -418,7 +430,7 @@ if (is_android) {
       [ "//build/config/android:default_orderfile_instrumentation" ]
 }
 
-if (is_clang && !is_nacl) {
+if (is_clang && !is_nacl && !is_mingw) {
   default_compiler_configs += [
     "//build/config/clang:extra_warnings",
     "//build/config/clang:find_bad_constructs",
@@ -446,7 +458,7 @@ set_defaults("rust_library") {
 
 # Compute the set of configs common to all linked targets (shared libraries,
 # loadable modules, executables) to avoid duplication below.
-if (is_win) {
+if (is_msvc) {
   # Many targets remove these configs, so they are not contained within
   # //build/config:executable_config for easy removal.
   _linker_configs = [
@@ -473,7 +485,7 @@ default_executable_configs = default_compiler_configs + [
                                "//build/config:executable_config",
                              ] + _linker_configs
 
-if (is_win) {
+if (is_msvc) {
   # Turn on linker CFI for executables, and position it so it can be removed
   # if needed.
   default_executable_configs += [ "//build/config/win:cfi_linker" ]
@@ -497,7 +509,7 @@ default_shared_library_configs = default_compiler_configs + [
                                    "//build/config:default_libs",
                                    "//build/config:shared_library_config",
                                  ] + _linker_configs
-if (is_win) {
+if (is_msvc) {
   # Turn on linker CFI for DLLs, and position it so it can be removed if needed.
   default_shared_library_configs += [ "//build/config/win:cfi_linker" ]
 }
diff --git a/config/compiler/BUILD.gn b/config/compiler/BUILD.gn
index 29c284ee0..0125019ad 100644
--- a/config/compiler/BUILD.gn
+++ b/config/compiler/BUILD.gn
@@ -322,14 +322,20 @@ config("compiler") {
 
   configs += [
     # See the definitions below.
-    ":clang_revision",
-    ":rustc_revision",
     ":compiler_cpu_abi",
     ":compiler_codegen",
     ":compiler_deterministic",
     ":clang_warning_suppression",
   ]
 
+  if (clang_use_chrome_plugins) {
+    configs += [ ":clang_revision" ]
+  }
+
+  if (enable_rust) {
+    configs += [ ":rustc_revision" ]
+  }
+
   # TODO(https://crbug.com/404297941): Disable clang_warning_suppression
   # configuration because the ICECC build doesn't distribute the
   # warning_suppression.txt file to other ICECC nodes. As a result, the nodes
@@ -355,8 +361,8 @@ config("compiler") {
   # Make signed overflow and pointer overflowdefined to wrap.
   # This avoids risking miscompilations and security bugs on overflow.
   # When UBSan is enabled, we want to continue flagging overflows as a bug.
-  if (!is_ubsan && (!is_win || is_clang)) {
-    if (is_win) {
+  if (!is_ubsan && (!is_msvc || is_clang)) {
+    if (is_msvc) {
       cflags += [ "/clang:-fno-strict-overflow" ]
     } else {
       cflags += [ "-fno-strict-overflow" ]
@@ -366,7 +372,7 @@ config("compiler") {
   # Don't emit the GCC version ident directives, they just end up in the
   # .comment section or debug info taking up binary size, and makes comparing
   # .o files built with different compiler versions harder.
-  if (!is_win || is_clang) {
+  if (!is_msvc || is_clang) {
     cflags += [ "-fno-ident" ]
   }
 
@@ -426,6 +432,18 @@ config("compiler") {
     if (fatal_linker_warnings && is_apple) {
       ldflags += [ "-Wl,-fatal_warnings" ]
     }
+  } else if (is_mingw) {
+    cflags += [ "-fno-strict-aliasing" ]
+
+    if (is_debug) {
+      cflags += [ "-fstack-protector-strong" ]
+    } else {
+      cflags += [ "-fstack-protector" ]
+    }
+
+    if (use_lld) {
+      ldflags += [ "-fuse-ld=lld" ]
+    }
   }
 
   # Non-Apple Posix and Fuchsia compiler flags setup.
@@ -574,7 +592,7 @@ config("compiler") {
     cflags += [ "-fmerge-all-constants" ]
 
     if (!use_sized_deallocation) {
-      if (is_win) {
+      if (is_msvc) {
         cflags += [ "/Zc:sizedDealloc-" ]
       } else {
         cflags += [ "-fno-sized-deallocation" ]
@@ -586,7 +604,7 @@ config("compiler") {
     }
   }
 
-  if (use_lld) {
+  if (use_lld && !is_mingw) {
     # TODO(thakis): Make the driver pass --color-diagnostics to the linker
     # if -fcolor-diagnostics is passed to it, and pass -fcolor-diagnostics
     # in ldflags instead.
@@ -605,7 +623,7 @@ config("compiler") {
     ldflags += [ "-Wl,-z,keep-text-section-prefix" ]
   }
 
-  if (is_clang) {
+  if (is_clang && !is_mingw) {
     cflags += [ "-fcrash-diagnostics-dir=" + clang_diagnostic_dir ]
     if (save_reproducers_on_lld_crash && use_lld) {
       ldflags += [
@@ -664,7 +682,7 @@ config("compiler") {
 
   # C11/C++11 compiler flags setup.
   # ---------------------------
-  if (is_linux || is_chromeos || is_android || current_os == "aix") {
+  if (is_linux || is_chromeos || is_android || is_mingw || current_os == "aix") {
     if (is_clang) {
       standard_prefix = "c"
 
@@ -682,7 +700,7 @@ config("compiler") {
     }
 
     cflags_c += [ "-std=${standard_prefix}11" ]
-    if (is_clang) {
+    if (is_clang || is_mingw) {
       if (defined(use_cxx17) && use_cxx17) {
         assert(!use_cxx23)
         cflags_cc += [ "-std=${standard_prefix}++17" ]
@@ -696,7 +714,7 @@ config("compiler") {
       # support "c++20"/"gnu++20".
       cflags_cc += [ "-std=${standard_prefix}++2a" ]
     }
-  } else if (is_win) {
+  } else if (is_msvc) {
     cflags_c += [ "/std:c11" ]
     if (defined(use_cxx17) && use_cxx17) {
       assert(!use_cxx23)
@@ -911,7 +929,7 @@ config("compiler") {
       if (use_lld && is_mac) {
         ldflags += [ "-Wl,--time-trace" ]
       }
-    } else if (is_win) {
+    } else if (is_msvc) {
       cflags += [
         # "Documented" here:
         # http://aras-p.info/blog/2017/10/23/Best-unknown-MSVC-flag-d2cgsummary/
@@ -940,7 +958,7 @@ config("compiler") {
   # present. On Android this increases binary size due to more thinks for long
   # jumps. Turn it off by default and enable selectively for targets where it's
   # beneficial.
-  if (use_lld && !enable_call_graph_profile_sort) {
+  if (use_lld && !enable_call_graph_profile_sort && !is_mingw) {
     if (is_win) {
       ldflags += [ "/call-graph-profile-sort:no" ]
     } else if (!is_wasm) {
@@ -950,7 +968,7 @@ config("compiler") {
   }
 
   if (is_clang && show_includes) {
-    if (is_win) {
+    if (is_msvc) {
       cflags += [
         "/clang:-H",
         "/clang:-fshow-skipped-includes",
@@ -966,7 +984,7 @@ config("compiler") {
   # This flag enforces that member pointer base types are complete. It helps
   # prevent us from running into problems in the Microsoft C++ ABI (see
   # https://crbug.com/847724).
-  if (is_clang && target_os != "chromeos" && (is_win || use_custom_libcxx)) {
+  if (is_clang && target_os != "chromeos" && (is_msvc || use_custom_libcxx)) {
     cflags += [ "-fcomplete-member-pointers" ]
   }
 
@@ -1240,22 +1258,26 @@ config("compiler_cpu_abi") {
     configs += [ "//build/config/chromeos:compiler_cpu_abi" ]
   }
 
-  if ((is_posix && !is_apple) || is_fuchsia) {
+  if ((is_posix && !is_apple) || is_fuchsia || is_mingw) {
     # CPU architecture. We may or may not be doing a cross compile now, so for
     # simplicity we always explicitly set the architecture.
     if (current_cpu == "x64") {
-      if (is_clang && !is_android && !is_fuchsia && !is_chromeos_device) {
+      if (is_clang && !is_android && !is_fuchsia && !is_mingw && !is_chromeos_device) {
         cflags += [ "--target=x86_64-unknown-linux-gnu" ]
         ldflags += [ "--target=x86_64-unknown-linux-gnu" ]
+      } else if (is_mingw) {
+        ldflags += [ "-m64" ]
       } else {
         cflags += [ "-m64" ]
         ldflags += [ "-m64" ]
       }
       cflags += [ "-msse3" ]
     } else if (current_cpu == "x86") {
-      if (is_clang && !is_android && !is_chromeos_device) {
+      if (is_clang && !is_android && !is_mingw && !is_chromeos_device) {
         cflags += [ "--target=i386-unknown-linux-gnu" ]
         ldflags += [ "--target=i386-unknown-linux-gnu" ]
+      } else if (is_mingw) {
+        ldflags += [ "-m32" ]
       } else {
         cflags += [ "-m32" ]
         ldflags += [ "-m32" ]
@@ -1277,7 +1299,7 @@ config("compiler_cpu_abi") {
         cflags += [ "-mtune=$arm_tune" ]
       }
     } else if (current_cpu == "arm64") {
-      if (is_clang && !is_android && !is_fuchsia && !is_chromeos_device) {
+      if (is_clang && !is_android && !is_fuchsia && !is_mingw && !is_chromeos_device) {
         cflags += [ "--target=aarch64-linux-gnu" ]
         ldflags += [ "--target=aarch64-linux-gnu" ]
       }
@@ -1595,7 +1617,7 @@ config("compiler_deterministic") {
   # Eliminate build metadata (__DATE__, __TIME__ and __TIMESTAMP__) for
   # deterministic build.  See https://crbug.com/314403
   if (!is_official_build) {
-    if (is_win && !is_clang) {
+    if (is_msvc && !is_clang) {
       cflags += [
         "/wd4117",  # Trying to define or undefine a predefined macro.
         "/D__DATE__=",
@@ -1635,7 +1657,7 @@ config("compiler_deterministic") {
       asmflags = [ "-Wa,-fdebug-compilation-dir,." ]
     }
 
-    if (is_win && use_lld) {
+    if (is_msvc && use_lld) {
       if (symbol_level == 2 || (is_clang && using_sanitizer)) {
         # Absolutize source file paths for PDB. Pass the real build directory
         # if the pdb contains source-level debug information and if linker
@@ -1677,7 +1699,7 @@ config("compiler_deterministic") {
 
 config("clang_revision") {
   if (is_clang && clang_base_path == default_clang_base_path &&
-      current_os != "zos") {
+      !is_mingw && current_os != "zos") {
     _perform_consistency_checks = current_toolchain == default_toolchain
     if (llvm_force_head_revision) {
       _head_revision_stamp_path = "//third_party/llvm-build/force_head_revision"
@@ -1886,7 +1908,7 @@ config("runtime_library") {
   # the C++ symbols. This config ensures the C++ symbols exist and are strong in
   # order to cause that replacement to occur by explicitly linking in clang's
   # compiler-rt library.
-  if (is_clang && !is_cronet_build) {
+  if (is_clang && !is_cronet_build && !is_mingw) {
     configs += [ "//build/config/clang:compiler_builtins" ]
   }
 
@@ -1932,7 +1954,7 @@ config("runtime_library") {
 # is broken out separately so nocompile tests can force-enable this setting
 # independently of the default warning flags.
 config("treat_warnings_as_errors") {
-  if (is_win) {
+  if (is_msvc) {
     cflags = [ "/WX" ]
   } else {
     cflags = [ "-Werror" ]
@@ -1983,7 +2005,7 @@ config("default_warnings") {
   ldflags = []
   configs = []
 
-  if (is_win) {
+  if (is_msvc) {
     if (fatal_linker_warnings) {
       arflags = [ "/WX" ]
       ldflags = [ "/WX" ]
@@ -2059,10 +2081,33 @@ config("default_warnings") {
       # files.
       cflags += [ "-Wno-packed-not-aligned" ]
     }
+
+    if (is_mingw) {
+      cflags += [
+        "-Wno-attributes",           # "__decspec(dllimport) inline"
+        "-Wno-format",               # PRIu64 llu support on MinGW
+        "-Wno-uninitialized",
+        "-Wno-unknown-pragmas",
+      ]
+      if (!is_clang) {
+        cflags_cc += [
+          "-Wno-ignored-attributes",
+          "-Wno-invalid-constexpr",
+          "-Wno-pessimizing-move",
+          "-Wno-shift-count-overflow",
+          "-Wno-subobject-linkage",    # Tests having code in header files
+        ]
+        cflags += [
+          "-Wno-array-bounds",
+          "-Wno-unused-but-set-variable",
+          "-Wno-stringop-overflow",    # False positive overflow error on gcc 10
+        ]
+      }
+    }
   }
 
   # Common Clang and GCC warning setup.
-  if (!is_win || is_clang) {
+  if (!is_msvc || is_clang) {
     cflags += [
       # Disables.
       "-Wno-missing-field-initializers",  # "struct foo f = {0};"
@@ -2246,7 +2291,7 @@ config("prevent_unsafe_narrowing") {
 # part of Chromium.
 
 config("chromium_code") {
-  if (is_win) {
+  if (is_msvc) {
     if (is_clang) {
       cflags = [ "/W4" ]  # Warning level 4.
 
@@ -2301,7 +2346,7 @@ config("chromium_code") {
     }
   }
 
-  if (is_clang) {
+  if (is_clang && !is_mingw) {
     cflags += [
       # Warn on missing break statements at the end of switch cases.
       # For intentional fallthrough, use [[fallthrough]].
@@ -2354,7 +2399,7 @@ config("no_chromium_code") {
   cflags_cc = []
   defines = []
 
-  if (is_win) {
+  if (is_msvc) {
     if (is_clang) {
       cflags += [ "/W3" ]  # Warning level 3.
     }
@@ -2405,7 +2450,7 @@ config("noshadowing") {
 # Allows turning Run-Time Type Identification on or off.
 
 config("rtti") {
-  if (is_win) {
+  if (is_msvc) {
     cflags_cc = [ "/GR" ]
   } else {
     cflags_cc = [ "-frtti" ]
@@ -2415,7 +2460,7 @@ config("rtti") {
 config("no_rtti") {
   # Some sanitizer configs may require RTTI to be left enabled globally
   if (!use_rtti) {
-    if (is_win) {
+    if (is_msvc) {
       cflags_cc = [ "/GR-" ]
     } else {
       cflags_cc = [ "-fno-rtti" ]
@@ -2467,7 +2512,7 @@ config("thin_archive") {
       "-T",
       "-S",
     ]
-  } else if (is_win && use_lld) {
+  } else if (is_msvc && use_lld) {
     arflags = [ "/llvmlibthin" ]
   }
 }
@@ -2478,7 +2523,7 @@ config("thin_archive") {
 # Note: exceptions are disallowed in Google code.
 
 config("exceptions") {
-  if (is_win) {
+  if (is_msvc) {
     # Enables exceptions in the STL.
     if (!use_custom_libcxx) {
       defines = [ "_HAS_EXCEPTIONS=1" ]
@@ -2491,7 +2536,7 @@ config("exceptions") {
 }
 
 config("no_exceptions") {
-  if (is_win) {
+  if (is_msvc) {
     # Disables exceptions in the STL.
     # libc++ uses the __has_feature macro to control whether to use exceptions,
     # so defining this macro is unnecessary. Defining _HAS_EXCEPTIONS to 0 also
@@ -2501,7 +2546,9 @@ config("no_exceptions") {
     if (!use_custom_libcxx) {
       defines = [ "_HAS_EXCEPTIONS=0" ]
     }
-  } else {
+  } else if (!is_mingw) {
+    # Do not explicitly set no-exceptions on MinGW, else we have to
+    # unset it in many other places.
     cflags_cc = [ "-fno-exceptions" ]
     cflags_objcc = cflags_cc
   }
@@ -2576,7 +2623,7 @@ config("no_incompatible_pointer_warnings") {
 
 # Shared settings for both "optimize" and "optimize_max" configs.
 # IMPORTANT: On Windows "/O1" and "/O2" must go before the common flags.
-if (is_win) {
+if (is_msvc) {
   common_optimize_on_cflags = [
     "/Oy-",  # Disable omitting frame pointers, must be after /O2.
     "/Zc:inline",  # Remove unreferenced COMDAT (faster links).
@@ -2631,7 +2678,7 @@ if (is_win) {
         "-Wl,-no_function_starts",
       ]
     }
-  } else if (current_os != "aix" && current_os != "zos") {
+  } else if (current_os != "aix" && current_os != "zos" && !is_mingw) {
     # Non-Mac Posix flags.
     # Aix does not support these.
 
@@ -2714,7 +2761,7 @@ config("default_stack_frames") {
 # [1]: https://pinpoint-dot-chromeperf.appspot.com/job/132bc772be0000
 # [2]: https://crrev.com/c/5447532
 config("optimize") {
-  if (is_win) {
+  if (is_msvc) {
     # clang-cl's /O2 corresponds to clang's -O3, and really want -O2 for
     # consistency with the other platforms.
     cflags = [
@@ -2738,7 +2785,7 @@ config("optimize") {
     }
 
     if (is_clang && use_ml_inliner && is_a_target_toolchain && !is_chromeos &&
-        !is_high_end_android) {
+        !is_mingw && !is_high_end_android) {
       cflags += [
         "-mllvm",
         "-enable-ml-inliner=release",
@@ -2763,7 +2810,7 @@ config("optimize") {
 
 # Turn off optimizations.
 config("no_optimize") {
-  if (is_win) {
+  if (is_msvc) {
     cflags = [
       "/Od",  # Disable optimization.
       "/Ob0",  # Disable all inlining (on by default).
@@ -2799,7 +2846,7 @@ config("no_optimize") {
 # elsewhere.
 config("optimize_max") {
   ldflags = common_optimize_on_ldflags
-  if (is_win) {
+  if (is_msvc) {
     # Favor speed over size, /O2 must be before the common flags.
     # /O2 implies /Ot, /Oi, and /GF.
     cflags = [ "/O2" ] + common_optimize_on_cflags
@@ -2820,7 +2867,7 @@ config("optimize_max") {
 # so that we don't need this disclaimer.
 config("optimize_speed") {
   ldflags = common_optimize_on_ldflags
-  if (is_win) {
+  if (is_msvc) {
     # Favor speed over size, /O2 must be before the common flags.
     # /O2 implies /Ot, /Oi, and /GF.
     cflags = [ "/O2" ] + common_optimize_on_cflags
@@ -2862,7 +2909,7 @@ config("default_optimization") {
 }
 
 _clang_sample_profile = ""
-if (is_clang && is_a_target_toolchain) {
+if (is_clang && is_a_target_toolchain && !is_mingw) {
   if (clang_sample_profile_path != "") {
     _clang_sample_profile = clang_sample_profile_path
   } else if (clang_use_default_sample_profile) {
@@ -2965,7 +3012,7 @@ config("win_pdbaltpath") {
 config("symbols") {
   rustflags = []
   configs = []
-  if (is_win) {
+  if (is_msvc) {
     if (is_clang) {
       cflags = [
         # Debug information in the .obj files.
@@ -3013,7 +3060,7 @@ config("symbols") {
 
     # On aix -gdwarf causes linker failures due to thread_local variables.
     # On zos -gdwarf causes INSUFFICIENT ABOVE THE LINE STORAGE WAS AVAILABLE.
-    if (current_os != "aix" && current_os != "zos") {
+    if (current_os != "aix" && current_os != "zos" && current_os != "win") {
       if (use_dwarf5) {
         cflags += [ "-gdwarf-5" ]
         rustflags += [ "-Zdwarf-version=5" ]
@@ -3062,7 +3109,7 @@ config("symbols") {
       ldflags += [ "-gsplit-dwarf" ]
     }
 
-    _enable_gdb_index = symbol_level == 2 && !is_apple && use_lld && !is_wasm
+    _enable_gdb_index = symbol_level == 2 && !is_apple && use_lld && !is_wasm && !is_mingw
     if (_enable_gdb_index) {
       if (is_clang) {
         # This flag enables the GNU-format pubnames and pubtypes sections,
@@ -3082,7 +3129,7 @@ config("symbols") {
     configs += [ "//build/config:compress_debug_sections" ]
   }
 
-  if (is_clang && is_win && !is_component_build) {
+  if (is_clang && is_msvc && !is_component_build) {
     # Remove unreferenced methods to reduce type info in symbols.
     # See: https://github.com/llvm/llvm-project/pull/87018.
     # The downside with this flag is precisely that: Unreferenced methods get
@@ -3095,7 +3142,7 @@ config("symbols") {
     cflags += [ "-gomit-unreferenced-methods" ]
   }
 
-  if (is_clang) {
+  if (is_clang && !is_mingw) {
     if (is_apple) {
       # TODO(crbug.com/40117949): Investigate missing debug info on mac.
       # Make sure we don't use constructor homing on mac.
@@ -3120,7 +3167,7 @@ config("symbols") {
 # when crash happens in unittests running on buildbot.
 config("minimal_symbols") {
   rustflags = []
-  if (is_win) {
+  if (is_msvc) {
     # Functions, files, and line tables only.
     cflags = []
 
@@ -3155,7 +3202,7 @@ config("minimal_symbols") {
       # TODO(thakis): Remove this once mac_deployment_target is 10.11.
       cflags += [ "-gdwarf-4" ]
       rustflags += [ "-Zdwarf-version=4" ]
-    } else if (!use_dwarf5 && current_os != "aix") {
+    } else if (!use_dwarf5 && current_os != "aix" && current_os != "win") {
       # On aix -gdwarf causes linker failures due to thread_local variables.
       # Recent clang versions default to DWARF5 on Linux, and Android is about
       # to switch. TODO: Adopt that in controlled way.
@@ -3195,7 +3242,7 @@ config("minimal_symbols") {
 # told to not generate debug information and the linker then just puts function
 # names in the final debug information.
 config("no_symbols") {
-  if (is_win) {
+  if (is_msvc) {
     ldflags = [ "/DEBUG" ]
 
     # All configs using /DEBUG should include this:
@@ -3313,7 +3360,7 @@ buildflag_header("compiler_buildflags") {
 }
 
 config("cet_shadow_stack") {
-  if (enable_cet_shadow_stack && is_win) {
+  if (enable_cet_shadow_stack && is_msvc) {
     assert(target_cpu == "x64")
     ldflags = [ "/CETCOMPAT" ]
   }
diff --git a/config/compiler/compiler.gni b/config/compiler/compiler.gni
index 61c3779e9..90a617ad0 100644
--- a/config/compiler/compiler.gni
+++ b/config/compiler/compiler.gni
@@ -315,7 +315,7 @@ if (symbol_level == -1) {
     # info or variable info, so we can leave that out to speed up the build.
     # Sanitizers also require symbols for filename suppressions to work.
     symbol_level = 1
-  } else if ((!is_linux && !is_chromeos && !is_fuchsia &&
+  } else if ((!is_linux && !is_chromeos && !is_fuchsia && !is_mingw &&
               current_os != "aix") || is_debug || is_castos ||
              is_cast_android) {
     # Linux builds slower by having symbols as part of the target binary,
diff --git a/config/linux/pkg-config.py b/config/linux/pkg-config.py
index f4d31de67..158208895 100755
--- a/config/linux/pkg-config.py
+++ b/config/linux/pkg-config.py
@@ -108,7 +108,7 @@ def main():
   # If this is run on non-Linux platforms, just return nothing and indicate
   # success. This allows us to "kind of emulate" a Linux build from other
   # platforms.
-  if "linux" not in sys.platform:
+  if sys.platform not in ["linux", "win32"]:
     print("[[],[],[],[],[]]")
     return 0
 
diff --git a/config/sanitizers/BUILD.gn b/config/sanitizers/BUILD.gn
index e2f39f029..53e4576e7 100644
--- a/config/sanitizers/BUILD.gn
+++ b/config/sanitizers/BUILD.gn
@@ -67,7 +67,7 @@ group("deps") {
     data += [ "//tools/memory/sanitizer/escalate_sanitizer_warnings.py" ]
   }
   if (is_asan || is_ubsan_any) {
-    if (is_win || is_apple) {
+    if (is_msvc || is_apple) {
       data_deps = [ ":copy_sanitizer_runtime" ]
     }
     if (is_apple) {
@@ -85,7 +85,7 @@ group("deps") {
 assert(!(is_win && is_asan && current_cpu == "x86"),
        "ASan is only supported in 64-bit builds on Windows.")
 
-if ((is_apple || is_win) && (is_asan || is_ubsan_any)) {
+if ((is_apple || is_msvc) && (is_asan || is_ubsan_any)) {
   _clang_rt_dso_full_path =
       "$clang_base_path/lib/clang/$clang_version/lib/$clang_rt_dso_path"
 
@@ -252,7 +252,7 @@ config("default_sanitizer_ldflags") {
         }
       }
     }
-  } else if (is_win) {
+  } else if (is_msvc) {
     # Windows directly calls link.exe instead of the compiler driver when
     # linking.  Hence, pass the runtime libraries instead of -fsanitize=address
     # or -fsanitize=fuzzer.
@@ -325,7 +325,7 @@ config("asan_flags") {
       # already on for Fuchsia). Pass the flag to turn it back off.
       cflags += [ "-fno-sanitize-address-globals-dead-stripping" ]
     }
-    if (is_win) {
+    if (is_msvc) {
       if (!defined(asan_win_blocklist_path)) {
         asan_win_blocklist_path =
             rebase_path("//tools/memory/asan/blocklist_win.txt", root_build_dir)
@@ -379,7 +379,7 @@ config("cfi_flags") {
 
     if (use_cfi_diag) {
       cflags += [ "-fno-sanitize-trap=cfi" ]
-      if (is_win) {
+      if (is_msvc) {
         cflags += [
           "/Oy-",
           "/Ob0",
diff --git a/config/sanitizers/sanitizers.gni b/config/sanitizers/sanitizers.gni
index e371f0288..07a6bcf64 100644
--- a/config/sanitizers/sanitizers.gni
+++ b/config/sanitizers/sanitizers.gni
@@ -418,7 +418,7 @@ fuzzing_engine_add_configs =
 
 # Expose clang_rt dynamic lib name to the dependents that need it as an input
 # when running an exeutable.
-if ((is_apple || is_win) && (is_asan || is_ubsan_any)) {
+if ((is_apple || is_msvc) && (is_asan || is_ubsan_any)) {
   if (is_mac || (is_ios && target_environment == "catalyst")) {
     if (is_asan) {
       clang_rt_dso_path = "darwin/libclang_rt.asan_osx_dynamic.dylib"
diff --git a/config/win/BUILD.gn b/config/win/BUILD.gn
index aaeadc313..4803bd492 100644
--- a/config/win/BUILD.gn
+++ b/config/win/BUILD.gn
@@ -48,6 +48,7 @@ declare_args() {
 # is applied to all targets. It is here to separate out the logic that is
 # Windows-only.
 config("compiler") {
+  if (is_msvc) {
   if (current_cpu == "x86") {
     asmflags = [
       # When /safeseh is specified, the linker will only produce an image if it
@@ -213,6 +214,15 @@ config("compiler") {
     # the source file is a no-op.
     "/ignore:4221",
   ]
+  } else { # is_mingw
+    cflags = []
+    if (current_cpu != "arm64"){
+      cflags += [ "-Wa,-mbig-obj" ]
+    }
+    if (!is_clang) {
+      cflags += [ "-fno-keep-inline-dllexport" ]
+    }
+  }
 }
 
 # This is included by reference in the //build/config/compiler:runtime_library
@@ -301,7 +311,7 @@ config("winver") {
 
 # Linker flags for Windows SDK setup, this is applied only to EXEs and DLLs.
 config("sdk_link") {
-  if (current_cpu == "x86") {
+  if (is_msvc && current_cpu == "x86") {
     ldflags = [
       "/SAFESEH",  # Not compatible with x64 so use only for x86.
       "/largeaddressaware",
@@ -313,19 +323,27 @@ config("sdk_link") {
 # targets who want different library configurations can remove this and specify
 # their own.
 config("common_linker_setup") {
-  ldflags = [
-    "/FIXED:NO",
-    "/ignore:4199",
-    "/ignore:4221",
-    "/NXCOMPAT",
-    "/DYNAMICBASE",
-  ]
-
-  if (win_linker_timing) {
-    ldflags += [
-      "/time",
-      "/verbose:incr",
+  if (is_mingw) {
+    # Enable DEP and ASLR
+    ldflags = [
+      "-Wl,-dynamicbase",
+      "-Wl,-nxcompat",
+    ]
+  } else {
+    ldflags = [
+      "/FIXED:NO",
+      "/ignore:4199",
+      "/ignore:4221",
+      "/NXCOMPAT",
+      "/DYNAMICBASE",
     ]
+
+    if (win_linker_timing) {
+      ldflags += [
+        "/time",
+        "/verbose:incr",
+      ]
+    }
   }
 }
 
@@ -335,12 +353,14 @@ config("default_cfg_compiler") {
   # with CFG enabled, such as system libraries.
   # The CFG guards are only emitted if |win_enable_cfg_guards| is enabled.
   if (win_enable_cfg_guards) {
-    if (is_clang) {
+    if (is_msvc && is_clang) {
       cflags = [ "/guard:cf" ]
+    } else {
+      cflags = [ "-fcf-protection" ]
     }
     rustflags = [ "-Ccontrol-flow-guard" ]
   } else {
-    if (is_clang) {
+    if (is_msvc && is_clang) {
       cflags = [ "/guard:cf,nochecks" ]
     }
     rustflags = [ "-Ccontrol-flow-guard=nochecks" ]
@@ -353,8 +373,10 @@ config("disable_guards_cfg_compiler") {
   # Emit table of address-taken functions for Control-Flow Guard (CFG).
   # This is needed to allow functions to be called by code that is built
   # with CFG enabled, such as system libraries.
-  if (is_clang) {
+  if (is_msvc && is_clang) {
     cflags = [ "/guard:cf,nochecks" ]
+  } else {
+    cflags = [ "-fcf-protection=none" ]
   }
   rustflags = [ "-Ccontrol-flow-guard=nochecks" ]
 }
@@ -367,7 +389,7 @@ config("cfi_linker") {
   # ASan and CFG leads to slow process startup. Chromium's test runner uses
   # lots of child processes, so this means things are really slow. Disable CFG
   # for now. https://crbug.com/846966
-  if (!is_debug && !is_asan) {
+  if (is_msvc && !is_debug && !is_asan) {
     # Turn on CFG bitmap generation and CFG load config.
     ldflags = [ "/guard:cf" ]
   }
@@ -403,6 +425,7 @@ config("cfi_linker") {
 # This config should also be used for any test binary whose goal is to run
 # tests with the full browser.
 config("delayloads") {
+  if (is_msvc) {
   ldflags = [
     "/DELAYLOAD:api-ms-win-core-synch-l1-2-0.dll",
     "/DELAYLOAD:api-ms-win-core-winrt-error-l1-1-0.dll",
@@ -453,11 +476,13 @@ config("delayloads") {
     "/DELAYLOAD:wsock32.dll",
     "/DELAYLOAD:wtsapi32.dll",
   ]
+  }
 }
 
 # This config (along with `:delayloads`) applies to chrome.exe & chrome_elf.dll.
 # Entries should not appear in both configs.
 config("delayloads_not_for_child_dll") {
+  if (is_msvc) {
   ldflags = [
     "/DELAYLOAD:crypt32.dll",
     "/DELAYLOAD:dbghelp.dll",
@@ -473,6 +498,7 @@ config("delayloads_not_for_child_dll") {
     "/DELAYLOAD:wintrust.dll",
     "/DELAYLOAD:ws2_32.dll",
   ]
+  }
 }
 
 # ACLs are placed on the filesystem in order to allow chrome to launch
@@ -527,7 +553,7 @@ config("default_crt") {
 # when the debug CRT is part of the bottleneck. This also avoids *implicitly*
 # defining _DEBUG.
 config("release_crt") {
-  if (is_component_build) {
+  if (is_msvc && is_component_build) {
     cflags = [ "/MD" ]
 
     # /MD specifies msvcrt.lib as the CRT library, which is the dynamic+release
@@ -539,7 +565,7 @@ config("release_crt") {
       # standard library, which libc++ needs for exception_ptr internals.
       ldflags = [ "/DEFAULTLIB:msvcprt.lib" ]
     }
-  } else {
+  } else if (!is_mingw) {
     cflags = [ "/MT" ]
 
     # /MT specifies libcmt.lib as the CRT library, which is the static+release
@@ -554,7 +580,7 @@ config("release_crt") {
 }
 
 config("dynamic_crt") {
-  if (is_debug) {
+  if (is_msvc && is_debug) {
     # This pulls in the DLL debug CRT and defines _DEBUG
     cflags = [ "/MDd" ]
 
@@ -570,7 +596,7 @@ config("dynamic_crt") {
     if (use_custom_libcxx) {
       ldflags = [ "/DEFAULTLIB:msvcprtd.lib" ]
     }
-  } else {
+  } else if (!is_mingw) {
     cflags = [ "/MD" ]
 
     # /MD specifies msvcrt.lib as the CRT library, which is the dynamic+release
@@ -584,7 +610,7 @@ config("dynamic_crt") {
 }
 
 config("static_crt") {
-  if (is_debug) {
+  if (is_msvc && is_debug) {
     # This pulls in the static debug CRT and defines _DEBUG
     cflags = [ "/MTd" ]
 
@@ -601,7 +627,7 @@ config("static_crt") {
     if (use_custom_libcxx) {
       ldflags = [ "/DEFAULTLIB:libcpmtd.lib" ]
     }
-  } else {
+  } else if (!is_mingw) {
     cflags = [ "/MT" ]
 
     # /MT specifies libcmt.lib as the CRT library, which is the static+release
@@ -620,13 +646,21 @@ config("static_crt") {
 # This is appended to the subsystem to specify a minimum version.
 # The number after the comma is the minimum required OS version.
 # Set to 10.0 since we only support >= Win10 since M110.
-subsystem_version_suffix = ",10.0"
+subsystem_version_suffix = "10.0"
 
 config("console") {
-  ldflags = [ "/SUBSYSTEM:CONSOLE$subsystem_version_suffix" ]
+  if (is_mingw) {
+    ldflags = [ "-Wl,-subsystem,console:$subsystem_version_suffix" ]
+  } else {
+    ldflags = [ "/SUBSYSTEM:CONSOLE,$subsystem_version_suffix" ]
+  }
 }
 config("windowed") {
-  ldflags = [ "/SUBSYSTEM:WINDOWS$subsystem_version_suffix" ]
+  if (is_mingw) {
+    ldflags = [ "-Wl,-subsystem,windows:$subsystem_version_suffix" ]
+  } else {
+    ldflags = [ "/SUBSYSTEM:WINDOWS,$subsystem_version_suffix" ]
+  }
 }
 
 # Incremental linking ----------------------------------------------------------
@@ -636,7 +670,7 @@ config("default_incremental_linking") {
   # Enable incremental linking for debug builds and all component builds - any
   # builds where performance is not job one.
   # TODO(thakis): Always turn this on with lld, no reason not to.
-  if (is_debug || is_component_build) {
+  if (is_msvc && (is_debug || is_component_build)) {
     ldflags = [ "/INCREMENTAL" ]
     if (use_lld) {
       # lld doesn't use ilk files and doesn't really have an incremental link
@@ -651,7 +685,7 @@ config("default_incremental_linking") {
       # in lld-link.
       ldflags += [ "/OPT:NOICF" ]
     }
-  } else {
+  } else if (!is_mingw) {
     ldflags = [ "/INCREMENTAL:NO" ]
   }
 }
diff --git a/config/win/manifest.gni b/config/win/manifest.gni
index 2feb96cf2..e4c3acc97 100644
--- a/config/win/manifest.gni
+++ b/config/win/manifest.gni
@@ -72,7 +72,7 @@ segment_heap_manifest = "//build/win/segment_heap.manifest"
 #     ...
 #   }
 
-if (is_win) {
+if (is_msvc) {
   template("windows_manifest") {
     config_name = "${target_name}__config"
 
diff --git a/config/win/visual_studio_version.gni b/config/win/visual_studio_version.gni
index bd4116693..65cd9a7ed 100644
--- a/config/win/visual_studio_version.gni
+++ b/config/win/visual_studio_version.gni
@@ -24,7 +24,7 @@ declare_args() {
   windows_sdk_version = ""
 }
 
-if (visual_studio_path == "") {
+if (is_msvc && visual_studio_path == "") {
   toolchain_data =
       exec_script("../../vs_toolchain.py", [ "get_toolchain_dir" ], "scope")
   visual_studio_path = toolchain_data.vs_path
@@ -33,7 +33,7 @@ if (visual_studio_path == "") {
   visual_studio_version = toolchain_data.vs_version
   wdk_path = toolchain_data.wdk_dir
   visual_studio_runtime_dirs = toolchain_data.runtime_dirs
-} else {
+} else if (!is_mingw) {
   assert(visual_studio_version != "",
          "You must set the visual_studio_version if you set the path")
   assert(windows_sdk_version != "",
diff --git a/toolchain/gcc_solink_wrapper.py b/toolchain/gcc_solink_wrapper.py
index 0dae7ab55..df6dd9cef 100755
--- a/toolchain/gcc_solink_wrapper.py
+++ b/toolchain/gcc_solink_wrapper.py
@@ -24,6 +24,9 @@ def CollectSONAME(args):
   # TODO(crbug.com/40797404): Come up with a way to get this info without having
   # to bundle readelf in the toolchain package.
   toc = ''
+  # MinGW's readelf doesn't work on PE files
+  if sys.platform == 'win32' and 'GCC' in sys.version:
+    return 0, toc
   readelf = subprocess.Popen(wrapper_utils.CommandToRun(
       [args.readelf, '-d', args.sofile]),
                              stdout=subprocess.PIPE,
@@ -38,6 +41,9 @@ def CollectSONAME(args):
 def CollectDynSym(args):
   """Replaces: nm --format=posix -g -D -p $sofile | cut -f1-2 -d' '"""
   toc = ''
+  # MinGW's nm doesn't work on PE/COFF files
+  if sys.platform == 'win32' and 'GCC' in sys.version:
+    return 0, toc
   nm = subprocess.Popen(wrapper_utils.CommandToRun(
       [args.nm, '--format=posix', '-g', '-D', '-p', args.sofile]),
                         stdout=subprocess.PIPE,
@@ -103,6 +109,9 @@ def main():
                       help='The strip binary to run',
                       metavar='PATH')
   parser.add_argument('--dwp', help='The dwp binary to run', metavar='PATH')
+  parser.add_argument('--objcopy',
+                      help='The objcopy binary to run',
+                      metavar='PATH')
   parser.add_argument('--sofile',
                       required=True,
                       help='Shared object file produced by linking command',
@@ -194,9 +203,19 @@ def main():
 
     # Finally, strip the linked shared object file (if desired).
     if args.strip:
+      if args.objcopy:
+        result = subprocess.call(wrapper_utils.CommandToRun(
+            [args.objcopy, '--only-keep-debug', args.sofile, args.output + '.debug']))
+        if result != 0:
+          return result
       result = subprocess.call(
           wrapper_utils.CommandToRun(
               [args.strip, '-o', args.output, args.sofile]))
+    if result != 0:
+      return result
+    if args.objcopy:
+      result = subprocess.call(wrapper_utils.CommandToRun(
+          [args.objcopy, '--add-gnu-debuglink', args.output + '.debug',args.output]))
 
   if dwp_proc:
     dwp_result = dwp_proc.wait()
diff --git a/toolchain/gcc_toolchain.gni b/toolchain/gcc_toolchain.gni
index c22ec9046..facba2cae 100644
--- a/toolchain/gcc_toolchain.gni
+++ b/toolchain/gcc_toolchain.gni
@@ -57,6 +57,7 @@ if (enable_resource_allowlist_generation) {
 #  - cc
 #  - cxx
 #  - ld
+#  - rc (mingw only)
 #
 # Optional parameters that control the tools:
 #
@@ -264,6 +265,11 @@ template("single_gcc_toolchain") {
     } else {
       nm = "nm"
     }
+    if (defined(invoker.rc)) {
+      rc = invoker.rc
+    } else {
+      rc = "windres"
+    }
     if (defined(invoker.dwp)) {
       dwp_switch = " --dwp=\"${invoker.dwp}\""
     } else {
@@ -364,6 +370,14 @@ template("single_gcc_toolchain") {
       outputs = [ "$object_subdir/{{source_name_part}}.pcm" ]
     }
 
+    tool("rc") {
+      depfile = "{{output}}.d"
+      command = "$rc -i {{source}} -o {{output}} {{include_dirs}} -O coff"
+      depsformat = "gcc"
+      description = "RC {{output}}"
+      outputs = [ "$object_subdir/{{source_name_part}}.rc.o" ]
+    }
+
     tool("asm") {
       # For GCC we can just use the C compiler to compile assembly.
       depfile = "{{output}}.d"
@@ -381,15 +395,17 @@ template("single_gcc_toolchain") {
       } else {
         rspfile = "{{output}}.rsp"
         rspfile_content = "{{inputs}}"
-        command = "\"$ar\" {{arflags}} -r -c -D {{output}} @\"$rspfile\""
+        command = "\"$ar\" {{arflags}} -r -c -s {{output}} @\"$rspfile\""
       }
 
       # Remove the output file first so that ar doesn't try to modify the
       # existing file.
-      if (host_os == "win") {
+      if (host_os == "win" && !is_mingw) {
         tool_wrapper_path =
             rebase_path("//build/toolchain/win/tool_wrapper.py", root_build_dir)
         command = "cmd /s /c \"\"$python_path\" $tool_wrapper_path delete-file {{output}} && $command\""
+      } else if (is_mingw) {
+        command = "$command"
       } else {
         command = "rm -f {{output}} && $command"
       }
@@ -426,9 +442,12 @@ template("single_gcc_toolchain") {
       tocfile = sofile + ".TOC"
 
       soname_flag = ""
-      if (current_os != "aix") {
+      if (current_os != "aix" && current_os != "win") {
         # -soname flag is not available on aix ld
         soname_flag = "-Wl,-soname=\"$soname\""
+      } else if (is_mingw) {
+        # Have MinGW linker generate an import library
+        soname_flag = "-Wl,--out-implib=\"$soname.a\""
       }
       link_command = "$ld -shared $soname_flag {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" @\"$rspfile\" {{rlibs}}"
 
@@ -464,6 +483,8 @@ template("single_gcc_toolchain") {
 
       if (target_cpu == "mipsel" && is_component_build && is_android) {
         rspfile_content = "-Wl,--start-group -Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}} -Wl,--end-group"
+      } else if (current_os == "win") {
+        rspfile_content = "-Wl,--whole-archive {{inputs}} -Wl,--no-whole-archive -Wl,--start-group {{solibs}} {{libs}} -Wl,--end-group"
       } else if (current_os == "aix") {
         # --whole-archive, --no-whole-archive flags are not available on the aix
         # ld.
@@ -606,7 +627,7 @@ template("single_gcc_toolchain") {
       # We need to specify link groups, at least, for single pass linkers. I.e.
       # Rust libraries are alpha-sorted instead of by dependencies so they fail
       # to link if not properly ordered or grouped.
-      link_command = "$ld {{ldflags}}${extra_ldflags} -o \"$unstripped_outfile\" $start_group_flag @\"$rspfile\" $end_group_flag {{solibs}} {{libs}} $start_group_flag {{rlibs}} $end_group_flag"
+      link_command = "$ld {{ldflags}}${extra_ldflags} -o \"$unstripped_outfile\" @\"$rspfile\" $start_group_flag {{solibs}} {{libs}} $end_group_flag {{rlibs}}"
 
       # Generate a map file to be used for binary size analysis.
       # Map file adds ~10% to the link time on a z620.
diff --git a/toolchain/siso.gni b/toolchain/siso.gni
index 63dea48db..f2b4456b2 100644
--- a/toolchain/siso.gni
+++ b/toolchain/siso.gni
@@ -6,13 +6,6 @@ import("//build/config/gclient_args.gni")
 # need to match with autoninja's logic.
 use_siso_default = false
 
-_is_ninja_used = path_exists(rebase_path(".ninja_deps", root_build_dir))
-
-if (path_exists("//build/config/siso/.sisoenv") &&
-    defined(build_with_chromium) && build_with_chromium && !_is_ninja_used) {
-  use_siso_default = true
-}
-
 declare_args() {
   # Placeholder to allow having use_siso in args.gn file.
   # Explicit `use_siso` in args.gn can override default.
diff --git a/toolchain/toolchain.gni b/toolchain/toolchain.gni
index 44dbc84d0..edf5b0c35 100644
--- a/toolchain/toolchain.gni
+++ b/toolchain/toolchain.gni
@@ -67,7 +67,7 @@ if (host_os == "mac") {
 }
 
 # Prefix for shared library files.
-if (is_posix || is_fuchsia) {
+if (is_posix || is_fuchsia || is_mingw) {
   shlib_prefix = "lib"
 } else {
   shlib_prefix = ""
@@ -88,12 +88,15 @@ if (is_fuchsia) {
 # four variables reduce the duplication in that boilerplate.
 stamp_description = "STAMP {{output}}"
 copy_description = "COPY {{source}} {{output}}"
-if (host_os == "win") {
+if (is_msvc) {
   _tool_wrapper_path =
       rebase_path("//build/toolchain/win/tool_wrapper.py", root_build_dir)
 
   stamp_command = "cmd /c type nul > \"{{output}}\""
   copy_command = "\"$python_path\" $_tool_wrapper_path recursive-mirror {{source}} {{output}}"
+} else if (is_mingw) {
+  stamp_command = "touch {{output}}"
+  copy_command = "cp -f {{source}} {{output}}"
 } else {
   stamp_command = "touch {{output}}"
   copy_command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
diff --git a/toolchain/win/BUILD.gn b/toolchain/win/BUILD.gn
index 87d1e4aa1..60f618abf 100644
--- a/toolchain/win/BUILD.gn
+++ b/toolchain/win/BUILD.gn
@@ -15,7 +15,7 @@ assert(is_win, "Should only be running on Windows")
 
 # Copy the VS runtime DLL for the default toolchain to the root build directory
 # so things will run.
-if (current_toolchain == default_toolchain) {
+if (is_msvc && current_toolchain == default_toolchain) {
   if (is_debug) {
     configuration_name = "Debug"
   } else {
@@ -30,7 +30,7 @@ if (current_toolchain == default_toolchain) {
               ])
 }
 
-if (target_cpu == "x86" || target_cpu == "x64") {
+if (is_msvc && (target_cpu == "x86" || target_cpu == "x64")) {
   win_toolchains("x86") {
     toolchain_arch = "x86"
   }
@@ -39,7 +39,7 @@ if (target_cpu == "x86" || target_cpu == "x64") {
   }
 }
 
-if (target_cpu == "arm64") {
+if (is_msvc && target_cpu == "arm64") {
   win_toolchains("arm64") {
     toolchain_arch = "arm64"
   }
@@ -80,3 +80,17 @@ if (target_os == "winuwp") {
     }
   }
 }
+
+if (is_mingw) {
+  mingw_toolchain("x86") {
+    toolchain_arch = "x86"
+  }
+
+  mingw_toolchain("x64") {
+    toolchain_arch = "x64"
+  }
+
+  mingw_toolchain("arm64") {
+    toolchain_arch = "arm64"
+  }
+}
diff --git a/toolchain/win/toolchain.gni b/toolchain/win/toolchain.gni
index 7dbd8a17e..1bf27f81d 100644
--- a/toolchain/win/toolchain.gni
+++ b/toolchain/win/toolchain.gni
@@ -10,7 +10,12 @@ import("//build/config/win/visual_studio_version.gni")
 import("//build/toolchain/cc_wrapper.gni")
 import("//build/toolchain/rbe.gni")
 import("//build/toolchain/toolchain.gni")
-import("//build/toolchain/win/win_toolchain_data.gni")
+
+if (is_mingw) {
+  import("//build/toolchain/gcc_toolchain.gni")
+} else {
+  import("//build/toolchain/win/win_toolchain_data.gni")
+}
 
 assert(is_win, "Should only be running on Windows")
 
@@ -867,3 +872,27 @@ template("win_toolchains") {
     }
   }
 }
+
+template("mingw_toolchain") {
+  gcc_toolchain("mingw_" + target_name) {
+    forward_variables_from(invoker, "*")
+    if (is_clang) {
+      cc = "clang"
+      cxx = "clang++"
+    } else {
+      cc = "gcc"
+      cxx = "g++"
+    }
+    ld = cxx
+    nm = "nm"
+    ar = "ar"
+    rc = "windres"
+    strip = "strip"
+    executable_extension = ".exe"
+    enable_linker_map = false
+    toolchain_args = {
+      current_os = "win"
+      current_cpu = toolchain_arch
+    }
+  }
+}
diff --git a/util/lastchange.py b/util/lastchange.py
index 3321a3e86..d08562291 100755
--- a/util/lastchange.py
+++ b/util/lastchange.py
@@ -21,8 +21,6 @@ _ROOT_DIR = os.path.abspath(
 
 sys.path.insert(0, _ROOT_DIR)
 
-import gclient_utils
-
 VersionInfo = collections.namedtuple(
     "VersionInfo", ("revision_id", "revision", "commit_position", "timestamp"))
 _EMPTY_VERSION_INFO = VersionInfo('0' * 40, '0' * 40, '', 0)
@@ -236,7 +234,10 @@ def GetGitTopDirectory(source_dir):
   Returns:
     The output of "git rev-parse --show-toplevel" as a string
   """
-  return _RunGitCommand(source_dir, ['rev-parse', '--show-toplevel'])
+  directory = _RunGitCommand(source_dir, ['rev-parse', '--show-toplevel'])
+  if sys.platform == 'win32' and 'GCC' in sys.version:
+    return subprocess.check_output(["cygpath", "-w", directory]).strip(b"\n").decode()
+  return directory
 
 
 def WriteIfChanged(file_name, contents):
@@ -264,9 +265,6 @@ def GetVersion(source_dir, commit_filter, merge_base_ref):
   if 'BASE_COMMIT_SUBMISSION_MS' in os.environ:
     return GetVersionInfoFromEnv()
 
-  if gclient_utils.IsEnvCog():
-    return _EMPTY_VERSION_INFO
-
   git_top_dir = None
   try:
     git_top_dir = GetGitTopDirectory(source_dir)
diff --git a/win/BUILD.gn b/win/BUILD.gn
index 0c47c2c8c..e244ea4e9 100644
--- a/win/BUILD.gn
+++ b/win/BUILD.gn
@@ -16,7 +16,7 @@ windows_manifest("default_exe_manifest") {
   ]
 }
 
-if (is_win) {
+if (is_msvc) {
   assert(host_os != "mac" || target_cpu != "x86",
          "Windows cross-builds from Mac must be 64-bit.")
 
@@ -78,4 +78,8 @@ if (is_win) {
       }
     }
   }
+} else {
+  group("runtime_libs") {
+    data = []
+  }
 }
