拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Windows 11编译安装pysqlcipher3:给SQLite加上AES加密

Windows 11编译安装pysqlcipher3:给SQLite加上AES加密

简介:面向Windows 11环境下的Python开发者,这份压缩包提供了pysqlcipher3库的完整编译安装文件,重点解决SQLCipher加密数据库在原生Windows平台编译困难、依赖配置繁琐的问题。资源共69个文件,体积仅153KB,内部以源码为主:25个py文件封装了加密数据库接口与测试代码,18个c文件与20个h文件组成底层C扩展及其头文件,还有rst文档、license授权、cfg配置以及构建脚本等辅助材料。这些辅助文档能帮助快速了解项目背景和版本变化,构建配置则明确了编译入口。目前已有607人学习下载。通过对照源码与构建配置,读者可以避开常见的编译器和依赖库问题,掌握在Windows 11下生成pysqlcipher3扩展模块的完整思路,理解其API调用方式,为在桌面应用中集成SQLite透明加密功能提供可直接落地的参考。无论是初学者还是经验丰富的开发者,均可按需提取使用。

1. Windows 11编译安装pysqlcipher3:给SQLite加一层加密,卡点不在pip而在编译链

windows11编译安装pysqlcipher3这个动作,本质上是在本地把OpenSSL、SQLCipher、Python的C扩展绑定三层东西依次编出来。pysqlcipher3是SQLCipher的Python接口,SQLCipher则是带AES加密能力的SQLite分支,PyPI上针对Windows的现成wheel很少,很多历史二进制包只对应老版本Python,直接pip install往往拉下来一个源码包然后编译失败。与其在源里赌运气,不如自己把这条链完整跑一遍。这个方案适合三类人:要求数据库文件落盘必须加密的;不想让业务数据以明文躺在服务器上的;以及被“PRAGMA key没效果”折磨过、确实需要SQLCipher完整语义的。下面按环境准备、底层依赖、Python绑定、排错、验证的顺序推进。

2. 编译pysqlcipher3的环境准备:Windows 11下的工具链取舍

2.1 为什么是MSVC而不是MinGW

Python的C扩展在Windows上绕不开编译器选择。pysqlcipher3的setup.py基于setuptools,在Windows下默认调用的就是MSVC。python.org官方安装包里的CPython是用MSVC编的,C扩展要和Python解释器共享运行时状态,编译器和ABI必须一致。常见的翻车是装了MinGW后用gcc编C扩展,表面能编过,一旦调用Python C API就崩,或者链接阶段出现一堆undefined symbol。与其事后排查ABI这种玄学,不如一开始就用Visual Studio Build Tools自带的MSVC。

另一个硬理由是SQLCipher源码里保留了SQLite官方的Makefile.msc,这是给MSVC的nmake用的构建脚本,直接就能编。MinGW那套autoconf方案要挂MSYS环境,在Windows 11上又多一个可变因素。所以我的习惯是:Windows下凡是涉及Python C扩展和带codec的SQLite,一律走MSVC这条链,不用MinGW给自己加戏。

2.2 四件套:Git、Python、Perl、NASM

按依赖关系需要四样基础工具,缺一个后面都会卡住。

Git for Windows用来克隆SQLCipher和pysqlcipher3源码,装的时候勾上“Add to PATH”。Python建议用64位官方安装包,3.8到3.12都可以,同样勾上Add Python to PATH。Perl用Strawberry Perl或ActivePerl,OpenSSL的Configure脚本是用Perl写的,机器上没有Perl连OpenSSL的构建配置都起不来。NASM是可选的汇编编译器,OpenSSL配置成VC-WIN64A时默认启用汇编优化,没有NASM会在nmake阶段报错;也可以配置时加no-asm跳过,但那样AES的AES-NI优化会丢掉,SQLCipher加解密性能差距能到数倍,建议还是装。

装完在CMD里确认四样东西都在PATH里:

git --version python --version perl -v nasm -v

git和python没输出版本,多半是安装时没勾PATH;perl没有就去装Strawberry Perl;nasm没有就下载安装包并把安装目录追加进PATH。四行命令都出版本号再继续,少一个后面就是莫名报错。

2.3 打开x64开发者命令行

C扩展编译必须在MSVC环境里做。最省事的是从开始菜单搜“x64 Native Tools Command Prompt for VS 2022”,右键以管理员身份打开。找不到这个快捷方式,说明Visual Studio Build Tools装得不全,需要补“使用C++的桌面开发”工作负载和Windows 11 SDK。

