Setting up TMKMAKE
Tmkmake is a port of the well-known UNIX make to the peculiarities of the AS/400 CL environment. As such, it can help to automate the building process of OS/400 objects, by taking computational care of dependencies instead of the developer being required to manually remember which objects to (re)create after changes.
Tmkmake is available in qusrtool library releases as early as V2R3, and at least as late as 7.2.
Preparations
You need to have the Example Tools Library component of the operating system installed. This install results in a library qusrtool. Content is explained in the source PF qattinfo members. General instructions can be found in the aaamap member. Tmkmake-specific instructions can be found in the tmkinfo member.
Note: Depending on the OS version qusrtool stems from, the source PFs have been saved in compressed save files to save space. If you see many save files in wrklib qusrtool, you need to unpack those:
SBMJOB CMD(CALL PGM(QUSRTOOL/UNPACKAGE) PARM('*ALL ' 1)) JOB(UNPACKQUT)
Building Tmkmake
The building process is rather straightforward. In the spirit of older machinery, I personally prefer to run non-interactive work as batch. By leaving out the sbmjob you can also run the build process in foreground.
- First, the building application needs to be compiled:
SBMJOB CMD(CRTCLPGM PGM(QGPL/TMKINST) SRCFILE(QUSRTOOL/QATTCL)) JOB(MAKEMAKE)
- Next, the building application needs to be run to build tmkmake and install additional components:
SBMJOB CMD(CALL PGM(QGPL/TMKINST) PARM(QGPL)) JOB(BUILDMAKE)
- Finally, the building application can be deleted:
SBMJOB CMD(DLTPGM PGM(QGPL/TMKINST)) JOB(DLTMAKE)
You can submit all three jobs in a row. By default, batch job concurrency is one: Each job is run in order of submission.
As usual, finished batch jobs are indicated by a message waiting indicator on your terminal. Run dspmsg to see if the jobs ran without errors.
Further preparation
My recommendations in here assume
- each "project" is contained in its own library,
- there is one source PF called sources containing all source members for objects to be generated.[1]
There is a typo resulting in a syntax error hidden somewhere in the default rule source member. Because I'm not interested in using implicit rules (see below), I renamed the default rules member, and created a new, empty one:
RNMM FILE(QGPL/QMAKSRC) MBR(BUILTIN) NEWMBR(BUILTIN$$$) ADDPFM FILE(QGPL/QMAKSRC) MBR(BUILTIN) SRCTYPE(C)
I'm always stuffing source members in a source PF called sources. UNIX make by default tries to read from a Makefile in the current directory. My changed command defaults combine that:
CHGCMDDFT CMD(TMKMAKE) NEWDFT('SRCFILE(*CURLIB/SOURCES) SRCMBR(MAKEFILE)')
Example
This is a very minimal example how to create an ILE RPG program from a source member:
# Variables used by rules
DSTLIB=MYLIB
SRCFILE=SOURCES
# Global rules for recreating everything, if required --------------------------
all: curlib MYPGM<PGM>
# This is to make sure that even if we run in batch, we can use unqualified
# names in rules. Because there are no dependents, the rule is executed always.
curlib:
CHGCURLIB CURLIB($(DSTLIB))
MYPGM<PGM>: MYPGM.$(SRCFILE)<FILE>
CRTBNDRPG PGM($(@F)) SRCFILE($(SRCFILE))
The term @F is expanded to the target file name. More examples of possible expansions can be found in the qusrtool/qattinfo.tmkinfo member.
Implicit rules
Tmkmake supports implicit rules, like the UNIX make also does. Instead of writing one rule for every target object and its associated source member, rules can be generalized to a target type and an automatic expansion of arguments for the command to be run.
UNIX make uses file name extensions for determining target files, and dependencies. Tmkmake uses explicit stating of object types, and source PF names according to IBM style. Since this is not compatible with my "one source file" approach, I didn't care about that feature.[2]
Bugs and oddities
Tmkmake seems to look up timestamps only once per run, contrary to UNIX make — which does this lookup individually after each rule being processed. This leads to rules being run multiple times by tmkmake, because updated objects' timestamps aren't considered. This is most apparent when using the automatic recursive evaluation of a chain of dependencies.
Note: I'm running a German language install of OS/400 with appropriate QCCSID system variable set to 237. Some of the mentioned oddities might stem from a lack of charset conversion within tmkmake.
@ was shown as § on my terminal for qattinfo members. I checked and saw that the PF has been created with CCSID 273, the default for my German language system. Apparently the content is in US encoding (037). Probably an installation routine bug. Running
CHGSRCPF FILE(QUSRTOOL/QATTINFO) CCSID(037)
fixed that.
Also, the expansion variable $@ in Makefiles doesn't work as expected. It seems to be expanded to $@) TYPE(*
which is an error for the target string in CRTxx
commands. Using § instead of @ works around this issue.
Weblinks
- Programming with Make on the AS/400, Part I, MC Press Online
- Programming with Make on the AS/400, Part 2, MC Press Online