使用cython的代码保护方案

简介: 建模开发平台即将推出了镜像构建的功能,以方便用户将开发好的代码迁移至其他环境执行。但在迁移过程中难免会有代码保护的需求,现提供一种基于cython的代码保护方案,能够在一定程度上解决代码保护的问题。

参考文档:

https://cython.org/

https://github.com/cython/cython

https://zhuanlan.zhihu.com/p/54296517


Cython介绍

Cython是一个类似于Python的编程语言,它是基于Python语言的扩展和优化。Cython语言是一种静态类型语言,同时也支持Python的动态类型特性,Cython代码会被转换成C语言代码,再编译成机器码,因此其执行速度比Python要快。

虽然Cython 的主要目的是带来性能的提升,但是基于它的原理:将 .py/.pyx 编译为 .c 文件,再将 .c 文件编译为 .so(Unix) 或 .pyd(Windows),其带来的另一个好处就是难以破解。但需要注意的是,cython本质上并非提供加密功能,而是通过编译成二进制文件后,提高他人阅读核心代码的难度,使用此方法加密代码还要注意代码安全。


方法

1)编写 setup.py:

可根据cython官方文档的指引,对您的代码进行编译。以下代码可供参考:

此脚本将会找到当前目录下所有含__init__.py文件的目录,并对他们进行编译,并在原地生成.so文件。

#encoding=utf-8fromsetuptoolsimportsetup, find_packagesfromsetuptools.extensionimportExtensionfromCython.BuildimportcythonizefromCython.Distutilsimportbuild_extfrompathlibimportPathimportshutilimportsys, os# some global variable, don't change them if you don't know what they meanmy_build_dir="build"classMyBuildExt(build_ext):
defrun(self):
build_ext.run(self)
build_dir=Path(self.build_lib)
root_dir=Path(__file__).parenttarget_dir=build_dirifnotself.inplaceelseroot_dirformoduleinmy_packages:
module=module.replace(".","/")
module_path=Path(module)
print(">>find modeule path:"+str(module_path))
self.copy_file(module_path/'__init__.py', root_dir, target_dir)
self.copy_file(module_path/'__main__.py', root_dir, target_dir)
forpinPath('.').iterdir():
ifp.is_file() andp.suffixnotin [".py", ".pyc"] andp.namenotinexclude_list:
self.copy_file(p, root_dir, target_dir)
print("copy end")
defcopy_file(self, path, source_dir, destination_dir):
ifnot (source_dir/path).exists():
returnshutil.copyfile(str(source_dir/path), str(destination_dir/path))
deffind_scrips():
scrips_list= []
forpinPath('.').iterdir():
ifp.is_file() and (p.namenotinexclude_list):
ifp.suffixin [".py"] and (notp.name.startswith(".")):
scrips_list.append(p.name)
print("find scrips:")
print(scrips_list)
print(exclude_list)
returnscrips_listif__name__=="__main__":
my_project_name="test"my_clang="gcc "ifos.path.isdir(my_build_dir):
print("Exist build dir, auto remove")
shutil.rmtree(my_build_dir)
print("===============start=================")
exclude_list= ["setup.py", ".DS_Store"]
os.environ["CC"]=my_clangmy_packages=find_packages()
print("packages:")
print(my_packages)
ext=[]
#找到所有的packageformoduleinmy_packages:
module=module.replace(".","/")
ext.append(Extension(module+".*", [module+"/*.py"]))
#找到根目录下的脚本ext.extend(find_scrips())
print("Extension:")
print(ext)
setup(
name=my_project_name,
ext_modules=cythonize(
ext,
build_dir=my_build_dir,
compiler_directives=dict(
always_allow_keywords=True            )),
cmdclass=dict(
build_ext=MyBuildExt        ),
packages=find_packages(where=".")
    )
print("===============end=================")

2)编译为 .c,再进一步编译为 .so 或 .pyd:

python setup.py build_ext --inplace

3)删除python源码,通过.so的方式进行执行:

find . -name'*py[c~]'-delete

4)编写启动脚本,执行过程中调用启动脚本:

from real_main import main
import sys
if __name__ =='__main__':
    main(sys.argv[1:])


