Get Python's LIB path

后端 未结 2 1411
耶瑟儿~
耶瑟儿~ 2020-12-20 21:38

I can see that INCLUDE path is sysconfig.get_path(\'include\').

But I don\'t see any similar value for LIB.

NumPy outright hardcode

相关标签:
2条回答
  • 2020-12-20 22:15

    Below is the (rather long) subroutine in skbuild.cmaker that locates libpythonxx.so/pythonxx.lib for the running Python. In CMake, 350-line Modules/FindPythonLibs.cmake is dedicated to this task.

    The part of the former that gets just the directory is much simpler though:

    libdir = dustutils.sysconfig.get_config_var('LIBDIR')
    if sysconfig.get_config_var('MULTIARCH'):
        masd = sysconfig.get_config_var('multiarchsubdir')
        if masd:
            if masd.startswith(os.sep):
                masd = masd[len(os.sep):]
            libdir = os.path.join(libdir, masd)
    
    if libdir is None:
        libdir = os.path.abspath(os.path.join(
            sysconfig.get_config_var('LIBDEST'), "..", "libs"))
    

    def get_python_library(python_version):
        """Get path to the python library associated with the current python
        interpreter."""
        # determine direct path to libpython
        python_library = sysconfig.get_config_var('LIBRARY')
    
        # if static (or nonexistent), try to find a suitable dynamic libpython
        if (python_library is None or
                os.path.splitext(python_library)[1][-2:] == '.a'):
    
            candidate_lib_prefixes = ['', 'lib']
    
            candidate_extensions = ['.lib', '.so', '.a']
            if sysconfig.get_config_var('WITH_DYLD'):
                candidate_extensions.insert(0, '.dylib')
    
            candidate_versions = [python_version]
            if python_version:
                candidate_versions.append('')
                candidate_versions.insert(
                    0, "".join(python_version.split(".")[:2]))
    
            abiflags = getattr(sys, 'abiflags', '')
            candidate_abiflags = [abiflags]
            if abiflags:
                candidate_abiflags.append('')
    
            # Ensure the value injected by virtualenv is
            # returned on windows.
            # Because calling `sysconfig.get_config_var('multiarchsubdir')`
            # returns an empty string on Linux, `du_sysconfig` is only used to
            # get the value of `LIBDIR`.
            libdir = du_sysconfig.get_config_var('LIBDIR')
            if sysconfig.get_config_var('MULTIARCH'):
                masd = sysconfig.get_config_var('multiarchsubdir')
                if masd:
                    if masd.startswith(os.sep):
                        masd = masd[len(os.sep):]
                    libdir = os.path.join(libdir, masd)
    
            if libdir is None:
                libdir = os.path.abspath(os.path.join(
                    sysconfig.get_config_var('LIBDEST'), "..", "libs"))
    
            candidates = (
                os.path.join(
                    libdir,
                    ''.join((pre, 'python', ver, abi, ext))
                )
                for (pre, ext, ver, abi) in itertools.product(
                    candidate_lib_prefixes,
                    candidate_extensions,
                    candidate_versions,
                    candidate_abiflags
                )
            )
    
            for candidate in candidates:
                if os.path.exists(candidate):
                    # we found a (likely alternate) libpython
                    python_library = candidate
                    break
    
        # TODO(opadron): what happens if we don't find a libpython?
    
        return python_library
    
    0 讨论(0)
  • 2020-12-20 22:29

    Since it's not a part of any official spec/doc, and, as shown by another answer, there are cases when none of appropriate variables from sysconfig/distutils.sysconfig .get_config_var() are set,

    the only way to reliably get it in all cases, exactly as a build would (e.g. even for a Python in the sourcetree) is to delegate to the reference implementation.

    In distutils, the logic that sets the library path for a compiler is located in distutils.commands.build_ext.finalize_options(). So, this code would get it with no side effects on the build:

    import distutils.command.build_ext    #imports distutils.core, too
    d = distutils.core.Distribution()
    b = distutils.command.build_ext.build_ext(d)  #or `d.get_command_class('build_ext')(d)',
                                                  # then it's enough to import distutils.core
    b.finalize_options()
    print b.library_dirs
    

    Note that:

    • Not all locations in the resulting list necessarily exist.
    • If your setup.py is setuptools-based, use setuptools.Distribution and setuptools.command.build_ext instead, correspondingly.
    • If you pass any values to setup() that affect the result, you must pass them to Distribution here, too.

    Since there are no guarantees that the set of the additional values you need to pass will stay the same, or that the next maintainer won't switch to another builder1; and the value is only needed when building an extension,

    • it seems like you aren't really supposed to get this value independently at all:
      • If you're using another build facility, you should rather subclass build_ext and get the value from the base method during the build.

    1Okay, I admit this particular one is a rather remote possibility

    0 讨论(0)
提交回复
热议问题