diff --git a/CMake/vtkWheelPreparation.cmake b/CMake/vtkWheelPreparation.cmake
index f2f807ab0c..9a4c3dc702 100644
--- a/CMake/vtkWheelPreparation.cmake
+++ b/CMake/vtkWheelPreparation.cmake
@@ -48,9 +48,9 @@ set(CMAKE_INSTALL_DOCDIR
 set(vtk_hierarchy_destination_args
   HIERARCHY_DESTINATION "${wheel_data_dir}/headers/hierarchy")
 set(setup_py_build_dir
-  "build/lib.${python_platform}-${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}")
+  "build/lib.${python_platform}-cpython-${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR}")
 # Required for Windows DLL placement.
-if (WIN32)
+if (WIN32 OR CYGWIN)
   set(CMAKE_INSTALL_BINDIR
     # Must correlate with `vtk_module_wrap_python(PYTHON_PACKAGE)` argument
     "${setup_py_build_dir}/vtkmodules")
diff --git a/Common/Core/vtkABI.h b/Common/Core/vtkABI.h
index 107727128a..da1c1f3e51 100644
--- a/Common/Core/vtkABI.h
+++ b/Common/Core/vtkABI.h
@@ -44,7 +44,7 @@
 #ifndef vtkABI_h
 #define vtkABI_h
 
-#if defined(_WIN32)
+#if defined(_WIN32) || defined(__CYGWIN__)
 #define VTK_ABI_IMPORT __declspec(dllimport)
 #define VTK_ABI_EXPORT __declspec(dllexport)
 #define VTK_ABI_HIDDEN
diff --git a/IO/EnSight/vtkEnSight6BinaryReader.cxx b/IO/EnSight/vtkEnSight6BinaryReader.cxx
index 080de74190..85b217b361 100644
--- a/IO/EnSight/vtkEnSight6BinaryReader.cxx
+++ b/IO/EnSight/vtkEnSight6BinaryReader.cxx
@@ -38,8 +38,8 @@
 #if defined(_WIN32)
 #define VTK_STAT_STRUCT struct _stat64
 #define VTK_STAT_FUNC _stat64
-#elif defined _DARWIN_FEATURE_64_BIT_INODE || defined __FreeBSD__ || defined __NetBSD__ ||         \
-  defined __OpenBSD__
+#elif defined _DARWIN_FEATURE_64_BIT_INODE || defined __FreeBSD__ || defined __NetBSD__ || \
+      defined __OpenBSD__ || defined __CYGWIN__
 // The BSDs use stat().
 #define VTK_STAT_STRUCT struct stat
 #define VTK_STAT_FUNC stat
diff --git a/IO/EnSight/vtkEnSightGoldBinaryReader.cxx b/IO/EnSight/vtkEnSightGoldBinaryReader.cxx
index 8a0ba1f596..c0405326bc 100644
--- a/IO/EnSight/vtkEnSightGoldBinaryReader.cxx
+++ b/IO/EnSight/vtkEnSightGoldBinaryReader.cxx
@@ -43,8 +43,8 @@
 #if defined(_WIN32)
 #define VTK_STAT_STRUCT struct _stat64
 #define VTK_STAT_FUNC _stat64
-#elif defined _DARWIN_FEATURE_64_BIT_INODE || defined __FreeBSD__ || defined __NetBSD__ ||         \
-  defined __OpenBSD__
+#elif defined _DARWIN_FEATURE_64_BIT_INODE || defined __FreeBSD__ || defined __NetBSD__ || \
+      defined __OpenBSD__ || defined __CYGWIN__
 // The BSDs use stat().
 #define VTK_STAT_STRUCT struct stat
 #define VTK_STAT_FUNC stat
diff --git a/IO/LSDyna/LSDynaFamily.cxx b/IO/LSDyna/LSDynaFamily.cxx
index 43a141f3d1..0b4c78c076 100644
--- a/IO/LSDyna/LSDynaFamily.cxx
+++ b/IO/LSDyna/LSDynaFamily.cxx
@@ -35,8 +35,9 @@ namespace
 // Decide which of 3 stat varieties to use: stat, stat64, __stat64
 // Usually stat uses 32 bit fields, and stat64 (with underscores in Windows) uses 64 bit fields.
 // But on the BSDs, stat uses 64 bit fields these days.
