Python 打包平台二进制文件

背景

不知道为什么 Python 怎么那么火,到处都有在用,导致不得不用Python来完成一些事情。

python 安装依赖需要用到 pip,而且还需要有外网,但是这对离线部署就很不友好。

所以 在一些场景下还是需要打包二进制的。

e.g

program

// app.py
from flask import Flask
import service.user
import service.algorithm

app = Flask(__name__)

@app.route("/")
def hello():
    return {"status": "UP"}


@app.route("/user/<name>", methods=['GET'])
def user_by_name(name):
    return service.user.user_by_name(name)

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5000)
pip install flask
python3 app.py

打包

通常情况下 有两个选择

  • pyinstaller
  • Nuitka

但不管哪种方式 生成出的二进制可执行文件 只能在相同但平台上使用。

pyinstaller

pyinstaller 生成的零碎文件比较多,一些依赖库非常零散的分布在文件目录上,且文件目录结构不能动。

安装依赖

pip install pyinstaller

生成二进制可执行文件

pyinstaller /path/to/app.py
pyinstaller /Users/wayne/PycharmProjects/AlphaProjects/pyweb/app.py 

73 INFO: PyInstaller: 5.0.1
74 INFO: Python: 3.8.9
82 INFO: Platform: macOS-12.4-arm64-arm-64bit
82 INFO: wrote /Users/wayne/PycharmProjects/AlphaProjects/pyweb/app.spec
85 INFO: UPX is not available.
85 INFO: Extending PYTHONPATH with paths
['/Users/wayne/PycharmProjects/AlphaProjects/pyweb']
172 INFO: checking Analysis
172 INFO: Building Analysis because Analysis-00.toc is non existent
172 INFO: Initializing module dependency graph...
173 INFO: Caching module graph hooks...
178 INFO: Analyzing base_library.zip ...
1252 INFO: Processing pre-find module path hook distutils from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks/pre_find_module_path/hook-distutils.py'.
1274 INFO: distutils: retargeting to non-venv dir '/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8'
2007 INFO: Caching module dependency graph...
2062 INFO: running Analysis Analysis-00.toc
2069 INFO: Analyzing /Users/wayne/PycharmProjects/AlphaProjects/pyweb/app.py
2847 INFO: Processing module hooks...
2847 INFO: Loading module hook 'hook-jinja2.py' from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
2848 INFO: Loading module hook 'hook-encodings.py' from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks'...
2872 INFO: Loading module hook 'hook-pickle.py' from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks'...
2874 INFO: Loading module hook 'hook-importlib_metadata.py' from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks'...
2875 INFO: Loading module hook 'hook-heapq.py' from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks'...
2876 INFO: Loading module hook 'hook-difflib.py' from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks'...
2877 INFO: Loading module hook 'hook-multiprocessing.util.py' from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks'...
2877 INFO: Loading module hook 'hook-sysconfig.py' from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks'...
2882 INFO: Loading module hook 'hook-xml.py' from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks'...
2904 INFO: Loading module hook 'hook-distutils.py' from '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks'...
2914 INFO: Looking for ctypes DLLs
2921 INFO: Analyzing run-time hooks ...
2923 INFO: Including run-time hook '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks/rthooks/pyi_rth_subprocess.py'
2923 INFO: Including run-time hook '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py'
2925 INFO: Including run-time hook '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py'
2926 INFO: Including run-time hook '/Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/hooks/rthooks/pyi_rth_inspect.py'
2929 INFO: Looking for dynamic libraries
3189 INFO: Looking for eggs
3190 INFO: Using Python library /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/Resources/Python.app/Contents/MacOS/../../../../Python3
3193 INFO: Warnings written to /Users/wayne/PycharmProjects/AlphaProjects/pyweb/build/app/warn-app.txt
3207 INFO: Graph cross-reference written to /Users/wayne/PycharmProjects/AlphaProjects/pyweb/build/app/xref-app.html
3213 INFO: checking PYZ
3213 INFO: Building PYZ because PYZ-00.toc is non existent
3213 INFO: Building PYZ (ZlibArchive) /Users/wayne/PycharmProjects/AlphaProjects/pyweb/build/app/PYZ-00.pyz
3485 INFO: Building PYZ (ZlibArchive) /Users/wayne/PycharmProjects/AlphaProjects/pyweb/build/app/PYZ-00.pyz completed successfully.
3489 INFO: EXE target arch: arm64
3489 INFO: Code signing identity: None
3489 INFO: checking PKG
3489 INFO: Building PKG because PKG-00.toc is non existent
3489 INFO: Building PKG (CArchive) app.pkg
3490 WARNING: Cannot find path @executable_path/../../../../Python3 (needed by /Users/wayne/PycharmProjects/AlphaProjects/venv/bin/python)
3495 INFO: Building PKG (CArchive) app.pkg completed successfully.
3496 INFO: Bootloader /Users/wayne/PycharmProjects/AlphaProjects/venv/lib/python3.8/site-packages/PyInstaller/bootloader/Darwin-64bit/run
3496 INFO: checking EXE
3496 INFO: Building EXE because EXE-00.toc is non existent
3496 INFO: Building EXE from EXE-00.toc
3496 INFO: Copying bootloader EXE to /Users/wayne/PycharmProjects/AlphaProjects/pyweb/build/app/app
3497 INFO: Converting EXE to target arch (arm64)
3517 INFO: Removing signature(s) from EXE
3533 INFO: Appending PKG archive to EXE
3535 INFO: Fixing EXE headers for code signing
3538 WARNING: Cannot find path @executable_path/../../../../Python3 (needed by /Users/wayne/PycharmProjects/AlphaProjects/venv/bin/python)
3541 INFO: Re-signing the EXE
3553 INFO: Building EXE from EXE-00.toc completed successfully.
3554 INFO: checking COLLECT
3554 INFO: Building COLLECT because COLLECT-00.toc is non existent
3554 INFO: Building COLLECT COLLECT-00.toc
3842 INFO: Building COLLECT COLLECT-00.toc completed successfully.

