在 PL/I 程序中实现 z/OS MVS 和 z/OS UNIX 的互操作性?

3

我在互联网上搜寻了各种资源,但没有找到一个我理解的明确答案,所以我在这里问:

如何从z/OS MVS调用z/OS UNIX代码?

我知道BPXBATCH PGM ...可以从z/OS MVS TSO调用z/OS UNIX程序。

但是我能否在z/OS MVS PL/I程序中执行此操作?

我的意思是,

  • 我是否可以静态链接z/OS MVS PL/I目标模块和z/OS UNIX C目标模块?(除了不同的编程语言外,两者之间是否存在区别?)
  • 还是我可以动态链接两者?

我的使用情况是:我有一个来自1970年代的旧PL/I库,现在需要进行网络化。据我所知,在z/OS UNIX世界中,网络化会很顺利。

旧的PL/I库静态链接了多个其他软件,我无法直接影响它们。

P.S.:是否有更多声望的人可以建立stackoverflow PLI标签?;-)


1
您是否正在使用IBM Enterprise PL/I? - cschneid
有点儿。 - fjf2002
我想说:就我所记得的,它是IBM Enterprise PL/I V4。我只是在使用它,我不是专家。 - fjf2002
3个回答

7
IBM的语言环境(LE)运行时的一个目的是使COBOL,PL/I,汇编和FORTRAN相互操作。 C和C ++后来也加入其中。生成非LE兼容代码的编译器彼此之间不兼容(如果你小心谨慎,则可以让所有玩家一起工作)。生成LE兼容代码的编译器彼此之间能够很好地协同工作。我曾经编写过使用C运行时例程(fopen,fseek,fread,fclose,各种正则表达式例程)的COBOL代码,并且由于LE而能够很好地工作。您对我的问题“您是否正在使用IBM企业PL / I”回答“有点”,可能表示您已处于不受支持的配置中。 如果您的运行时是LE,则可以调用IBM提供的C运行时例程。 如果您的运行时包括某些旧的不受支持的OS PL / I例程,则可能可以使IBM提供的对C运行时例程的调用工作--但如果是我在那种情况下,我不会睡得很安稳。如果您可以重新链接旧代码以使用旧的OS PL / I运行时例程的LE版本,则可能会发现自己站稳脚跟。

感谢您的回复。我们已经静态链接了来自不同语言(COBOL、PL/I、汇编)的目标模块。在我看来,您错过了主题。我的问题是:我可以混合使用 z/OS UNIX 目标模块吗?或者这无关紧要? - fjf2002
@fjf2002 如果你的意思是“我能否调用那些通过z/Unix命令行编译而设计为可被调用的模块”,那么是的,但前提是你提供它们所需的先决条件。如果你的意思是“我能否调用像curl和nslookup这样的模块,如果我将它们静态链接到我的现有代码中”,那么可能不行。 - cschneid
好的,让我看看是否理解。我试着换句话说:(1) 我登录到 z/OS UNIX,编译一些 C 代码目标模块。然后我登录到 ISPF,编译一些 1970 年代的 PL/I 模块,并静态链接到 UNIX C 模块,它会工作吗? (2) 如果正确,那么有什么阻止我链接到libcurl库或其他z/OS UNIX库? (3) 动态链接呢?有其他情况吗?参考我的第一个帖子。(4) 我不确定你所说的先决条件是什么意思? - fjf2002