也可以用通用方式手动启动:

call "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat" cl

vcvars64.bat的作用是把MSVC工具链的INCLUDE、LIB、PATH整套环境变量设置到当前终端。cl不带参数会打印编译器版本和使用说明,看到输出说明MSVC环境正常。注意必须用x64版本。Python是64位,OpenSSL和SQLCipher也编64位,混用x86工具集会直接导致LNK1112,后面排错章节会专门讲。

2.4 先把编译目录规划好

编译会产生一堆源码、中间文件和产物,别让它们散落各处。我一般固定这么安排:OpenSSL最终安装到C:\openssl,SQLCipher源码放C:\build\sqlcipher,pysqlcipher3源码放C:\build\pysqlcipher3。路径短、无空格,后面配环境变量时少踩很多引号问题。Windows 11默认用户目录带空格,一旦路径里有空格,perl Configure和nmake都容易出边界错误,短路径能直接规避。

2.5 vcpkg能用,但只适合探路

经常有同行问:用vcpkg install sqlcipher不是更快吗?vcpkg确实能装,它会自己把OpenSSL编出来,然后给一套include和lib。问题是pysqlcipher3的setup.py要找的是SQLCipher的sqlite3.h和sqlite3.lib,vcpkg默认输出的头文件和库位置不够直观,而且经常给出静态库或带特定运行库标志的版本,和Python编译器的/MD标志一旦不一致,链接阶段就是一堆红字。vcpkg适合拿来做可行性验证,真到要给项目锁定版本、随时改参数重编的时候,还是手动编OpenSSL和SQLCipher更可控。手动编的每一步产物在哪、用了什么参数、给谁引用都清清楚楚,排错不用靠猜。

3. 先编底层库:OpenSSL与SQLCipher在Windows 11下的构建顺序

3.1 为什么要先OpenSSL后SQLCipher

SQLCipher的加密后端默认就是OpenSSL。SQLCipher源码里的sqlite3.c会调用openssl/evp.h里的EVP接口做AES-256-CBC加解密。所以SQLCipher编译前必须已经有OpenSSL的include和lib,否则连头文件都找不到。先编OpenSSL,再编SQLCipher,最后编pysqlcipher3,这个顺序不能乱。反过来先把SQLCipher编出来,基本不可能。

3.2 克隆SQLCipher源码并固定版本

不推荐下载zip,git clone可以拿到完整tag历史,后续切版本、看差异、打补丁都方便:

cd C:\build git clone https://github.com/sqlcipher/sqlcipher.git cd sqlcipher git tag --list "v4*"

git tag --list "v4*"会列出4.x的所有稳定tag,挑最新的一个checkout即可。固定版本的意义在于可复现,过几个月再编一次,tag不同,依赖行为可能有差异。生产项目建议把用到的tag记录在构建脚本注释里。

3.3 编译OpenSSL:perl Configure与nmake

在已经激活vcvars64的终端里执行:

cd C:\build\openssl perl Configure VC-WIN64A --prefix=C:\openssl --openssldir=C:\openssl\ssl nmake nmake install

VC-WIN64A是OpenSSL在Windows MSVC下64位构建的固定配置名。--prefix指定最终安装目录,后续nmake install会把头文件放到C:\openssl\include、库放到C:\openssl\lib、DLL放到C:\openssl\bin。--openssldir设成C:\openssl\ssl,主要是让openssl.exe运行时能按固定路径找到openssl.cnf。正式环境建议在nmake之后补一条nmake test,OpenSSL自测要跑十几分钟,但能省掉后续“SQLCipher编译失败到底是谁的锅”的排查时间。编译成功的标志是C:\openssl\lib下出现libcrypto.lib和libssl.lib,以及C:\openssl\bin里的libcrypto-3-x64.dll。

如果nmake阶段报找不到nasm,两种处理:装NASM后重开终端再编,或者回到Configure加no-asm。后一种不推荐,SQLCipher每个数据库页都要过一遍AES,没有AES-NI汇编优化的性能损失直接反映在业务查询延迟上。

3.4 用nmake编SQLCipher:Makefile.msc的路子

SQLCipher源码自带的Makefile.msc就是给MSVC用的。区别在于SQLCipher的sqlite3.c默认开启了codec实现,并依赖OpenSSL头文件,所以编译前要把OpenSSL路径通过环境变量传给MSVC:

cd C:\build\sqlcipher set INCLUDE=C:\openssl\include;%INCLUDE% set LIB=C:\openssl\lib;%LIB% nmake /f Makefile.msc

Makefile.msc默认会生成sqlite3.dll、sqlite3.lib、sqlite3.exe等文件。INCLUDE和LIB这两个环境变量,是MSVC在编译和链接阶段搜索头文件与库的默认路径。只设include不设lib,编译能过但链接会报LNK1181打不开libcrypto.lib,所以两条必须一起配。

SQLCipher 4.x默认编译时已经带SQLITE_HAS_CODEC和SQLCIPHER_CRYPTO_OPENSSL宏,不需要手动加。如果遇到openssl头文件都找到了、但EVP函数链接不上的情况,去确认源码里有没有这两个宏,而不是盲目加include。

3.5 验证这一层产物

编译完别急着编Python层,先检查三个文件是否就位:

dir C:\openssl\lib\libcrypto.lib dir C:\build\sqlcipher\sqlite3.lib dir C:\build\sqlcipher\sqlite3.dll
  • libcrypto.lib是OpenSSL的导入库,链接阶段要用
  • sqlite3.lib是SQLCipher的导入库,pysqlcipher3链接它
  • sqlite3.dll是运行时DLL,Python import pysqlcipher3之后会加载它,同时加载libcrypto-3-x64.dll
产物位置用途
libcrypto.libC:\openssl\libSQLCipher和pysqlcipher3链接时用
libcrypto-3-x64.dllC:\openssl\binPython进程运行时要能找到
sqlite3.libC:\build\sqlcipherpysqlcipher3链接时用
sqlite3.dllC:\build\sqlcipherPython进程运行时要能找到

这一层最常见的报错有两个:一是nmake: command not found,说明vcvars64没在当前终端激活;二是找不到openssl/evp.h或libcrypto.lib,说明INCLUDE和LIB没配对。这两个问题在第5章展开。

4. 再编Python绑定:pysqlcipher3的setup.py参数与wheel安装

4.1 先读setup.py,别让黑匣子背锅

很多人习惯拿到包就pip install,失败后一头雾水。其实pysqlcipher3的setup.py逻辑不复杂:把PySQLite改写的C文件编译成扩展模块,链接时找sqlite3.lib,头文件找sqlite3.h。难点在于它不会自动知道SQLCipher装在哪里,需要手动把路径指给它。

克隆源码:

cd C:\build git clone https://github.com/pysqlcipher/pysqlcipher3.git cd pysqlcipher3

克隆完先打开setup.py,重点看它向哪里搜索include和lib。知道它用什么顺序找头文件,排错时才能判断“会不会先找到别处的sqlite3.h”。这个文件不长,但值得读完再动手,后面所有路径问题都跟它相关。

4.2 把SQLCipher和OpenSSL的路径喂给MSVC

pysqlcipher3的setup.py最终还是要走MSVC编译器,而MSVC搜索头文件和库时INCLUDE、LIB环境变量优先级很高。最通用的做法就是设置两个环境变量:

set INCLUDE=C:\build\sqlcipher;C:\openssl\include;%INCLUDE% set LIB=C:\build\sqlcipher;C:\openssl\lib;%LIB%

这个顺序有讲究。C:\build\sqlcipher放在最前面,是为了确保include找到的是SQLCipher的sqlite3.h,而不是机器上其他SQLite开发包里的同名头文件。如果把系统SQLite路径放前面,编译照样能过,但连出来的是普通SQLite,跑PRAGMA key直接无效。这个坑我踩过一次,属于编译期不报错、运行期才暴露的问题。

提示:INCLUDE环境变量里SQLCipher的路径必须排在其他SQLite路径前面。这个顺序就是加密是否生效的分水岭。

部分历史版本的setup.py还支持--with-includes和--with-libs自定义参数,直接把路径传给构建器。新版setuptools对自定义参数的兼容时好时坏,遇到unrecognized option就用环境变量方案,效果一致。

4.3 build_ext编译:inplace与force的使用场景

编译命令:

python setup.py build_ext --inplace --force

--inplace表示生成的pyd落在当前源码目录,方便直接import测试。--force是强制重新编译。改过setup.py、换过OpenSSL版本或调整过INCLUDE/LIB顺序后必须加,否则MSVC会拿缓存的对象文件偷懒,导致换了依赖还报旧错。

