- 构建工具
- 开发工具
- CLI
【免费下载链接】CMake
Mirror of CMake upstream repository
UseSWIG是 CMake 官方模块,用于在构建系统中集成 SWIG 中的底层实现原理(自定义命令生成、支持文件管理、依赖跟踪与各语言目标命名规则),能够直接在真实项目中编写可复制的 SWIG 绑定构建配置。
前置条件:先 FindSWIG 再 include(UseSWIG)
UseSWIG模块本身不负责查找 SWIG 可执行文件,官方文档明确说明“假设 FindSWIG 模块已被加载”。因此标准用法是:
find_package(SWIG COMPONENTS python) # 先定位 SWIG 与目标语言支持 if(SWIG_FOUND) include(UseSWIG) swig_add_library(mymod LANGUAGE python SOURCES mymod.i) endif()find_package(SWIG ...)由 FindSWIG 提供,它会解析swig -version与swig -swiglib输出,产出以下结果变量:
SWIG_FOUND:是否找到(指定版本的)SWIG 及所请求的语言组件;SWIG_VERSION:SWIG 版本号;SWIG_<lang>_FOUND:使用COMPONENTS/OPTIONAL_COMPONENTS时,每个小写目标语言是否可用;SWIG_DIR:SWIG 安装的Lib目录路径(swig -swiglib的结果),实现中会以SWIG_LIB=${SWIG_DIR}环境变量传给 swig 调用;SWIG_EXECUTABLE(缓存变量):SWIG 可执行文件路径,可手工指定。
COMPONENTS中的语言名必须是小写,且与swig_add_library的LANGUAGE参数一致(如python、perl5)。也支持版本范围与可选组件:
find_package(SWIG 4.0 COMPONENTS python OPTIONAL_COMPONENTS fortran)swig_add_library:模块的核心命令
该命令自 CMake 3.8 引入,用于“以给定名称和指定语言定义 swig 模块”,完整语法为:
swig_add_library(<name> [TYPE <SHARED|MODULE|STATIC|USE_BUILD_SHARED_LIBS>] LANGUAGE <language> [NO_PROXY] [DEBUG_POSTFIX <postfix>] [OUTPUT_DIR <directory>] [OUTFILE_DIR <directory>] SOURCES <file>... )由swig_add_library创建的目标拥有与 add_library 目标相同的能力,可直接用于任何接受目标的命令(例如target_link_libraries)。
TYPE:库类型
SHARED、MODULE、STATIC语义与add_library完全一致;指定USE_BUILD_SHARED_LIBS时,根据当前 BUILD_SHARED_LIBS 变量值为ON或OFF决定生成SHARED或STATIC库;未指定时默认MODULE(动态加载模块)。实现中(Modules/UseSWIG.cmake),当类型为MODULE时还会自动设置NO_SONAME ON,避免模块携带 soname。
LANGUAGE:目标语言
指定 SWIG 的封装目标语言,版本演进如下:
- CMake 3.1 起支持 Go 和 Lua;
- CMake 3.2 起支持 R;
- CMake 3.18 起支持 Fortran。
模块内部会通过SWIG_MODULE_INITIALIZE宏将语言名转大写与小写,分别用于生成文件和 swig 的-<lang>命令行旗标。语言名无法识别时会直接FATAL_ERROR(SWIG Error: Language "..." not found)。
NO_PROXY:跳过代理层
CMake 3.12 引入,对应 swig 的-noproxy选项,阻止生成目标语言的代理(proxy)包装层。例如 Python 模式下,正常会生成一个mymod.py代理文件(内含import _mymod),而NO_PROXY会跳过该层。实现中(Modules/UseSWIG.cmake)会将该标记并入SWIG_MODULE_<name>_EXTRA_FLAGS,且若CMAKE_SWIG_FLAGS已含-noproxy则不重复追加。
DEBUG_POSTFIX:调试配置后缀
CMake 4.2 引入,用于管理目标的 DEBUG_POSTFIX 属性,目前仅对python语言有意义。若全局属性 DEBUG_CONFIGURATIONS 已定义,则为每个调试配置定义<CONFIG>_POSTFIX目标属性;未定义时默认使用DEBUG(实现见 Modules/UseSWIG.cmake 与 L1005-L1009)。
OUTPUT_DIR 与 OUTFILE_DIR:输出目录控制
两者均为 CMake 3.12 引入,分别对应 swig 的-outdir(语言特定文件输出目录)与-o(生成的 C/C++ 源文件输出目录)。
OUTPUT_DIR的取值优先级为:
- 命令的
OUTPUT_DIR选项; CMAKE_SWIG_OUTDIR变量;- 未指定时取决于
UseSWIG_MODULE_VERSION:值为 1 或未定义时输出到 CMAKE_CURRENT_BINARY_DIR;值为 2 时使用专有目录,其路径可通过只读目标属性SWIG_SUPPORT_FILES_DIRECTORY获取。
OUTFILE_DIR的取值优先级为:命令选项OUTFILE_DIR→ 变量SWIG_OUTFILE_DIR→ 否则回退到OUTPUT_DIR或CMAKE_SWIG_OUTDIR。
重要提示:当
UseSWIG_MODULE_VERSION为 2 时,强烈建议为每个目标使用独立的专有输出目录。因为目标构建时输出目录内容会被整体清空(见下文支持文件管理),共用一个目录会在不同目标间互相干扰、甚至误删文件。
SOURCES:接口文件识别
SOURCES中扩展名为.i的文件会被识别为 SWIG 工具输入,其余文件按常规方式编译链接。该默认行为可通过变量SWIG_SOURCE_FILE_EXTENSIONS(CMake 3.14 起)覆盖。实现中(Modules/UseSWIG.cmake)会把扩展名列表拼成正则过滤出 SWIG 输入,若一个都没有则报错SWIG_ADD_LIBRARY: no SWIG interface files specified。
版本行为变化与注意事项
- CMake 3.13:当策略 CMP0078 为
NEW时,命令创建名为<name>的标准目标;旧行为则使用不同目标名,并存入SWIG_MODULE_<name>_REAL_NAME变量。 - CMake 3.15:替代库名(例如通过 OUTPUT_NAME 属性设置)会传递给 Python 和 CSharp 包装库。
- CMake 3.21:当策略 CMP0122 为
NEW时,CSharp 生成的库使用标准命名约定,否则沿用旧行为。 - 多配置生成器:模块不支持 SWIG 生成的“随配置变化”的文件,所有构建配置必须产生相同的生成源文件。
- Makefile 生成器:若某些源文件的
USE_SWIG_DEPENDENCIES属性为FALSE,模块不追踪文件依赖,需要依赖<name>_swig_compilation自定义目标来确保 SWIG 生成文件已存在;其他生成器可直接依赖 SWIG 生成的源文件。
源文件属性:在调用 swig_add_library 之前设置
SWIG 输入文件(.i)上的源文件属性必须在调用swig_add_library之前设置,以便生成文件正确继承所需设置:
| 属性 | 引入版本 | 说明 |
|---|---|---|
CPLUSPLUS | — | 以 C++ 模式调用 SWIG(-c++),生成.cxx而非.c |
SWIG_FLAGS | 3.12 弃用 | 向 SWIG 可执行文件传递自定义旗标(已被下列细粒度属性取代) |
INCLUDE_DIRECTORIES/COMPILE_DEFINITIONS/COMPILE_OPTIONS | 3.12 | 追加 SWIG 编译旗标,语义同 INCLUDE_DIRECTORIES 等属性 |
USE_TARGET_INCLUDE_DIRECTORIES | 3.13 | 为TRUE时把目标 INCLUDE_DIRECTORIES 转发给 SWIG;FALSE时忽略;未设置时参考目标属性SWIG_USE_TARGET_INCLUDE_DIRECTORIES |
GENERATED_INCLUDE_DIRECTORIES/GENERATED_COMPILE_DEFINITIONS/GENERATED_COMPILE_OPTIONS | 3.12 | 作用于生成的 C/C++ 文件,填充生成文件的INCLUDE_DIRECTORIES、COMPILE_DEFINITIONS、COMPILE_OPTIONS属性 |
DEPENDS | 3.12 | 为源文件指定额外依赖 |
USE_SWIG_DEPENDENCIES | 3.20 | 为TRUE时由 swig 工具自身生成隐式依赖,仅对 Makefile、Ninja、Xcode(3.21 起)和 Visual Studio(3.22 起)生成器有意义,默认FALSE |
SWIG_MODULE_NAME | — | 指定目标语言中的实际模块导入名,当无法从源码自动扫描或与文件基名不同时必须设置 |
OUTPUT_DIR | 3.19 | 为该源文件指定语言特定文件的输出目录(-outdir) |
OUTFILE_DIR | 3.19 | 为该源文件指定生成源文件的输出目录(-o) |
典型示例:
set_property(SOURCE mymod.i PROPERTY CPLUSPLUS ON) set_property(SOURCE mymod.i PROPERTY SWIG_MODULE_NAME mymod_realname) swig_add_library(mymod LANGUAGE python SOURCES mymod.i)关于SWIG_MODULE_NAME:从 CMake 3.14 起,若策略 CMP0086 为NEW,会向 SWIG 编译器传递-module <module_name>;否则模块名依赖 SWIG 自行从%module指令扫描。模块名自动扫描逻辑见 Modules/UseSWIG.cmake:先读取源属性SWIG_MODULE_NAME,其次用正则匹配.i文件中的%module foo语法,再次匹配%module (options=...) foo语法,最后回退到文件基名。
目标属性:对整个 SWIG 模块统一配置
目标级属性可对模块内所有 SWIG 输入文件统一生效:
| 属性 | 引入版本 | 说明 |
|---|---|---|
SWIG_INCLUDE_DIRECTORIES/SWIG_COMPILE_DEFINITIONS/SWIG_COMPILE_OPTIONS | 3.12 | 作用于所有 SWIG 输入文件,语义同目标属性 INCLUDE_DIRECTORIES、COMPILE_DEFINITIONS、COMPILE_OPTIONS |
SWIG_USE_TARGET_INCLUDE_DIRECTORIES | 3.13 | 为TRUE时转发目标INCLUDE_DIRECTORIES给 SWIG;FALSE或未定义时忽略;可被源属性USE_TARGET_INCLUDE_DIRECTORIES覆盖 |
SWIG_GENERATED_INCLUDE_DIRECTORIES/SWIG_GENERATED_COMPILE_DEFINITIONS/SWIG_GENERATED_COMPILE_OPTIONS | 3.12 | 填充所有生成的 C/C++ 文件的INCLUDE_DIRECTORIES、COMPILE_DEFINITIONS、COMPILE_FLAGS属性 |
SWIG_DEPENDS | 3.12 | 为所有 SWIG 输入文件增加依赖 |
官方示例:
set(UseSWIG_TARGET_NAME_PREFERENCE STANDARD) swig_add_library(mymod LANGUAGE python SOURCES mymod.i) set_property(TARGET mymod PROPERTY SWIG_COMPILE_DEFINITIONS MY_DEF1 MY_DEF2) set_property(TARGET mymod PROPERTY SWIG_COMPILE_OPTIONS -bla -blb)只读目标属性:获取支持文件信息
以下两个是输出型(只读)属性,用于查询 SWIG 接口编译产生的支持文件信息:
SWIG_SUPPORT_FILES(3.12 起):SWIG 编译期间生成的包装文件列表。例如:set(UseSWIG_TARGET_NAME_PREFERENCE STANDARD) swig_add_library(mymod LANGUAGE python SOURCES mymod.i) get_property(support_files TARGET mymod PROPERTY SWIG_SUPPORT_FILES)注意:只列出最主要的支持文件;若使用
%template等 SWIG 高级特性,关联支持文件可能未列出,此时优先使用SWIG_SUPPORT_FILES_DIRECTORY属性处理支持文件。SWIG_SUPPORT_FILES_DIRECTORY(3.12 起):支持文件生成目录。当源属性OUTPUT_DIR被定义时,该属性可能包含多个目录(实现见 Modules/UseSWIG.cmake,所有去重后的输出目录都会追加进该属性)。
支持文件清单的组装逻辑(Modules/UseSWIG.cmake)依据模块头部的语言扩展名表按后缀过滤生成源:例如 Python 为.py、Java 为.java与JNI.java、CSharp 为.cs与PINVOKE.cs、Perl/Perl5 为.pm(见 L424-L428)。
CMake 变量:全局定制 swig_add_library 与 SWIG
| 变量 | 引入版本 | 说明 |
|---|---|---|
UseSWIG_MODULE_VERSION | 3.12 | 取 1 或未定义:应用旧行为;取 2:采用关于支持文件的新策略——SWIG 接口编译前会清空支持文件输出目录。取值非法时报错 |
CMAKE_SWIG_FLAGS | — | 为所有 swig 调用追加旗标 |
CMAKE_SWIG_OUTDIR | — | 指定语言特定文件输出目录(-outdir),优先级低于命令OUTPUT_DIR选项 |
SWIG_OUTFILE_DIR | 3.8 | 指定生成源文件输出目录;未指定时使用CMAKE_SWIG_OUTDIR |
SWIG_MODULE_<name>_EXTRA_DEPS | — | 为<name>生成的模块指定额外依赖 |
SWIG_SOURCE_FILE_EXTENSIONS | 3.14 | 覆盖默认仅将.i视为 SWIG 源的行为,例如set(SWIG_SOURCE_FILE_EXTENSIONS ".i" ".swg") |
SWIG_USE_SWIG_DEPENDENCIES | 3.20 | 为TRUE时由 swig 自身生成隐式依赖,仅对 Makefile、Ninja、Xcode(3.21 起)、Visual Studio(3.22 起)生成器有意义,默认FALSE;未定义的源文件属性USE_SWIG_DEPENDENCIES会以该变量值初始化 |
另外,模块还维护UseSWIG_TARGET_NAME_PREFERENCE变量(LEGACY或STANDARD)控制目标命名:STANDARD使用<name>原名,LEGACY下 Python 非NO_PROXY模块的目标名带_前缀(_<name>),因为生成的module.py含import _modulename语句,需要对应的_modulename.so(Unix)/_modulename.pyd(Windows)二进制(见 Modules/UseSWIG.cmake)。策略CMP0078为NEW时强制为STANDARD。
已废弃命令:swig_link_libraries
swig_link_libraries(<name> <item>...)自 CMake 3.13 起弃用,应改用带标准目标名的 target_link_libraries,或在旧目标命名下使用${SWIG_MODULE_<name>_REAL_NAME}。新命令与target_link_libraries能力相同:
- 策略
CMP0078为NEW时,swig_add_library创建标准目标<name>,应直接使用target_link_libraries; - 旧行为(
CMP0078为OLD且UseSWIG_TARGET_NAME_PREFERENCE为"LEGACY",或 CMake 3.12 之前)下,推荐使用target_link_libraries(${SWIG_MODULE_<name>_REAL_NAME} ...)而非该命令。
实现中(Modules/UseSWIG.cmake)还兼容了SWIG_ADD_MODULE宏——调用它会打印弃用警告并转调swig_add_library。
源码级原理:SWIG 编译是如何接入构建系统的
自定义命令与生成文件命名
核心函数SWIG_ADD_SOURCE_TO_MODULE(Modules/UseSWIG.cmake)为每个.i文件生成一个add_custom_command:先创建输出目录,再以SWIG_LIB=${SWIG_DIR}环境变量调用${SWIG_EXECUTABLE},依次拼接-<lang>、源文件旗标(含-I、-D前缀转换的生成器表达式)、-outdir、-c++(CPLUSPLUS 时)、-module(CMP0086 NEW 时)、额外旗标、-o <生成文件>,最后是输入文件本身。
生成的主源文件名规则为:
<outfiledir>/<源文件基名><语言大写>_wrap.c # C 模式 <outfiledir>/<源文件基名><语言大写>_wrap.cxx # C++ 模式(SWIG_CXX_EXTENSION)把语言名拼入文件名是为了让同一个.i文件可被封装为多种语言而互不冲突。生成文件与额外支持文件均被标记GENERATED 1,并写入ADDITIONAL_CLEAN_FILES。
输出目录与支持文件管理(UseSWIG_MODULE_VERSION 2)
当UseSWIG_MODULE_VERSION大于 1 时,每个源文件使用专有工作目录<workingdir>/<源文件基名>.files,并在自定义命令中插入两步脚本调用(Modules/UseSWIG.cmake):
ACTION=CLEAN:先清空输出目录中的旧生成文件,再删除工作目录,防止过时文件残留;ACTION=COPY:编译完成后把工作目录中的新文件复制回输出目录。
这两步由 Modules/UseSWIG/ManageSupportFiles.cmake 实现(GLOB_RECURSE收集文件 →file(REMOVE)/file(COPY))。这正是文档强调“每个目标使用独立输出目录”的原因。
依赖跟踪的两种策略
- 默认关闭:
USE_SWIG_DEPENDENCIES为FALSE时,Makefile 生成器额外引入时间戳机制(__SWIG_COMPUTE_TIMESTAMP,见 Modules/UseSWIG.cmake):自定义命令输出为<name><LANGUAGE>.stamp时间戳文件,生成源作为BYPRODUCTS,并利用IMPLICIT_DEPENDS CXX做隐式依赖;同时创建<name>_swig_compilation自定义目标依赖这些时间戳(L954-L958),解决依赖文件被移除时的重建问题(对应上游 issue #16830)。 - 开启时:
USE_SWIG_DEPENDENCIES为TRUE(仅 Makefile/Ninja/Xcode/Visual Studio)时,swig 以-MD -MF <name>.d生成 depfile,通过自定义命令的DEPFILE机制接入 Ninja 等的依赖扫描。
各语言目标命名规则
SWIG_ADD_LIBRARY函数后半段(Modules/UseSWIG.cmake)针对不同语言调整目标 PREFIX/SUFFIX 属性,使产物名符合各语言运行时约定:
- Octave:
PREFIX ""、SUFFIX ".oct"; - Go:
PREFIX ""; - Java:macOS 上
SUFFIX ".jnilib",MINGW/CYGWIN/MSYS 上PREFIX ""(对应System.loadLibrary("LIBRARY")的查找规则); - Lua(MODULE 类型):
PREFIX ""; - Python:非 NO_PROXY 时
PREFIX "_",Windows 上SUFFIX ".pyd"(自 Python 2.5 起扩展模块后缀),并应用DEBUG_POSTFIX; - R / Ruby / Perl / Perl5:
PREFIX "",Ruby 与 Perl 在 macOS 上分别使用.bundle、.dylib后缀; - CSharp:策略 CMP0122 为
NEW时保持默认前缀,否则PREFIX ""(macOS 上SUFFIX ".dylib"); - Fortran:不覆盖库前缀。
CSharp 与 Python 的特殊旗标
- CSharp 模式下自动补
-dllimport $<TARGET_FILE_BASE_NAME:...>,确保生成代码里的DllImport名称与 CMake 创建的库名一致(Modules/UseSWIG.cmake); - Python 单输入文件且非 NO_PROXY 时自动补
-interface旗标,使代理代码中的名称与库名匹配(L662-L669)。
测试与验证:RunCMake/UseSWIG
仓库在 Tests/RunCMake/UseSWIG 提供针对策略行为的回归测试,是理解模块行为边界的直接参考:
CMP0078-NEW/OLD/WARN.cmake与CMP0078-common.cmake:验证新旧目标命名行为。公共测试文件设置CMP0086 NEW、指定SWIG_EXECUTABLE与SWIG_DIR后include(UseSWIG)并调用swig_add_library(example LANGUAGE python TYPE MODULE SOURCES example.i),随后打印PREFIX与SWIG_MODULE_example_REAL_NAME,对照-stdout.txt/-stderr.txt期望输出;CMP0086-NEW/OLD/WARN.cmake:验证SWIG_MODULE_NAME是否传递-module旗标;CMP0122-NEW/OLD/WARN.cmake与-check.cmake:验证 CSharp 目标命名约定;example.i(%module example)与runme.py:最小 Python 绑定示例;SetPOSTFIX.cmake:验证调试后缀设置。
这些测试同时展示了最小可用配置形态:cmake_minimum_required+project(... C)+include(<测试>.cmake),再配合SWIG_EXECUTABLE变量即可在 CI 中模拟 SWIG 存在的情形。
最小实战模板
综合以上内容,一个完整的 Python 绑定项目只需:
cmake_minimum_required(VERSION 3.20) project(mypybind CXX) find_package(SWIG 4.0 COMPONENTS python REQUIRED) include(UseSWIG) set(UseSWIG_MODULE_VERSION 2) # 启用支持文件目录管理 # 源文件属性必须在 swig_add_library 之前设置 set_property(SOURCE mymod.i PROPERTY CPLUSPLUS ON) set_property(SOURCE mymod.i PROPERTY SWIG_MODULE_NAME mymod) swig_add_library(mymod TYPE MODULE LANGUAGE python SOURCES mymod.i ) target_link_libraries(mymod PRIVATE MyCppLib) target_include_directories(mymod PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) # 查询生成的支持文件(只读属性) get_property(_swig_support TARGET mymod PROPERTY SWIG_SUPPORT_FILES) message(STATUS "SWIG support files: ${_swig_support}")构建后即可在输出目录获得mymod.py(代理层)与_mymod.so/_mymod.pyd(二进制扩展),完成一次完整的“C/C++ → Python”自动封装流程。
适用前提与限制:以上行为以当前仓库(Modules/UseSWIG.cmake)为准;多配置生成器不支持随配置变化的生成文件,Makefile 生成器默认不跟踪 SWIG 隐式依赖(需依赖
<name>_swig_compilation目标或显式开启USE_SWIG_DEPENDENCIES),使用UseSWIG_MODULE_VERSION 2时务必为每个目标配置独立输出目录。
- 构建工具
- 开发工具
- CLI
【免费下载链接】CMake
Mirror of CMake upstream repository
相关推荐
Apache OpenDAL™ 多语言绑定详解:C、C++、Java、Python 等20+语言支持
Apache OpenDAL™ 多语言绑定详解:C、C++、Java、Python 等20+语言支持 Apache OpenDAL™ 是一个强大的数据访问层项目
数据存储后端NumPy 与 SWIG 完全指南:用 numpy.i 为 C/C++ 数组自动生成 Python 封装
NumPy 与 SWIG 完全指南:用 numpy.i 为 C/C++ 数组自动生成 Python 封装 SWIG(Simplified Wrapper and
科学计算数据分析动漫下载加速终极指南:如何用专业Tracker列表实现500%速度提升
动漫下载加速终极指南:如何用专业Tracker列表实现500%速度提升 还在为动漫资源下载速度慢如蜗牛而烦恼吗? 动漫Tracker加速 项目为您提供了一套完整
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考