使用从著名的关于 RPG 异常和错误处理的 IBM 红皮书中学到的概念,我编写了一个服务程序QGPL/ERRFUNC
来实现可重用的错误函数,如Assert
、Throw
、ThrowMsg
、Rethrow
和GetErrorMsg
。我一直在几个不同的程序中使用它们,并且它们运行良好。
刚才,我Throw
在一个 RPG ILE 程序中使用了该函数,该程序还静态调用access
用于 IFS 文件系统上的流文件的 C 样式函数。该程序将无法编译,并出现“为符号抛出多次提供定义”的绑定错误。据我所知,使用命令编译时无法获取绑定详细信息CRTBNDRPG
,但我能够注释掉我的H DFTACTGRP(*NO)
规范,然后使用CRTRPGMOD
附加CRTPGM
参数编译它DETAIL(*EXTENDED)
。这将打印出编译器在确定要静态绑定到哪些过程时查看的所有过程名称的扩展列表。这揭示了“投掷”的双重定义。在 72 页列表的深处,IBM 提供的服务程序QJVAJNI
(Java Native Interface) 被引用,它包含一个导出的过程,也称为“Throw”。
现在,解决我当前问题的最简单方法是简单地重命名我的“Throw”过程,修改并重新编译我的服务程序,然后修改并重新编译所有引用它的程序。我可能会遵循该解决方案,但这种行为引发了几个令人不安的问题:
为什么 C 风格的 IFS 函数使用 Java 本地接口来完成它的工作?我看到像这样的服务程序的导入
QC2IFS
在QC2POSIX
上下文中完全有意义。看起来 IBM 在这里引入了一个我们必须忍受的意外依赖项。我确信它是引用 的 C 服务程序之一,QJVAJNI
因为当我注释掉access
函数调用时,QJVAJNI
不会引用 。有可能对QJVAJNI
服务程序的引用有好几层深,意思是一个导入一个导入。为什么绑定器通过服务程序导入如此彻底地递归?活页夹看起来像是经历了每个服务程序使用的每个导入,无论该导入是否被程序和被绑定的子过程使用。那有必要吗?递归检查每个级别使用的导入不是有效吗?有没有办法改变这种行为?
如果对上述两个问题无能为力,这是否意味着要保证绑定始终有效(特别是对于“通用”功能,如错误处理),必须确保没有任何其他导出的过程机器上的任何地方同名?我不知道有任何设施(如命名空间)可以缓解这个问题。据我所知,ILE 编译器不使用其他平台在这种情况下可能使用的任何方法,例如重载或名称修改。像我在一些 C 导出中看到的那样开始“非正式命名空间”是否是一个好习惯(例如
_C_NEU_IFS_feof
) 以防止名称冲突?或者,有没有办法在发布服务程序之前搜索机器上所有导出的程序以查找您想要的名称?IBM 红皮书的作者是 ILE 编程领域的一些重量级人物。他们像我一样将他们推荐的导出之一命名为“Throw”(尽管使用不同的参数列表)。他们是否遇到过类似的问题?他们有不同的方法来解决名称冲突吗?
我发现*DUPPROC
可以为 指定一个选项CRTPGM
,但我不确定这是一个好主意。文档说“当允许多个重复过程时,指定模块和服务程序列表中与导入请求匹配的第一个导出过程是选择的过程。” 你能确定哪个符号将在列表中排在第一位吗?顺序是否严格定义?