-#if (VTK_SIZEOF_ID_TYPE == 8) && !defined(_DARWIN_FEATURE_64_BIT_INODE) &&                         \
-  !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
+#if (VTK_SIZEOF_ID_TYPE == 8) && !defined(_DARWIN_FEATURE_64_BIT_INODE) && \
+  !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && \
+  !defined(__CYGWIN__)
 #ifndef _WIN32
 #define USE_STAT_64
 #else
diff --git a/ThirdParty/loguru/vtkloguru/loguru.cpp b/ThirdParty/loguru/vtkloguru/loguru.cpp
index 468675d512..1d39cbcff5 100644
--- a/ThirdParty/loguru/vtkloguru/loguru.cpp
+++ b/ThirdParty/loguru/vtkloguru/loguru.cpp
@@ -72,13 +72,13 @@
 
 // TODO: use defined(_POSIX_VERSION) for some of these things?
 
-#if defined(_WIN32) || defined(__CYGWIN__)
+#if defined(_WIN32)
 	#define LOGURU_PTHREADS    0
 	#define LOGURU_WINTHREADS  1
 	#ifndef LOGURU_STACKTRACES
 		#define LOGURU_STACKTRACES 0
 	#endif
-#elif defined(__rtems__) || defined(__ANDROID__)
+#elif defined(__rtems__) || defined(__ANDROID__) || defined(__CYGWIN__)
 	#define LOGURU_PTHREADS    1
 	#define LOGURU_WINTHREADS  0
 	#ifndef LOGURU_STACKTRACES
@@ -576,7 +576,7 @@ namespace loguru
 			#elif LOGURU_PTHREADS
 				char old_thread_name[16] = {0};
 				auto this_thread = pthread_self();
-				#if defined(__APPLE__) || defined(__linux__)
+				#if defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__)
 					pthread_getname_np(this_thread, old_thread_name, sizeof(old_thread_name));
 				#endif
 				if (old_thread_name[0] == 0) {
@@ -584,7 +584,7 @@ namespace loguru
 						pthread_setname_np(main_thread_name);
 					#elif defined(__FreeBSD__) || defined(__OpenBSD__)
 						pthread_set_name_np(this_thread, main_thread_name);
-					#elif defined(__linux__)
+					#elif defined(__linux__) || defined(__CYGWIN__)
 						pthread_setname_np(this_thread, main_thread_name);
 					#endif
 				}
@@ -927,7 +927,7 @@ namespace loguru
 				pthread_setname_np(name);
 			#elif defined(__FreeBSD__) || defined(__OpenBSD__)
 				pthread_set_name_np(pthread_self(), name);
-			#elif defined(__linux__)
+			#elif defined(__linux__) || defined(__CYGWIN__)
 				pthread_setname_np(pthread_self(), name);
 			#endif
 		#elif LOGURU_WINTHREADS
@@ -960,7 +960,7 @@ namespace loguru
 			} else {
 				buffer[0] = 0;
 			}
-		#elif defined(__APPLE__) || defined(__linux__)
+		#elif defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__)
 			pthread_getname_np(thread, buffer, length);
 		#else
 			buffer[0] = 0;
@@ -975,6 +975,8 @@ namespace loguru
 				(void)thr_self(&thread_id);
 			#elif defined(__OpenBSD__)
 				unsigned thread_id = -1;
+            #elif defined(__CYGWIN__)
+                uint64_t thread_id = (uint64_t)pthread_self();
 			#else
 				uint64_t thread_id = thread;
 			#endif
diff --git a/ThirdParty/netcdf/vtknetcdf/include/vtk_netcdf_mangle.h b/ThirdParty/netcdf/vtknetcdf/include/vtk_netcdf_mangle.h
index 02feb08226..a1a49c1a95 100644
--- a/ThirdParty/netcdf/vtknetcdf/include/vtk_netcdf_mangle.h
+++ b/ThirdParty/netcdf/vtknetcdf/include/vtk_netcdf_mangle.h
@@ -1246,7 +1246,7 @@
 #define write_numrecs vtknetcdf_write_numrecs
 
 /* Only define strlcat conditionally, as it's provided by system headers on the BSDs. */
