背景

在对易语言程序进行静态编译时,可能会遇到支持库作者未提供库的静态库版本的情况。

编译时提示缺少静态库

笔者在数年前针对此开发了一个工具SalHeEStaticLibECodeMaker专门用于临时性解决该问题。

环境准备

编译环境

工具准备

  • SalHeELibTools&SalHeEStaticLibECodeMaker: 该仓库中源代码目前已长久未更新,您可以直接下载压缩包,并找到Tools\SalHeELibToolsTools\SalHeEStaticLibECodeMaker,里面有预编译好的可执行文件,也有程序的源码。请注意,该预编译好的可执行文件是从笔者机器上拷贝下来,无法保证其在传播过程中不被感染,建议您从源码编译并运行程序(建议使用Win7或XP编译)。
    • SalHeEStaticLibECodeMaker: 用于生成静态库的代码
    • SalHeELibTools: 用于将编译后的文件转换为可供易语言静态编译的静态库

案例中使用到的支持库及测试源码

生成静态库代码

先打开SalHeEStaticLibECodeMaker,这里我们将程序界面中的重新包装动态库勾选上(这一步并不是必须的,如何选择请参见什么是重新包装动态库?)。

SalHeEStaticLibECodeMaker

原理

SalHeEStaticLibECodeMaker的原理是为您生成针对对应支持库的静态库代码,您手动根据提示将其使用易语言编译后,借助SalHeELibTools将其转换成可供静态编译的支持库静态库。

什么是重新包装动态库?

在易语言支持库中,如果一个支持库希望静态编译,那么它需要在通知函数中补充支持库某些函数导出名并通知给易语言,否则易语言不知道将易语言程序中对支持库的调用静态链接哪个导出函数上。然而,有些支持库并没有在内部实现该改造,所以我们需要做点小工作,让它把这些信息返回给易语言。

重新包装动态库中生成的动态库便是做该工作的,到时候我们将获得一个易语言支持库的动态库版本(fne)。

而对于那些响应了函数导出名给易语言的支持库,不需要重新包装动态库

目前已更新: 针对必须要重新包装动态库的支持库,程序会主动提醒并且强制要求您主动开启重新包装动态库

生成支持库代码

将所需要处理的支持库拖拽到SalHeEStaticLibECodeMaker窗口中,程序将自动为对应支持库生成重新包装动态库代码静态库代码

根据提示,我们获得了两个代码文件:

  • 重新包装动态库代码: YunScript_reload_CODE.txt
  • 静态库代码: YunScript_static_ECODE.txt

受限于程序编写时的技术限制,SalHeEStaticLibECodeMaker以文本文档格式存储了库的易语言代码,所以您需要针对两个库各自新建易语言DLL程序,并将代码粘贴到其中去。

编译包装后的支持库

重新包装动态库代码静态库代码在易语言中建立并粘贴后,您还需要处理以下事务:

  1. 打开两个源码的图片资源表常量数据表
  2. LIB_FILE_NAME: 改为您期望在运行时输出的原支持库文件名(上面解释过,实际生成的库相当于增加了一层调用层,实际运行是需要依赖原支持库的)
  3. LIB_DATA: 导入原支持库文件
  4. _SALHE_ESTATIC_LIB_ECODE_MAKER_TAG: 导入elang-lib-sdk\Tools\SalHeELibTools\Code\StaticLibTag\<TAG_FILE>,并记住<TAG_FILE>,假设我们这里选取_SALHE_ESTATIC_LIB_ECODE_MAKER_TAG

编译重新包装动态库

对于不需要重新包装动态库的支持库,您可以跳过此步。

重新包装动态库代码编译,并命名为<支持库>.fne,这里我们对于该支持库,命名为YunScript.fne

现在,您可以将这个“新”的支持库放入到易语言lib目录中去。

编译并转换获得静态库

静态库代码使用黑月编译(编译得到的DLL并不能直接作为静态库使用,还需要转换),并将其命名为YunScript.xxx(xxx代表任意后缀名,但是文件名YunScript必须对应)。

为何需要黑月编译?经过反汇编调试发现易语言静态编译的DLL在获取函数指针的时候,跟可执行文件在运行期的行为表现不一致,导致将函数转换成cdecl调用方式时出错,最终导致调用库函数时栈不平衡。

经测试,黑月编译后可保证一致性。

嗯,至少目前来说我个人得到的是这么个结论。

打开SalHeELibTools,在← 置入代码标识中选择您之前在编译包装后的支持库中的第4步中选择的标识文件<TAG_FILE>,我们在上面的步骤中选了_SALHE_ESTATIC_LIB_ECODE_MAKER_TAG,所以这里也选_SALHE_ESTATIC_LIB_ECODE_MAKER_TAG

选择正确的置入代码标识

这里一定不能选错,否则SalHeELibTools不能正常处理您的静态库。

准备完成后,将YunScript.xxx拖入SalHeELibTools,等待转换完成。

转换成功提示

转换完成后,您便可以看到上图中的提示,并在YunScript.xxx所在目录下找到YunScript_static.lib文件,该文件便可与放入易语言的static_lib目录下。然后开始享受静态编译吧!

静态编译效果

将我们处理好的重新包装动态库静态库正确安装后,便可以进行静态编译了。

静态编译测试

相关问题

静态库配套问题

静态库与重新包装动态库或原支持库必须配套使用,也就是说:

  • 当您使用重新包装动态库时,必须使用勾选了重新包装动态库时生成的静态库
  • 当您未使用重新包装动态库时(也就是说你使用原本的支持库动态库作为动态库),必须使用未勾选了重新包装动态库时生成的静态库

仅是临时性方案

该方案比较建议用于应急,在您没有支持库源码以生成静态库时它是一个不错的选择,不建议用于作为发布静态库的选择。

留言

如果编译后的程序不能执行,您可以在本文下方进行留言,或者前往GitHub仓库开启Issue。