注意事项

Cython 源代码的语法是 Python语法的一个超集,也就是说,任何可以在 Python 中使用的语法,也可以在 Cython 中使用。但是,以下几种 Python语法在 Cython 中是不支持的:

1.动态类型变量声明:在 Cython 中,变量必须是静态类型,需要在声明时指定数据类型。

2.不支持 eval() 函数和 exec语句:因为 Cython 是一种编译型语言,无法像 Python一样动态生成代码。

3.不支持生成器表达式和列表推导式:Cython 中不能直接使用生成器表达式和列表推导式,但是可以使用类似于 Python 中的 for 循环语句来达到相同的效果。

4.不支持一些 Python 内置函数:例如 zip(), filter(), map() 等,但是 Cython 提供了自己的实现,用于替代这些函数。

5.不支持 slots 特殊变量:Cython 中不支持 slots 特殊变量来限制类的属性,但是可以使用 cdef class 来实现类的属性限制。

6.不支持一些 Python 模块和库:例如 asyncio, logging 等,因为这些模块和库在 Cython 中不可用。

7.不支持 Python 的全局解释器锁(GIL):Cython 中没有 GIL,因此可以使用 Python 的多线程模块来实现并发编程。

相关文章
|
C语言 Perl 存储
优化求解器之MPS文件的格式简介
在使用MindOpt优化求解器解决实际问题时,其中重要的一环在于如何建立优化模型,以及存储优化模型以便于作为求解器的输入文件。存储优化模型的文件,其关键在于定义一种清晰的格式,用来说明优化模型的数学结构和相关的数据。接下来我们将发布一系列文章,对常见的MPS/LP等格式的模型文件和命名规范进行简要的介绍。
优化求解器之MPS文件的格式简介
|
编解码 Ubuntu 编译器
Qt开发笔记之编码x264码流并封装mp4(四):mp4v2库的介绍和windows平台编译
Qt开发笔记之编码x264码流并封装mp4(四):mp4v2库的介绍和windows平台编译
Qt开发笔记之编码x264码流并封装mp4(四):mp4v2库的介绍和windows平台编译
|
机器学习/深度学习 算法 数据挖掘
【Python机器学习】K-Means对文本聚类和半环形数据聚类实战(附源码和数据集)
【Python机器学习】K-Means对文本聚类和半环形数据聚类实战(附源码和数据集)
459 0
|
达摩院 算法 Java
选择优化求解器的关键因素:以MindOpt为例
选择一款适合自己业务需求的求解器我们一般需要考量什么呢?可求解的问题类型?问题规模?本文将介绍一些需要考虑的重要因素,并且介绍阿里达摩院MindOpt优化求解器在这些因素下的表现。
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
806 113
|
缓存 达摩院 算法
如何通过阿里达摩院MindOpt获得MILP多个解
在2024年1月达摩院新发布的MindOpt 优化求解器V1.1.0版本中,新增加了一个"MIP/SolutionNumber"参数,可以用于获取MILP多个解。有些业务里,会想要找到更多的可行解,目标值不一定最优,用于给业务指导。本篇案例将讲解如何使用此功能。
527 1
|
人工智能 达摩院 算法
什么是优化技术?给算法小白同学的快速讲解和上手文
经常被尊贵的客户问,什么是优化技术,能干啥?小白一文快速入门,并掌握业界前沿的高效上手方案!
831 1
|
Go
Go 1.21 新内置函数:min、max 和 clear
Go 1.21 版本已经正式发布,它带来了许多新特性和改进。其中引入了的三个新内置函数:max、min 和 clear,接下来的内容将详细介绍这些函数的用途和特点。
538 1
Python语言如何使用MindOpt建模并求解混合整数线性规划问题
MindOpt是一款高效的优化算法软件包,求解算法实现了线性规划(LP)、混合整数线性规划(MILP)、二次规划(QP),可以支持命令行、c、c++、java和python调用。接下来我们将发布一系列文章,讲述各个语言如何使用 MindOpt 来求解数学规划问题。
Python语言如何使用MindOpt建模并求解混合整数线性规划问题