ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

conda 虚拟包(Virtual Packages)完整指南:检测机制、覆盖策略与插件化实现

conda 虚拟包(Virtual Packages)完整指南:检测机制、覆盖策略与插件化实现 conda 虚拟包Virtual Packages完整指南检测机制、覆盖策略与插件化实现【免费下载链接】condaA system-level, binary package and environment manager running on all major operating systems and platforms.项目地址: https://gitcode.com/GitHub_Trending/co/conda虚拟包Virtual Packages是 conda 求解器solver中的一类特殊包它们不真实存在于任何频道中而是由 conda 在求解时动态注入用于让真实包可以声明对系统层面能力如驱动版本、CPU 特性、内核版本的依赖。本文基于当前仓库的官方文档 docs/source/user-guide/tasks/manage-virtual.rst 展开结合conda/plugins/virtual_packages/下的源码实现系统讲解虚拟包的概念、内置虚拟包清单、如何用conda info查看检测结果以及如何通过环境变量和.condarc覆盖检测结果进行故障排查读完你能够熟练诊断包要求某个系统特性但本机不满足这一类求解失败问题。什么是虚拟包虚拟包被注入到 conda 求解器中目的是让真实包能够依赖那些存在系统中、但无法由 conda 直接管理的特性例如系统驱动的版本号或 CPU 特性。虚拟包并不是真实包因此不会出现在conda list的输出中作为替代conda在求解时运行一小段检测代码探测与虚拟包对应的系统特性是否存在、版本几何。这种设计使得包作者可以在 recipe 中书写诸如__cuda 11.8、__glibc 2.17这样的依赖约束而最终用户无需手动安装任何CUDA 元包conda 会自动把宿主机的实际能力注入求解器参与版本匹配。当前内置的虚拟包清单文档列出的当前受支持的内置虚拟包如下虚拟包含义__cuda显示驱动display driver所支持的最大 CUDA 版本__osxmacOS 版本如适用__glibc操作系统支持的 glibc 版本__linux运行在 Linux 上时可用__unix运行在 OSX 或 Linux 上时可用__win运行在 Windows 上时可用__conda用于求解的 conda 自身版本未来 conda 版本还会加入更多虚拟包。所有虚拟包统一以双下划线前缀leading double-underscore命名以示区分如__cuda、__glibc。从源码结构看当前仓库的内置虚拟包分别实现在 conda/plugins/virtual_packages/ 目录下的独立模块中archspec.py、conda.py、cuda.py、freebsd.py、linux.py、osx.py、windows.py并由 conda/plugins/virtual_packages/init.py 中的plugins列表统一注册plugins [archspec, conda, cuda, freebsd, linux, osx, windows]。从 22.11.0 起虚拟包是插件自 conda22.11.0版本起虚拟包被实现为 conda 插件。也就是说上述每个检测模块都通过插件钩子hook暴露自己的能力。以 linux.py 为例其核心就是hookimpl修饰的conda_virtual_packages()函数hookimpl def conda_virtual_packages() - Iterable[CondaVirtualPackage]: if not context.subdir.startswith(linux-): return # 1: __unix00 (always exported if target subdir is linux-*) yield CondaVirtualPackage( nameunix, versionNone, buildNone, # override_entityNone, # no override allowed ) ...关于 conda 插件机制的更多细节可参阅 docs/source/dev-guide/plugins/virtual_packages.rst 与 docs/source/user-guide/concepts/conda-plugins.rst。虚拟包如何被检测逐模块源码解读理解各虚拟包的检测逻辑有助于判断为什么 conda 认为我机器上没有 CUDA这类问题。__conda恒常导出的 conda 版本conda/plugins/virtual_packages/conda.py 是最简单的虚拟包它直接暴露 conda 自身的__version__始终导出且不允许覆盖override_entityNonehookimpl def conda_virtual_packages() - Iterable[CondaVirtualPackage]: from ... import __version__ # 1: __condaVERSION0 (always exported) yield CondaVirtualPackage( nameconda, version__version__, buildNone, )__cuda在子进程中探测显示驱动支持的 CUDA 版本conda/plugins/virtual_packages/cuda.py 的实现最有代表性。它的探测过程在macOS ARM64Apple Silicon上直接判定 CUDA 不可用快捷路径出于安全考虑不使用fork启动方式而是通过multiprocessing.get_context(spawn)创建独立子进程来加载驱动库避免子进程继承父进程的文件描述符与句柄导致崩溃若在沙箱环境中无法创建多进程原语则记录警告并假定 CUDA 不可用子进程内按平台查找驱动库文件并调用 CUDA Driver APIcuInit、cuDriverGetVersion读取版本号macOSlibcuda.1.dylib、libcuda.dylib及/usr/local/cuda/lib/下的路径macOS 上 CUDA 库仅随 CUDA SDK 安装可能不在库路径中Linuxlibcuda.so及 RHEL/CentOS/Fedora/usr/lib64/nvidia/、Ubuntu/usr/lib/x86_64-linux-gnu/、WSL/usr/lib/wsl/lib/等常见路径同时搜索带.1版本后缀的库Windowsnvcuda64.dll/nvcuda32.dll/nvcuda.dll在调用cuInit前会先弹出popCUDA_VISIBLE_DEVICES环境变量避免其为空或非法值导致CUDA_ERROR_NO_DEVICE/CUDA_ERROR_INVALID_DEVICE版本号由驱动 API 返回的整数换算为主版本.次版本字符串f{value // 1000}.{(value % 1000) // 10}例如 10020 →10.2检测结果通过functools.cache缓存cached_cuda_version同一进程内只探测一次。__linux、__glibc基于 subdir 与 libc 探测linux.py 的逻辑是只有当context.subdir以linux-开头时才导出虚拟包。此时依次 yield 三个虚拟包__unix恒为0只要目标是linux-*就导出__linux版本来自context.platform_system_release解析出的发行版版本号并经过linux_version_validate校验——只保留内核版本字符串中前三或四个数字点分组件匹配LINUX_VERSION_PATTERN re.compile(r\d\.\d(\.\d)?(\.\d)?)丢弃厂商后缀注意这会导致-rcN开发内核的版本排序失真__glibc通过linux_get_libc_version()定义于 conda/common/_os/linux.py探测实际 libc 家族与版本探测失败时例如通过CONDA_SUBDIR指定 Linux 平台默认回退为glibc。libc_family, libc_version linux_get_libc_version() if not (libc_family and libc_version): # Default to glibc when using CONDA_SUBDIR var libc_family glibc yield CondaVirtualPackage( namelibc_family, versionlibc_version, buildNone, override_entityversion, )__osx、__win、__unix与 FreeBSDosx.pysubdir以osx-开头时导出__unix0与__osx版本版本取自context.os_distribution_name_versionwindows.pysubdir以win-开头时导出__win版本freebsd.pysubdir以freebsd-开头时仅导出__unix0注意上述平台模块都处理了在非目标平台上通过CONDA_SUBDIR/--platform模拟目标平台的情况此时平台版本探测结果会被置为None例如在 macOS 上模拟linux-64时__linux的版本不再有效。__archspecCPU 特性以 build 号形式导出archspec.py 与前面几个不同它导出的虚拟包名为__archspec版本恒为1而CPU 架构名如x86_64作为 build 号暴露override_entity为buildhookimpl def conda_virtual_packages() - Iterable[CondaVirtualPackage]: # 1: __archspec1BUILD yield CondaVirtualPackage( namearchspec, version1, buildarchspec_build, override_entitybuild, )archspec_build()调用 conda/core/index.py 中的get_archspec_name()获取架构名取不到时返回NULL表示不导出该虚拟包。CondaVirtualPackage 数据类与优先级规则所有检测结果最终统一为 conda/plugins/types.py 中定义的CondaVirtualPackage数据类其关键字段字段说明name虚拟包名不带__前缀导出时自动加前缀version版本字符串、None等价于0或返回字符串 /None/NULL的延迟调用函数build同上但对应 build 号override_entityversion或build声明该字段可被CONDA_OVERRIDE_NAME环境变量覆盖empty_override覆盖变量被设为空字符串时使用的值默认NULL即跳过导出version_validation可选的覆盖版本校验函数CondaVirtualPackage.to_virtual_package()是核心汇合点其执行顺序即优先级规则环境变量覆盖os.getenv(f{APP_NAME}_OVERRIDE_{self.name}.upper())即CONDA_OVERRIDE_NAME优先级最高.condarc覆盖未设置环境变量时回退到context.override_virtual_packages覆盖值处理若覆盖值被 strip 后为空字符串则使用empty_override默认NULL→ 该虚拟包被跳过延迟求值未被覆盖的 version/build 若为可调用对象此时才真正执行探测函数若 version 或 build 为NULL返回NULL不导出若配置了version_validation则对覆盖后的版本做校验最终通过PackageRecord.virtual_package(f__{self.name}, version, build)生成一个虚拟包记录注入求解器。查看已检测到的虚拟包请在终端中执行以下操作。要查看 conda 检测到的虚拟包列表运行conda info如果某个包被检测到它就会出现在输出的virtual packages一节中示例如下active environment : base active env location : /Users/demo/dev/conda/devenv shell level : 1 user config file : /Users/demo/.condarc populated config files : /Users/demo/.condarc conda version : 4.6.3.post88f640d35a conda-build version : 3.17.8 python version : 3.7.2.final.0 virtual packages : __cuda10.0 base environment : /Users/demo/dev/conda/devenv (writable) channel URLs : https://repo.anaconda.com/pkgs/main/osx-64 https://repo.anaconda.com/pkgs/main/noarch https://repo.anaconda.com/pkgs/free/osx-64 https://repo.anaconda.com/pkgs/free/noarch https://repo.anaconda.com/pkgs/r/osx-64 https://repo.anaconda.com/pkgs/r/noarch package cache : /Users/demo/dev/conda/devenv/pkgs /Users/demo/.conda/pkgs envs directories : /Users/demo/dev/conda/devenv/envs /Users/demo/.conda/envs platform : osx-64 user-agent : conda/4.6.3.post88f640d35a requests/2.21.0 CPython/3.7.2 Darwin/17.7.0 OSX/10.13.6 UID:GID : 502:20 netrc file : None offline mode : False上例中virtual packages : __cuda10.0表明本机显示驱动支持的最高 CUDA 版本被检测为 10.0。如果你怀疑某个虚拟包例如__cuda没有被正确检测可以对照上一节的源码探测路径排查驱动库是否位于 conda 搜索的路径列表中。覆盖检测结果故障排查出于排障目的conda 允许通过环境变量或.condarc配置覆盖虚拟包检测结果。这在以下场景中非常有用包要求__cuda11.8但本机驱动检测到的版本略低或未检测到 CUDA而你知道实际运行环境如远程 GPU 集群、WSL、容器是满足的需要在无 GPU 的构建机上交叉安装面向 GPU 环境的依赖需要为自定义虚拟包临时指定版本。方式一环境变量单次生效优先级最高可以在执行conda install命令时设置环境变量。这种方式优先级最高但覆盖变量必须在每次安装需要该覆盖的包时都重新设置。示例CONDA_OVERRIDE_CUDA12.8 conda install pytorch支持的内置变量如下表变量名覆盖实体示例CONDA_OVERRIDE_ARCHSPECBuild 号x86_64CONDA_OVERRIDE_CUDA版本号12.8CONDA_OVERRIDE_GLIBC版本号2.17CONDA_OVERRIDE_LINUX版本号5.15.0CONDA_OVERRIDE_OSX版本号11.0CONDA_OVERRIDE_WIN版本号10.0.22631对于任意自定义虚拟包变量名统一为CONDA_OVERRIDE_NAME其中NAME是虚拟包名覆盖的实体是该虚拟包override_entity字段声明的值——即version版本号或buildbuild 号。这一规则与源码中to_virtual_package()的逻辑完全对应环境变量优先于.condarc且覆盖值会先 strip 空白再使用。方式二.condarc中的override_virtual_packages持久生效如果不想每次安装包时都重新设置覆盖变量conda 提供了在.condarc文件中持久配置覆盖值的能力override_virtual_packages: archspec: x86_64 cuda: 12.8 glibc: 2.17 osx: 11.0 mycustompackage: 1.2.3要点说明配置项对应的源码位于 conda/base/context.py_override_virtual_packages参数加载器支持virtual_packages与override_virtual_packages两个别名见 L550-L552override_virtual_packages属性会移除键名中的双下划线前缀__cuda→cuda因此两种写法都可用键名支持任意自定义虚拟包名如示例中的mycustompackage.condarc中该配置的完整说明可参见.condarc参考文档中的 override-virtual-packages 一节优先级上环境变量始终高于.condarc配置只有未设置对应CONDA_OVERRIDE_NAME时context.override_virtual_packages中的值才会生效。自定义虚拟包从检测到覆盖的完整链路如果你需要为自己的场景新增一个虚拟包例如自定义操作系统代号可以基于插件机制实现在插件中定义hookimpl的conda_virtual_packages()yield 一个CondaVirtualPackage(namemycustompackage, version1.2.3, buildNone, override_entityversion)并注册到插件管理器。之后该虚拟包会以__mycustompackage的名称出现在conda info的virtual packages一节并可被真实包的依赖约束引用可通过CONDA_OVERRIDE_MYCUSTOMPACKAGE2.0 conda install ...临时或.condarc中的override_virtual_packages: {mycustompackage: 2.0}持久覆盖其版本。完整插件开发流程可参阅 docs/source/dev-guide/plugins/virtual_packages.rst相关单元测试覆盖了插件注册、检测与覆盖行为见 tests/plugins/test_virtual_packages.py 与 tests/plugins/test_manager.py。小结与排查速查虚拟包是 conda 注入求解器的系统能力描述不是真实包不出现在conda list中命名统一带__前缀用conda info查看virtual packages一节确认检测结果检测失败时先对照源码确认探测路径如 CUDA 驱动库位置必要时用CONDA_OVERRIDE_NAME单次、最高优先级或.condarc的override_virtual_packages持久显式覆盖覆盖实体取决于虚拟包的override_entity字段version覆盖版本号build覆盖 build 号覆盖值为空字符串时默认跳过该虚拟包自 22.11.0 起虚拟包全部插件化自定义虚拟包只需实现conda_virtual_packages钩子并注册插件。【免费下载链接】condaA system-level, binary package and environment manager running on all major operating systems and platforms.项目地址: https://gitcode.com/GitHub_Trending/co/conda创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表