目录结构

.
|____dist
| |____app
| | |____lib-dynload
| | | |_____lzma.cpython-38-darwin.so
| | | |____readline.cpython-38-darwin.so
| | | |_____hashlib.cpython-38-darwin.so
| | | |_____blake2.cpython-38-darwin.so
| | | |_____posixshmem.cpython-38-darwin.so
| | | |____resource.cpython-38-darwin.so
| | | |_____decimal.cpython-38-darwin.so
| | | |____zlib.cpython-38-darwin.so
| | | |____termios.cpython-38-darwin.so
| | | |_____sha1.cpython-38-darwin.so
| | | |_____codecs_cn.cpython-38-darwin.so
| | | |____binascii.cpython-38-darwin.so
| | | |_____uuid.cpython-38-darwin.so
| | | |_____md5.cpython-38-darwin.so
| | | |____pyexpat.cpython-38-darwin.so
| | | |_____bz2.cpython-38-darwin.so
| | | |____grp.cpython-38-darwin.so
| | | |____mmap.cpython-38-darwin.so
| | | |_____pickle.cpython-38-darwin.so
| | | |____array.cpython-38-darwin.so
| | | |_____ssl.cpython-38-darwin.so
| | | |_____posixsubprocess.cpython-38-darwin.so
| | | |____unicodedata.cpython-38-darwin.so
| | | |_____csv.cpython-38-darwin.so
| | | |_____opcode.cpython-38-darwin.so
| | | |_____sha256.cpython-38-darwin.so
| | | |_____multiprocessing.cpython-38-darwin.so
| | | |_____sha3.cpython-38-darwin.so
| | | |_____sha512.cpython-38-darwin.so
| | | |____math.cpython-38-darwin.so
| | | |____select.cpython-38-darwin.so
| | | |_____codecs_tw.cpython-38-darwin.so
| | | |_____random.cpython-38-darwin.so
| | | |_____socket.cpython-38-darwin.so
| | | |_____datetime.cpython-38-darwin.so
| | | |_____asyncio.cpython-38-darwin.so
| | | |_____codecs_kr.cpython-38-darwin.so
| | | |_____bisect.cpython-38-darwin.so
| | | |_____scproxy.cpython-38-darwin.so
| | | |_____queue.cpython-38-darwin.so
| | | |_____codecs_iso2022.cpython-38-darwin.so
| | | |_____contextvars.cpython-38-darwin.so
| | | |_____codecs_hk.cpython-38-darwin.so
| | | |_____multibytecodec.cpython-38-darwin.so
| | | |_____json.cpython-38-darwin.so
| | | |_____ctypes.cpython-38-darwin.so
| | | |_____struct.cpython-38-darwin.so
| | | |_____heapq.cpython-38-darwin.so
| | | |_____codecs_jp.cpython-38-darwin.so
| | |____markupsafe
| | | |_____speedups.cpython-38-darwin.so
| | |____app
| | |____Python3
| | |____importlib_metadata-4.11.3.dist-info
| | | |____RECORD
| | | |____LICENSE
| | | |____WHEEL
| | | |____top_level.txt
| | | |____INSTALLER
| | | |____METADATA
| | |____base_library.zip
|____app.py
|____app.spec
|____build
| |____app
| | |____Analysis-00.toc
| | |____PKG-00.toc
| | |____app
| | |____PYZ-00.toc
| | |____base_library.zip
| | |____app.pkg
| | |____EXE-00.toc
| | |____PYZ-00.pyz
| | |____warn-app.txt
| | |____xref-app.html
| | |____COLLECT-00.toc
| | |____localpycos
| | | |____struct.pyo
|____service
| |____user.py

