Summary:
See also: Tools, Form Files, Message Files, Localized Strings.
Source code modules (4gl) must be compiled to p-code modules (42m) with the fglcomp tool. Compiled p-code modules are portable; you can compile a module on a Windows platform and install it on a Unix production machine.
The following lines show a compilation in a Unix shell session:
$ cat xx.4gl
main
display "hello"
end main
$ fglcomp xx.4gl
$ ls -s xx.42m
4 xx.42m
If an error occurs, the compiler writes an error file with the .err extension.
$ cat xx.4gl
main
let x = "hello"
end main
$ fglcomp xx.4gl
Compilation was not successful. Errors found: 1.
The file xx.4gl has been written.
$ cat xx.err
main
let x = "hello"
| The symbol 'x' does not represent a defined variable.
| See error number -4369.
end main
With the -M option, you can force the compiler to display an error message instead of generating an .err error file:
$ fglcomp xx.4gl
xx.4gl:2:8 error:(-4369) The symbol 'x' does not represent a defined variable.
By default, the compiler does not raise any warnings. You can turn on warnings with the -W option:
$ cat xx.4gl
main
database test1
select count(*) from x, outer(y) where x.k = y.k
end main
$ fglcomp -W stdsql xx.4gl
xx.4gl:3: warning: SQL statement or language instruction with specific SQL syntax.
When a warning is raised, you can use the -W error option to force the compiler to stop as if an error was found.
For more details about warning options, see the fglcomp tool.
Starting with Genero BDL 2.21, it is possible to define module dependencies with the IMPORT FGL instruction. Imported module elements such as functions, variables, user types and constants can be shared and used in the current module. Module importation is a straightforward way to define module dependencies, allowing program compilation without a link phase.
The next source example imports the myutils and account modules, and uses the init() and set_account() functions of the imported modules (note that the first function call is qualified with the module name - this is optional but required to resolve ambiguities when the same function name is used by different modules):
01
IMPORT FGL myutils02
IMPORT FGL account03
MAIN04
CALL myutils.init()05
CALL set_account("CFX4559")06
...07
END MAIN
By declaring module dependencies with the IMPORT FGL instruction, you instruct the fglcomp compiler and fglrun runtime system to load/check the specified modules, and there is no longer a need to link programs or use libraries.
Note that imported modules must be compiled before compiling the importing module, and no circular references are allowed (module A importing module B, which imports module A).
Note that the FGLLDPATH environment variable specifies the directories to search for the Genero BDL modules used by IMPORT.
With the IMPORT FGL instruction, language elements such as module variables, user types and constants can be shared between modules. The PRIVATE / PUBLIC modifiers can be used to hide / publish elements to other modules. The next example declares a module variable that can be used by other modules, and a private function to be used only locally:
01
PUBLIC DEFINE custlist DYNAMIC ARRAY OF RECORD02
id INT,03
name VARCHAR(50),04
address VARCHAR(200)05
END RECORD06
...07
PRIVATE FUNCTION myfunction()08
...
For more details, see IMPORT.
Compiled 42m modules can be grouped in libraries by using the Genero linker. The library files get the 42x extension. If none of the modules defines the MAIN block, the linker creates a library; if a MAIN block is present, the linker creates a program.
Library 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.
The following lines show a link procedure to create a library in a Unix shell session:
$ fglcomp fileutils.4gl
$ fglcomp userutils.4gl
$ fgllink -o libutils.42x fileutils.42m userutils.42m
When you create a library, all functions of the 42m modules used in the link command are registered in the 42x file.
Keep in mind that the 42x library file does not contain the 42m p-code. When deploying your application, you must provide all compiled 42m modules.
When creating a 42x library, all functions must be uniquely defined; otherwise, error -6203 will be returned by the linker.
The 42x libraries are typically used to link the final 42r programs:
$ fglcomp mymain.4gl
$ fgllink -o myprog.42r mymain.42m libutils.42x
Note that 42r programs must be re-linked if the content of 42x libraries have changed. In the above example, if a function of the userutils.4gl source file was removed, you must recompile userutils.4gl, re-link the libutils.42x library and re-link the myprog.42r program.
It is possible to create a library by referencing other 42x library files in the link command, as long as 42M modules can be found:
$ fglcomp module_1.4gl
$ fglcomp module_2.4gl
$ fgllink -o lib_A.42x module_1.42m
$ fgllink -o lib_B.42x module_2.42m lib_A.42x
$ fgllink -o myprog.42r lib_B.42x -- will hold functions of
module_1 and module_2.
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. You can specify a search path with the FGLLDPATH environment variable; see Linking Programs for more details.
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 libutils.42x fileutils.42m userutils.42m
Genero programs 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.
The generated 42r program files do not contain the 42m p-code. When deploying your application, you must provide all 42m modules, as well as 42r program files. Since 42x library files are only used to build programs, you do not have to deploy 42x library files.
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.
The following lines show a link procedure to create a library in a Unix shell session:
$ fglcomp main.4gl
$ fglcomp store.4gl
$ fgllink -o stores.42r main.42m store.42m
If you omit the -o option in the fgllink command, the default output file will have the .42x extension and 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.
When linking a 42r program by using 42x libraries, the modules defined in a library are included only if one of the symbols in the module is used by the program. However, all symbols of 42m modules specified in the command line will always be referenced in the resulting 42r program file. The same function symbols can be defined in distinct libraries; the linker will select the function of the first library that was specified in the command line.
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.
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.
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. You can specify a search path with the FGLLDPATH environment variable:
$ 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.
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.
The link procedure 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.
When linking a program with modules using the IMPORT FGL instruction, you do not have to specify the imported modules in the link line, since these modules will be loaded dynamically at runtime. However, any symbol used by the imported module must be resolved by the linker. Therefore, 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. For example, if the main module imports module MA to call the function FA, which in turn calls a function FB from module MB, but MA does not import MB, you will have to specify MB in the link line to have the linker resolve the FB function.
When linking a .42r program by using a .42x library, if none of the functions of a module in the .42x library are used in the program, the complete module is excluded by the linker. This may cause undefined function errors at runtime, such as when a function is only used in a dynamic call (an initialization function, for example.)
The following case illustrates this behavior:
$ cat x1.4gl
function fx11()
end function
function fx12()
end function
$ cat x2.4gl
function fx21()
end function
function fx22()
end function
$ cat prog.4gl
main
call fx11()
end main
$ fglcomp x1.4gl
$ fglcomp x2.4gl
$ fglcomp prog.4gl
$ fgllink -o lib.42x x1.42m x2.42m
$ fgllink -o prog.42r prog.42m lib.42x
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 un-trappable error -1338.
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
Most UNIX platforms provide the make utility program to compile projects. The make program is an interpreter of Makefiles. These files contain directives to compile and link programs and/or generate other kind of files.
When developing on Microsoft Windows platforms, you may use the NMAKE utility provided with Visual C++, however this tool does not have the same behavior as the Unix make program. To have a compatible make on Windows, you can install a GNU make or third party Unix tools such as Cygwin.
For more details about the make utility, see the platform-specific documentation.
The follow example shows a typical Makefile for Genero applications:
#------------------------------------------------------ # Generic makefile rules to be included in Makefiles .SUFFIXES: .42s .42f .42m .42r .str .per .4gl .msg .hlp FGLFORM=fglform -M FGLCOMP=fglcomp -M FGLLINK=fglrun -l FGLMKMSG=fglmkmsg FGLMKSTR=fglmkstr FGLLIB=$$FGLDIR/lib/libfgl4js.42x all:: .msg.hlp: $(FGLMKMSG) $*.msg $*.hlp .str.42s: $(FGLMKSTR) $*.str $*.42s .per.42f: $(FGLFORM) $*.per .4gl.42m: $(FGLCOMP) $*.4gl clean:: rm -f *.hlp *.42? *.out #----------------------------- # Makefile example include Makeincl FORMS=\ customers.42f\ orderlist.42f\ itemlist.42f MODULES=\ customerInput.42m\ zoomOrders.42m\ zoomItems.42m customer.42x: $(MODULES) $(FGLLINK) -o customer.42x $(MODULES)
all:: customer.42x $(FORMS)
The compiler version used to build the 42m modules must be compatible to the runtime system used to execute the programs. The fglcomp compiler writes version information in the generated 42m files. This can be useful on site, if you need to check the version of the compiler that was used to build the 42m nodules.
To extract build information, run fglrun with the -b option:
$ fglrun -b mymodule.42m
2.11.01-1161.12 /home/devel/stores/mymodule.4gl 15
The output shows the following fields:
2.11.01-1161.12
).fglrun -b can read the header of pcode modules compiled with older versions of fglcomp and display version information for such old modules. If fglrun cannot recognize a pcode module, it returns with an execution status that is different from zero.
When reading build information of a 42x or 42r file, fglrun scans all modules used to build the library or program. You will see different versions in the first column if the modules were compiled with different versions of fglcomp. However, it's not recommended that you mix versions on a production site:
$ fglrun -b myprogram.42r
2.11.01-1161.12 /home/devel/stores/mymodule1.4gl 15
2.10.02-1148.36 /home/devel/stores/mymodule2.4gl 15
2.11.01-1161.12 /home/devel/stores/mymodule3.4gl 15
If you need to write timestamp information in the pcode modules, you can use the --timestamp option of fglcomp:
$ fglcomp --timestamp mymodule.4gl
$ fglrun -b mymodule.42m
2008-12-24 11:22:33 2.11.05-1169.84 /home/devel/stores/mymodule.4gl 15
However, with timestamp information in pcode modules, you will not be able to easily compare 42m files (based on a checksum, for example). Without the timestamp, fglcomp generates exactly the same pcode module if the source file was not modified.
To check if the version of the runtime system corresponds to the pcode version, run fglrun with the -V option.