6
关于z/OS和UNIX服务之间的关系,存在很多混淆,但需要记住的是这并不是两个独立的事物......几乎所有任务都可以成为UNIX进程并进行USS函数调用,只要设置正确。
因此,实际上你的问题可以分为两个问题:
1. 我如何使我的任务成为UNIX进程,以便我可以发出USS内核功能?
2. 我的PL/I编译器是否与LE运行库兼容,并且是否与使用其他LE语言构建代码的对象库兼容?
第一部分 - 如何将您的进程标记为UNIX进程 - 是相当简单的。IBM的方法要求您在调用UNIX函数之前连接到USS内核(OMVS地址空间),但通常在首次调用USS函数时会自动发生。
在使用USS之前,您需要进行一定的系统设置。当然,OMVS本身必须处于活动状态(虽然现在已经很少见了)。您的安全管理员需要给您一个UID号码,并可能为您创建一个主目录。假设这部分设置没有问题,您所需做的就是调用USS函数,现在您就是一个UNIX Services进程。
几乎任何应用程序都可以调用IBM的USS可调用服务(这是所有名称以BPX1/BPX4开头的模块)- 所有这需要支持标准操作系统链接的东西。实际上,这几乎就是IBM的运行库所做的。一个很好的测试是调用BPX1GPI(这是UNIX“getpid()”)......它返回您的UNIX进程ID,如果您可以让它工作,那么大多数其他UNIX Services也是可以使用的。如果您跟踪LE“getpid()”实现,会发现它不过是BPX1GPI上面的一层薄薄的封装,因此您没有理由不能自己调用底层函数......这适用于大多数USS内核函数,而不仅仅是getpid(),所以如果您无法弄清楚如何打开套接字,调用BPX1SOC通常是一个很好的“计划B”。
请记住,在成为UNIX进程和在类似bash shell下运行之间存在差异......shell执行诸如设置STDIN/OUT/ERR等操作 - 如果需要这些操作,您需要自行完成,如果您只是从无处连接到USS,您无法调用像printf()这样的东西,直到您设置了标准文件描述符。
一个简单的开始方式可能是编写一个短小的C程序,以UNIX进程形式运行,设置STDIN/OUT/ERR(以及其他任何您需要的内容),然后调用您当前的PL/I程序。这种方法能够包含您当前代码所需的所有USS项,而无需在PL/I中执行任何操作。您还可能发现,这是完成某些其他具有挑战性的PL/I操作的便捷方式,例如调用DLL函数......只需编写一个简短的C函数来完成所需操作,然后从PL/I代码中调用此函数即可。
关于你提出的第二个问题,如果你所使用的PL/I是LE运行时(除非它非常老),那么混合来自其他库的代码比听起来要简单得多。至于核心运行时部分,在大多数情况下,LE运行时函数都足够智能,“双模式”地工作,也就是说相同的运行时函数在USS进程和非USS进程中都可以工作。目标代码就是目标代码,一个z/OS文件打开和UNIX Services文件打开之间的区别仅仅是运行时是否调用SVC 19(用于z/OS OPEN)或BPX1OPN(用于UNIX Services文件)。这意味着一旦你的代码被定义为USS进程,你几乎可以自由地混合使用z/OS和USS函数。
这也意味着,假设在LE级别没有不兼容性等问题,你也可以在PL/I程序中使用类似"libxyz.a"这样的东西。在binder解析所有内容的方式符合你的期望之前,可能会有一些挑战,但只要坚持不懈,一切都应该能够正常工作。
有些事情在PL/I中会比较困难(我很抱歉,我不是PL/I专家)。例如像你的libcurl示例一样调用某个库是DLL而不是静态存档。同样,这里的技巧可能是使用一个短小的C“桥头堡”,你可以从PL/I中调用该桥头堡,而该代码可以完成加载和调用DLL所需的魔法操作。否则,一旦你把所有的部件整合在一起,我认为你会发现这是一个相当容易的练习。

1
阻止 PL/I 直接调用 C 库函数的部分是,在 LE PL/I-C-ILC 中,C 程序必须定义一个条目,作为从 PL/I 调用 (#pragma linkage(myentry,PLI)) - 而库函数没有提供这个。 - piet.t
1
很好的观点 - 更有理由在PLI代码周围使用“C”存根...例如,PL/I将此包装器称为“my_printf()”,并且可以使用您提到的#pragma编译包装函数,并调用标准运行时“printf()”函数(或其他函数)。 - Valerie R
Valerie,想请教你一下,能否看一下我的元帖“合并/清理标签 [zos]、[mvs]、[zseries] 和 [mainframe]”,并以比我更了解这些标签的人的身份发表评论? - JoshMc

3

请仅回答问题中有关'C和PL/I对象的静态链接'部分。

C或PL/I编译出的对象只是编译好的对象。无论您在TSO还是USS上编译它们,都没有区别;它们所在的位置(PDS / PDSE或HFS目录)也没有区别。

实际上,您可以轻松地将HFS中的文件(例如hello.o)复制到PDS中。

cp hello.o "//'MYHLQ.OBJ(HELLO)'"

甚至可以在USS上编译,然后将.o输出到PDS中。
c89 -c hello.c -o "//'MYHLQ.OBJ(HELLO)'"

然后使用BINDER进行链接(或反过来,从PDS复制对象到HFS,然后使用ld进行链接)

然而,有两种目标文件格式:XOBJ和GOFF。

GOFF是较新的格式,如果您使用XPLINK,则需要它。在z/OS上的64位LE程序也需要XPLINK。GOFF本身还需要PDS/E。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接