import subprocess
import sys
# find_library(name) returns the pathname of a library, or None.
if os.name == "nt":
def _get_build_version():
"""Return the version of MSVC that was used to build Python.
For Python 2.3 and up, the version number is included in
sys.version. For earlier versions, assume the compiler is MSVC 6.
"""
# This function was copied from Lib/distutils/msvccompiler.py
prefix = "MSC v."
i = sys.version.find(prefix)
if i == -1:
return 6
i = i + len(prefix)
s, rest = sys.version[i:].split(" ", 1)
majorVersion = int(s[:-2]) - 6
if majorVersion >= 13:
majorVersion += 1
minorVersion = int(s[2:3]) / 10.0
# I don't think paths are affected by minor version in version 6
if majorVersion == 6:
minorVersion = 0
if majorVersion >= 6:
return majorVersion + minorVersion
# else we don't know what version of the compiler this is
return None
def find_msvcrt():
"""Return the name of the VC runtime dll"""
version = _get_build_version()
if version is None:
# better be safe than sorry
return None
if version <= 6:
clibname = 'msvcrt'
elif version <= 13:
clibname = 'msvcr%d' % (version * 10)
else:
# CRT is no longer directly loadable. See issue23606 for the
# discussion about alternative approaches.
return None
# If python was built with in debug mode
import importlib.machinery
if '_d.pyd' in importlib.machinery.EXTENSION_SUFFIXES:
clibname += 'd'
return clibname+'.dll'
def find_library(name):
if name in ('c', 'm'):
return find_msvcrt()
# See MSDN for the REAL search order.
for directory in os.environ['PATH'].split(os.pathsep):
fname = os.path.join(directory, name)
if os.path.isfile(fname):
return fname
if fname.lower().endswith(".dll"):
continue
fname = fname + ".dll"
if os.path.isfile(fname):
return fname
return None
/util.py
下面是对你提供的 ctypes
相关源码的逐行解释,主要针对 Windows 平台(os.name == "nt"
)的动态库查找逻辑:
前置导入
python
复制编辑
import subprocess import sys
-
导入
subprocess
和sys
模块,尽管subprocess
在这段代码中没有用到,可能是复制时带上了。
判断操作系统是否为 Windows
python
复制编辑
if os.name == "nt":
-
判断是否是 Windows 系统(
os.name == "nt"
),只有在 Windows 上才会执行下面定义的函数。
_get_build_version
函数:获取构建 Python 的 MSVC(微软编译器)版本
python
复制编辑
def _get_build_version():
-
返回当前 Python 所使用的 MSVC 编译器的大致版本号。
python
复制编辑
prefix = "MSC v." i = sys.version.find(prefix)
-
在
sys.version
字符串中查找 "MSC v.",这是 MSVC 编译器的标志。 -
例如,
sys.version
中可能包含:MSC v.1929 64 bit (AMD64)
。
python
复制编辑
if i == -1: return 6
-
如果找不到,说明是非常早期的版本,默认认为是 MSVC 6。
python
复制编辑
i = i + len(prefix) s, rest = sys.version[i:].split(" ", 1)
-
提取编译器版本号部分,例如从 "1929 64 bit (AMD64)" 中取出 "1929"。
python
复制编辑
majorVersion = int(s[:-2]) - 6
-
s[:-2]
获取主版本号(例如 "19"),并减去 6 得到一个映射值。
python
复制编辑
if majorVersion >= 13: majorVersion += 1
-
特殊处理:如果主版本 >= 13,加 1。目的是匹配不同 MSVC 版本号的行为。
python
复制编辑
minorVersion = int(s[2:3]) / 10.0
-
提取次版本号并除以 10,例如从 "1929" 中提取 "2",变为 0.2。
python
复制编辑
if majorVersion == 6: minorVersion = 0
-
如果主版本是 6,忽略次版本,直接设为 0。
python
复制编辑
if majorVersion >= 6: return majorVersion + minorVersion
-
返回完整的版本号,例如
19.2
。
python
复制编辑
return None
-
如果判断失败,返回 None。
find_msvcrt
函数:获取 MSVC 运行库对应的 DLL 名
python
复制编辑
def find_msvcrt():
-
返回 VC 运行库(C runtime)的 DLL 名字,比如
msvcr100.dll
。
python
复制编辑
version = _get_build_version() if version is None: return None
-
如果无法判断版本,返回 None。
python
复制编辑
if version <= 6: clibname = 'msvcrt' elif version <= 13: clibname = 'msvcr%d' % (version * 10)
-
根据 MSVC 版本号确定运行库名字:
-
MSVC6:
msvcrt.dll
-
MSVC7~13:
msvcr70.dll
~msvcr130.dll
-
python
复制编辑
else: return None
-
对于更新的 MSVC(比如 MSVC2015+),运行库不再以这种方式存在,直接返回 None。
python
复制编辑
import importlib.machinery if '_d.pyd' in importlib.machinery.EXTENSION_SUFFIXES: clibname += 'd'
-
如果是 Python debug 版本(扩展名带
_d.pyd
),附加d
,即msvcr100d.dll
。
python
复制编辑
return clibname+'.dll'
-
最终拼接
.dll
后缀,返回如"msvcr100.dll"
。
find_library
函数:核心函数,用于查找库路径
python
复制编辑
def find_library(name):
-
根据名字查找动态库的路径。
python
复制编辑
if name in ('c', 'm'): return find_msvcrt()
-
libc
或libm
(数学库)在 Windows 上都映射到 msvcrt 系列。
python
复制编辑
for directory in os.environ['PATH'].split(os.pathsep):
-
遍历系统的环境变量 PATH 中所有目录。
python
复制编辑
fname = os.path.join(directory, name) if os.path.isfile(fname): return fname
-
如果找到了同名文件(如
"sqlite3"
),直接返回。
python
复制编辑
if fname.lower().endswith(".dll"): continue fname = fname + ".dll" if os.path.isfile(fname): return fname
-
如果未带
.dll
,尝试加上.dll
后缀再找一次。
python
复制编辑
return None
-
如果找不到,就返回
None
。
总结作用
这段代码的作用是:
-
判断 Python 当前使用的 MSVC 版本(Windows 特有)。
-
根据该版本确定运行时 DLL(如
msvcrt.dll
)。 -
通过 PATH 环境变量遍历查找指定库的实际路径,主要用于
ctypes
载入库时定位动态链接库。
如果你还想了解这段代码是如何集成进 ctypes.util.find_library()
的全局逻辑或其在 POSIX 系统上的 counterpart,也可以继续展开。需要我补充吗?