Create makefile - JeffBerman/Bob GitHub Wiki

How to create a Bob makefile

This page documents how to create a makefile, which is a text file that tells Bob and GNU Make how to build your code.

Overview

Better Object Builder uses GNU Make to determine what code needs to be compiled. Make takes as input a makefile, which tells it what objects should be compiled, what source code they need, and what other objects they are dependent on. Some of this is written by you, and some is gleaned by Bob.

By itself, Make has no concept of ILE objects, and doesn't know how to compile an RPG module or bind together a service program. Better Object Builder provides that functionality in the form of a general purpose makefile called IBMiMake, which contains all the special instructions for building various types of IBM i objects, while letting users override certain compile parameters. Each of your project makefiles will contain a statement that tells Make to include IBMiMake's functionality. That way, when your makefile says "build module XY1001 from source file XY1001.RPGLE", Make will know how to do that.

Each of your projects will have its own makefile specific to that project's objects.

Makefile layout

A Bob project makefile consists of three sections:

  • A header area that imports the generic IBMiMake makefile and defines some object type targets
  • An object list area where you specify each object that should get built
  • A rules area that defines dependency information and custom compile settings for each object

Creating a makefile

You are about to create a makefile to describe the objects Bob should build. If a project directory doesn't yet exist, create one now.

Start a new makefile for your project by copying Makefile.sample from the Bob folder into your project directory, then rename it Makefile. Open it in any text editor that supports Unix-style LF line endings. (For a better experience, use an editor that can syntax-color makefiles, such as Notepad++ (Windows), BBEdit (Mac), or Visual Studio Code (both). All are free to use or have unlimited trial periods.)

Header section

The makefile's header section should not be altered. It contains code that imports the IBMiMake generic makefile, defines the all target to build all objects, and sets up some object type dependencies.

Object List section

The object list section is where you list out each object Bob should build, grouped by object type and separated by spaces. Object names should be specified as they appear in the Integrated File System (IFS), so program names end in .PGM, files end in .FILE, etc. All object names should be in upper case. For ease of maintenance, it is recommended that the objects are listed alphabetically. Here's an example of part of an object list section:

PFs: JB001.FILE JB010.FILE

LFs: JB001A.FILE JB001B.FILE JB010A.FILE

MODULEs: JB100.MODULE JB110.MODULE JB120.MODULE JB200.MODULE

SRVPGMs: JB200.SRVPGM

PGMs: JB100.PGM JB110.PGM

In this example, Make is told that five files should be built (two PFs and three LFs), four modules, one service program, and two programs. We haven't yet told it how to build these objects, only that they exist and should be built.

Rules section

The rules section specifies dependency information and custom compile settings. This is where Bob is told which source files and other objects are needed to build each object, and is where object-specific compile settings are overridden.

To create a rule, first write the object name (with the IFS suffix), followed by a colon and a space. Then write the name of the object's source file:

JB001.FILE: JB001.PF

If the object depends on other objects, add them to the end, separated by spaces:

JB001A.FILE: JB001A.LF JB001.FILE

Defined above is logical file JB001A.FILE. It is compiled from source code JB001A.LF, and it depends on physical file JB001.FILE. Specifying dependencies is important, for this is what causes the logical file to automatically get recompiled when source code for its dependent physical file changes.

Continuing with our example makefile:

JB001.FILE: JB001.PF

JB001A.FILE: JB001A.LF JB001.FILE

JB001B.FILE: JB001B.LF JB001.FILE

JB010.FILE: JB010.PF

JB010A.FILE: JB010A.LF JB010.FILE

JB100.MODULE: JB100.RPGLE JB001A.FILE JB001B.FILE

JB100.PGM: JB100.MODULE

JB110.MODULE: JB110.RPGLE

JB110.PGM: JB110.MODULE JB120.MODULE

JB120.MODULE: JB120.CLLE JB010A.FILE

JB200.MODULE: JB200.RPGLE

JB200.SRVPGM: JB200.BND JB200.MODULE

Above, we see that module JB100 is compiled from source file JB100.RPGLE and uses two files: JB001A and JB001B. We would say that JB100.MODULE has three dependencies. When any of its dependencies change (either of the logical files or the RPGLE source file), module JB100 will be automatically recompiled. Program JB100 is built from module JB100.

Program JB110 is built from two modules: JB110 and JB120.

Service program JB200 contains one module, JB200, and uses binder language in source file JB200.BND to contol its exports and signatures.

Just to drive the point home, when source file JB001A.LF changes, the following objects will automatically be rebuilt with the next build: logical file JB001A, module JB100, and program JB100.

In summary, for the rules section, simply specify each object, followed by its source file (source-based objects) or primary object (non source-based objects),followed by any remaining dependencies.


:zap: Tip

The Bob developers like to add a comment before each object rule that specifies the object name and intended compile command. We find the syntax coloring helps the eye quickly locate object rules, and the compile command helps clarify what Make should do. Makefile comments begin with a #. Example:


