资源描述
2.3 第六章 用CRTRPGMOD和CRTDGM命令建立程序
两步程序建立步骤包括使用CRTRPGMOD命令把源语句编译成模块,然后使用CRTPGM命令把一个或多个模块连接成为程序。使用这种可以建立永久模块。这样做的结果,是使一个应用程序模块化,而不必重新编译整个应用程序。也允许在不同的应用程序中都使用同一个模块。
本章的内容包括:
由RPG Ⅳ源语句建立模块目标
使用CRTPGM命令把模块连接成程序
阅读连接清单
修改模块或程序
2.3.1 建立模块目标
模块是ILE编译程序的输出,它是不可运行的目标(类型为*MODULE),是ILE程序的基本连接模块。
一个模块由一个或多个过程组成。允许的过程个数取决于语言类型。一个ILE RPG/400模块由一个过程组成,它有自己的LR语义、周期、文件控制块和静态存储空间。
模块的建立包括源成员的编译,如果编译成功,建立一个*MODULE目标。*MODULE目标包括模块中进口和出口引用的清单。如果在编译时有要求的还包括调试数据。模块本身不能运行。必须连接一个或多个模块成为可运行的程序目标,也可以连接一个或多个模块建立一个服务程序(类型为*SRVPGM)。然后,通过静态过程调用访问连接在一起的模块中的过程。
这种连接模块的方法允许做下面的事情:
重复使用一段代码,一般会使程序变得更短小。短小的程序性能更好且易于调试。
维护共享编码,使其向程序的其他部分传送错误代码的机会很少,更有效地管理大的程序。模块方式允许把以前的程序分割为可以独立管理的多个部分。如果程序需要改进,只需重新编译那些被改动的模块。
可以根据任务的需要选择最合适的语言建立模块,然后连接这些模块建立多种语言编写的程序。
有关模块的详细信息,请参考ILE概念。
2.3.1.1 使用CRTRPGMOD命令
使用(CRTRPGMOD)命令建立模块。可以交互地,或作为批处理输入流的一部分,或在命令语言(CL)程序中使用该命令。
如果交互地使用该命令并需要提示的话,键入CRTRPGMOD,然后按F4(提示)键,如果需要帮助,键入CRTRPGMOD然后按F1(帮助)键。
表3列出了CRTRPGMOD命令的参数及系统提供的默认值。命令的语法图解和参数描述见于附录C,1.3节中的“建立命令”。
表3.按功能分组的CRTRPGMOD参数及其系统默认值
模块标识
MODULE(*CURLIB/*CTLSPEC) 确定建立的模块名和库名
SRCFILE(*LIBL/QRPGLESRC) 指定源文件和库名
SRCMBR(*MODULE) 指定包含源语句的文件成员
TEXT(*SRCMBRTXT) 为模块提供简要描述
模块建立
GENLVL(10) 确定模块建立的错误级别(0-20)
OPTION(*GEN) *GEN/*NOGEN,决定模块是否建立
DBGVIEW(*STMT) 指定要包含在模块中的调试视图的类型
OPTIMIZE(*NONE) 确定优化级别
REPLACE(*YES) 确定是否替换已存在的模块
AUT(*LIBCRTAUT) 指定建立模块的权限
TGTRLS(*CURRENT) 指定目标要运行的软件版本
编译清单
OUTPUT(*PRINT) 确定是否产生编译清单
INDENT(*NONE) 确定是否在清单中显示缩进,如选,并指定标记缩进 的字符
OPTION(*XREF *NOSECLVL 指定编译清单包含的内容
*SHOWCPY(*EXPDDS *EXT)
数据转换选项
CVTCPT(*NONE) 指定如何处理外部描述文件中的变量数据
ALWNULL(*NO) 确定模块是否接受来自允许空值字段的值
F1XNBR(*NONE) 确定无效的区位十进制数据是否修整转换为压缩型 数据
运行时的考虑
SRTSEQ(*HEX) 指定要使用的排序顺序表
LANGID(*JOBRUN) 与SRTSEQ一起使用,指定排序序列的语言识别 程序
TRUNCNBR(*YES) 指定当发生数字溢出时采取的动作
如果需要,那么CRTRPGMOD命令产生一个绝大部分与CRTBNDPGM命令所产生的相同的清单。(由CRTRPGMOD建立的清单绝不会包括代码生成和连接单元)。
关于使用编译清单的信息,参见2.2.2节的“使用编译清单”。
在附录D中给出了一个样本编译清单,即附录1.4节中的“编译清单”。
2.3.1.1.1 使用CRTRPGMOD默认值建立模块
在本例中使用CRTRPGMOD命令及其参数默认值建立一个名为INCALC的模块目标。INCALC的源语句如图22所示。
1.为了建立模块目标,键入:
CRTRPGMOD MODULE(MYLIB/INCALC) SRCFILE(MYLIB/QRPGLESRC)
模块将以命令中指定的名字INCALC建立在库MYLIB中。模块的源语句是在库 MYLIB文件QRPGLESRC中的源成员INCALC。
该模块目标可以使用语句视图进行调试,并产生模块的编译清单。
2.进入以下的CL命令之一来看编译清单
DSPJOB并选择选项4(显示假脱机文件)
WRKJOB
WRKOUTQ队列名
WRKSPLF
*===============================================================*
* 模 块 名: INCALC *
* 有关文件: N/A *
* 有关程序: TRNSRPT *
* 说 明:它用参数列表中的字段计算交易的收入。在所有计算完成 *
* 之后返回到TRNSRPT。 *
*===============================================================*
C *ENTRY PLIST
C PARM Prod 10
C PARM Qty 5 0
C PARM Disc 3 2
C PARM Inc 11 1
C SELECT
C WHEN Prod = 'Model 1'
C EVAL Inc = 1500 * Qty * Disc
C WHEN Prod = 'Model 2'
C EVAL Inc = 3500 * Qty * Disc
C WHEN Prod = 'Model 8'
C EVAL Inc = 32000 * Qty * Disc
C WHEN Prod = 'Model 12'
C EVAL Inc = 28000 * Qty * Disc
C OTHER
C EVAL Inc = 0
C ENDSL
* Return to the caller TRNSRPT. *
C RETURN
图22 成员INCALC的源语句
2.3.1.2 建立一个有源语句调试的模块
在此例中,建立了一个可以用源语句调试的程序ILE RPG/400模块目标。此模块的源语句如图23所示。
为建立模块目标,键入:
CRTRPGMOD MODULE(MYLIB/TRNSRPT)SRCFILE(MYLIB/QRPGLESRC)
DBGVIEW(*SOURCE)
该模块建立在库MYLIB中,名字与源成员名相同,即TRNSRPT。该模块目标可使用源语句视图进行调试。关于其它有效视图的信息,参见3.1.2节中的“ 准备一个可以Debug的程序”。
命令也将产生TRNSRPT模块的编译清单。
*===============================================================*
* 模 块 名: TRNSRPT *
* 有关文件: TRNSDTA(物理文件) *
* 有关程序: INCALC (计算程序) *
* 说 明:这个程序从物理文件TRNSDTA中读每个交易记录,它调用 *
* 做计算的INCALC并返回一个值,然后打出交易记录。 *
*===============================================================*
FTRNSDTA IP E DISK
FQSYSPRT O F 80 PRINTER
*
ITRNREC 01
* Call the calculation procedure INCALC. *
C 01 CALLB 'INCALC'
C PARM PROD
C PARM QTY
C PARM DISCOUNT
C PARM INCOME 11 1
C
OQSYSPRT D 01 1
O 12 'PRODUCT: '
O PROD 25
O 40 'QUANTITY: '
O QTY 45
O 60 'INCOME: '
O INCOME 2 75
图23 模块TRNSRPT的源程序
模块TRNSDTA的DDS如图24所示。
A*****************************************************************
A* 有关文件:TRNSRPT *
A* 说 明:这是一个物理文件TRNSDTA,它有一个记录格式TRNREC。 *
A*****************************************************************
A* PARTS TRANSACTION FILE -- TRNSDTA
A R TRNREC
A PROD 10S 0 TEXT('Product')
A QTY 5S 0 TEXT('Quantity')
A DISCOUNT 3S 2 TEXT('Discount')
图24 TRNSDTA的DDS
2.3.1.3 其他例子
关于建立模块的更多的例子,参见:
2.4.4节中的“样本服务程序”是为服务程序建立模块的例子。
2.4.4.2节中的“连接一个程序”是建立供服务程序使用的模块的例子。
2.5.7.1.1节中的“为运行时数组动态分配存储空间”是为运行时数组动态分配存储空间而建立模块的例子。
3.1.13节中的“调试源程序样本的例子”,是建立在样本调试程序中使用的RPG和C模块的例子。
2.3.1.4 连接ILE RPG/400模块
在ILE RPG/400中,过程的各项边界是:
LR语义的作用域
打开文件的作用域
周期的作用域
既然每个 ILE RPG/400模块有且仅有一个过程,那么过程的作用域与模块的作用域是相同的,所以当把两个模块连接在一起时,程序有多个周期。每个过程一个周期。
注意:在其它的ILE语言中过程作用域也许与模块作用域不相同,因为他们的概念及处理的方法是不同的。
2.3.1.5 相关的CL命令
模块可以使用的CL命令:
显示模块(DSPMOD)
修改模块(CHGMOD)
删除模块(DELMOD)
处理模块(WRKMOD)
有关这些命令的详细信息见CL参考手册。
2.3.2 把模块连接成程序
连接是把一个或多个模块以及可选的服务程序,连起来建立一个可运行的ILE程序的过程,并解释它们之间传递的符号。做这些连接和解释的系统代码叫做AS/400系统连接程序。
作为连接处理的一部分,必须有一个过程被标识为启动过程,或叫程序入口过程。当程序被调用时,程序入口过程接收从命令行传来的参数,并得到程序初始控制权。与程序入口过程相关的用户代码是用户的入口过程。
每个ILE RPG/400模块都隐含地包括一个程序入口过程。但是对其它的ILE语言来说可能不是这样的。例如,ILE C/400模块只有当包含main()函数时才有程序入口过程。
图25给出了程序目标内部结构的概念。它显示了通过连接TRNSRT和INCALC两个模块而建立的程序目标TRPT。TRNSRPT为入口模块。
*PGM(TRPT)
TRNSRPT模块
程序入口例程
用户入口例程
INCALC模块
过程
图25 程序TRPT的结构
在一个连接的目标内,过程可以通过静态过程调用相互联系,这些连接调用要比外部调用快。因此,由一个有多个连接调用的连接程序组成的应用程序,要比与之相似但是包含有之间是外部调用的若干独立程序组成的应用程序性能要快。
为了把模块连接在一起,可把它们连接成为服务程序(类型为*SRVPGM)。服务程序允许在程序模块外对模块进行编码和维护。公共子例程可以建立为服务程序,如果对子例程修改的话,那么这些修改可以通过再次连接服务程序来完成,而使用这些公共子例程的程序就不必重新建立。关于服务程序的详细信息参见第七章2.4节中的“建立服务程序”。
关于连接处理过程和连接信息,参见ILE概念。
2.3.2.1 使用CRTPGM命令
建立程序(CRTPGM)命令由一个或多个以前建立的模块来建立程序目标。如果有要求的话,还包括一个或多个服务程序。还可以连接由任何ILE建立模块命令建立的模块,这些命令如CRTRPGMOD,CRTCMOD,CRTCBLMOD及CRTCLMOD。
注意:需要的模块和服务程序必须事先建立。
在使用CRTPGM命令建立模块前,应该:
1.为程序命名
2.指定一个或多个要连接成程序目标的模块,如果需要的话,还应包括要连接的服务程序。
3.标识出哪个模块中有程序入口过程。
通过CRTPGM命令的ENTMOD参数指出哪个模块包含程序入口过程。默认值为ENTMOD(*FIRST),表示在MODULE参数列表中的第一个模块是入口过程模块。
如果把多于一个的ILE RPG/400模块连接在一起,那么应该指定*FIRST或者某个模块名作为程序入口过程的模块名。当只连接一个模块或者连接几个模块,但只有一个模块包含程序入口过程时,可以指定ENTMOD(*ONLY)。例如,如果连接一个RPG模块和一个没有main()函数的C模块,那么可以指定ENTMOD(*ONLY)。
4.指定程序要使用的活动组
如果程序没有特别要求或者你不能确定应使用哪一活动组,可以指定名为QILE的命名活动组。让应用程序在自己的活动组中运行是很好的想法。因此,可以在应用之后命名活动组。
注意:CRTPGM的默认活动组是*NEW。这表示应用程序会在自己的活动组中运行,并且活动组会在程序结束时终止。也就是说无论是否置LR为ON,程序会在下一次调用到它时有其自身数据的新的拷贝。关于活动组的详细信息参见2.5.6.1节中的“指定一个活动组。”
要用CRTPGM命令建立程序,执行以下步骤:
1.输入CRTPGM命令。
2.输入命令参数的适当值。
表4列出了CRTPGM命令的参数及其默认值。关于CRTPGM命令及参数的完整描述,参见CL参考手册。
表4 CRTPGM命令的参数及其默认值
参数组 参数(默认值)
标识 PGM(库名/程序名)
MODULE(*PGM)
程序访问 ENTMOD(*FIRST)
连接 BNDSRVPGM(*NONE)
BNDDIR(*NONE)
运行时 ACTGRP(*NEW)
其它 OPTION(*GEN *NODUPPROC *NODUPVAR *WARN
*RSLVREF)
DETAIL(*NONE)
ALWUPD(*YES)
ALWRINZ(*NO)
REPLACE(*YES)
AUT(*LIBCRTAUT)
TEXT(*ENTMODTXT)
TGTRLS(*CURRENT)
USRPRF(*USER)
一旦你发出了CRTPGM命令,系统应执行以下操作:
1.把列出的模块拷贝到程序目标中,并把服务程序连接到程序目标上。
2.标识包含程序入口过程的模块并且定位在此模块中的第一个入口。
3.按所列出的次序检查模块,并检查第一个入口参数与模块出口参数是否相匹配。
4.返回到第一个模块并定位在下一个入口参数。
5.解析第一个模块中的所有入口参数。
6.继续下一个模块并解析所有入口参数。
7.解析其后的每一个模块中的所有入口参数,直到所有的入口参数都被解析。
8.如果某一个入口参数不能与一个出口参数相一致,则连接过程终止且不产生程序目标。
9.一旦所有的入口解析完毕,则连接过程终止,并建立程序目标。
注意:如果指定一个变量作为出口(使用EXPROT键字),有可能变量名会是连接程序目标内另外过程中某个变量名。
在这种情况下,结果可能是不可预测的,关于如何处理这种情况请参考ILE概念。
2.3.2.1.1 连接多个模块
本例显示了如何用CRTPGM命令连接两个ILE RPG/400模块成为程序TRPT。这个程序执行以下操作:
模块TRNSRPT从文件TRNSDTA中读每个交易记录,然后用连接过程调用CALLB调用模块INCALC。
INCALC计算每笔交易的收入,INCALC返回到TRNSRPT。然后TRNSRPT打印交易记录。
TRNSRPT,INCALC和TRNSDTA的源语句如2.3.1.2节中的图23和2.3.1.1.1节中的图22,和2.3.1.2节中的图24所示。
1.首先建立模块TRNSRPT,键入:
CRTRPGMOD MODULER(MYLIB/TRNSRPT)
2.然后建立模块INCALC,键入:
CRTRPGMOD MODULE(MYLIB/INCALC)
3.建立程序目标,键入:
CRTPGM PGM(MYLIB/TRPT)MODULE(TRNSRPT INCALC)
ENTMOD(*FIRST) ACTGRP(TRPT)
CRTPGM命名在库MYLIB中建立程序目标TRPT。
注意TRNSRPT在MODULE的参数中被第一个列出;这表示它包含程序入口过程。如果INCALC被第一个列出那么它将包含程序入口过程;但是TRNSRPT没有被INCALC调用将不会运行。
程序将在命名活动组TRPT中运行。这就确保了其它的程序不能影响到它的资源。
2.3.2.2附加的例子
关于建立程序的其他的例子,参见:
2.4.4.2节中的“连接到一个程序”,是连接一个模块和服务程序的例子。
3.1.13节中的“凋试例子的样本源程序”是建立包含RPG和C模块的程序的例子。
2.3.2.3有关的CL命令
对程序操作可使用以下的CL命令:
修改程序(CHGPGM)
删除程序(DLTPGM)
显示程序(DSPPGM)
显示程序参考(DSPPGMREF)
更新程序(UPDPGM)
处理程序(WRKPGM)
关于这些命令的详细资料,参见CL参考手册。
2.3.3 使用连接清单
连接过程可以产生一个清单,它描述了使用的资源,遇到的目标和符号,以及在连接过程中解决或未解决的问题。该清单是作为键入CRTPGM命令后作业产生的假脱机文件。该命令在默认情况下是不产生这些信息的,但是可以选择DETAIL参数的值来产生三种不同明细的清单:
*BASIC
*EXTENDED
*FULL
根据参数DETAIL值的不同,连接清单会包含以下内容:
表5.基于DETAIL参数的连接清单单元
单元名 *BASIC *EXTENDED *FULL
命令选项总计 x x x
简要总计表 x x x
扩展总计表 x x
连接信息清单 x x
交叉引用清单 x
连接统计 x
如果连接不成功的话,这个清单中的信息可以帮助你诊断问题所在,或对连接过程中遇到的情况给出反馈信息。如果希望把这个清单做为文件保存,那么可以使用拷贝假脱机文件(CPYSPLF)命令。把这个清单复制成一个数据库文件。
注意:CRTBNDRPG命令不会产生连接清单,然而,如果在连接阶段发生了连接错误,那么会把错误记录在工作日志中,并且编译清单会包含与此有关的信息。
关于基本连接清单的例子,参见2.4.4.4节中的“连接清单样本”。
关于连接清单的详细资料,参见ILE概念。
2.3.4修改模块或程序
由于改进或维护的原因,可能要修改ILE目标。可以使用调试信息或由CRTPGM命令产生的连接清单来找出哪些需要修改。此信息可以确定哪些模块需要修改,哪些过程或字段需要经常修改。另外,可能希望修改模块或程序的优化级和可视性。这在调试程序或模块,或当把一个程序做为产品时经常遇到的。与重新建立目标相比,这种修改可以更快的进行,并占用较少的系统资源。
最后,当你做完应用程序时,可能希望缩减程序的尺寸。ILE程序由于包括了一些附加数据,这使它们与类似的OPM程序相比要大一些。
以上每项都需要修改不同的数据。你需要的资源对ILE程序来讲可能是无效的。
以下的单元告诉你如何:
更新程序
修改优化级
修改可视性
缩减目标尺寸
注意:在本单元里目标是用来表示ILE模块或ILE程序的。
2.3.4.1使用UPDPGM命令
通常,可以根据需要替换模块来修改程序。不必重新建立程序。当你为其它地方提供应用程序时,这是很有帮助的。只需发出修订过的模块,然后接收地就可以用UPDPGM或UPDSRVPGM命令更新应用程序。
UPDPGM命令处理程序和模块。这条命令的参数与CRTPGM命令的参数非常相似。例如,要替换程序中的模块,键入MODULE参数的模块名和库名。
UPDPGM命令要求被替换的模块是程序建立时库中的那个模块。你可以指定替换所有的模块,或只替换某些模块。
UPDPGM命令要求模块目标是已经存在的。当你已经用编译和连接二步建立程序后,就很容易地使用这条命令。因为模块目标已经存在,只需在发出命令时指定模块名和所在库就可以了。
要更新用CRTBNDRPG命令建立的程序,必需保证修改过的模块在QTEMP库中。这是因为当CRTBNDRPG命令发出时使用的临时模块都是在QTEMP库中的。只要模块已经在QTEMP中了,就可以使用UPDPGM命令来替换该模块。
2.3.4.2 修改优化级
目标优化即根据编译的代码,为了使运行时的性能更好而要做的一些处理,也会做出必要的修改。通常要求的优化级越高,建立目标的时间越长。在运行时,优化过的程序或服务程序比相应的未优化的程序或服务程序运行的速度要快。
但是,对于较高级别的优化,当在调试显示或从异常中恢复时字段的值可能是不准确的。另外,优化了的代码可能会把源调试用的断点的位置作改动,因为优化做了修改可能要重新组成或删除一些语句。
为了确保字段的内容反映它们的最近当前值,特别是在异常恢复后,可以在相应的定义规范表中使用NDOPT键字。有关的信息,请参见3.2.2.4节中的“优化考虑”。
在调试时要防止发生这个问题,可以在调试程序时不选优化就可以在程序调试时准确地显示模块中的字段等信息,以后把程序投入运行时,再提高优化级以提高程序的效率。
要确定程序目标目前的优化级别,使用DSPPGM命令。这个命令显示了当前优化级。要修改程序的优化级,使用CHGPGM命令。优化程序参数可以指定以下值:*FULL,*BASIC,*NONE。对建立命令的OPTIMIZE参数可以指定相同的值。当该命令运行时程序自动地按指定的级别重新建立。
类似地,确定模块当前的优化级别,使用DSPMOD命令。这条命令显示的第2页指出了当前的优化级。要修改优化级别,使用CHGMOD命令。然后用UPDPGM或CRTPGM命令重新建立程序。
2.3.4.3 删去可视性
可视性包括两类数据,存储在一个目标内,允许修改目标而不必重新编译源程序。增加了某些数据使目标的尺寸变大。你可以删除这些数据从而缩减目标的大小。但是一旦这些数据删除了,可视性也就同时被删除。必须重新编译源语句并重建程序来替换这些数据。这两种数据是:
建立数据:由*CRTDTA表示。这种数据用于把代码翻译成机器指令是必要的。你要自己修改优化级,目标必须包含这种数据。
调试数据:由*DBGDTA表示。这种数据对于调试目标是必要的。
可以使用CHGPGM命令或CHGMOD命令分别从程序或模块中删除这类数据。也可以两种都删除,也可以都不删除。删除所有的可视性使目标尺寸减至最小(不包括压缩)。如果不重新建立的话,目标就没有可能被修改。因此,必须确保拥有建立程序所需要的所有源码或者拥有带CRTDATA的类似的程序目标。要重新建立程序,必须有访问源代码的权利。
2.3.4.4 缩减目标的大小
ILE程序或模块的建立数据(*CRTDTA)参数可能会占目标大小的一半以上。通过删除或压缩这些数据,可以明显地减少程序需要的二级存储空间。
如果删除这些数据,那么要保证有建立程序所需的所有源程序,或有CRTDATA参数的程序目标,否则的话不能修改目标。
还有一种方法压缩目标,即使用压缩目标命令(CPROBJ)。压缩的目标与非压缩目标相比占有较少的系统存储空间。如果调用压缩的目标,那么包含可运行代码的那部分目标自动地解压缩。也可以使用解压缩目标(DCPOBJ)命令。
关于这些CL命令的详细资料,参见CL参考手册。
展开阅读全文