保持目录结构不变 可执行文件为 dist/app/app

Nuitka

Nuitka 是我认为一个比较好的一个方式,但更耗时更耗资源。

Nuitka 会把 Python 模块转换为 C 程序,然后使用 libpython 和它自己的静态 C 文件以与 CPython 相同的方式执行。

安装依赖

pip install nuitka

生成二进制可执行文件

python -m nuitka --follow-imports app.py
python3 -m nuitka --follow-imports app.py

Nuitka-Options:INFO: Used command line options: --follow-imports app.py
Nuitka:INFO: Starting Python compilation with Nuitka '0.7.7' on Python '3.8' commercial None.
Nuitka-Plugins:INFO: anti-bloat: Handling module 'pydoc' with 1 change(s) for: remove module ability to display GUI with tkinter and topics data.                              
Nuitka-Plugins:INFO: implicit-imports: Implicit dependencies of module 'flask.app' added 'jinja2.ext'.                                                                         
Nuitka:INFO: Completed Python level compilation and optimization.                                                                                                              
Nuitka:INFO: Generating source code for C backend compiler.
Nuitka:INFO: Running data composer tool for optimal constant value handling.                                                                                                   
Nuitka:INFO: Running C compilation via Scons.
Nuitka-Scons:INFO: Backend C compiler: clang (clang).
Nuitka-Scons:INFO: Scons: Inherited CPPFLAGS='-I/opt/homebrew/opt/node@16/include' variable.
Nuitka-Scons:INFO: Scons: Inherited LDFLAGS='-L/opt/homebrew/opt/node@16/lib' variable.
Nuitka-Scons:INFO: Backend linking program (no progress information available).                                                                                                
Nuitka-Scons:WARNING: You are not using ccache.
Nuitka:INFO: Keeping build directory 'app.build'.
Nuitka:INFO: Successfully created 'app.bin'.

目录结构

