Python项目打包发布汇总
【Python】Python项目打包发布(一)(基于Pyinstaller打包多目录项目)
【Python】Python项目打包发布(二)(基于Pyinstaller打包PyWebIO项目)
【Python】Python项目打包发布(三)(基于Aardio打包多目录项目)
【Python】Python项目打包发布(四)(基于Nuitka打包PySide6项目)
【Python】Python项目打包发布(五)(制作Windows安装包)
说明
制作Windows安装包的工具有很多,其中比较知名的有:
- NSIS
- WiX
- InnoSetup
- InstallShield
- Advanced Installer
- …
比如Tarui自带的就有WiX和NSIS
1、NSIS
Python 环境下,已有开源工具包pynsist
github地址:https://github.com/takluyver/pynsist
说明
pynsist并没有对Python文件做任何编译处理,只是生成了Python文件脚本的快捷方式,打包目录下会包括整个Python环境。个人体验欠佳,不推荐。
2、InnoSetup
Inno Setup 是一个功能强大的免费安装程序制作工具。它具有易于使用的脚本语言,可以创建具有自定义界面、安装选项和脚本操作的安装程序。
Inno Setup配合nuitka体验极佳!推荐作为Python环境下的工具链。可以参考我在https://github.com/KmBase/Umi-OCR下写的nuitka_build.py一键打包脚本的配置
本脚本的主要功能有:
nuitka 生成可执行文件、zipfile制作portable文件、 InnoSetup制作安装文件。如不需要生成zip压缩包,或制作安装包。可以自行注释掉create_portable()、create_portable()对应语句
if __name__ == '__main__':
build()
create_portable()
if SYSTEM == 'Windows':
create_portable()
说明
nuitka是一个可以将Python代码转换为C++代码并编译为可执行文件或扩展模块的工具。可以明显提高python项目的加载运行速度。Inno Setup 是一个免费的 Windows 安装程序制作软件,十分简单实用的打包小工具。
使用步骤
1、安装项目依赖
pip install -r requirements.txt
2、安装nuitka
pip install -U nuitka
3、安装Inno Setup
官网下载地址:https://jrsoftware.org/download.php/is.exe
中文语言包:https://raw.githubusercontent.com/jrsoftware/issrc/main/Files/Languages/Unofficial/ChineseSimplified.isl
请保存语言包到Inno Setup安装目录
4、执行脚本
python nuitka_build.py
5、安装
-
生成build目录,包括nuitka编译过程文件目录(main.build)、可执行文件目录(main.release)、Inno Setup安装脚本(.iss)
-
用Inno Setup打开生成的.iss文件,或双击.iss打开。点击Run,生成安装文件
-
release目录包含portable压缩文件以及安装文件
-
双击安装文件,可以采用安装Umi-OCR到指定位置
6、卸载
控制面板找到Umi-OCR,卸载即可
附录
自用build.py
# subprocess.call(['pip', 'install', '-U', 'nuitka'])
# subprocess.call(['pip', 'install', '-r', 'requirements.txt'])
release = False
SYSTEM = platform.system()
ARCH = platform.architecture()[0][:2]
APP_VERSION = global_var.__version__
APP_NAME = global_var.SOFTWARE_NAME
GUID = uuid.uuid4() # 用于打包的唯一标识
# GUID = ""
EXEC_NAME = global_var.EXEC_NAME
APP_URL = global_var.APP_URL
APP_ICON = global_var.APP_ICON
APP_PUBLISHER = global_var.APP_PUBLISHER
PROJECT_DIR = Path(__file__).absolute().parent
SOURCE_DIR = Path('./')
BUILD_DIR = Path('build')
if not BUILD_DIR.exists():
BUILD_DIR.mkdir()
OUTPUT_DIR = BUILD_DIR / f'{SYSTEM}-{ARCH}'
DIST_DIR = Path.joinpath(OUTPUT_DIR, f'{global_var.EXEC_NAME}.dist')
ICON_DIR = Path.joinpath(DIST_DIR, APP_ICON)
print(APP_VERSION)
RELEASE_DIR = Path('release') / APP_VERSION
print(RELEASE_DIR)
if not RELEASE_DIR.exists():
os.makedirs(RELEASE_DIR, exist_ok=True)
def build():
nuitka_cmd = [
'python',
'-m',
'nuitka',
'--mingw64',
'--show-progress',
'--show-memory',
'--standalone',
'--include-data-dir=data=data',
'--include-data-dir=view/res=view/res',
"--include-data-dir=pj=pj",
'--enable-plugin=pyside6',
'--nofollow-import-to=tkinter',
f'--output-dir={OUTPUT_DIR}'
]
if platform.system() == 'Windows':
nuitka_cmd.extend([f'--windows-icon-from-ico={APP_ICON}'])
elif platform.system() == 'Linux':
nuitka_cmd.extend([f'--linux-icon={APP_ICON}'])
else:
pass
if release:
nuitka_cmd.extend(['--disable-console'])
else:
nuitka_cmd.extend(['--enable-console'])
nuitka_cmd.append(f'{SOURCE_DIR}/{EXEC_NAME}.py')
process = subprocess.run(nuitka_cmd, shell=True)
if process.returncode != 0:
raise ChildProcessError('Nuitka building failed.')
print('Building done.')
def create_portable():
file_list = glob.glob(f'{OUTPUT_DIR / APP_NAME}.dist/**', recursive=True)
file_list.sort()
portable_file = RELEASE_DIR / f'{APP_NAME}-{APP_VERSION}-Portable-{SYSTEM}-{ARCH}.zip'
print('Creating portable package...')
with ZipFile(portable_file, 'w', compression=ZIP_DEFLATED) as zf:
for file in file_list:
file = Path(file)
name_in_zip = f'{APP_NAME}-{ARCH}/{"/".join(file.parts[3:])}'
print(name_in_zip)
if file.is_file():
zf.write(file, name_in_zip)
print('Creating portable package done.')
def update_iss():
settings = {
'APP_NAME': APP_NAME,
'APP_URL': APP_URL,
'GUID': GUID,
'APP_PUBLISHER': APP_PUBLISHER,
'APP_VERSION': APP_VERSION,
'EXEC_NAME': EXEC_NAME,
'PROJECT_DIR': str(PROJECT_DIR),
'OUTPUT_DIR': str(OUTPUT_DIR),
'DIST_DIR': str(DIST_DIR),
'RELEASE_DIR': str(RELEASE_DIR),
'ICON_DIR': str(ICON_DIR),
'ARCH': ARCH,
'ARCH_MODE': 'ArchitecturesInstallIn64BitMode=x64' if ARCH == '64' else ''
}
iss_template = f'nuitka-setup-template.iss'
iss_work = Path(BUILD_DIR) / f'{APP_NAME}-{ARCH}.iss'
with open(iss_template) as template:
iss_script = template.read()
for key in settings:
iss_script = iss_script.replace(f'%%{key}%%', settings.get(key))
with open(iss_work, 'w') as iss:
iss.write(iss_script)
return iss_work
def check_iss():
if ARCH == '64':
program_files = os.environ.get('ProgramFiles(x86)')
else:
program_files = os.environ.get('ProgramFiles')
iss_compiler = Path(program_files) / 'Inno Setup 6' / 'Compil32.exe'
if iss_compiler.exists():
return iss_compiler
return None
def create_setup():
iss_work = update_iss()
iss_compiler = check_iss()
if iss_compiler:
print('Creating Windows Installer...', end='')
compiler_cmd = [str(iss_compiler), '/cc', str(iss_work)]
process = subprocess.run(compiler_cmd)
if process.returncode != 0:
raise ChildProcessError('Creating Windows installer failed.')
print('done')
自用nuitka-setup-template.iss
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={#GUID}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DisableProgramGroupPage=yes
LicenseFile={#MyProjectDir}\LICENSE
;InfoBeforeFile={#MyProjectDir}\README.md
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputDir={#MyProjectDir}\%%RELEASE_DIR%%
OutputBaseFilename={#MyAppName}-{#MyAppVersion}-Setup-Windows-%%ARCH%%
SetupIconFile={#MyProjectDir}\{#MyIcon}
Compression=lzma
SolidCompression=yes
WizardStyle=modern
%%ARCH_MODE%%
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "{#MyProjectDir}\{#MyDist}\{#MyAppExeName}.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MyProjectDir}\{#MyDist}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
参考文献:
https://www.cnblogs.com/chrisfang/p/17027553.html
inno setup打包程序安装出现CreateProcess failed;code 740