我一直在互联网上的各种资源中闲逛,但找不到我理解的明确答案,所以我在这里问:
如何从 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库与我无法直接影响的其他多个软件静态链接。
PS:声誉更高的人可以建立一个堆栈溢出PLI标签吗?;-)
IBM 语言环境 (LE) 运行时的一个目的是使 COBOL、PL/I、Assembler 和 FORTRAN 可互操作。 C和C++后来也来了。
生成不符合 LE 标准的代码的编译器彼此配合得不好(如果你小心的话,你可以让所有玩家一起工作)。 生成符合 LE 标准的代码的编译器可以很好地相互配合。 我编写了使用 C 运行时例程(fopen、fseek、fread、fclose、各种正则表达式例程)的 COBOL 代码,并且由于 LE 而工作正常。
您对我关于您是否正在使用 IBM Enterprise PL/I 的问题的回答"嗯,有点">可能表明您已经处于不受支持的配置中。
如果您的运行时是 LE,那么调用 IBM 提供的 C 运行时例程应该没问题。 如果您的运行时包含一些旧的不受支持的 OS PL/I 例程,您也许能够调用 IBM 提供的 C 运行时例程来工作 - 但在这种情况下,我不会睡得很香。 如果您可以重新链接旧代码以使用旧操作系统 PL/I 运行时例程的 LE 版本,您可能会发现自己处于更坚实的基础。
关于 z/OS 和 UNIX 服务之间的关系有很多混淆,但要记住的是,这不是两个不同的东西......几乎任何任务都可以成为UNIX进程,并通过适当的设置进行USS函数调用。
所以你的问题实际上是两个问题合二为一:
- 如何将我的任务称为 UNIX 进程,以便我可以发出 USS 内核函数?
- 我的 PL/I 编译器是否与 LE 运行时以及具有使用其他 LE 语言构建的代码的对象库兼容?
第一部分 - 如何让你的进程被称为UNIX进程 - 非常简单。IBM 的方法要求您先连接到 USS 内核(OMVS 地址空间),然后才能调用 UNIX 函数,但通常在您第一次调用 USS 函数时自动发生这种情况。
在使用USS之前,您确实需要进行一定数量的系统设置。当然,OMVS本身必须是活跃的(尽管现在很少见)。您的安全管理员需要为您提供 UID 编号,并可能为您创建一个主目录。假设这部分没问题,您需要做的就是调用 USS 函数,现在您是一个 UNIX 服务进程。
几乎任何应用程序都可以调用IBM的USS可调用服务(这是名称以BPX1/BPX4开头的所有模块) - 所需要的只是支持标准操作系统链接的东西。事实上,这几乎就是IBM运行时库所做的。一个好的测试是调用BPX1GPI(即UNIX "getpid()")...它返回您的 UNIX 进程 ID,如果您可以使其正常工作,则可以使用大多数其他 UNIX 服务。如果你要追踪 LE "getpid()" 实现,你会发现它只不过是BPX1GPI上的一层薄薄的,所以没有理由你不能自己调用底层函数......这适用于大多数 USS 内核函数,而不仅仅是 getpid(),所以如果你不知道如何打开套接字,调用 BPX1SOC 总是一个好的"B 计划"。
请记住,作为一个 UNIX 进程和在 bash shell 之类的东西下运行是有区别的......shell 会执行诸如设置 STDIN/OUT/ERR 之类的操作 - 如果您需要这些东西,如果您只是突然连接到 USS,则需要自己执行此操作。在设置标准文件描述符之前,您不能调用 printf() 之类的东西。
一个简单的入门方法可能是为自己编写一个作为UNIX进程运行的简短C程序,设置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函数。
这也意味着没有理由不能在PL/I程序中使用"libxyz.a"之类的东西,假设LE级别没有不兼容等等。让活页夹以您期望的方式解决所有问题可能是一个挑战,但如果您坚持下去,它应该会起作用。
PL/I会有一些困难的事情(我很抱歉 - 我不是PL/I专家)。例如,调用类似于 libcurl 示例的内容,其中库是 DLL 而不是静态存档。同样,这里的诀窍可能是使用可以从 PL/I 调用的简短 C"存根",并且该代码可以执行加载和调用 DLL 所需的魔力。否则,我认为一旦你把所有部分放在一起,你会发现这是一个非常简单的练习。
只回答问题的"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 进行链接(或者反过来,将 OBJECT 从 PDS 复制到 HFS,并使用 ld 进行链接)
但是,有 2 种对象文件格式,XOBJ 和 GOFF。
GOFF是较新的格式,如果您使用XPLINK,则它是先决条件。 z/OS 上的 64 位 LE 程序也预先要求 XPLINK。 GOFF本身也预先要求PDS/E。