Compiling program code files (.4gl)
The .4gl source files must be compiled to .42m p-code files, in order to be loaded by the runtime system.
Understanding .4gl source compilation
Genero BDL source code modules (with .4gl file extension) must be compiled to p-code modules (with .42m file extension) by using the fglcomp tool.
Compiled p-code modules are independent of the platform and processor architecture. They are interpreted by the Genero runtime system (fglrun).
The following lines show the compilation of the prog.4gl source, in a UNIX™ shell session:
$ cat prog.4gl
MAIN
DISPLAY "hello"
END MAIN
$ fglcomp prog.4gl
$ ls -s prog.42m
4 prog.42m
Verbose compilation
--verbose
option of the compiler to get detailed information
about the source
compilation:$ fglcomp --verbose main.4gl
[loading fglhelp]
[parsing main.4gl]
[parsing mod1.4gl]
[parsing mod2.4gl]
[building mod2]
[writing mod2.42m]
[building mod1]
[writing mod1.42m]
[building main]
[writing main.42m]
[total modules: 4 variables: 6 funtions: 274 types: 9 fields: 10]
Compiling several .4gl sources in a single command
Several .4gl source files can be provided to fglcomp: The compiler builds a dependency tree of imported modules, and compiles the files in the calculated order.
For example, if the main.4gl module imports module1.4gl, but does not import module2.4gl, when passing main.4gl module1.4gl module2.4gl as arguments to fglcomp, the compiler will first compile the module1.4gl because it is imported by main.4gl, then main.4gl and finaly module2.4gl (assuming no .42m file exists before executing this command):
$ rm *.42m
$ fglcomp --verbose main.4gl module1.4gl module2.4gl
[loading fglhelp]
[parsing main.4gl]
[parsing module1.4gl]
[building module1]
[writing module1.42m]
[building main]
[writing main.42m]
[parsing module1.4gl]
[building module1]
[writing module1.42m]
[parsing module2.4gl]
[building module2]
[writing module2.42m]
[total modules: 6 variables: 6 funtions: 274 types: 11 fields: 20]
MATCHES
-style pattern on the
command line, to achieve pathname expansion:fglcomp [a-z]*.4gl
fglcomp '[a-z]*.4gl'
For more details about supported patterns and wildcards, see the os.Path.glob utility method.
Automatic compilation of imported modules
When compiling a .4gl module that imports other modules with the
IMPORT FGL
instruction, fglcomp will automatically compile the imported modules, if
they are located in the same directory of the current module, and if the .4gl
source is more recent as the .42m file.
For more details about auto-compilation of imported modules, see Auto-compilation of (local) imported modules.
Stricter compilation options
By default, fglcomp allows you to compile legacy application sources in a relaxed manner. For example, it is possible to compile a module calling a function which is not defined in that module, and resolved during the link process.
IMPORT FGL
, consider using
fglcomp options that make the compilation stricter:--resolve-calls
: To check that all functions used by a module are defined locally, or by imported modules.-W all
: To print all type of warnings.-W error
: To stop compilation if a warning occurs.-M
: To write error messages to standard output instead of producing a .err file.
For more details about fglcomp options, see the fglcomp command reference topic.
Additionally, the linker provides options
such as --print-imports
and --print-missing-imports
, that produce
useful information to use new language features.
Compiling in make mode
The fglcomp compiler supports the --make
option, to compile
all provided sources, in the way the make utility does: If the
.42m file is older than the .4gl file, it will
be recompiled. If the .42m is up-to-date with the
.4gl, it is not recompiled.
As with a regular compilation (not using the --make
option), for a provided
.4gl module, imported modules will be automatically compiled when needed.
To test the compilation process and dependencies without actually compiling the modules, add the
--simulate
option, to see what modules would be compiled. The
--simulate
option can also be used without the --make
option:
fglcomp will then print the modules that would be compiled, even if the
.42m file is up to date.
For example:
$ tree .
.
|-- bin
|-- dir1
| |-- module1.4gl
| |-- module2.4gl
| `-- module3.4gl
|-- prog1.4gl
`-- prog2.4gl
2 directories, 5 files
$ head *.4gl */*.4gl
==> prog1.4gl <==
IMPORT FGL module1
MAIN
CALL module1.function1()
END MAIN
==> prog2.4gl <==
IMPORT FGL module2
MAIN
CALL module2.function2()
END MAIN
==> dir1/module1.4gl <==
FUNCTION function1()
END FUNCTION
==> dir1/module2.4gl <==
IMPORT FGL module3
FUNCTION function2()
CALL module3.function3()
END FUNCTION
==> dir1/module3.4gl <==
FUNCTION function3()
END FUNCTION
$ cd bin
$ fglcomp --make --simulate ../*.4gl ../*/*.4gl
[fglcomp ../dir1/module1.4gl]
[fglcomp ../prog1.4gl]
[fglcomp ../dir1/module3.4gl]
[fglcomp ../dir1/module2.4gl]
[fglcomp ../prog2.4gl]
$ fglcomp --make *.4gl dir1/*.4gl
[fglcomp ../dir1/module1.4gl]
[fglcomp ../prog1.4gl]
[fglcomp ../dir1/module3.4gl]
[fglcomp ../dir1/module2.4gl]
[fglcomp ../prog2.4gl]
$ ls
module1.42m module2.42m module3.42m prog1.42m prog2.42m
IMPORT FGL
dependence
tree:$ sleep 1 && touch ../dir1/module3.4gl ../prog1.4gl
$ fglcomp --make ../*.4gl ../*/*.4gl
[fglcomp ../prog1.4gl]
[fglcomp ../dir1/module3.4gl]
[fglcomp ../dir1/module2.4gl]
[fglcomp ../prog2.4gl]
Producing make-style dependency rules
module1
and thus the main.42m compilation depends from
module1.42m:$ head *.4gl
==> main.4gl <==
IMPORT FGL module1
MAIN
CALL module1.function1()
END MAIN
==> module1.4gl <==
FUNCTION function1()
END FUNCTION
$ fglcomp --dependencies main.4gl
main.42m: main.4gl module1.42m
$(FGLCOMP) $<
module1.42m: module1.4gl
$(FGLCOMP) $<
Providing the source files in an arguments file
The fglcomp compiler supports the @argfile
argument, to
provide a file that contains the list of source files to be compiled. This can be used when it is
not possible to pass all source files in the command line.
Only source files must be specified in the arguments file. Compiler options must be provided in the command line.
The argument file must contain one source file per line:
$ cat mysources.txt
module1.4gl
module2.4gl
module3.4gl
$ fglcomp -M -W all @mysources.txt
$ cat mysources.txt
module[123]*.4gl
$ fglcomp -M -W all @mysources.txt
Handling fglcomp compiler errors
If an error occurs, the compiler writes an error file by default with the .err extension.
$ cat prog.4gl
MAIN
LET x = "hello"
END MAIN
$ fglcomp prog.4gl
Compilation was not successful. Errors found: 1.
The file prog.4gl has been written.
$ cat prog.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 prog.4gl
xx.4gl:2:8 error:(-4369) The symbol 'x' does not represent a defined variable.
Produce compiler warnings with -W
To improve code quality, enable compiler warnings with the -W
option:
$ cat prog.4gl
MAIN
DATABASE test1
SELECT COUNT(*) FROM x, OUTER(y) WHERE x.k = y.k
END MAIN
$ fglcomp -W stdsql prog.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.
Some warnings are generated by default (without using the -W
option), when the
source code uses a feature that is considered as "fragile" yet to be supported for backward
compatibility.
By default warnings go to the stderr stream. When creating a
.err file, warnings can be redirected to the .err file
with the -W to-err-file option
.
For the complete list of warning options, see -W
option in fglcomp command reference.