这里写目录标题
1、打包工具
在Python中,项目打包和跨平台运行通常涉及以下几个主要方面:打包工具、依赖管理和跨平台兼容性。让我们一一来看。
打包工具:
Python中常用的打包工具有多个选择,其中两个主要的是 setuptools 和 PyInstaller。
-
1.setuptools: 主要用于将Python代码打包成可发布的安装包(例如.tar.gz、.whl),并可以通过PyPI进行分发。它可以管理项目的依赖项,并生成安装脚本。
使用 setuptools 可以创建一个 setup.py 文件,其中包含项目的元数据和安装要求。然后,通过运行以下命令来构建和安装项目:python setup.py sdist # 创建源分发包 python setup.py bdist_wheel # 创建Wheel分发包 python setup.py install # 安装项目
-
2.PyInstaller: 主要用于将Python代码打包成可执行文件,这样用户无需安装Python解释器即可运行应用程序。PyInstaller会将Python代码和依赖项打包成一个独立的可执行文件,适合发布和分发给终端用户。
使用PyInstaller,你可以通过以下命令来打包你的Python项目:pyinstaller --onefile your_script.py # 打包成可执行文件
–onefile 选项将所有依赖打包到一个可执行文件中。
优缺点
优点:支持多平台,打包后的程序体积较小,且不需要额外安装Python解释器。
缺点:在某些情况下,打包后的程序可能无法正确识别Python依赖项,导致程序运行出错。 -
3.使用 cx_Freeze 打包
cx_Freeze 也是一个用于将Python脚本打包成独立可执行文件的工具。pip install cx_Freeze 然后,创建一个 setup.py 文件来配置 cx_Freeze: python 复制代码 from cx_Freeze import setup, Executable setup( name="your_project", version="0.1", description="Your Project Description", executables=[Executable("your_script.py")] ) 然后运行以下命令来生成可执行文件: bash 复制代码 python setup.py build
优缺点
优点:打包过程相对灵活,可以通过配置文件来定制打包过程。
缺点:打包后的程序体积可能较大,且需要额外安装Python解释器。
总结
PyInstaller 和 cx_Freeze:用于将 Python 脚本打包成可执行文件,不转换为 C 代码。
Cython:将 Python 代码转换为 C 扩展模块,提高执行效率。
Nuitka:将 Python 代码编译为独立的 C/C++ 可执行文件,提高性能。
Pyrex:类似于 Cython,但使用较少。
2、加密
PyArmor:对 Python 代码进行加密和混淆。
Nuitka:将 Python 代码编译为 C++,生成可执行文件。
Cython:将 Python 代码编译为 C 代码,提高性能并隐藏源代码。
使用 PyArmor
PyArmor 是一个常用的工具,可以对 Python 脚本进行混淆和加密,使其更难被逆向工程。
步骤:
安装 PyArmor:
pip install pyarmor
使用 PyArmor 混淆和打包你的脚本:
bash
复制代码
pyarmor pack -e " --onefile" your_script.py
-e 选项用于指定 PyInstaller 的选项,--onefile 会将所有内容打包到一个文件中。
3、创建启动命令
创建一个启动脚本,假设你要启动的程序是编译后的可执行文件:
在项目根目录下创建一个 start.sh 文件(Linux/MacOS)或 start.bat 文件(Windows),内容如下:
start.sh (Linux/MacOS)
#!/bin/bash
./dist/your_script
记得给予脚本执行权限:
chmod +x start.sh
start.bat (Windows)
复制代码
dist\your_script.exe
4、整个过程
https://www.cnblogs.com/gaiqingfeng/p/13229278.html
分为两种:
1、先打包再加密(pyinstaller打包,再pyarmor加密)
2、先加密再打包(pyc转成pyd,再打包)
选用:pyarmor加密,然后再用打包工具打包
pyinstaller打包的py文件会转为pyc格式, 但这种文件很容易破解出源码,打包成pyc格式,再加密。
pyinstaller abc.py # 要打包的top代码
-F # 只生成单个的exe文件, 缺点是运行exe时要先解压.
-w # 不生成命令行窗口.
--debug # 生成带debug信息的exe文件.
--clean # 运行前清理编译的临时文件;
--icon # 工具的top图标文件
--distpath # 输出的exe存放的目录
--workpath # 编译的临时文件存放的目录
--hidden-import # 隐含import的模块, 比如自定义/第三方的import模块等
--key # 加密密钥
打包后目录其中:
build 文件夹是存放打包时临时文件用的
dist 文件夹存放了打包好的应用
build-hello.spec 内容是 PyInstaller 根据我们的命令行生成的打包参数
生成的文件夹和文件
dist/:包含打包生成的可执行文件。
build/:构建过程中生成的临时文件。
my_script.spec:PyInstaller 的配置文件,包含打包过程的所有设置。
使用pyinstaller的—key选项加密。
加密:
https://www.cnblogs.com/gaiqingfeng/p/13229278.html
https://blog.csdn.net/XiaoXiaoYunXing/article/details/138784820
加密方法1: 将py文件转为pyd格式(先加密再打包)
pyd是动态链接库文件, 本质上与dll文件相同, 安全性比pyc文件高很多. 所以这种方式不算真正意义上的加密, 而是一个编译过程.参考:https://blog.csdn.net/paddy0213/article/details/129882471
将python文件二进制pyd文件,将Python文件加密为PYD文件实际上是指将Python代码编译为扩展模块。PYD文件是Windows平台上Python的动态链接库(DLL)文件,相当于在Unix/Linux系统中的SO文件。这种做法可以让Python代码以二进制形式存在,提高一定的反编译难度,从而达到某种程度上的“加密”效果。
要将Python代码编译为PYD文件,通常需要使用Cython或其他类似工具。Cython允许你使用静态类型注释的Python代码,并将其编译为C代码,然后进一步编译为机器代码。
加密方法2: 使用pyinstaller的—key选项
操作如下:
安装Visual Studio 2017 Community, 需要用到它的c语言编译功能;
安装PyCrypto模块: pip install PyCrypto –i https://pypi.douban.com/simple, 需要调用该模块;
运行pyinstaller --key 0123456789 –F [other options]
对生成的exe破解时, 会报告Fail to decompress xx, probably encrypted. 破解输出的目录中生成的是xx.pyc.encrypted文件, 不再是xx.pyc.
注意: 只能加密py文件, 如果加密的模块是pyd文件, 则pyd文件会直接打包, 不会被加密.
听说密钥也一并打包到输出文件中了, 所以好像也不安全. 感觉还是pyd靠谱些, 至少差不多是C编译后的文件.
加密方法3:pyinstaller打包,再pyarmor加密
旧版本的pyarmor
使用 PyInstaller:
有时候,PyArmor 可能无法处理某些复杂的包。在这种情况下,你可以尝试使用 PyInstaller,它在处理复杂包和依赖项方面有更好的支持。你可以先使用 PyInstaller 打包你的应用程序,然后使用 PyArmor 对其进行保护。
bash
复制代码
pyinstaller --onefile your_script.py
pyarmor pack dist/your_script
示例过程
以下是一个具体的示例,展示如何打包并加密一个简单的Python脚本:
编写示例Python脚本(example.py):
python
复制代码
# example.py
def main():
print("Hello, this is a protected script!")
if __name__ == "__main__":
main()
使用PyInstaller打包:
bash
复制代码
pyinstaller --onefile example.py
使用PyArmor加密:
bash
复制代码
pyarmor pack -e " --onefile" example.py
生成许可证(可选):
bash
复制代码
pyarmor licenses -e 2024-12-31 user
通过以上步骤,你将获得一个既打包又加密的Python可执行文件,从而保护了你的代码不被逆向工程和篡改。
pyinstaller --onefile your_script.py
主要参数说明:
–onefile: 将所有文件打包成一个可执行文件。
–noconsole: (Windows特有)不显示控制台窗口。
–icon: 指定图标文件。
pyarmor pack -e " --onefile" your_script.py
主要参数说明:
-e: 指定PyInstaller的打包选项。
-e " --onefile": 传递给PyInstaller的选项,这里是将代码打包成单个文件。
加密方法4:新版本pyarmor(包含pyinstaller)
https://pyarmor.readthedocs.io/zh/stable/reference/man.html
https://blog.csdn.net/wuShiJingZuo/article/details/136631412
–pack <onefile,onedir,FC,DC,NAME.spec>
首先加密脚本,然后把加密脚本打包成为单文件或者单个目录
在 v8.5.4 之前,用户需要首先调用 PyInstaller 进行打包,然后打包好的可执行文件传过来
现在所有的一切都由 Pyarmor 来完成,用户只需要告诉 Pyarmor 是打包成为单个文件或者单个目录
原来的方式依旧支持,只是不在推荐使用,有可能在下一个主版本就不在支持
在 8.5.4 版本加入: 支持 onefile 和 onedir
在 8.5.8 版本加入: 支持 .spec 后缀文件
这个选项一旦设置为 onefile 或者 onedir ,Pyarmor 会分析输入脚本的源代码,找到其导入的所有模块和包。如果模块和包和输入脚本在相同的目录下面,那么也会自动的加密这些依赖包。但是对于所依赖的 Python 系统包,以及其他不在当前目录的第三方包,则不会进行加密,只是把这些引用的包记录下来。
把所有的相关脚本加密之后,Pyarmor 接下来就会调用 PyInstaller 对所有加密脚本进行打包,没有加密的系统模块和第三方的包会被打进最后的包里面。
PyArmor 的基本概念包括加密、混淆和授权管理:
加密:加密是指将 Python 脚本转换为加密格式,使其不可读,从而防止源代码泄露。
混淆:混淆是指对 Python 脚本进行变换和重构,使其难以理解和分析,从而增加破解的难度。
授权管理:授权管理是指对加密后的 Python 脚本进行授权管理,限制脚本的运行权限和有效期限
主要功能
PyArmor 提供了一系列强大的功能,用于保护 Python 代码的安全性和机密性。
1. 加密 Python 脚本
加密是 PyArmor 的核心功能之一,它可以将 Python 脚本转换为加密格式,使其不易被读取和理解。通过加密,可以有效防止源代码泄露和盗用。
pyarmor encrypt --output=encrypted_script.py original_script.py
2. 混淆 Python 脚本
混淆是 PyArmor 的另一个重要功能,它可以对 Python 脚本进行变换和重构,使其难以理解和分析。通过混淆,可以增加破解的难度,提高代码的安全性。
pyarmor obfuscate --output=obfuscated_script.py original_script.py
3. 生成可执行文件
PyArmor 还提供了将加密后的 Python 脚本打包成可执行文件的功能,这样可以方便地分发和部署加密的代码。
pyarmor pack --output=packed_script.exe original_script.py
4. 设置授权管理规则
授权管理是 PyArmor 的另一个重要功能,它可以帮助开发人员设置代码的运行权限和有效期限,以确保其在合法授权范围内使用。
pyarmor licenses --expired=2024-12-31
使用方法:
加密 Python 脚本
pyarmor encrypt --output=encrypted_script.py original_script.py
混淆 Python 脚本
pyarmor obfuscate --output=obfuscated_script.py original_script.py
生成可执行文件
pyarmor pack --output=packed_script.exe original_script.py
设置授权管理规则
pyarmor licenses --expired=2024-12-31
原文链接:https://blog.csdn.net/wuShiJingZuo/article/details/136631412
加密方法5:cx_Freeze和PyArmor(先加密再打包)
使用PyArmor加密脚本
使用PyArmor加密您的Python脚本。假设您有一个名为main.py的脚本,您可以这样加密它:
sh
复制代码
pyarmor pack -x " --exclude dist" -e " --onefile" -e " --noconsole" main.py
这将生成一个加密的main.py,并将其放入dist目录中。
创建cx_Freeze的setup.py脚本
接下来,创建一个setup.py脚本,用于使用cx_Freeze打包应用程序:
python
复制代码
from cx_Freeze import setup, Executable
import os
# 使用PyArmor加密后的脚本路径
encrypted_script = "dist/main.py"
# 构建选项
build_exe_options = {
"packages": ["os", "fastapi", "uvicorn"],
"excludes": ["tkinter"],
"include_files": ["path/to/your/static/files", "path/to/your/templates"]
}
base = None
setup(
name="fastapi_app",
version="0.1",
description="My FastAPI Application!",
options={"build_exe": build_exe_options},
executables=[Executable(encrypted_script, base=base)]
)
使用cx_Freeze打包应用程序
最后,运行setup.py脚本以打包应用程序:
sh
复制代码
python setup.py build
总结
通过上述步骤,您可以使用PyArmor加密Python脚本,然后使用cx_Freeze将加密后的脚本打包为可执行文件。这样,您可以保护您的代码不被轻易反编译,同时提供一个独立的可执行文件供用户使用。
5、跨平台:
1、PyInstaller :由于 PyInstaller 不能直接生成多平台的可执行文件,你需要分别在每个平台上进行打包。需要用docker
创建多平台启动命令
2、pyarmor支持跨平台,(内置PyInstaller )
https://pyarmor.readthedocs.io/zh/v5.8.0/advanced.html
让加密脚本可以在多个平台运行
从 v5.7.5 版本开始,平台名称已经标准化,所有可用名称在这里 标准平台名称 ,并且支持运行加密脚本在多个平台。
为了支持加密脚本在多个平台运行,需要把把相关平台的动态库都添加到 运行辅助 包 中,这样就可以在这些平台正常运行加密脚本。例如,使用下面的命令可以加密一个可 运行于 Windows/Linux/MacOS 下面的脚本:
pyarmor obfuscate --platform windows.x86_64
–platform linux.x86_64
–platform darwin.x86_64
foo.py
6、压缩
5. 打包项目
将编译后的文件和启动脚本打包到一个压缩文件中:
bash
复制代码
tar -czvf your_project.tar.gz dist/ start.sh
或者使用 .zip 格式:
bash
复制代码
zip -r your_project.zip dist/ start.sh
6. 解压和启动
解压缩文件并运行启动脚本即可:
bash
复制代码
tar -xzvf your_project.tar.gz
cd your_project
./start.sh # Linux/MacOS
batch
复制代码
unzip your_project.zip
cd your_project
start.bat # Windows
6、打包配置
直接进入虚拟环境打包既可以,没包含的包在配置中包含进去。
1、pyinstaller配置
https://pyinstaller.org/en/stable/usage.html
PyInstaller配置文件中添加没导进的包,hidden-import 参数手动指定这些模块。
初始化:
pyinstaller myscript.py
修改后运行:
pyinstaller myscript.spec
使用隐藏导入:
有时 PyInstaller 不能自动检测到某些动态导入的模块。你可以通过 --hidden-import 参数手动指定这些模块。例如:
pyinstaller --onefile --hidden-import transformers main.py
检查 PyInstaller 的 spec 文件:
PyInstaller 会生成一个 .spec 文件,用于定义打包过程中的各种设置。你可以编辑这个文件,以确保所有需要的模块和文件都被正确处理。例如,你可以在 spec 文件中添加隐藏导入:
python
复制代码
a = Analysis(['main.py'],
pathex=['/path/to/your/project'],
binaries=[],
datas=[('path/to/model/file', '.')], # Add your data files here
hiddenimports=['transformers'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
cipher=block_cipher,
noarchive=False)
2、Pyarmor --pack使用到pyinstaller
相关用法和pyinstaller一样
https://pyarmor.readthedocs.io/zh/stable/reference/man.html#cmdoption-pyarmor-gen-assert-import
https://pyarmor.readthedocs.io/zh/stable/topic/repack.html
在 v8.5.4 之前,用户需要首先调用 PyInstaller 进行打包,然后打包好的可执行文件传过来。现在所有的一切都由 Pyarmor 来完成,用户只需要告诉 Pyarmor 是打包成为单个文件或者单个目录。原来的方式依旧支持,只是不在推荐使用,有可能在下一个主版本就不在支持:
在 8.5.4 版本加入: 支持 onefile 和 onedir
在 8.5.8 版本加入: 支持 .spec 后缀文件
使用其他 PyInstaller 选项:
如果需要为应用程序增加图标,不显示控制台窗口等,只需要把 PyInstaller 的相关选项通过配置项 pack:pyi_options 传递给 Pyarmor 即可。
例如,使用 PyInstaller 选项 -w 不显示控制台窗口:
pyarmor cfg pack:pyi_options = " -w"
请注意 " -w" 的头部需要有一个额外空格,否则 shell 可能会报错
配置文件选项:使用命令 pyarmor cfg 配置
有三种类型的配置文件
全局配置 文件,一个 .ini 格式的文件 ~/.pyarmor/config/global
本地配置 文件,一个 .ini 格式的文件 .pyarmor/config
模块私有配置 每一个模块可以有自己的私有配置,存放在 本地配置 的目录下面
使用命令 pyarmor cfg 来查看和设置配置文件选项。
3、cx_Freeze配置
1.编码问题,在代码中添加:
# -*- coding: utf-8 -*-
import sys
import codecs
# 确保标准输出和错误输出使用UTF-8编码
sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
sys.stderr = codecs.getwriter("utf-8")(sys.stderr.detach())
2、有些包没包含问题
添加代码中的import包,不是pip导出的,代码相关即可
7、相关bug
1.cx_Freeze中文字符编码问题
UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-5: ordinal not in range(128)
1. 使用UTF-8编码
确保所有的Python源文件都使用UTF-8编码,并在文件的开头声明编码:
python
复制代码
# -*- coding: utf-8 -*-
2. 设置系统环境变量
在运行cx_Freeze之前,设置系统环境变量以确保使用UTF-8编码。在Linux系统上,可以使用以下命令:
sh
复制代码
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
3. 修改setup.py脚本
确保在setup.py脚本中正确处理编码。这里是一个示例的setup.py脚本:
python
复制代码
# -*- coding: utf-8 -*-
from cx_Freeze import setup, Executable
import os
# 获取虚拟环境的路径
venv_path = os.getenv('VIRTUAL_ENV', '')
# 构建选项
build_exe_options = {
"packages": ["os", "your_package"], # 替换为您的应用程序包
"excludes": ["tkinter"], # 如果不需要,可以排除
"include_files": [
("path/to/your/static/files", "static"),
("path/to/your/templates", "templates")
],
"include_msvcr": True # 包含Microsoft Visual C++ Redistributable(如果需要)
}
# 需要包含的虚拟环境包路径
if venv_path:
build_exe_options["packages"].extend([
"site-packages/" + p for p in os.listdir(os.path.join(venv_path, "lib", "python3.x", "site-packages"))
])
setup(
name="my_app",
version="0.1",
description="My Application Description",
options={"build_exe": build_exe_options},
executables=[Executable("main.py", base=None)]
)
4. 确保中文文件名和路径
如果您的项目包含中文文件名或路径,确保这些路径在代码中正确编码和解码。例如,使用os.path处理路径,避免手动拼接字符串。
5. 确保中文输出和日志
如果您的应用程序需要打印或记录中文字符,确保使用print和日志记录时正确处理编码。例如:
python
复制代码
import sys
import codecs
# 确保标准输出和错误输出使用UTF-8编码
sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
sys.stderr = codecs.getwriter("utf-8")(sys.stderr.detach())
6. 测试和调试
在构建之前,确保在开发环境中测试所有功能,特别是处理中文字符的部分。确保所有涉及到文件读写、打印输出、日志记录的部分都能正确处理中文字符。
总结
通过以上步骤,您可以确保在使用cx_Freeze打包Python应用程序时正确处理中文字符。确保所有源文件和操作都使用UTF-8编码,并在必要时设置系统环境变量以支持UTF-8。
2、PyArmor 可能无法处理某些复杂的包
包导不进来主要原因是PyInstaller打包问题,在PyInstaller配置文件中添加没导进的包。
transformer报错:
RuntimeError: Failed to import transformers.models.gemma2.configuration_gemma2 because of the following error (look up to see its traceback):
No module named ‘transformers.models.gemma2.configuration_gemma2’
方法一:
PyInstaller先打包,再加密
使用 PyInstaller:
有时候,PyArmor 可能无法处理某些复杂的包。在这种情况下,你可以尝试使用 PyInstaller,它在处理复杂包和依赖项方面有更好的支持。你可以先使用 PyInstaller 打包你的应用程序,然后使用 PyArmor 对其进行保护。
bash
复制代码
pyinstaller --onefile your_script.py
pyarmor pack dist/your_script
方法二:
2.先排除,再手动添加
打包示例:
下面是一个使用 PyArmor 打包 Python 项目的示例,假设你有一个名为 main.py 的脚本依赖 transformers:
bash
复制代码
pyarmor pack -x " --exclude transformers" main.py
这条命令会排除 transformers 包,然后你可以手动将其包含在最终的打包目录中。
手动添加 transformers:
如果上述方法仍然有问题,你可以考虑手动将 transformers 及其依赖项添加到打包目录。以下是一个简化的步骤:
使用 pip 安装 transformers:
bash
复制代码
pip install transformers -t ./build
使用 PyInstaller 或其他打包工具(如 cx_Freeze 或 PyArmor)打包你的主脚本,并确保将 ./build 目录添加到打包路径中。
方法三:
PyInstaller配置文件中添加没导进的包
使用隐藏导入:
有时 PyInstaller 不能自动检测到某些动态导入的模块。你可以通过 --hidden-import 参数手动指定这些模块。例如:
pyinstaller --onefile --hidden-import transformers main.py
检查 PyInstaller 的 spec 文件:
PyInstaller 会生成一个 .spec 文件,用于定义打包过程中的各种设置。你可以编辑这个文件,以确保所有需要的模块和文件都被正确处理。例如,你可以在 spec 文件中添加隐藏导入:
python
复制代码
a = Analysis(['main.py'],
pathex=['/path/to/your/project'],
binaries=[],
datas=[('path/to/model/file', '.')], # Add your data files here
hiddenimports=['transformers'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
cipher=block_cipher,
noarchive=False)
8、打包加密案例
官方文档:https://pyarmor.readthedocs.io/zh/stable/tutorial/getting-started.html#id4
1、方法一:pyarmor加密打包(内置pyinstaller打包)
pyarmor 打包成单个文件
pyarmor gen --pack onefile test.py
#运行是否缺少包
./dist/demo8_test
如果缺少包,配置pyarmor的pyinstaller打包项。只需要把 PyInstaller 的相关选项通过配置项 pack:pyi_options 传递给 Pyarmor 即可。
pyarmor cfg pack:pyi_options + " --hidden-import transformers.models.gemma2.configuration_gemma2"
配置文件的位置:
配置文件选项:使用命令 pyarmor cfg 配置
有三种类型的配置文件
全局配置 文件,一个 .ini 格式的文件 ~/.pyarmor/config/global
**本地配置 文件,一个 .ini 格式的文件 .pyarmor/config**
模块私有配置 每一个模块可以有自己的私有配置,存放在 本地配置 的目录下面
使用命令 pyarmor cfg 来查看和设置配置文件选项。
数据打包:
https://pyinstaller.org/en/stable/spec-files.html#spec-file-operation
https://pyinstaller.org/en/stable/runtime-information.html?highlight=data#using-file
When your script executes, you could find help_data.txt by using its base folder path, as described in the previous section. However, this data file is part of a module, so you can also retrieve its contents using the standard library function pkgutil.get_data():
import pkgutil
help_bin = pkgutil.get_data( 'helpmod', 'help_data.txt' )
This returns the contents of the help_data.txt file as a binary string. If it is actually characters, you must decode it:
help_utf = help_bin.decode('UTF-8', 'ignore')
2、方法二:pyarmor加密,cx_Freeze打包
pyarmor加密
https://pyarmor.readthedocs.io/zh/stable/tutorial/getting-started.html#id4
cx_Freeze打包
from cx_Freeze import setup, Executable
#报import某个包错误,将代码中所有import的包加到下面,不要全部加pip导出的包名
packages=['typing','fastapi','uvicorn','pydantic','uuid','transformers','numpy']
setup(
name = "MyApp",
version = "0.1",
description = "My application!",
executables = [Executable("demo8_test.py")],
options={'build_exe': {
'packages': packages ,
# "include_path": 'path'
}},
)
#进入虚拟环境,执行以下命令即可完成打包
# python setup.py build
#代码中有中文,在代码文件中添加一下代码
# import sys
# import codecs
# # 确保标准输出和错误输出使用UTF-8编码
# sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
# sys.stderr = codecs.getwriter("utf-8")(sys.stderr.detach())
#中文字符问题,其他附加项(以上不能解决可以加)
# -*- coding: utf-8 -*-
# 终端环境变量
# export LANG=en_US.UTF-8
# export LC_ALL=en_US.UTF-8
数据文件:
# cx_Freeze打包加密
from cx_Freeze import setup, Executable
#报import某个包错误,将代码中所有import的包加到下面,不要全部加pip导出的包名
packages=['typing','fastapi','uvicorn','pydantic','uuid','transformers','numpy','codecs','sys']
# 在这里定义要打包的数据文件,源路径:目标路径(支持文件和目录),目标路径不能是绝对路径,在代码中用目标路径
include_files = [
('/nfs2/jiyuan.chen/Security-Model/model/server_test_model', 'data/model'),
('/nfs2/zhaochuan.cai/czc_test/datrie/pydatrie/filter_pydatrie.dat','data/dat/filter_pydatrie.dat')
]
# model_path='/nfs2/jiyuan.chen/Security-Model/model/server_test_model'
# dat_path="/nfs2/zhaochuan.cai/czc_test/datrie/pydatrie/filter_pydatrie.dat"
setup(
name = "MtApp",
version = "1.0",
description = "Mt security application!",
executables = [Executable("demo9.py")],
options={'build_exe': {
'packages': packages ,
'include_files': include_files # 数据文件/目录
}},
)
#进入虚拟环境,执行以下命令即可完成打包
# python setup.py build
# python setup.py build_exe
#代码中有中文,在代码文件中添加一下代码
# import sys
# import codecs
# # 确保标准输出和错误输出使用UTF-8编码
# sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
# sys.stderr = codecs.getwriter("utf-8")(sys.stderr.detach())
#中文字符问题,其他附加项(以上不能解决可以加)
# -*- coding: utf-8 -*-
# 终端环境变量
# export LANG=en_US.UTF-8
# export LC_ALL=en_US.UTF-8
# python demo9.py -m /nfs2/jiyuan.chen/Security-Model/model/server_test_model -d /nfs2/zhaochuan.cai/czc_test/datrie/pydatrie/filter_pydatrie.dat
9、引用打好的包
可以直接执行打包好的文件,以命令行的形式传参。也可以用下下面的方法,在脚本中调用该包。
1.代码中设置对多种设置方式的支持(命令参数,环境变量,默认值):
#1、给路径参数赋值
#命领行参数获取
def get_Parser():
# 定义一个ArgumentParser实例:
parser = argparse.ArgumentParser(
prog='mt_security', # 程序名
description='mt_security relevant arg.', # 描述
epilog='Mt ArgumentParser, 2024' # 说明信息
)
# 允许用户输入简写的-x:
parser.add_argument('-m', '--model',help='model path parameter', required=False,default=None)
parser.add_argument('-d', '--dat', help='Dat tree path parameter',required=False,default=None)
parser.add_argument('-p', '--port', help='api port parameter',required=False,default='8888',type=int)
# 解析参数:
args = parser.parse_args()
print('解析完参数:',args)
return args
args=get_Parser()
#环境变量获取
Model_env = os.getenv('Model')
Dat_env= os.getenv('Dat')
Port_env= os.getenv('Portmt')
print('环境变量:',Model_env,Dat_env,Port_env)
port=Port_env if Port_env else args.port
model_path='/nfs2/jiyuan.chen/Security-Model/model/server_test_model'
dat_path="/nfs2/zhaochuan.cai/czc_test/datrie/pydatrie/filter_pydatrie.dat"
# model_path=''
# dat_path=''
# 选取存在的路径
for path in [args.model,Model_env,model_path] :
if path and os.path.exists(path): model_path=path; break
for path in [args.dat,Dat_env,dat_path] :
if path and os.path.exists(path): dat_path=path; break
print('模型路径:',model_path)
print('dat字典树路径:',dat_path)
if not model_path or not dat_path:
print('路径为空')
quit("程序终止:路径不能为空,请设置正确的模型路径")
2.源启动脚本:
#!/bin/bash
# 启用调试模式
set -x
#环境变量,变量名和等号之间不能有空格。
Model_env=/nfs2/jiyuan.chen/Security-Model/model/server_test_model
Dat_env=/nfs2/zhaochuan.cai/czc_test/datrie/pydatrie/filter_pydatrie.dat
Port_env=6666
python -u demo10.py \
-m $Model_env \
-d $Dat_env \
-p $Port_env \
# >> log_scure.log 2>&1 &
# nohup bash start.sh >> log_scure.log 2>&1 &
3.在脚本中引用打好的包
#!/bin/bash
# 启用调试模式
set -x
#环境变量,变量名和等号之间不能有空格。
# Model_env=/nfs2/jiyuan.chen/Security-Model/model/server_test_model
# Dat_env=/nfs2/zhaochuan.cai/czc_test/datrie/pydatrie/filter_pydatrie.dat
Model_env=data/model
Dat_env=data/dat/filter_pydatrie.dat
Port_env=8888
./demo10 \
-m $Model_env \
-d $Dat_env \
-p $Port_env \
# >> log_scure.log 2>&1 &
# python -u demo10.py \
# -m $Model_env \
# -d $Dat_env \
# -p $Port_env \
# # >> log_scure.log 2>&1 &
# nohup bash start.sh >> log_scure.log 2>&1 &
10、跨架构
使用qemu静态文件启动目标架构dockers。
注意:目标架构是哪个,就下载哪个文件
下载:https://github.com/multiarch/qemu-user-static/releases/tag/v7.2.0-1
https://blog.csdn.net/m0_53195006/article/details/129890780
https://blog.csdn.net/happyblreay/article/details/139743957
x86_64平台通过qemu-user-static 运行arm64的docker镜像:
1、下载目标架构的qemu
下载路径:link
https://github.com/multiarch/qemu-user-static/releases
wget https://github.com/multiarch/qemu-user-static/releases/download/v7.2.0-1/qemu-aarch64-static.tar.gz
#下载后需要解压
tar -xzf xxx.tar.gz
2、初始化binfmt
#初始化和重置binfmt
docker run --rm --privileged multiarch/qemu-user-static --reset
#设置binfmt(可能会失败,原因未知,解决方式是手动mount qemu-aarch64-static到容器;)
docker run --rm --privileged multiarch/qemu-user-static -p yes
qemu-user-static结合binfmt_misc来实现arm架构的指令模拟(文末有详细介绍)
可以通过检查 /proc/sys/fs/binfmt_misc 下的内容来确认是否成功启用。
root@testhost1:/root>ls -al /proc/sys/fs/binfmt_misc
total 0
drwxr-xr-x 2 root root 0 May 21 15:11 .
dr-xr-xr-x 1 root root 0 May 21 23:11 ..
-rw-r--r-- 1 root root 0 Jun 17 14:58 qemu-aarch64
在安装并配置好 qemu-user-static 与 binfmt_misc 后,你就可以直接使用 Docker 运行 ARM64 的镜像了。这时,Docker 与 QEMU 联动,能够在你的 x86_64 机器上模拟 ARM64 架构。
3、拉取arm版本的镜像
docker pull arm64v8/ubuntu:20.04
4、运行arm容器
需要把qemu-aarch64-static映射到目标容器里
需要指定目标容器的platform
docker run -it --rm --platform linux/arm64 -v $(pwd)/qemu-aarch64-static:/usr/bin/qemu-aarch64-static arm64v8/ubuntu:20.04 uname -m
#ok
docker run --cpus 48 --shm-size 32G --gpus all --memory 500gb --privileged=true -v /nfs2:/nfs2 -p 8065:8888 -it --platform linux/arm64 -v $(pwd)/qemu-aarch64-static:/usr/bin/qemu-aarch64-static --name czc_arch_pytest python:3.10.14-bookworm /bin/bash
docker run --cpus 48 --shm-size 32G --gpus all --memory 500gb -it \
--privileged=true -v /nfs2:/nfs2 -p 8065:8888 \
--platform linux/arm64 -v $(pwd)/qemu-aarch64-static:/usr/bin/qemu-aarch64-static \
--name czc_arch_pytest python:3.10.14-bookworm /bin/bash
问题:网络一直限速,不知道是不是容器问题
11、影响日志输出问题
多进程启动:uvicorn demo11test:app --host 0.0.0.0 --port 8888 --workers 4 时,
报错:logging stream.write(msg + self.terminator) ValueError: underlying buffer has been detached
原因:cx_Freeze打包时,解决编码问题的代码影响。
检查流对象是否被关闭:
确保你在程序运行过程中没有意外关闭或分离流对象。
import sys
# 确保 sys.stdout 或 sys.stderr 没有被关闭
assert not sys.stdout.closed
assert not sys.stderr.closed
解决:将以下代码注释掉
# # 解决打包中文编码问题
# import sys
# import codecs
# # 确保标准输出和错误输出使用UTF-8编码
# sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
# sys.stderr = codecs.getwriter("utf-8")(sys.stderr.detach())