A note about dependencies

In the example above, files were listed as dependencies of RPG modules. In reality, however, Bob automatically determines certain dependencies so that you don't need to manually maintain them. Bob stores these automatically-generated dependencies in directory .deps, created in your project directory. Each time a project is built, dependency definitions in .deps are updated for the built objects.

Currently, Bob detects these types of dependencies automatically:

Source Code Type Detected Dependencies
Fixed-format RPGLE, SQLRPGLE /COPY files
/INCLUDE files
F-spec files (Disk, Workstn, Printer)
D-spec externally-described files
ILE C, SQLC #include files

Detection for more types of source code is being continually added. Currently on the roadmap are detections for free-format RPG, physical file DDS (REF, REFFLD), logical file DDS (PFILE and JFILE), display file DDS (REF, REFFLD, and MSGCON), and printer file DDS (REF, MSGCON).

In short, dependencies that Bob can automatically glean will be specified by Bob in the .deps directory. All other dependencies should be listed by you in the project makefile.

Overriding compile settings

The generic IBMiMake makefile establishes what are hopefully sensible defaults for compile settings. All of your projects will reference the same IBMiMake file, so you can change its defaults to those shared among your projects (for example, TGTRLS is by default set to V6R1M0).

On the other hand, let's say you have an object that needs to be specially compiled at V7R1M0. This directive is implemented by use of target-specific variables, which is added as a separate line in the object's rule:

JB110.MODULE: private TGTRLS := V7R1M0
JB110.MODULE: JB110.RPGLE

Above, module JB110 will be compiled at a target release of V7R1M0. The private modifier tells Make that the scope of the TGTRLS override is limited to JB110.MODULE.

The current list of overrideable compile attributes is:

  • ACTGRP
  • AUT
  • BNDDIR
  • COMMIT
  • CURLIB
  • DBGVIEW
  • DETAIL
  • DFTACTGRP
  • DLTPCT
  • HLPID
  • HLPPNLGRP
  • OBJTYPE
  • OPTION
  • PAGESIZE
  • PGM
  • PMTFILE
  • PRDLIB
  • REUSEDLT
  • RPGPPOPT
  • RSTDSP
  • SIZE
  • STGMDL
  • SYSIFCOPT
  • TERASPACE
  • TEXT
  • TYPE
  • TGTCCSID
  • TGTRLS
  • VLDCKR

Switches and options

Bob's functionality and behavior can be adjusted by setting the values of certain options in the makefile. Syntactically, setting an option is identical to overriding a compile attribute (as detailed above); the format is object_name: private option := value.

Following are the available makefile options.

CREATE_TYPEDEF

Setting CREATE_TYPEDEF to YES for a *FILE object (LF, PF, PRTF) results in a separate include-ready source file being generated that contains a typedef structure for the file object's record formats. This feature is useful for C code that can no longer rely on #pragma mapinc, which doesn't work with IFS source code. The generated file is named after the original source file, but with .H appended (source file JB001.PF results in include file JB001.PF.H) Under the covers, the GENCSRC command is called. Note that in the resulting struct, Bob changes int to long int to work with the SQL C compiler.

Example:

# JB001.FILE -- CRTPF
JB001.FILE: private TEXT = Jumbo test file
JB001.FILE: private CREATE_TYPEDEF = YES
JB001.FILE: JB001.PF
LIBL

The LIBL variable can be set to contain a set of libraries that Bob will add to the library list prior to issuing a compiler command (such as CRTRPGMOD). It can be set at a global or object level. This is useful if, for example, a CL program uses a command located in a different library, as the CL compiler requires the command to be available for a successful compile.

Note that when a build first starts, LIBL is initialized to the build library, so you'll want to add to LIBL, not replace its contents.

Example of global makefile use -- every compile will contain these libraries in the library list:

########## END OF "DO NOT MODIFY" SECTION ##########

LIBL += SOMELIB1 SOMELIB2

Example of object-specific use -- only this one object will be compiled with extra libraries in the library list:

# JB010.MODULE -- CRTCLMOD
JB010.MODULE: private TEXT = My CL module
JB010.MODULE: LIBL += SOMELIB1 SOMELIB2
JB010.MODULE: JB010.CLLE

Inspecting the first line of the module's compile log file (Logs/{timestamp}/JB010.CLLE.log) reveals that the additional libraries were in fact specified:

Command is > BOBTOOLS/EXECWLIBS LIB(MYLIB SOMELIB1 SOMELIB2) CMD(BOBTOOLS/crtfrmstmf obj(MYLIB/JB010) cmd(CRTCLMOD)... <

Further reading

To learn more about makefile syntax, see the official GNU Make documentation. Just remember that every object referenced in a Bob makefile must have an IFS file suffix (.PGM, .FILE, etc.) and be written in upper case.