Linking programs
Describes how to link .42m modules together to build a .42r program file.
Purpose of .42r program files
Traditional Genero programming allows you to call a function without seeing the definition of that function. The goal of linking programs is to resolve function symbols and build a .42r program file.
IMPORT FGL
instead of traditional linking. When using IMPORT
FGL
, the link stage is no longer required, and the 42m module containing the
MAIN
block can be directly executed.Genero .42r program files are created by linking several
.42m modules and/or .42x libraries together, where one of the modules defines
a MAIN
block.
By convention, the resulting program file gets the .42r extension.
Program linking is done with the fglrun tool by using
the -l
option. The fgllink tool can be
used for convenience; it is a simple script calling fglrun -l
.
$ fglcomp main.4gl
$ fglcomp store.4gl
$ fgllink -o stores.42r main.42m store.42m
-o
option in the fgllink
command, the default output file will get the .42x extension (used for
libraries), with the name of the module containing the MAIN
block. The
.42r file extension is used by convention, to distinguish a program dictionary
file from a library dictionary file.Symbol resolution with the linker
The purpose of the linking phase is to check for missing function symbols, and reference all the symbols in the resulting .42r program file.
IMPORT FGL
method is the preferred method for linking. However, you can
mix both methods. The job of the linker is to resolve symbols that are not already resolved by the
compiler from IMPORT FGL
usage.Any function used in the .42m modules specified in the link line must be provided. Missing symbols will result in a -1338 linker error:
$ cat main.4gl
MAIN
CALL myfunc()
END MAIN
$ fglcomp main.4gl
$ fgllink -o prog.42r main.42m
ERROR(-1338):The function 'myfunc' has not been defined in any module in the program.
When linking a 42r program, global symbols must be unique; otherwise, error -6203 will be returned by the linker. The same error will be returned when linking a 42x library by using modules defining the same functions.
The link process searches recursively for the functions used by the program. For example, if the
MAIN
block calls function FA in module MA, and FA calls FB in module MB, all
functions from module MA and MB will be included in the 42r program definition.
The linking process steps in detail
When linking a .42r program (with modules possibly using IMPORT FGL
), the linker works as
follows:
- Loads all modules specified on the command-line. Builds a symbol-table of all public functions. Raises error -6203, if a public function is defined more than once.
- Loads all imported modules (if not specified on the command line). Adds public functions to the
symbol-table.
- If an imported function is already defined by a linked module, the imported function will be ignored.
- If an imported function is not defined by a linked module, and is defined more than once, then this function is marked as "ambiguous" (this is legal, no warning or error is produced).
- All unresolved symbols on any module (linked modules and imported modules) will be resolved.
Understand the difference in case of error -6203 and -8401:
- Error -6203: A function in a linked module is defined more then once. That's illegal.
- Error -8401: A function in an imported module is define more then once, and used by the linker to resolve a symbol. It's legal to define an imported function more than once, but this function can not be used by the linker.
Content of a .42r program file
The generated 42r program files do not contain the 42m p-code, it is basically a dictionary of global symbols used by the program.
When deploying an application, both 42m modules and 42r program files must be provided.
All symbols referenced in a module must exist in the final 42r program dictionary file. If a symbol is not found, the runtime system stops with error -1338. This error is fatal and cannot be trapped with an exception handler.
P-Code module find path FGLLDPATH
If you do not specify an absolute path for a file, the linker searches by default for 42m modules and 42x libraries in the current directory.
$ FGLLDPATH=/usr/dev/lib/maths:/usr/dev/lib/utils
$ export FGLLDPATH
$ ls /usr/dev/lib/maths
mathlib1.42x
mathlib2.42x
mathmodule11.42m
mathmodule12.42m
mathmodule22.42m
$ ls /usr/dev/lib/utils
fileutils.42m
userutils.42m
dbutils.42m
$ fgllink -o myprog.42r mymodule.42m mathlib1.42x fileutils.42m
In this example the linker will find the specified files in the /usr/dev/lib/maths and /usr/dev/lib/utils directories defined in FGLLDPATH.
Library versus module function precedence
When creating a .42r program by linking .42m modules with .42x libraries, if the same function is defined in a 42m and in a module of a 42x library, the function of the specified 42m module will be selected by the linker, and the function of the library will be ignored.
However, the linker will raise error -6203, if two 42m modules specified in the link command define the same function.
Exclusion of unused library module
The following case illustrates this behavior:
$ cat module1.4gl
FUNCTION func11()
END FUNCTION
$ cat module2.4gl
FUNCTION func21()
END FUNCTION
$ cat main.4gl
MAIN
CALL func11()
END MAIN
$ fglcomp module1.4gl
$ fglcomp module2.4gl
$ fglcomp main.4gl
$ fgllink -o lib.42x module1.42m module2.42m
$ fgllink -o prog.42r main.42m lib.42x -- Only module1.42m is included in .42r
Here, module x1.42m
(with functions fx11
and
fx12
) will be referenced in the .42r program file, but
functions of module x2.42m
will not. At runtime, any dynamic call to functions
fx21()
or fx22()
will fail with an untrappable error -1338.
Symbol conflicts with IMPORT FGL and linking
The job of the linker is to resolve symbols that are not already solved by the compiler from
IMPORT FGL
usage.
If the same function is defined by a linked module and an imported module, and the function is called without the module prefix, the imported function takes precedence over the linked module function.
$ cat module1.4gl
FUNCTION func11()
DISPLAY "module1.func11()"
END FUNCTION
$ cat module2.4gl
IMPORT FGL module1
FUNCTION func21()
DISPLAY "module2.func21()"
CALL func11() -- from module1, because it is imported
END FUNCTION
$ cat module3.4gl
FUNCTION func11() -- Same name as in module1.4gl
DISPLAY "module3.func11()"
END FUNCTION
$ cat main.4gl
MAIN
CALL func11() -- from module3, because it is linked
CALL func21()
END MAIN
$ fglcomp module1.4gl
$ fglcomp module2.4gl
$ fglcomp module3.4gl
$ fglcomp main.4gl
$ fgllink -o prog.42r main.42m module2.42m module3.42m
$ fglrun prog.42r
module3.func11()
module2.func21()
module1.func11()
Imported module using linked functions
When linking a program with modules using the IMPORT FGL
instruction, the imported modules do not have to be specified in
the link line.
However, if the imported module uses functions that come from other modules, which are not imported by this module, these non-imported modules must be specified in the link command line.
module1
to call the
func11()
, which in turn calls func21()
from
module2
, but module1
does not import module2
,
then module2 must be linked to the
program:$ cat module1.4gl
FUNCTION func11()
DISPLAY "module1.func11()"
CALL func21()
END FUNCTION
$ cat module2.4gl
FUNCTION func21()
DISPLAY "module2.func21()"
END FUNCTION
$ cat main.4gl
IMPORT FGL module1
MAIN
CALL module1.func11()
END MAIN
$ fglcomp module1.42m
$ fglcomp module2.42m
$ fglcomp main.4gl
$ fglrun main.42m
module1.func11()
Program stopped at 'module1.4gl', line number 3.
FORMS statement error number -1338.
The function 'func21' has not been defined in any module in the program.
$ fgllink -o prog.42r main.42m module2.42m
$ fglrun prog.42r
module1.func11()
module2.func21()
Linking programs with C Extensions
If you are using C-Extensions, you may need to use
the -e
option to specify the list of extension modules if the
IMPORT
keyword is not used:
$ fgllink -e extlib,extlib2,extlib3 -o stores.42r main.42m store.42m