From 64aef5456afafc7922d6908be12204627c887393 Mon Sep 17 00:00:00 2001 From: Maxwell Dreytser Date: Tue, 23 Jan 2024 01:36:28 -0500 Subject: [PATCH] Add Nuitka-Python hooks. --- setuptools/_distutils/_msvccompiler.py | 10 ++++-- setuptools/_distutils/ccompiler.py | 14 +++++++- setuptools/_distutils/command/build_ext.py | 39 ++++++++++++++++------ setuptools/_distutils/msvccompiler.py | 8 ++--- setuptools/_distutils/sysconfig.py | 4 +++ setuptools/_distutils/unixccompiler.py | 19 +++++++++-- setuptools/command/build_ext.py | 25 +++++++++++++- 7 files changed, 97 insertions(+), 22 deletions(-) diff --git a/setuptools/_distutils/_msvccompiler.py b/setuptools/_distutils/_msvccompiler.py index a2159fef838..46ef8bc54d4 100644 --- a/setuptools/_distutils/_msvccompiler.py +++ b/setuptools/_distutils/_msvccompiler.py @@ -265,17 +265,18 @@ def initialize(self, plat_name=None): self.rc = _find_exe("rc.exe", paths) # resource compiler self.mc = _find_exe("mc.exe", paths) # message compiler self.mt = _find_exe("mt.exe", paths) # message compiler + self.dumpbin = _find_exe("dumpbin.exe", paths) self.preprocess_options = None # bpo-38597: Always compile with dynamic linking # Future releases of Python 3.x will include all past # versions of vcruntime*.dll for compatibility. - self.compile_options = ['/nologo', '/O2', '/W3', '/GL', '/DNDEBUG', '/MD'] + self.compile_options = ['/nologo', '/O2', '/W3', '/GL', '/DNDEBUG', '/MT'] self.compile_options_debug = [ '/nologo', '/Od', - '/MDd', + '/MTd', '/Zi', '/W3', '/D_DEBUG', @@ -457,6 +458,7 @@ def link( extra_postargs=None, build_temp=None, target_lang=None, + extra_midargs=None, ): if not self.initialized: self.initialize() @@ -498,6 +500,8 @@ def link( if extra_preargs: ld_args[:0] = extra_preargs + if extra_midargs: + ld_args.extend(extra_midargs) if extra_postargs: ld_args.extend(extra_postargs) @@ -552,6 +556,8 @@ def library_option(self, lib): return self.library_filename(lib) def find_library_file(self, dirs, lib, debug=0): + if len(dirs) == 1 and os.path.isfile(os.path.join(dirs[0], lib)): + return os.path.join(dirs[0], lib) # Prefer a debugging library if found (and requested), but deal # with it if we don't have one. if debug: diff --git a/setuptools/_distutils/ccompiler.py b/setuptools/_distutils/ccompiler.py index 8876d730986..57af78c6655 100644 --- a/setuptools/_distutils/ccompiler.py +++ b/setuptools/_distutils/ccompiler.py @@ -655,6 +655,7 @@ def link( extra_postargs=None, build_temp=None, target_lang=None, + extra_midargs=None, ): """Link a bunch of stuff together to create an executable or shared library file. @@ -718,6 +719,7 @@ def link_shared_lib( build_temp=None, target_lang=None, ): + raise NotImplementedError('Building shared libs is disabled for Nuitka-Python') self.link( CCompiler.SHARED_LIBRARY, objects, @@ -749,6 +751,7 @@ def link_shared_object( build_temp=None, target_lang=None, ): + raise NotImplementedError('Building shared libs is disabled for Nuitka-Python') self.link( CCompiler.SHARED_OBJECT, objects, @@ -777,6 +780,7 @@ def link_executable( extra_preargs=None, extra_postargs=None, target_lang=None, + extra_midargs=None, ): self.link( CCompiler.EXECUTABLE, @@ -792,6 +796,7 @@ def link_executable( extra_postargs, None, target_lang, + extra_midargs, ) # -- Miscellaneous methods ----------------------------------------- @@ -1013,6 +1018,9 @@ def library_filename( fmt = getattr(self, lib_type + "_lib_format") ext = getattr(self, lib_type + "_lib_extension") + if libname.endswith(ext): + ext = "" + dir, base = os.path.split(libname) filename = fmt % (base, ext) if strip_dir: @@ -1248,5 +1256,9 @@ def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries): "no library file corresponding to '%s' found (skipping)" % lib ) else: - lib_opts.append(compiler.library_option(lib)) + lib_file = compiler.find_library_file(library_dirs, lib_name) + if lib_file is not None and lib_file.endswith('.a'): + lib_opts.append(lib_file) + else: + lib_opts.append(compiler.library_option(lib)) return lib_opts diff --git a/setuptools/_distutils/command/build_ext.py b/setuptools/_distutils/command/build_ext.py index 06d949aff16..761e83fb87e 100644 --- a/setuptools/_distutils/command/build_ext.py +++ b/setuptools/_distutils/command/build_ext.py @@ -8,6 +8,8 @@ import os import re import sys +import json +import shutil from distutils._log import log from site import USER_BASE @@ -581,18 +583,33 @@ def build_extension(self, ext): # Detect target language, if not provided language = ext.language or self.compiler.detect_language(sources) - self.compiler.link_shared_object( - objects, - ext_path, - libraries=self.get_libraries(ext), - library_dirs=ext.library_dirs, - runtime_library_dirs=ext.runtime_library_dirs, - extra_postargs=extra_args, - export_symbols=self.get_export_symbols(ext), + self.compiler.create_static_lib( + objects, ext_path, + output_dir=os.path.abspath("."), debug=self.debug, - build_temp=self.build_temp, - target_lang=language, - ) + target_lang=language) + + result_path = self.compiler.library_filename(ext_path, + output_dir=os.path.abspath(".")) + + with open(result_path + '.link.json', 'w') as f: + json.dump({ + 'libraries': self.get_libraries(ext), + 'library_dirs': ext.library_dirs, + 'runtime_library_dirs': ext.runtime_library_dirs, + 'extra_postargs': extra_args}, f) + + for lib in self.get_libraries(ext): + for dir in ext.library_dirs: + lib_install_dir = os.path.join(os.path.dirname(ext_path), dir) + print(os.path.join(ext_path, dir, lib + '.lib')) + if os.path.isfile(os.path.join(dir, lib + '.lib')): + if not os.path.isabs(dir): + if not os.path.exists(lib_install_dir): + os.makedirs(lib_install_dir) + shutil.copyfile(os.path.join(dir, lib + '.lib'), + os.path.join(lib_install_dir, lib + '.lib')) + break def swig_sources(self, sources, extension): """Walk the list of source files in 'sources', looking for SWIG diff --git a/setuptools/_distutils/msvccompiler.py b/setuptools/_distutils/msvccompiler.py index ac8b68c08c6..8fda0c1a330 100644 --- a/setuptools/_distutils/msvccompiler.py +++ b/setuptools/_distutils/msvccompiler.py @@ -314,11 +314,11 @@ def initialize(self): self.preprocess_options = None if self.__arch == "Intel": - self.compile_options = ['/nologo', '/O2', '/MD', '/W3', '/GX', '/DNDEBUG'] + self.compile_options = ['/nologo', '/O2', '/MT', '/W3', '/GX', '/DNDEBUG'] self.compile_options_debug = [ '/nologo', '/Od', - '/MDd', + '/MTd', '/W3', '/GX', '/Z7', @@ -326,11 +326,11 @@ def initialize(self): ] else: # Win64 - self.compile_options = ['/nologo', '/O2', '/MD', '/W3', '/GS-', '/DNDEBUG'] + self.compile_options = ['/nologo', '/O2', '/MT', '/W3', '/GS-', '/DNDEBUG'] self.compile_options_debug = [ '/nologo', '/Od', - '/MDd', + '/MTd', '/W3', '/GS-', '/Z7', diff --git a/setuptools/_distutils/sysconfig.py b/setuptools/_distutils/sysconfig.py index 1a38e9fa797..2f2efd32757 100644 --- a/setuptools/_distutils/sysconfig.py +++ b/setuptools/_distutils/sysconfig.py @@ -345,6 +345,10 @@ def customize_compiler(compiler): # noqa: C901 else: archiver = ar + ' ' + ar_flags + cflags = ' '.join([x for x in cflags.split(' ') if + not x.startswith('-I') or ( + 'Nuitka-Python-Deps' not in x and 'dependencies' not in x)]) + cc_cmd = cc + ' ' + cflags compiler.set_executables( preprocessor=cpp, diff --git a/setuptools/_distutils/unixccompiler.py b/setuptools/_distutils/unixccompiler.py index 0248bde87b0..7c4f87db9b7 100644 --- a/setuptools/_distutils/unixccompiler.py +++ b/setuptools/_distutils/unixccompiler.py @@ -128,6 +128,13 @@ class UnixCCompiler(CCompiler): if sys.platform[:6] == "darwin": executables['ranlib'] = ["ranlib"] + # Nuitka: Make sure to use the original settings + executables["compiler"] = sysconfig.get_config_var("CC") + executables["compiler_so"] = sysconfig.get_config_var("CC") + executables["compiler_cxx"] = sysconfig.get_config_var("CXX") + executables["linker_so"] = sysconfig.get_config_var("CC") + executables["linker_exe"] = sysconfig.get_config_var("CC") + # Needed for the filename generation methods provided by the base # class, CCompiler. NB. whoever instantiates/uses a particular # UnixCCompiler instance should set 'shared_lib_ext' -- we set a @@ -228,6 +235,7 @@ def link( extra_postargs=None, build_temp=None, target_lang=None, + extra_midargs=None, ): objects, output_dir = self._fix_object_args(objects, output_dir) fixed_args = self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) @@ -240,11 +248,14 @@ def link( output_filename = os.path.join(output_dir, output_filename) if self._need_link(objects, output_filename): - ld_args = objects + self.objects + lib_opts + ['-o', output_filename] + ld_args = objects + self.objects if debug: ld_args[:0] = ['-g'] + if extra_midargs: + ld_args += extra_midargs if extra_preargs: ld_args[:0] = extra_preargs + ld_args += lib_opts + ['-o', output_filename] if extra_postargs: ld_args.extend(extra_postargs) self.mkpath(os.path.dirname(output_filename)) @@ -253,6 +264,8 @@ def link( # building an executable or linker_so (with shared options) # when building a shared library. building_exe = target_desc == CCompiler.EXECUTABLE + if not building_exe: + raise NotImplemented("No shared libs in Nuitka-Python") linker = (self.linker_exe if building_exe else self.linker_so)[:] if target_lang == "c++" and self.compiler_cxx: @@ -385,10 +398,10 @@ def find_library_file(self, dirs, lib, debug=0): >>> compiler.find_library_file(reversed(dirs), 'abc').replace('\\', '/') '/foo/bar/existing/libabc.a' """ - lib_names = ( + lib_names = [lib] + [ self.library_filename(lib, lib_type=type) for type in 'dylib xcode_stub shared static'.split() - ) + ] roots = map(self._library_root, dirs) diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py index 6056fe9b24b..ec9e3156b0f 100644 --- a/setuptools/command/build_ext.py +++ b/setuptools/command/build_ext.py @@ -1,6 +1,8 @@ import os import sys import itertools +import json +import shutil from importlib.machinery import EXTENSION_SUFFIXES from importlib.util import cache_from_source as _compiled_file_name from typing import Dict, Iterator, List, Tuple @@ -387,7 +389,7 @@ def _compile_and_remove_stub(self, stub_file: str): os.unlink(stub_file) -if use_stubs or os.name == 'nt': +if False: # use_stubs or os.name == 'nt': # Build shared libraries # def link_shared_object( @@ -455,3 +457,24 @@ def link_shared_object( basename = basename[3:] self.create_static_lib(objects, basename, output_dir, debug, target_lang) + + result_path = self.library_filename(basename, output_dir=os.path.abspath(".")) + + with open(result_path + '.link.json', 'w') as f: + json.dump({ + 'libraries': libraries, + 'library_dirs': ext.library_dirs, + 'runtime_library_dirs': library_dirs, + 'extra_postargs': extra_postargs, + 'extra_preargs': extra_preargs}, f) + + for lib in libraries: + for dir in library_dirs: + lib_install_dir = os.path.join(output_dir, dir) + if os.path.isfile(os.path.join(dir, lib + '.lib')): + if not os.path.isabs(dir): + if not os.path.exists(lib_install_dir): + os.makedirs(lib_install_dir) + shutil.copyfile(os.path.join(dir, lib + '.lib'), + os.path.join(lib_install_dir, lib + '.lib')) + break