编译成功后会看到C:\build\pysqlcipher3目录下出现pysqlcipher3.cp312-win_amd64.pyd之类的文件。文件名里的cp312对应Python 3.12,如果是3.11就是cp311。看到这个文件说明C扩展构建这一关过了,但还没到安装阶段。

4.4 打包成wheel再安装

直接把pyd留在源码目录也能跑,但不规范。规范做法是先打wheel,再pip安装,这样site-packages里是干净的一个包:

python setup.py bdist_wheel pip install dist\pysqlcipher3-*.whl

bdist_wheel生成的whl会带平台标签,Windows下的64位包一般是win_amd64。pip install这个whl会把它装进当前Python环境的site-packages。装完立刻验证整个链路是否真的打通:

python -c "from pysqlcipher3 import dbapi2; print(dbapi2.connect(':memory:').execute('PRAGMA cipher_version').fetchone())"

能输出版本号说明链接的确实是SQLCipher。PRAGMA cipher_version是SQLCipher独有的语法,官方SQLite不认识,能查到就说明没被“狸猫换太子”。如果这里报错,回到第5章的5.4条查头文件顺序。

4.5 关于pip install .的坑

不少教程建议直接pip install .,我不推荐。pip install .会先构建再安装,构建报错时日志和进程混杂在一起,定位困难。而且pip在隔离构建环境时可能拿不到你设置好的INCLUDE和LIB,导致刚才怎么编都编过的代码,一到pip就找不到头文件。先build_ext --inplace确认编译无误,再bdist_wheel出包,最后pip install whl,每一步结果明确,真出问题也能立刻知道是哪一步。这条顺序对_setuptools_新版环境尤其重要,某些Python 3.12配老setuptools的组合,直接pip install .会在构建后端阶段就崩掉,根本走不到编译环节。

5. pysqlcipher3在Windows 11编译安装的报错排查:5个高频坑与对应修法

下面五条都是我在Windows 11上实际踩过的,按“现象→原因→解决”写清楚。

5.1 C1083:打不开openssl/evp.h

现象:编译到SQLCipher相关C文件时报fatal error C1083: Cannot open include file: 'openssl/evp.h': No such file or directory。

原因:MSVC的include搜索路径里没有C:\openssl\include。常见情况是编译SQLCipher时只配置了SQLCipher路径,漏掉OpenSSL;或者OpenSSL执行的是nmake而不是nmake install,include目录根本没生成。

解决:先确认C:\openssl\include\openssl\evp.h存在,然后设置:

set INCLUDE=C:\openssl\include;%INCLUDE%

如果再SQLCipher那层报错,就在sqlcipher目录下设置;如果在pysqlcipher3那层报错,就在pysqlcipher3目录下设置。两边都要有。只配一边就会出现“这个工程过了,那个工程又挂”。

5.2 LNK1181:打不开libcrypto.lib

现象:链接阶段报LNK1181: cannot open input file 'libcrypto.lib'。

原因:LIB环境变量里没有OpenSSL的lib目录。MSVC链接器搜索.lib文件时只看LIB环境变量和命令行显式参数,不会自己去C盘翻。

解决:

set LIB=C:\openssl\lib;%LIB%

然后重新build_ext。注意INCLUDE和LIB要同时重新设一遍,两个变量是配套的。只设一个,会出现头文件找到了、库又找不到的交替报错。我见过有人在这两个变量之间反复横跳了半小时,其实把两个set命令写在同一个bat里一次执行就行。

5.3 编译成功,import报DLL load failed

现象:python -c "import pysqlcipher3"报ImportError: DLL load failed while importing pysqlcipher3: 找不到指定的模块。

原因:pysqlcipher3.pyd链接了sqlite3.dll和libcrypto-3-x64.dll,但Python进程运行时按PATH和当前目录找不到这些DLL。Windows加载DLL的搜索顺序不会自动包含C:\build\sqlcipher和C:\openssl\bin。

解决:把这两个目录加进PATH,或者更推荐的做法是把sqlite3.dll、libcrypto-3-x64.dll、libssl-3-x64.dll复制到site-packages里pysqlcipher3包的旁边。我一般用复制方案,部署到别的机器时不会因为目标机PATH差异再翻车。复制完再import,如果还报找不到模块,用依赖检查工具看pyd到底缺哪个DLL。