.
|____app.bin
|____app.build
| |____module.jinja2.async_utils.o
| |____module.werkzeug.wrappers.request.o
| |____module.flask.typing.const
| |____module.itsdangerous._json.c
| |____module.werkzeug.sansio.response.o
| |____build_definitions.h
| |____module.flask.testing.const
| |____module.werkzeug._reloader.c
| |____module.click.termui.const
| |____module.click._textwrap.o
| |____module.flask.config.o
| |____module.click.decorators.const
| |______helpers.o
| |____module.click._termui_impl.o
| |____module.jinja2.exceptions.c
| |____module.flask.ctx.c
| |____module.click.exceptions.c
| |______loader.o
| |______helpers.h
| |____module.click.formatting.const
| |____module.flask.config.const
| |____module.itsdangerous.encoding.c
| |____module.service.algorithm.o
| |____module.werkzeug.sansio.multipart.const
| |____module.click.core.c
| |____module.flask.wrappers.o
| |____module.service.user.o
| |____module.werkzeug.debug.const
| |____module.werkzeug.utils.const
| |____module.jinja2.runtime.o
| |____module.flask.app.o
| |____module.click.globals.c
| |____module.itsdangerous.serializer.o
| |____module.flask.json.const
| |____module.werkzeug.user_agent.c
| |____module.jinja2.bccache.c
| |____module.jinja2.constants.const
| |____module.werkzeug._reloader.const
| |____module.jinja2.compiler.o
| |____module.jinja2.exceptions.const
| |____module.werkzeug.debug.console.o
| |____module.jinja2.c
| |____module.jinja2.ext.c
| |____module.werkzeug.formparser.const
| |____module.click.shell_completion.const
| |____module.werkzeug.exceptions.o
| |____module.flask.signals.o
| |____module.click._compat.o
| |____module.click.parser.const
| |____module.jinja2.parser.const
| |____module.werkzeug.debug.o
| |____module._virtualenv.c
| |____module.werkzeug.routing.o
| |____module.werkzeug.test.const
| |____module.jinja2.environment.o
| |____module.jinja2.lexer.c
| |____module.flask.logging.o
| |____module.jinja2.nodes.const
| |____module.flask.json.tag.c
| |____module.werkzeug.wsgi.o
| |____module.flask.scaffold.const
| |____module.flask.globals.const
| |____module.flask.scaffold.c
| |____module.werkzeug.sansio.o
| |____module.jinja2.idtracking.o
| |____.sconsign-38.dblite
| |____module.itsdangerous.encoding.const
| |____module.jinja2.tests.const
| |____module.werkzeug.sansio.request.c
| |____module.werkzeug.utils.o
| |____module.flask.globals.o
| |____module.werkzeug.datastructures.o
| |______constants_data.c
| |____module.werkzeug.test.c
| |____module.jinja2.debug.const
| |____module.werkzeug.urls.o
| |____scons-report.txt
| |____module.jinja2.parser.o
| |____module.werkzeug.debug.repr.const
| |____module.click.termui.o
| |____module.jinja2.runtime.const
| |____module.itsdangerous.signer.c
| |____module.werkzeug.debug.tbtools.o
| |____module.flask.helpers.c
| |____module.jinja2.utils.const
| |____module.jinja2.async_utils.const
| |____module.itsdangerous.c
| |____module.werkzeug.debug.repr.o
| |____module.flask.testing.o
| |____module.werkzeug.http.c
| |____module.flask.signals.const
| |____module.werkzeug.local.const
| |____module.click.exceptions.const
| |____module.click.shell_completion.c
| |____module.jinja2.tests.o
| |____module.click.c
| |____module.jinja2.idtracking.const
| |____module.werkzeug.wrappers.const
| |____module.flask.blueprints.o
| |____module.click._textwrap.const
| |____module.service.c
| |____module.werkzeug.c
| |____module.werkzeug.security.const
| |____module.click.parser.o
| |____module.werkzeug.serving.const
| |____module.werkzeug.formparser.c
| |____module.click.utils.c
| |____module.click.const
| |____module.click._compat.const
| |____module.itsdangerous.url_safe.o
| |____module.werkzeug.sansio.multipart.c
| |______constants.const
| |____module.click.decorators.c
| |____module.werkzeug.debug.console.const
| |____module.jinja2.optimizer.o
| |____module.click.formatting.c
| |____module.jinja2.constants.o
| |____module.werkzeug.debug.tbtools.const
| |____module.werkzeug.routing.const
| |____module.click.types.c
| |____module.werkzeug.serving.c
| |____module.markupsafe.o
| |____module.itsdangerous._json.const
| |____module.werkzeug.security.o
| |____module.jinja2.optimizer.const
| |____module.flask.json.o
| |____module.jinja2.filters.o
| |____module.flask.cli.c
| |____module.flask.typing.o
| |____module.click.testing.c
| |____module.itsdangerous.url_safe.const
| |____module.werkzeug.sansio.utils.o
| |____module.werkzeug._internal.c
| |____module.flask.sessions.o
| |____module._virtualenv.const
| |____module.flask.debughelpers.o
| |____module.zipp.o
| |____module.jinja2.visitor.const
| |____module.itsdangerous.signer.const
| |____module.itsdangerous.exc.o
| |____module.werkzeug.middleware.c
| |____module.jinja2.nodes.c
| |____module.jinja2.debug.o
| |____module.jinja2.defaults.c
| |____module.markupsafe._native.c
| |____static_src
| | |____MainProgram.c
| | |____CompiledCellType.o
| | |____InspectPatcher.c
| | |____CompiledFunctionType.o
| | |____MetaPathBasedLoader.o
| | |____CompiledGeneratorType.c
| | |____InspectPatcher.o
| | |____CompiledCellType.c
| | |____MainProgram.o
| | |____CompiledFunctionType.c
| | |____CompiledGeneratorType.o
| | |____MetaPathBasedLoader.c
| |____module.flask.c
| |____module.jinja2.visitor.c
| |____module.jinja2._identifier.o
| |____module.werkzeug.wrappers.response.c
| |____module.werkzeug.wrappers.o
| |______bytecode.const
| |____module.__main__.c
| |____module.flask.templating.c
| |____module.jinja2.loaders.o
| |____module.werkzeug.middleware.shared_data.o
| |____module.jinja2.utils.o
| |______constants.c
| |____module.itsdangerous.timed.o
| |____module.flask.ctx.const
| |____module.click.core.const
| |____module.werkzeug.local.c
| |____module.jinja2.bccache.o
| |____module.werkzeug.user_agent.o
| |____module.flask.templating.const
| |____module.jinja2.compiler.c
| |____module.werkzeug.debug.console.c
| |____module.jinja2.o
| |____module.click.core.o
| |____module.click.utils.const
| |____module.jinja2.compiler.const
| |____module.service.user.c
| |____module.flask.wrappers.c
| |____module.jinja2.runtime.c
| |____module.flask.app.c
| |____module.werkzeug.sansio.request.const
| |____module.zipp.const
| |____module.werkzeug.user_agent.const
| |____module.click.globals.o
| |____module.itsdangerous.serializer.c
| |____module.click._termui_impl.c
| |______helpers.c
| |____module.jinja2.exceptions.o
| |____module.flask.config.c
| |______loader.c
| |____module.click.exceptions.o
| |____module.flask.ctx.o
| |____module.jinja2.environment.const
| |____module.werkzeug.http.const
| |____module.flask.json.tag.const
| |____module.flask.logging.const
| |____module.service.algorithm.c
| |____module.werkzeug.middleware.shared_data.const
| |____module.itsdangerous.encoding.o
| |____module.werkzeug.wrappers.request.const
| |____module.jinja2.async_utils.c
| |____module.werkzeug.wrappers.request.c
| |____module.service.const
| |____module.click.testing.const
| |____module.werkzeug._reloader.o
| |____module.itsdangerous._json.o
| |____module.werkzeug.sansio.response.c
| |____module.click._textwrap.c
| |____module.markupsafe.const
| |____module.jinja2._identifier.const
| |____module.jinja2.parser.c
| |____module.click.termui.c
| |____module.jinja2.defaults.const
| |____module.click.types.const
| |____module.werkzeug.urls.c
| |____module.werkzeug.debug.tbtools.c
| |____module.itsdangerous.signer.o
| |____module.jinja2.filters.const
| |____module.flask.helpers.o
| |____module.werkzeug.sansio.c
| |____module.service.user.const
| |____module.werkzeug.datastructures.const
| |____module.flask.cli.const
| |____module.jinja2.idtracking.c
| |____module.werkzeug.datastructures.c
| |____module.werkzeug.sansio.request.o
| |____module.werkzeug.utils.c
| |____module.flask.globals.c
| |____module.werkzeug.test.o
| |______constants_data.o
| |____module.jinja2.environment.c
| |____module.werkzeug.routing.c
| |____module.werkzeug._internal.const
| |____module.flask.app.const
| |____module.flask.logging.c
| |____module.jinja2.lexer.o
| |____module.flask.json.tag.o
| |____module.werkzeug.wsgi.c
| |____module.click.globals.const
| |____module.flask.scaffold.o
| |______constants.bin
| |____module.werkzeug.exceptions.c
| |____module.jinja2.ext.o
| |____module.flask.signals.c
| |____module.flask.wrappers.const
| |____module.click._compat.c
| |____module.werkzeug.debug.c
| |____module._virtualenv.o
| |____module.itsdangerous.timed.const
| |____module.click.decorators.o
| |____module.click.formatting.o
| |____module.jinja2.optimizer.c
| |____module.flask.blueprints.const
| |____module.werkzeug.exceptions.const
| |____module.jinja2.constants.c
| |____module.jinja2.bccache.const
| |____module.werkzeug.formparser.o
| |____module.werkzeug.o
| |____module.click.parser.c
| |____module.click.utils.o
| |____module.itsdangerous.serializer.const
| |____module.click._termui_impl.const
| |____module.werkzeug.wrappers.response.const
| |____module.werkzeug.sansio.multipart.o
| |____module.itsdangerous.const
| |____module.itsdangerous.url_safe.c
| |____module.click.shell_completion.o
| |____module.werkzeug.sansio.const
| |____module.click.o
| |____module.jinja2.tests.c
| |____module.flask.blueprints.c
| |____module.itsdangerous.exc.const
| |____module.service.o
| |____module.__main__.const
| |____@link_input.txt
| |____module.itsdangerous.o
| |____module.werkzeug.debug.repr.c
| |____module.markupsafe._native.const
| |____module.flask.testing.c
| |____module.werkzeug.http.o
| |____module.flask.sessions.const
| |____module.__main__.o
| |____module.flask.templating.o
| |____module.jinja2.loaders.c
| |____module.werkzeug.wsgi.const
| |______constants.h
| |____module.werkzeug.middleware.shared_data.c
| |____module.jinja2.utils.c
| |____module.werkzeug.local.o
| |______constants.o
| |____module.itsdangerous.timed.c
| |____module.werkzeug.sansio.response.const
| |____module.flask.o
| |____module.werkzeug.const
| |____module.jinja2.const
| |____module.markupsafe._native.o
| |____module.werkzeug.wrappers.response.o
| |____module.werkzeug.wrappers.c
| |____module.jinja2._identifier.c
| |____module.jinja2.visitor.o
| |____module.flask.helpers.const
| |____module.flask.sessions.c
| |____module.werkzeug._internal.o
| |____module.werkzeug.sansio.utils.c
| |____module.werkzeug.middleware.const
| |____module.flask.debughelpers.c
| |____module.zipp.c
| |____module.flask.const
| |____module.werkzeug.urls.const
| |____module.werkzeug.middleware.o
| |____module.jinja2.lexer.const
| |____module.itsdangerous.exc.c
| |____module.jinja2.debug.c
| |____module.jinja2.nodes.o
| |____module.jinja2.defaults.o
| |____module.flask.debughelpers.const
| |____module.werkzeug.serving.o
| |____module.markupsafe.c
| |____module.jinja2.ext.const
| |____module.click.types.o
| |____module.werkzeug.security.c
| |____module.jinja2.filters.c
| |____module.flask.json.c
| |____module.service.algorithm.const
| |____module.jinja2.loaders.const
| |____module.werkzeug.sansio.utils.const
| |____module.flask.cli.o
| |____module.flask.typing.c
| |____module.click.testing.o
|____app.py
|____service
| |____user.py

可执行文件: app.bin