python项目打包加密和跨平台运行

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())
  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值