5.4 能import,也能连库,但PRAGMA key后数据根本没加密

现象:整个编译链路全过,代码里执行PRAGMA key='...',再插入数据,用普通sqlite3命令行打开同一个文件居然能读到明文。

原因:pysqlcipher3编译时include到的sqlite3.h不是SQLCipher的,链接的sqlite3.lib也不是SQLCipher的。最典型的是机器上装了其他SQLite开发包,其include和lib路径在INCLUDE/LIB里排在SQLCipher前面。编译器不会报错,因为普通SQLite和SQLCipher的API签名在基本层面一致,只是SQLCipher多出codec的支持,普通SQLite直接忽略PRAGMA key。

解决:检查INCLUDE第一项是不是C:\build\sqlcipher,LIB第一项是不是C:\build\sqlcipher。不确定时,临时把环境变量里其他SQLite路径清掉再重编。验证方法就是4.4那行PRAGMA cipher_version。能输出版本才是真的SQLCipher,否则编了个寂寞。

5.5 LNK1112/LNK2038:32位和64位混用

现象:链接时报LNK1112: module machine type 'x64' conflicts with target machine type 'x86',或者LNK2038: mismatch detected for '_MSC_VER'。

原因:用了非x64的VS命令行,或者OpenSSL/SQLCipher是x64,但Python是32位版本;也可能是OpenSSL和SQLCipher用的MSVC工具集版本不一致。

解决:先确认Python架构:

python -c "import struct; print(struct.calcsize('P')*8)"

输出64说明是64位Python。然后打开“x64 Native Tools Command Prompt for VS 2022”,把三个库全部在同一套MSVC下重新编。注意vcvars64.bat设置的环境变量只对当前终端会话有效,新开一个终端忘记重新call,就会退回系统默认编译器,混入不同版本的_MSC_VER直接触发LNK2038。这个问题最容易在“睡了一觉,第二天继续编”的时候出现,别问我怎么知道的。

6. 编译后的验证与进阶:让pysqlcipher3在Windows 11上稳定服役

6.1 最小加密读写验证

编译安装完成后,第一件事是跑一个完整的加密读写闭环:

from pysqlcipher3 import dbapi2 as sqlite conn = sqlite.connect("secret.db") cur = conn.cursor() cur.execute("PRAGMA key='change-me'") cur.execute(""" CREATE TABLE IF NOT EXISTS accounts ( id INTEGER PRIMARY KEY, email TEXT NOT NULL ) """) cur.execute("INSERT INTO accounts(email) VALUES (?)", ("alice@example.com",)) conn.commit() conn.close()

关键点:PRAGMA key必须在任何建表、写入之前执行,否则表结构会落在未加密的数据库页上,整个文件头就是明文状态。连接关闭后用系统自带sqlite3命令行打开secret.db,如果提示file is not a database,说明加密生效。如果还能正常打开看到表和明文,回到第5章排查链接的头文件和库。

6.2 用dumpbin检查DLL依赖

部署前可以用Visual Studio自带的dumpbin查看pyd的依赖清单:

dumpbin /dependents C:\build\pysqlcipher3\pysqlcipher3.cp312-win_amd64.pyd

输出里会列出sqlite3.dll、libcrypto-3-x64.dll、VCRUNTIME140.dll等。VCRUNTIME140.dll是MSVC运行时,目标机器缺的话装VC++ Redistributable即可。sqlite3.dll和libcrypto-3-x64.dll要跟pyd一起分发,复制到pysqlcipher3所在目录是最省心的部署方式。这条命令比任何理论分析都直观,运行报错时能直接看到缺谁。

6.3 一个值得留住的习惯

我现在的做法是把第2章到第4章的全部命令固化成一个setup_env.cmd脚本,里面写好vcvars64的调用、INCLUDE和LIB的设定、OpenSSL和SQLCipher的nmake命令。每次换机器、重装系统后双击执行,十分钟恢复环境。第一次折腾的时候没有留脚本,半年后换电脑全部重来,一个下午就没了,属于标准的“编译一时爽,重编火葬场”。如果要把功能交付给团队,记得把sqlite3.dll、libcrypto-3-x64.dll和pysqlcipher3的whl一起放进交付物,而不是让每个人都从源码编一遍。给同行省两小时,比写十页文档都实在。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表