Programs / Importing modules |
The IMPORT FGL instruction imports module symbols.
IMPORT FGL modulename
With IMPORT FGL modulename, the symbols of the named .42m module can be referenced in the current module.
The name specified after the IMPORT FGL instruction is case-sensitive.
The imported module symbols that can be referenced are:
PUBLIC DEFINE custlist DYNAMIC ARRAY OF RECORD id INT, name VARCHAR(50), address VARCHAR(200) END RECORD ... PRIVATE FUNCTION myfunction() ...
When importing modules 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. Further, the compiler can check the number of parameters and returning values in functions calls, and the completion in source code editors is improved as it can suggest all imported symbols.
Imported modules should be compiled before compiling the importing module. However, if the 42m file of the imported module is not existing, or is older as the corresponding source file, fglcomp will automatically compile the imported module. To avoid implicit compilation of imported modules, use the --implicit=none option of fglcomp. If the .42m file exists but the .4gl source file cannot be found, fglcomp imports the .42m file as is.
The FGLLDPATH environment variable specifies the directories to search for the modules used by IMPORT FGL.
No circular references are allowed. For example when module A imports module B, which in turn imports module A, you cannot compile one of the modules because the 42m file of the imported module is needed. Thus fglcomp will give error -8403, indicating that the imported module cannot be found:
IMPORT FGL module_b FUNCTION func_a() CALL func_b() END FUNCTION
IMPORT FGL module_a FUNCTION func_b() CALL func_a() END FUNCTION
Traditional linking is still supported for backward compatibility. To ease migration from traditional linking to imported modules, you can mix IMPORT FGL usage with fgllink. By default, even when IMPORT FGL is used, fglcomp does not raise an error if a referenced function is not found in the imported modules. This is mandatory to compile the 42m file to be linked later with the module defining the missing function. Use the -W implicit or the --resolve-calls option to check for imported functions.
When the -W implicit option is used and at least one IMPORT FGL is defined in the module, fglcomp will print warning -8406 for any referenced function that cannot be found in the imported modules. This option is silently ignored if no IMPORT FGL is used in the module.
To enable full symbol resolution by the compiler, use the --resolve-calls option. This option will force the compiler to check all function symbols referenced in a module, and raise error -8406, if a symbol could not be found in the imported modules. This option is typically used in programs that are only using IMPORT FGL and do not longer use the link phase.
$ cat main.4gl MAIN CALL func1() END MAIN $ cat mod1.4gl FUNCTION func1() CALL func2() END FUNCTION $ cat mod2.4gl FUNCTION func2() CALL func1() END FUNCTION $ fglrun --print-imports main.42m mod1.42m mod2.42m -- in main.4gl IMPORT FGL mod1 -- in mod1.4gl IMPORT FGL mod2 -- in mod2.4gl # Cyclic import: IMPORT FGL mod1 # caused by CALL func1
If a symbol is defined twice with the same name in two different modules, the symbol must be qualified by the name of the module. This feature overcomes the traditional 4gl limitation requiring unique function names within a program. In the next example, both imported modules define the same "init()" function, but this can be resolved by adding the module name followed by a dot before the function names:
IMPORT FGL orders IMPORT FGL customers MAIN CALL orders.init() CALL customers.init() ... END MAIN
If a symbol is defined twice with the same name in the current and the imported module, an unqualified symbol will reference the current module symbol. The next example calls the "init()" function with and without a module qualifier, the second call will reference the local function:
IMPORT FGL orders MAIN CALL orders.init() -- orders module function CALL init() -- local function ... END MAIN FUNCTION init() ... END FUNCTION
PRIVATE DEFINE current_account VARCHAR(20) PUBLIC FUNCTION set_account(id) DEFINE id VARCHAR(20) LET current_account = id END FUNCTION ... -- File: myutils.4gl PRIVATE DEFINE initialized BOOLEAN PUBLIC TYPE t_prog_info RECORD name STRING, version STRING, author STRING END RECORD PUBLIC FUNCTION init() LET initialized = TRUE ... END FUNCTION PUBLIC FUNCTION fini() LET initialized = FALSE ... END FUNCTION
PRIVATE DEFINE initialized BOOLEAN PUBLIC TYPE t_prog_info RECORD name STRING, version STRING, author STRING END RECORD PUBLIC FUNCTION init() LET initialized = TRUE ... END FUNCTION PUBLIC FUNCTION fini() LET initialized = FALSE ... END FUNCTION
IMPORT FGL myutils IMPORT FGL account DEFINE filename STRING DEFINE proginfo t_prog_info -- Type is defined in myutils MAIN LET proginfo.name = "program" LET proginfo.version = "0.99" LET proginfo.author = "scott" CALL myutils.init() -- with module prefix CALL set_account("CFX4559") -- without module prefix END MAIN