-
Notifications
You must be signed in to change notification settings - Fork 144
Building Source Code for Multiple Environments
Recently, some users of zAppBuild have requested additional guidance on a specific build scenario. The use case is about a single program, which is built to be executed in multiple runtime environments, i.e in BATCH as well in CICS. Their existing build process requires either to compile + link edit or only link edit the source code for each of the different runtime environments. The source code is only maintained once.
The following note outlines the required modifications to integrate this process into the zAppBuild language scripts.
The scenario assumes, that the executable needs to include particular environment-specific object modules, such as the various language stubs for MQ, which are specified through the INCLUDE control statement
of the linkage editor.
In that configuration, the build process must invoke the linkage editor twice to:
- include the environment specific object module
- store the executable in a dedicated output load library
- pass different values for the
deployType
This below sample is based on the zAppBuild codebase at commit 99624f6
Add the additional output library to build-conf/Cobol.properties
cobol_onlineLoadPDS = ${hlq}.CICSLOAD
Add the new output library to list of output datasets at build-conf/Cobol.properties to make sure that the dataset is automatically created.
cobol_loadDatasets = ${cobol_loadPDS},${cobol_onlineLoadPDS}
Application teams need to specify which programs require to be link edited for multi-runtime use. A new file property allows the teams to specify which programs require to be built for multiple environments in file.properties. The deployType
will be derived from the default for BATCH and ONLINE modules.
# new property to define multi runtime module flag to source code
cobol_multiruntimeModule = true :: **/cobol/member.cbl
# new properties for configure the link edit include statements depending on multi runtime use
# Using DBB PropertyMappings
cobol_linkEditStream_MRM = INCLUDE OBJECT(@{member}) \n INCLUDE SYSLIB(CUSTBAT) :: BatchModule
cobol_linkEditStream_MRM = INCLUDE OBJECT(@{member}) \n INCLUDE SYSLIB(CUSTCICS) :: OnlineModule
The Cobol.groovy
language script needs to process the new build properties.
In the mainline section of the Cobol.groovy language script, we need to evaluate the new build property cobol_multiruntimeModule
to invoke the link edit step twice for files which have the multiruntimeModule
flag set active.
Additionally, we need to ensure the two output libraries are correctly used to store the batch modules in cobol_loadPDS
and the CICS modules in cobol_onlineLoadPDS
. This is passed to the createLinkEditCommand
method.
String needsLinking = props.getFileProperty('cobol_linkEdit', buildFile)
if (needsLinking.toBoolean()) {
// replaces line 62 and will perform the default link edit
MVSExec linkEdit
String defaultTargetLibrary
//evaluate multiuse flag
String isMultiUseModule = props.getFileProperty('cobol_multiruntimeModule', buildFile)
if (isMultiUseModule.toBoolean()){ // Multi-Runtime Module: Run link edit for BATCH environment first:
// Get the deployType for Batch
cobol_deployType = props.getFileProperty('cobol_deployType', buildFile)
// evaluate the cobol_linkEditStream_MRM PropertyMapping for BatchModule
PropertyMappings linkEditStream_MRM = new PropertyMappings("cobol_linkEditStream_MRM")
String cobol_linkEditStream_MRM = linkEditStream_MRM.getValue("BatchModule")
linkEdit = createLinkEditCommand(buildFile, logicalFile, member, props.cobol_loadPDS, cobol_deployType, cobol_linkEditStream_MRM, logFile)
rc = linkEdit.execute()
maxRC = props.getFileProperty('cobol_linkEditMaxRC', buildFile).toInteger()
if (rc > maxRC) {
bindFlag = false
String errorMsg = "*! The link edit return code ($rc) for $buildFile exceeded the maximum return code allowed ($maxRC) in multi-runtime link edit step BATCH"
println(errorMsg)
props.error = "true"
buildUtils.updateBuildResult(errorMsg:errorMsg,logs:["${member}.log":logFile])
} else { // Multi-Runtime Module: Run link edit for ONLINE environment as second step:
// Get the deployType for Online
cobol_deployTypeCICS = props.getFileProperty('cobol_deployTypeCICS', buildFile)
// get the cobol_linkEditStream_MRM for OnlineModules
cobol_linkEditStream_MRM = linkEditStream_MRM.getValue("OnlineModule")
linkEdit = createLinkEditCommand(buildFile, logicalFile, member, props.cobol_onlineLoadPDS, cobol_deployTypeCICS, cobol_linkEditStream_MRM, logFile)
rc = linkEdit.execute()
maxRC = props.getFileProperty('cobol_linkEditMaxRC', buildFile).toInteger()
if (rc > maxRC) {
bindFlag = false
String errorMsg = "*! The link edit return code ($rc) for $buildFile exceeded the maximum return code allowed ($maxRC) in multi-runtime link edit step ONLINE"
println(errorMsg)
props.error = "true"
buildUtils.updateBuildResult(errorMsg:errorMsg,logs:["${member}.log":logFile])
}
}
} else { // non-multiuse modules: single link module to target library depending on file flag
if (buildUtils.isCICS(logicalFile)){ // store load module in cics module library
defaultTargetLibrary = props.cobol_loadPDS
linkEdit = createLinkEditCommand(buildFile, logicalFile, member, defaultTargetLibrary, null, null, logFile)
} else { // store load module in default module library
defaultTargetLibrary = props.cobol_onlineLoadPDS
linkEdit = createLinkEditCommand(buildFile, logicalFile, member, defaultTargetLibrary, null, null, logFile)
}
rc = linkEdit.execute()
maxRC = props.getFileProperty('cobol_linkEditMaxRC', buildFile).toInteger()
if (rc > maxRC) {
bindFlag = false
String errorMsg = "*! The link edit return code ($rc) for $buildFile exceeded the maximum return code allowed ($maxRC)"
println(errorMsg)
props.error = "true"
buildUtils.updateBuildResult(errorMsg:errorMsg,logs:["${member}.log":logFile])
}
}
// scan module from defaultTargetLibrary
if(!props.userBuild && !isZUnitTestCase){
// only scan the load module if load module scanning turned on for file
String scanLoadModule = props.getFileProperty('cobol_scanLoadModule', buildFile)
if (scanLoadModule && scanLoadModule.toBoolean())
impactUtils.saveStaticLinkDependencies(buildFile, defaultTargetLibrary, logicalFile)
}
}
The signature of createLinkEditCommand method, requires to be updated to take a new set of arguments, which differ from the two environments.
def createLinkEditCommand(String buildFile, LogicalFile logicalFile, String member, String targetLoadPDS, String deployType, String linkEditStream, File logFile) {
and update the appropriate configuration of the link edit step.
String parms = props.getFileProperty('cobol_linkEditParms', buildFile)
String linker = props.getFileProperty('cobol_linkEditor', buildFile)
// EYE-CATCHER: modified next line
if (linkEditStream == null) linkEditStream = props.getFileProperty('cobol_linkEditStream', buildFile)
String linkDebugExit = props.getFileProperty('cobol_linkDebugExit', buildFile)
// obtain githash for buildfile
String cobol_storeSSI = props.getFileProperty('cobol_storeSSI', buildFile)
if (cobol_storeSSI && cobol_storeSSI.toBoolean() && (props.mergeBuild || props.impactBuild || props.fullBuild)) {
String ssi = buildUtils.getShortGitHash(buildFile)
if (ssi != null) parms = parms + ",SSI=$ssi"
}
// define the MVSExec command to link edit the program
MVSExec linkedit = new MVSExec().file(buildFile).pgm(linker).parm(parms)
// Create a physical link card
if ( (linkEditStream) || (props.debug && linkDebugExit!= null)) {
def langQualifier = "linkedit"
buildUtils.createLanguageDatasets(langQualifier)
def lnkFile = new File("${props.buildOutDir}/linkCard.lnk")
if (lnkFile.exists())
lnkFile.delete()
if (linkEditStream)
lnkFile << " " + linkEditStream.replace("\\n","\n").replace('@{member}',member)
else
lnkFile << " " + linkDebugExit.replace("\\n","\n").replace('@{member}',member)
if (props.verbose)
println("Copying ${props.buildOutDir}/linkCard.lnk to ${props.linkedit_srcPDS}($member)")
new CopyToPDS().file(lnkFile).dataset(props.linkedit_srcPDS).member(member).execute()
// Alloc SYSLIN
linkedit.dd(new DDStatement().name("SYSLIN").dsn("${props.linkedit_srcPDS}($member)").options("shr"))
// add the obj DD
linkedit.dd(new DDStatement().name("OBJECT").dsn("${props.cobol_objPDS}($member)").options('shr'))
} else { // no debug && no link card
// Use &&TEMP from Compile
}
// add DD statements to the linkedit command
// EYE-CATCHER: modified next line
if (deployType == null ) deployType = buildUtils.getDeployType("cobol", buildFile, logicalFile)
if(isZUnitTestCase){
linkedit.dd(new DDStatement().name("SYSLMOD").dsn("${props.cobol_testcase_loadPDS}($member)").options('shr').output(true).deployType('ZUNIT-TESTCASE'))
}
else {
// EYE-CATCHER: updated target pds
linkedit.dd(new DDStatement().name("SYSLMOD").dsn("${targetLoadPDS}($member)").options('shr').output(true).deployType(deployType))
}