-#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(_BSD_SOURCE)
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(_BSD_SOURCE) && !defined(__CYGWIN__)
 #define strlcat vtknetcdf_strlcat
 #endif
 
diff --git a/Utilities/KWSys/vtksys/Status.hxx.in b/Utilities/KWSys/vtksys/Status.hxx.in
index 16efaefdf3..e815f133f7 100644
--- a/Utilities/KWSys/vtksys/Status.hxx.in
+++ b/Utilities/KWSys/vtksys/Status.hxx.in
@@ -9,6 +9,11 @@
 
 namespace @KWSYS_NAMESPACE@ {
 
+/** From <X11/Xlib.h>
+ */
+#undef Status
+#undef Success
+
 /** \class Status
  * \brief OS-specific status of a system operation.
  */
diff --git a/Wrapping/Python/vtkmodules/__init__.py.in b/Wrapping/Python/vtkmodules/__init__.py.in
index 25bf15447e..72b97ca5f6 100644
--- a/Wrapping/Python/vtkmodules/__init__.py.in
+++ b/Wrapping/Python/vtkmodules/__init__.py.in
@@ -5,10 +5,32 @@ from __future__ import absolute_import
 import sys
 
 
+# Python doesn't provide os.add_dll_directory for Cygwin.
+def add_dll_directory(path):
+    import ctypes
+    # Assumption: handle is closed when garbage collected.
+    k32 = ctypes.CDLL("Kernel32.dll")
+    # ctyps/dlsym can't find the enums so we use the hex values.
+    # Only works with LOAD_LIBRARY_SEARCH_DEFAULT_DIRS.
+    k32.SetDefaultDllDirectories(0x1000)
+    cookie = k32.AddDllDirectory(path)
+    # Unlike the real class, this isn't a context manager.
+    def remove_dll_directory():
+        k32.RemoveDllDirectory(cookie)
+    remove_dll_directory.close = remove_dll_directory
+    return remove_dll_directory
+
 def _windows_dll_path():
     import os
+    try:
+        add_dll_directory_f = os.add_dll_directory
+    except AttributeError:
+        add_dll_directory_f = add_dll_directory
     _vtk_python_path = '@VTK_PYTHON_SITE_PACKAGES_SUFFIX@/vtkmodules'
-    _vtk_dll_path = '@CMAKE_INSTALL_BINDIR@'
+    if sys.platform == 'cygwin':
+        _vtk_dll_path = _vtk_python_path
+    else:
+        _vtk_dll_path = '@CMAKE_INSTALL_BINDIR@'
     # Compute the DLL path based on the location of the file and traversing up
     # the installation prefix to append the DLL path.
     _vtk_dll_directory = os.path.dirname(os.path.abspath(__file__))
@@ -21,7 +43,7 @@ def _windows_dll_path():
     if os.path.exists(_vtk_dll_directory):
         # We never remove this path; it is required for VTK to work and there's
         # no scope where we can easily remove the directory again.
-        _ = os.add_dll_directory(_vtk_dll_directory)
+        _ = add_dll_directory_f(_vtk_dll_directory)
 
     # Build tree support.
     try:
@@ -30,7 +52,7 @@ def _windows_dll_path():
         # Add any paths needed for the build tree.
         for path in _build_paths.paths:
             if os.path.exists(path):
-                _ = os.add_dll_directory(path)
+                _ = add_dll_directory_f(path)
     except ImportError:
         # Relocatable install tree (or non-Windows).
         pass
@@ -39,7 +61,7 @@ def _windows_dll_path():
 # CPython 3.8 added behaviors which modified the DLL search path on Windows to
 # only search "blessed" paths. When importing SMTK, ensure that SMTK's DLLs are
 # in this set of "blessed" paths.
-if sys.version_info >= (3, 8) and sys.platform == 'win32':
+if sys.version_info >= (3, 8) and sys.platform in ('win32', 'cygwin'):
     _windows_dll_path()
 
 
