本帖最后由 lovingxiaobing 于 2020-3-4 17:30 编辑

本文所使用到的工具:

msys2(mingw-w64)

nm

dlltool

python

近段时间想要学点opengl es,在PC上运行需要模拟的工具。

我找了找有很多种,ANGLE、PowerVR、ARM-Mail、AdrenoSDK...这些我都亲自找过,不过都是只能用在msvc上使用。。。最后我选着了ANGLE,这货不仅是开源的,而且还被很多浏览器用来作为WebGL的后端,它在windows上是将D3D转成OpenGL ES接口。现在最主要的问题就是使用MINGW来编译,看了几天它的文档,怎么都配置不好,(I'm so vegetable)。

ANGLE在每个使用ANGLE的项目里都有动态库(libegl.dll、libglesv2.dll),我目前在很多软件的项目里面都找到了它,包括QQ、微信,tim,还有很多使用或者非使用Chromium内核的浏览器以及WebApp的目录下都能找到ANGLE.下面是Chrome的安装目录和QQ的安装目录下的找到的:


pic1.PNG (125.89 KB, 下载次数: 0)

2020-3-4 17:00 上传


pic2.PNG (135.31 KB, 下载次数: 0)

2020-3-4 17:00 上传


pic3.PNG (30.85 KB, 下载次数: 0)

2020-3-4 17:00 上传

emmmmm, 跑题啦?没有把,我想说的是,有些开源库我们可以找到别人编译好的,接下来就是找头文件啦,我们可以去ANGLE的开源页,但是谷歌的开源网站有抢,我们也可以去Github找他的mirro(https://github.com/google/angle),我现在在做关于Opengl ES的,也可以去找EGL-Registry(https://github.com/KhronosGroup/EGL-Registry)、OpenGL-Registry(https://github.com/KhronosGroup/OpenGL-Registry)、、、、总之有很多办法可以得到头文件!

看到了这里,上面的可能就是废话啦!哈哈哈!

就只有2点:

找到编译好的动态库

找到头文件(有一些不开源的, 条件允许的话可以自己捏)

下面就是制作(我是以我现在需要的来掩饰的):

先准备好libEGL.dll和libGLESv2.dll这两个文件(问了文章简短,我就以libEGL.dll作为掩饰要弄的)。

我们需要从这个动态库中导出符号, 用来捏def文件.(关于def文件msdn上有文档)

如何导出dll中的符号,有多种方法,可以使用dumpbin、depends、等等可以导出DLL中的符号的工具。


pic4.PNG (32.18 KB, 下载次数: 0)

2020-3-4 17:00 上传

将这些符号拷贝到libEGL.def文件中,并保存.


pic5.PNG (83.88 KB, 下载次数: 0)

2020-3-4 17:00 上传

现在还剩最后一个问题,就是x86下stdcall修饰的函数是被改名的,gcc内部在查找符号时,是以改名后的名字取查找的。


pic6.PNG (74.96 KB, 下载次数: 0)

2020-3-4 17:00 上传

如果是64位的系统就不需要改名,可以跳过下面半手工改名的步骤。

stdcall修饰的函数,被改名的名字格式是(这里以mingw32中为例子),

单个下划线 + 函数名 + @ + 函数参数总大小.

就如上图所示,我的机器是32位的。

如果我们自己一个一个函数去动脑子算,那很浪费时间,我们可以让机器代替我们算,我们可以从头文件总的函数来给我们要是用的符号加上外部依赖。(我在说啥。。。)

反正就是让编译器知道有这么个形式的函数,让他帮我们算好,我们再拿出来清洗清洗就可以用了。。。

我们可以做一张表,来把所有的函数都加入到里面,让他依赖外部符号。


pic7.PNG (37.19 KB, 下载次数: 0)

2020-3-4 17:00 上传

差不多就这样子,现在我们就用py写一个脚本来批量做这件事,我们把libEGL.def文件中每一个函数名都写到这个table中


pic8.PNG (207.92 KB, 下载次数: 0)

2020-3-4 17:00 上传

下面我们就要动工啦,我们编译一下这个文件(不要链接!因为我们还没有做好导入库!)


pic.png (83.87 KB, 下载次数: 0)

2020-3-4 17:07 上传

这是执行nm后得到的结果,按照这个格式,我们就把"函数名@参数总大小"提取出来,再写回到libEGL.def中,我们在刚才那个脚本的基础上再加上执行和清洗的逻辑。


pic9.PNG (158.4 KB, 下载次数: 0)

2020-3-4 17:00 上传

对于这个def文件的最后一步是补上正确语法,如果你是64位的windows,直接跳到这一步,不需要修改名字。


pic10.PNG (15.84 KB, 下载次数: 0)

2020-3-4 17:00 上传

上面标出黄色部分就是要补上的,你也可以把这个补上正确语法的写入到脚本中,这儿就不再赘述了。有些库的导出函数可能在头文件中没有相关的声明,可能得自己补上,或者从def中删掉这个函数.

到了我们最后一步,就是制作导入库!


pic11.PNG (112.18 KB, 下载次数: 0)

2020-3-4 17:00 上传

OK, 我们已经整出来啦!!

接下来我们就写一段代码测试一下!


pic12.PNG (141.93 KB, 下载次数: 0)

2020-3-4 17:00 上传

可以使用了!!

上面我是以一个例子来讲的,可能不算得上是干货~~~

下面我就把这个脚本完善一下,给大家参考参考吧(仅供参考!)。。。

代码:

[Python] 纯文本查看 复制代码################

# 请使用未改名的def

################

import subprocess
import os
header = r'''
#define EGL_EGLEXT_PROTOTYPES
#include "EGL/egl.h"
#include "EGL/eglext.h"
'''
decl = r"#define DECL_EGL_FUNCTION(name) ((void*)&name)"
table = r'''
static void* table[] = {
%s
};
'''
gClearString = None
with open("libEGL.def", "r") as f:
symbol = f.read()
fname = symbol.split("\n")
tableSrc = table % (",\n".join(("DECL_EGL_FUNCTION({})".format(name) for name in fname)))
src = "\n".join([header, decl, tableSrc])
with open("libEGL.c", "w+") as eglSrc:
eglSrc.write(src)
subprocess.call(["gcc", "-c", "libEGL.c", "-I", "."])
nmPip = subprocess.Popen(["nm", "-g", "libEGL.o"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
dirtyString = nmPip.communicate()[0].decode()
clearString = [s.split("_")[-1].strip() for s in dirtyString.split("\n")]
gClearString = "\n".join(clearString)
with open("libEGL.def", "w") as f:
f.write("\n".join(['LIBRARY "libEGL.dll"', 'EXPORTS', gClearString]))
subprocess.call(["dlltool", "--kill-at",
"--dllname", "libEGL.dll",
"--input-def", "libEGL.def",
"--output-lib", "libEGL.a"])
os.remove("libEGL.c")
os.remove("libEGL.o")

我还会再提供EGL和GLESv2的导入库ANGLG-IMLIB,给需要的人

下面是文中一些代码的附件

(因论坛限制附件大小,我就存到微云中分享给大家~~~)

(附件文件名为: demo.zip、ANGLE-IMPLIB.zip)

https://share.weiyun.com/5xSzBVg

(包教不包会)

还有一件事ANGLE它自己也提供了EGL、GLES的def文件。。。。

还有一件事,上面的示例不是固定死的,主要是使用dlltool这个工具来生成mingw支持的导入库。其余自己自由发挥,也可以参考我的方法。

还有一件事,这个自己捏导入库适用于懒得编译或者太难编译的开源库以及一些动态库的静态链接。