linux系统

1、py文件编译为pyc文件:具有一定的保密性,但有可能被反编译

pyc是一种二进制文件,是由py文件经过编译后,生成的文件,是一种byte code,py文件变成pyc文件后,加载的速度有所提高,而且pyc是一种跨平台的字节码,是由python的虚拟机来执行的,这个是类似于JAVA或者.NET的虚拟机的概念。

pyc的内容,是跟python的版本相关的,不同版本编译后的pyc文件是不同的,2.5编译的pyc文件,2.4版本的 python是无法执行的


2、setup编译为whl格式第三方库:生成whl格式第三方库,可直接pip install 安装,但安装后,代码开源,不利于代码保护



3、pyinstaller打包生成dist文件夹:代码保护极好,但打包内容过多,臃肿

本次又个需求,在ubuntu上面开发的python代码程序需要打包成一个可执行程序然后交付给甲方,因为不能直接给源码给甲方,所以寻找方法将python开发的源码打包成一个可执行程序,注意是打包成在ubuntu上面的可执行程序,不是打包成在window上的可执行程序,如果需要打包成windows上的可执行程序请参照此博客,链接:windows下打包python源码成可执行文件

本次在ubuntu上打包python源码的方法和在window上打包的有点类似,大概流程如下:

1.在ubuntu上安装easy_install

#sudo apt-get install python-setuptools python-dev build-essential

2.下载并安装pyinstaller

在网址下载pyisntaller的包,地址:http://www.pyinstaller.org/,下载对应的tar包

假设下载下来的包是:pyinstaller_2.1.tar.gz

然后使用命令解压包:#tar -cf pyinstaller_2.1.tar.gz

进入解压后的目录:#cd pyinstaller_2.1

最后执行命令安装pyinstaller:#sudo python setup.py install

如果中间没有报错的话,pyinstaller就安装完成了。

PyInstaller 不仅支持 -F、-D 选项,而且也支持如表 1 所示的常用选项。

表 1 PyInstaller 支持的常用选项

-h,--help

查看该模块的帮助信息

-F,-onefile

产生单个的可执行文件

-D,--onedir

产生一个目录(包含多个文件)作为可执行程序

-a,--ascii

不包含 Unicode 字符集支持

-d,--debug

产生 debug 版本的可执行文件

-w,--windowed,--noconsolc

指定程序运行时不显示命令行窗口(仅对 Windows 有效)

-c,--nowindowed,--console

指定使用命令行窗口运行程序(仅对 Windows 有效)

-o DIR,--out=DIR

指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件

-p DIR,--path=DIR

设置 Python 导入模块的路径(和设置 PYTHONPATH 环境变量的作用相似)。也可使用路径分隔符(Windows 使用分号,Linux 使用冒号)来分隔多个路径

-n NAME,--name=NAME

指定项目(产生的 spec)名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字

在表 1 中列出的只是 PyInstaller 模块所支持的常用选项,如果需要了解 PyInstaller 选项的详细信息,则可通过 pyinstaller -h 来查看。

3.打包python项目源码

假如说你的python源码的结构目录如下:

total 16
 drwxrwxr-x 2 jelly jelly 4096 Mar 14 15:13 config
 drwxrwxr-x 2 jelly jelly 4096 Mar 14 15:13 database
 -rw-rw-r-- 1 jelly jelly    2 Mar 14 15:13 main.py
 -rw-rw-r-- 1 jelly jelly    3 Mar 14 15:13 manager.py


图中可以看到有两个文件夹,两个py源码文件,mian.py是主函数文件

然后,我们使用命令打包源码

#pyinstaller -F main.py

然后就会生成如下目录

total 28
drwxrwxr-x 3 jelly jelly 4096 Mar 14 15:18 build
drwxrwxr-x 2 jelly jelly 4096 Mar 14 15:13 config
drwxrwxr-x 2 jelly jelly 4096 Mar 14 15:13 database
drwxrwxr-x 2 jelly jelly 4096 Mar 14 15:18 dist
-rw-rw-r-- 1 jelly jelly    2 Mar 14 15:13 main.py
-rw-rw-r-- 1 jelly jelly  813 Mar 14 15:18 main.spec
-rw-rw-r-- 1 jelly jelly    3 Mar 14 15:13 manager.py

图中dist文件夹下面就是生成的可执行文件,可以使用命令./main执行生成的可执行文件

但是此时你会发现有问题,因为这个打包的方法它只会打包当前目录下的所有py文件,而不会打包config和database这两个文件夹,所以此时的可执行文件打包的并不完整,此时该怎么做呢,咱们接着来

4.重新打包

重新打包的的意思是需要修改那个main.spec文件,然后再使用这个文件进行打包,操作流程如下

打开main.spec文件,修改前如下内容

# -*- mode: python ; coding: utf-8 -*-
 
block_cipher = None
a = Analysis(['main.py'],
             pathex=['/home/jelly/test'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='main',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True )

修改后的main.spec文件内容如下:

# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['main.py'],
             pathex=['/home/jelly/test'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
 
dict_database = Tree('/home/jelly/test/database',prefix='database')
a.datas += dict_database
dict_config = Tree('/home/jelly/test/config',prefix='config')
a.datas += dict_config
 
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='main',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True )

可以看到,中间添加了添加两个文件夹的绝对路径,是和这个路径相对应的

pathex=['/home/jelly/test'],

这个路径是之前工具自己生成的,所以我们添加的两个目录的绝对路径也和它保持一致,这个修改完成后久可以了

5.编译生成

安装第4步的修改完成后,再执行命令

#pyinstaller mian.spec

即可,这样打包的程序就包含了两个依赖的文件夹了

其实最后感觉和在window上面打包生成window上的可执行文件的流程差不多,工具也都是用的pyinstaller打包。

 

4、(强烈建议)打包为so文件:

代码保护极好,只能知道输入输出;
 1)第一种只给.so文件到另一平台,但需要和本地编译环境一直,本地是python3.7,那此.so文件也只能在python3.7环境中运行;

2)给中间结果.c文件,让其在自己平台上编译,运行python setup.py build_ext编译,只需要在setup.py中将py文件修改为.c文件即可。