diff --git a/setup.py b/setup.py index bfc2a38..09da73e 100644 --- a/setup.py +++ b/setup.py @@ -36,8 +36,8 @@ import winreg from collections.abc import MutableSequence from pathlib import Path from setuptools import Extension, setup +from setuptools._distutils import ccompiler from setuptools.command.build import build -from setuptools.command.build_ext import build_ext from setuptools.modified import newer_group from tempfile import gettempdir from typing import TYPE_CHECKING, Iterable @@ -53,6 +53,21 @@ else: from distutils._msvccompiler import MSVCCompiler from distutils.command.install_data import install_data + +def my_new_compiler(**kw): + if "compiler" in kw and kw["compiler"] in (None, "msvc"): + return my_compiler() + return orig_new_compiler(**kw) + + +# No way to cleanly wedge our compiler sub-class in. +orig_new_compiler = ccompiler.new_compiler +ccompiler.new_compiler = my_new_compiler # type: ignore[assignment] # Assuming the caller will always use only kwargs + + +# This import has to be delayed to AFTER the compiler hack +from setuptools.command.build_ext import build_ext # noqa: E402 + build_id_patch = build_id if not "." in build_id_patch: build_id_patch += ".0" @@ -118,7 +133,8 @@ class WinExt(Extension): extra_link_args = extra_link_args or [] if export_symbol_file: - extra_link_args.append("/DEF:" + export_symbol_file) + if "MSC" in sys.version: + extra_link_args.append("/DEF:" + export_symbol_file) # Some of our swigged files behave differently in distutils vs # MSVC based builds. Always define DISTUTILS_BUILD so they can tell. @@ -163,7 +179,7 @@ class WinExt(Extension): def finalize_options(self, build_ext): # distutils doesn't define this function for an Extension - it is # our own invention, and called just before the extension is built. - if not build_ext.mingw32: + if "MSC" in sys.version: if self.pch_header: self.extra_compile_args = self.extra_compile_args or [] @@ -219,6 +235,61 @@ class WinExt(Extension): break if found_mfc: break + else: + # Set our C++ standard + self.extra_compile_args.append("-std=c++17") + # This is needed for pythoncom + self.extra_compile_args.append("-fpermissive") + + # MinGW-w64 doesn't define these. + self.extra_compile_args.append("-D__WIN32__") + # Extra compile args + if "AMD64" in sys.version: + self.extra_compile_args.append("-D_M_X64") # pythoncom & win32ui + self.extra_compile_args.append("-D_AMD64_") # mapi + elif "ARM64" in sys.version: + self.extra_compile_args.append("-D_M_ARM64") # pythoncom & win32ui + self.extra_compile_args.append("-D_ARM64_") # mapi + else: + self.extra_compile_args.append("-D_M_IX86") # pythoncom & win32ui + self.extra_compile_args.append("-D_X86_") # mapi + + # If someone needs a specially named implib created, handle that + if self.implib_name: + implib = os.path.join(build_ext.build_temp, self.implib_name) + suffix = "_d" if build_ext.debug else "" + self.extra_link_args.append( + "-Wl,--out-implib,%s%s.dll.a" % (implib, suffix) + ) + + if "64 bit" in sys.version: + self.extra_link_args.append("-m64") + else: + self.extra_link_args.append("-m32") + + # Silenced some annoying warnings + self.extra_compile_args.append("-Wno-attributes") + self.extra_compile_args.append("-Wno-conversion-null") + self.extra_compile_args.append("-Wno-deprecated-declarations") + self.extra_compile_args.append("-Wno-invalid-offsetof") + self.extra_compile_args.append("-Wno-return-type") + self.extra_compile_args.append("-Wno-sign-compare") + self.extra_compile_args.append("-Wno-strict-aliasing") + self.extra_compile_args.append("-Wno-uninitialized") + self.extra_compile_args.append("-Wno-unknown-pragmas") + self.extra_compile_args.append("-Wno-unused") + self.extra_compile_args.append("-Wno-write-strings") + + if "Clang" in sys.version: + self.extra_compile_args.append("-Wno-missing-braces") + self.extra_compile_args.append("-Wno-missing-exception-spec") + self.extra_compile_args.append("-Wno-nonportable-include-path") + self.extra_compile_args.append("-Wno-self-assign") + else: + self.extra_compile_args.append("-Wno-class-memaccess") + self.extra_compile_args.append("-Wno-nonnull-compare") + self.extra_compile_args.append("-Wno-pointer-arith") + self.extra_compile_args.append("-Wno-sequence-point") self.extra_compile_args.append("-DUNICODE") self.extra_compile_args.append("-D_UNICODE") @@ -229,6 +300,19 @@ class WinExt_pythonwin(WinExt): def __init__(self, name, **kw): kw.setdefault("extra_compile_args", []).extend(["-D_AFXDLL", "-D_AFXEXT"]) + if "GCC" in sys.version: + kw.setdefault("extra_compile_args", []).extend( + ["-DMINGW_HAS_SECURE_API=1"]) + + kw["libraries"] = kw.get("libraries", "") + " mfc100u" + if name == "win32ui": + kw["libraries"] = kw.get("libraries", "") + " winspool" + elif name == "win32uiole": + kw["libraries"] = kw.get("libraries", "") + " win32ui pythoncom" + elif name == "dde": + kw["libraries"] = kw.get("libraries", "") + " win32ui" + kw["libraries"] = kw.get("libraries", "") + " pywintypes" + WinExt.__init__(self, name, **kw) def get_pywin32_dir(self): @@ -239,7 +323,7 @@ class WinExt_pythonwin_subsys_win(WinExt_pythonwin): def finalize_options(self, build_ext): WinExt_pythonwin.finalize_options(self, build_ext) - if build_ext.mingw32: + if "GCC" in sys.version: self.extra_link_args.append("-mwindows") else: self.extra_link_args.append("/SUBSYSTEM:WINDOWS") @@ -250,6 +334,9 @@ class WinExt_pythonwin_subsys_win(WinExt_pythonwin): class WinExt_win32(WinExt): def __init__(self, name, **kw): + if "GCC" in sys.version: + if name not in ["_win32sysloader"]: + kw["libraries"] = kw.get("libraries", "") + " pywintypes" WinExt.__init__(self, name, **kw) def get_pywin32_dir(self): @@ -266,6 +353,8 @@ class WinExt_ISAPI(WinExt): class WinExt_win32com(WinExt): def __init__(self, name, **kw): kw["libraries"] = kw.get("libraries", "") + " oleaut32 ole32" + if "GCC" in sys.version: + kw["libraries"] = kw.get("libraries", "") + " uuid pythoncom pywintypes" WinExt.__init__(self, name, **kw) def get_pywin32_dir(self): @@ -328,11 +417,16 @@ class WinExt_system32(WinExt): class WinExt_pythonservice(WinExt): + def __init__(self, name, **kw): + if "GCC" in sys.version: + kw["libraries"] = kw.get("libraries", "") + " pywintypes" + WinExt.__init__(self, name, **kw) + # special handling because it's a "console" exe. def finalize_options(self, build_ext): WinExt.finalize_options(self, build_ext) - if build_ext.mingw32: + if "GCC" in sys.version: self.extra_link_args.append("-mconsole") self.extra_link_args.append("-municode") else: @@ -856,18 +950,368 @@ class my_build_ext(build_ext): return new_sources -def my_new_compiler(**kw): - if "compiler" in kw and kw["compiler"] in (None, "msvc"): - return my_compiler() - return orig_new_compiler(**kw) +class mingw_build_ext(build_ext): + def finalize_options(self): + build_ext.finalize_options(self) + # The pywintypes library is created in the build_temp + # directory, so we need to add this to library_dirs + self.library_dirs.append(self.build_temp) -# No way to cleanly wedge our compiler sub-class in. -orig_new_compiler = ccompiler.new_compiler -ccompiler.new_compiler = my_new_compiler # type: ignore[assignment] # Assuming the caller will always use only kwargs + # Add extra VC++ SDK library dir + if "64 bit" in sys.version: + x64_dir = "/x64" + else: + x64_dir = "" + + # VC++ custom dirs for ATL/MFC + if "SDKDIR" in os.environ: + sdk_info = os.environ.get("SDKDIR") + else: + sdk_info = "." + #self.include_dirs.append(sdk_info + "/atlmfc/include") + #self.library_dirs.append(sdk_info + "/atlmfc/lib" + x64_dir) + + self.excluded_extensions = [] # list of (ext, why) + self.swig_cpp = True + + def _why_cant_build_extension(self, ext): + """Return None, or a reason it can't be built.""" + # axdebug fails to build on 3.11 due to Python "frame" objects changing. + # This could be fixed, but is almost certainly not in use any more, so + # just skip it. + if ext.name == "axdebug" and sys.version_info >= (3, 11): + return "AXDebug no longer builds on 3.11 and up" + + if ext.name in ["exchange", "exchdapi"]: + return "No library for utility functions available." + + # Comment out below to enable Pythonwin extensions + if ext.name in ["win32ui", "win32uiole", "dde", "Pythonwin"]: + return "Unsupported due to ATL/MFC usage." + + def _build_scintilla(self): + path = "Pythonwin/Scintilla/win32" + makefile = "scintilla_mingw.mak" + makeargs = [] + + if self.debug: + makeargs.append("DEBUG=1") + if not self.verbose: + makeargs.append("QUIET=1") + # We build the DLL into our own temp directory, then copy it to the + # real directory - this avoids the generated .lib/.exp + build_temp = os.path.abspath(os.path.join(self.build_temp, "scintilla")) + self.mkpath(build_temp) + makeargs.append("SUB_DIR_O=%s" % build_temp) + makeargs.append("SUB_DIR_BIN=%s" % build_temp) + + # Deliberately not using self.spawn() to avoid stdout from always + # printing the parsed arguments for the makefile. + cwd = os.getcwd() + os.chdir(path) + try: + import subprocess + cmd = subprocess.call(["make", "-f", makefile] + makeargs) + finally: + os.chdir(cwd) -class my_compiler(MSVCCompiler): + # The DLL goes into the Pythonwin directory. + if self.debug: + base_name = "scintilla_d.dll" + else: + base_name = "scintilla.dll" + self.copy_file( + os.path.join(self.build_temp, "scintilla", base_name), + os.path.join(self.build_lib, "pythonwin"), + ) + + def build_extensions(self): + # First, sanity-check the 'extensions' list + self.check_extensions_list(self.extensions) + + self.found_libraries = {} + + if hasattr(self.compiler, "initialize") and not self.compiler.initialized: + self.compiler.initialize() + + # Always use cxx as the linker + cxx = os.environ.get('CXX') + self.compiler.set_executables(linker_exe=cxx) + + # Here we hack a "pywin32" directory (one of 'win32', 'win32com', + # 'pythonwin' etc), as distutils doesn't seem to like the concept + # of multiple top-level directories. + assert self.package is None + for ext in self.extensions: + try: + self.package = ext.get_pywin32_dir() + except AttributeError: + raise RuntimeError("Not a win32 package!") + self.build_extension(ext) + + for ext in W32_exe_files: + self.package = ext.get_pywin32_dir() + ext.finalize_options(self) + why = self._why_cant_build_extension(ext) + if why is not None: + self.excluded_extensions.append((ext, why)) + assert why, "please give a reason, or None" + print(f"Skipping {ext.name}: {why}") + continue + self.build_exefile(ext) + + for ext in [*self.extensions, *W32_exe_files]: + # Stamp the version of the built target. + # Do this externally to avoid suddenly dragging in the + # modules needed by this process, and which we will soon try and update. + ext_path = self.get_ext_fullpath(ext.name) + self.spawn( + [ + sys.executable, + Path(__file__).parent / "win32" / "Lib" / "win32verstamp.py", + f"--version={pywin32_version}", + "--comments=https://github.com/mhammond/pywin32", + f"--original-filename={os.path.basename(ext_path)}", + "--product=PyWin32", + "--quiet" if "-v" not in sys.argv else "", + ext_path, + ] + ) + + # Only build scintilla if Pythonwin extensions are enabled + pythonwin_dir = os.path.join(self.build_temp, "pythonwin") + if os.path.exists(pythonwin_dir): + self._build_scintilla() + + # Copy cpp lib files needed to create Python COM extensions + clib_files = ( + ["win32", "pywintypes%s.dll.a"], + ["win32com", "pythoncom%s.dll.a"], + ["win32com", "axscript%s.dll.a"], + ) + for clib_file in clib_files: + target_dir = os.path.join(self.build_lib, clib_file[0], "libs") + if not os.path.exists(target_dir): + self.mkpath(target_dir) + suffix = "_d" if self.debug else "" + fname = clib_file[1] % suffix + self.copy_file(os.path.join(self.build_temp, fname), target_dir) + + # Search the MFC dll. + try: + target_dir = os.path.join(self.build_lib, "pythonwin") + mfc_files = ["libmfc100u.dll"] + + if "64 bit" in sys.version: + plat_dir = "x64" + else: + plat_dir = "x86" + + # Locate the redist directory. + target_file = os.path.join(target_dir, "Pythonwin.exe") + if os.path.exists(target_file): + mfcdll_dir = os.path.join(sdk_info, "redist", plat_dir) + if not os.path.isdir(mfcdll_dir): + raise RuntimeError("Can't find the redist dir at %r" % (mfcdll_dir)) + for f in mfc_files: + self.copy_file(os.path.join(mfcdll_dir, f), target_dir) + except (EnvironmentError, RuntimeError) as exc: + if os.path.exists(target_file): + print("Can't find the requested MFC DLL:", exc) + pass + + def build_exefile(self, ext): + suffix = "_d" if self.debug else "" + logging.info("building exe '%s'", ext.name) + leaf_name = f"{ext.get_pywin32_dir()}/{ext.name}{suffix}.exe" + full_name = os.path.join(self.build_lib, leaf_name) + + sources = list(ext.sources) + depends = sources + ext.depends + objects = self.compiler.compile( + sources, + output_dir=os.path.join(self.build_temp, ext.name), + include_dirs=ext.include_dirs, + debug=self.debug, + extra_postargs=ext.extra_compile_args, + depends=ext.depends, + ) + + self.compiler.link( + "executable", + objects, + full_name, + libraries=self.get_libraries(ext), + library_dirs=ext.library_dirs, + runtime_library_dirs=ext.runtime_library_dirs, + extra_postargs=ext.extra_link_args, + debug=self.debug, + build_temp=self.build_temp, + ) + + def build_extension(self, ext): + # Some of these extensions are difficult to build, requiring various + # hard-to-track libraries et (eg, exchange sdk, etc). So we + # check the extension list for the extra libraries explicitly + # listed. We then search for this library the same way the C + # compiler would - if we can't find a library, we exclude the + # extension from the build. + # Note we can't do this in advance, as some of the .lib files + # we depend on may be built as part of the process - thus we can + # only check an extension's lib files as we are building it. + why = self._why_cant_build_extension(ext) + if why is not None: + assert why, "please give a reason, or None" + self.excluded_extensions.append((ext, why)) + print(f"Skipping {ext.name}: {why}") + return + self.current_extension = ext + + ext.finalize_options(self) + + # Ensure the SWIG .i files are treated as dependencies. + for source in ext.sources: + if source.endswith(".i"): + self.find_swig() # for the side-effect of the environment value. + # Find the swig_lib .i files we care about for dependency tracking. + ext.swig_deps = glob.glob( + os.path.join(os.environ["SWIG_LIB"], "python", "*.i") + ) + ext.depends.extend(ext.swig_deps) + break + else: + ext.swig_deps = None + + try: + build_ext.build_extension(self, ext) + except: + print() + print("WARNING: building of extension '%s' failed" % (ext.name)) + print() + return + + def get_ext_filename(self, name): + # We need to fixup some target filenames. + suffix = "_d" if self.debug else "" + if name in ["pywintypes", "pythoncom"]: + ver = f"{sys.version_info.major}{sys.version_info.minor}" + return f"{name}{ver}{suffix}.dll" + if name in ["perfmondata", "PyISAPI_loader"]: + return f"{name}{suffix}.dll" + if name.endswith("win32.pythonservice"): + return f"win32/pythonservice{suffix}.exe" + elif name.endswith("pythonwin.Pythonwin"): + return f"pythonwin/Pythonwin{suffix}.exe" + return build_ext.get_ext_filename(self, name) + + def get_export_symbols(self, ext): + if ext.is_regular_dll: + return None + return build_ext.get_export_symbols(self, ext) + + def find_swig(self): + if "SWIG" in os.environ: + swig = os.environ["SWIG"] + else: + # We know where our swig is + swig = os.path.abspath("swig/swig.exe") + lib = os.path.join(os.path.dirname(swig), "swig_lib") + os.environ["SWIG_LIB"] = lib + return swig + + def swig_sources(self, sources, ext=None): + new_sources = [] + swig_sources = [] + swig_targets = {} + # XXX this drops generated C/C++ files into the source tree, which + # is fine for developers who want to distribute the generated + # source -- but there should be an option to put SWIG output in + # the temp dir. + # Adding py3k to the mix means we *really* need to move to generating + # to the temp dir... + target_ext = ".cpp" + for source in sources: + (base, sext) = os.path.splitext(source) + if sext == ".i": # SWIG interface file + if os.path.split(base)[1] in swig_include_files: + continue + swig_sources.append(source) + # Patch up the filenames for various special cases... + if os.path.basename(base) in swig_interface_parents: + swig_targets[source] = base + target_ext + else: + new_target = f"{base}_swig{target_ext}" + new_sources.append(new_target) + swig_targets[source] = new_target + else: + new_sources.append(source) + + if not swig_sources: + return new_sources + + swig = self.find_swig() + for source in swig_sources: + swig_cmd = [swig, "-python", "-c++", "-dnone"] + swig_cmd.extend(self.current_extension.extra_swig_commands) + + if "64 bit" in sys.version: + swig_cmd.append("-DSWIG_PY64BIT") + else: + swig_cmd.append("-DSWIG_PY32BIT") + target = swig_targets[source] + interface_parent = swig_interface_parents.get( + os.path.basename(os.path.splitext(source)[0]), + None, # "normal" swig file - no special win32 issues. + ) + # Using win32 extensions to SWIG for generating COM classes. + if interface_parent is not None: + # generating a class, not a module. + swig_cmd.append("-pythoncom") + if interface_parent: + # A class deriving from other than the default + swig_cmd.extend(["-com_interface_parent", interface_parent]) + + # This 'newer' check helps python 2.2 builds, which otherwise + # *always* regenerate the .cpp files, meaning every future + # build for any platform sees these as dirty. + # This could probably go once we generate .cpp into the temp dir. + fqsource = os.path.abspath(source) + fqtarget = os.path.abspath(target) + rebuild = self.force or ( + ext and newer_group(ext.swig_deps + [fqsource], fqtarget) + ) + + # can remove once edklib is no longer used for 32-bit builds + if source == "com/win32comext/mapi/src/exchange.i": + rebuild = True + + logging.debug("should swig %s->%s=%s", source, target, rebuild) + if rebuild: + swig_cmd.extend(["-o", fqtarget, fqsource]) + logging.info("swigging %s to %s", source, target) + out_dir = os.path.dirname(source) + cwd = os.getcwd() + os.chdir(out_dir) + try: + self.spawn(swig_cmd) + finally: + os.chdir(cwd) + else: + logging.info("skipping swig of %s", source) + + return new_sources + + +if "MSC" in sys.version: + base_compiler = MSVCCompiler +else: + from setuptools._distutils.cygwinccompiler import Mingw32CCompiler + base_compiler = Mingw32CCompiler + + +class my_compiler(base_compiler): def link( self, target_desc, @@ -895,22 +1339,6 @@ class my_compiler(MSVCCompiler): *args, **kw, ) - # Here seems a good place to stamp the version of the built - # target. Do this externally to avoid suddenly dragging in the - # modules needed by this process, and which we will soon try and - # update. - args = [ - sys.executable, - # NOTE: On Python 3.7, all args must be str - str(Path(__file__).parent / "win32" / "Lib" / "win32verstamp.py"), - f"--version={pywin32_version}", - "--comments=https://github.com/mhammond/pywin32", - f"--original-filename={os.path.basename(output_filename)}", - "--product=PyWin32", - "--quiet" if "-v" not in sys.argv else "", - output_filename, - ] - self.spawn(args) # Work around bpo-36302/bpo-42009 - it sorts sources but this breaks # support for building .mc files etc :( @@ -922,7 +1350,7 @@ class my_compiler(MSVCCompiler): return (e, b) sources = sorted(sources, key=key_reverse_mc) - return MSVCCompiler.compile(self, sources, **kwargs) + return base_compiler.compile(self, sources, **kwargs) def spawn(self, cmd: MutableSequence[str]) -> None: # type: ignore[override] # More restrictive than supertype is_link = cmd[0].endswith("link.exe") or cmd[0].endswith('"link.exe"') @@ -982,6 +1410,10 @@ class my_install_data(install_data): ################################################################ +pywintypes_lib = "" +if "GCC" in sys.version: + pywintypes_lib = "pywintypes" + pywintypes = WinExt_system32( "pywintypes", sources=[ @@ -1007,6 +1439,7 @@ pywintypes = WinExt_system32( ], extra_compile_args=["-DBUILD_PYWINTYPES"], libraries="advapi32 user32 ole32 oleaut32", + implib_name=pywintypes_lib, pch_header="PyWinTypes.h", ) @@ -1043,10 +1476,10 @@ for name, libraries, sources in ( """, ), ("timer", "user32", "win32/src/timermodule.cpp"), - ("win32cred", "AdvAPI32 credui", "win32/src/win32credmodule.cpp"), + ("win32cred", "advapi32 credui", "win32/src/win32credmodule.cpp"), ( "win32crypt", - "Crypt32 Advapi32", + "advapi32 crypt32", """ win32/src/win32crypt/win32cryptmodule.cpp win32/src/win32crypt/win32crypt_structs.cpp @@ -1097,7 +1530,7 @@ for name, libraries, sources in ( "win32/src/win32print/win32print.cpp", ), ("win32process", "advapi32 user32", "win32/src/win32process.i"), - ("win32profile", "Userenv", "win32/src/win32profilemodule.cpp"), + ("win32profile", "userenv", "win32/src/win32profilemodule.cpp"), ("win32ras", "rasapi32 user32", "win32/src/win32rasmodule.cpp"), ( "win32security", @@ -1135,7 +1568,7 @@ for name, libraries, sources in ( """, ), ("win32console", "kernel32", "win32/src/win32consolemodule.cpp"), - ("win32ts", "WtsApi32", "win32/src/win32tsmodule.cpp"), + ("win32ts", "wtsapi32", "win32/src/win32tsmodule.cpp"), ("_win32sysloader", "", "win32/src/_win32sysloader.cpp"), ("win32transaction", "kernel32", "win32/src/win32transactionmodule.cpp"), ): @@ -1152,7 +1585,7 @@ win32_extensions += [ WinExt_win32( "win32evtlog", sources=""" - win32\\src\\win32evtlog_messages.mc win32\\src\\win32evtlog.i + win32/src/win32evtlog_messages.mc win32/src/win32evtlog.i """.split(), libraries="advapi32 oleaut32", delay_load_libraries="wevtapi", @@ -1178,7 +1611,7 @@ win32_extensions += [ WinExt_win32( "_winxptheme", sources=["win32/src/_winxptheme.i"], - libraries="gdi32 user32 comdlg32 comctl32 shell32 Uxtheme", + libraries="gdi32 user32 comdlg32 comctl32 shell32 uxtheme", ), ] win32_extensions += [ @@ -1215,6 +1648,13 @@ dirs = { "win32com": "com/win32com/src", } +pythoncom_lib = pythoncom_dep = "" +win32ui_lib = "" +if "GCC" in sys.version: + pythoncom_lib = "pythoncom" + pythoncom_dep = " uuid pywintypes" + win32ui_lib = "win32ui" + # The COM modules. pythoncom = WinExt_system32( "pythoncom", @@ -1290,9 +1730,10 @@ pythoncom = WinExt_system32( {win32com}/include\\PyIServerSecurity.h """.format(**dirs) ).split(), - libraries="oleaut32 ole32 user32 urlmon", + libraries="oleaut32 ole32 user32 urlmon" + pythoncom_dep, export_symbol_file="com/win32com/src/PythonCOM.def", extra_compile_args=["-DBUILD_PYTHONCOM"], + implib_name=pythoncom_lib, pch_header="stdafx.h", base_address=dll_base_address, ) @@ -1301,7 +1742,7 @@ com_extensions = [ pythoncom, WinExt_win32com( "adsi", - libraries="ACTIVEDS ADSIID user32 advapi32", + libraries="activeds adsiid user32 advapi32", sources=( """ {adsi}/adsi.i {adsi}/adsi.cpp @@ -1775,6 +2216,7 @@ pythonwin_extensions = [ "Pythonwin/Win32uiHostGlue.h", "Pythonwin/win32win.h", ], + implib_name=win32ui_lib, optional_headers=["afxres.h"], ), WinExt_pythonwin( @@ -2012,6 +2454,19 @@ ext_modules = ( win32_extensions + com_extensions + pythonwin_extensions + other_extensions ) +if "GCC" in sys.version: + my_build_ext = mingw_build_ext + install_scripts = [] + binary_scripts = {} +else: + install_scripts = ["pywin32_postinstall.py", "pywin32_testall.py",] + binary_scripts = { + "console_scripts": [ + "pywin32_postinstall = win32.scripts.pywin32_postinstall:main", + "pywin32_testall = win32.scripts.pywin32_testall:main", + ] + } + cmdclass = { "build": my_build, "build_ext": my_build_ext, @@ -2046,17 +2501,9 @@ dist = setup( classifiers=classifiers, cmdclass=cmdclass, # This adds the scripts under Python3XX/Scripts, but doesn't actually do much - scripts=[ - "win32/scripts/pywin32_postinstall.py", - "win32/scripts/pywin32_testall.py", - ], + scripts=install_scripts, # This shortcuts `python -m win32.scripts.some_script` to just `some_script` - entry_points={ - "console_scripts": [ - "pywin32_postinstall = win32.scripts.pywin32_postinstall:main", - "pywin32_testall = win32.scripts.pywin32_testall:main", - ] - }, + entry_points=binary_scripts, ext_modules=ext_modules, package_dir={ "win32com": "com/win32com", @@ -2165,7 +2612,7 @@ if "build_ext" in dist.command_obj: print("*** NOTE: The following extensions were NOT %s:" % what_string) for ext, why in excluded_extensions: print(f" {ext.name}: {why}") - if ext.name not in skip_whitelist: + if "MSC" in sys.version and ext.name not in skip_whitelist: skipped_ex.append(ext.name) print("For more details on installing the correct libraries and headers,") print("please execute this script with no arguments (or see the docstring)")