The flx tool

The executable flx is the primary tool used to interface components of Felix for the purpose of building, testing, and running Felix programs.

To work, flx must be on your $PATH or must be invoked using an absolute or relative pathname.

It is your responsibility to choose how your OS finds the flx program.

Once flx starts, it should be able to find everything else it needs automatically. By default, it uses the hard coded installation directory to find things, which is /usr/local/lib/felix/felix-version on Unix systems or C:usrlocallibfelixfelix-version on Windows, where felix-version is the version of Felix installed.

You can override this hard coded default in several ways. The best way is to create a configuration file named:

$HOME/.felix/config/felix.fpc

on Unix systems or

$USERPROFILE\.felix\config\felix.fpc

on Windows. This file just needs to specify the installation directory:

FLX_INSTALL_DIR=/home/users/me/work/felix

You can also use an environment variable with the same name.

The flx tool needs to know the location of a lot of components, but it will derived most of these correctly from the single location given by the FLX_INSTALL_DIR.

If you build Felix from the git repository, then from the top level of the repository the installation directory is build/release on Unix or build/release on Windows. That is a relative file name, so you should set the variable to the corresponding absolute filename, which would be given by

echo $PWD/build/release

on Unix.

Basic Usage

Once it is all set up, you should be able to run felix programs like this:

flx hello.flx

This should work no matter what you current directory is, no matter where the target file is, and it should not write anything important anywhere except in $HOME/.felix/cache. You may find a couple of files like

flxg_stats.txt

floating about, that just contains some performance stats for the compiler, you can delete it freely, or complain so I can stop polluting your system.

Stand alone executable

To make a stand alone executable you should do this:

flx --static -c -od . hello.flx

and you will find the executable afterwards in the current directory. It will be named hello on Unix like systems or hello.exe on Windows. You can then run it as usual by ./hello on Unix, or just hello on Windows.

The --static switch tells Felix to use static linkage, which is required for a standalone executable. Normally Felix uses dynamic linkage.

The -c switch tells Felix not to run the program.

The -od . means to set the output directory to the current directory ..

You can also use -ox myhello to set the output pathname to myhello without specifying the extension. If you want to specify the extension you can use -o myhello.exe for example. The reason not to do this should be clear, it makes the command OS dependent.

The reason for the -od switch is more subtle: flx has a batch mode which can run a whole set of programs based on a regular expression. In this case you don’t know the name of the file to output, since it is determined by matching the regular expression against a whole directory of felix programs. When you build Felix, the batch mode is used to run all the regression tests.

Compiling Felix with added C++

Felix is specifically designed to work with C and C++. To this end, you can write Felix programs which requires C++ code you also supply.

It is not the purpose of this document to describe how to embed C++ into Felix. However let us assume you have Felix code which depends on the C++ file mycxx.cpp. You can then use this command to compile the C++ as well as the Felix code:

flx mycxx.cpp myfelix.flx

This will compile the mycxx.cpp file using the same C++ compiler Felix uses, generate C++ for myfelix.flx, and compile than, and link the compiled object files together and run them.

Felix does dependency checking on the C++ file. So it will not recompile the file if you do not change it.

Felix recognises the extension .c as C code, and .cpp, .cxx, and .cc for C++ code. We recommend you follow the convention that .cxx is used for translation units containing main() function, and .cpp for all others. This is the convention that Felix itself uses, and it has an impact when autobuilding Felix itself, using the specialised build tools.

Compiling Felix with added object files

Sometimes you want to compile C++ code to object files yourself. In this case you can just add the object files to the command line. On x86_64 platforms in particular you need to take care that you compile the file for the same operational model as you will use with Felix. With static linkage, you can then run your program like:

flx --static mycxx.o myfelix.flx

On Windows, object files have the extension obj instead. If you leave out the --static switch like this:

flx mycxx.o myfelix.flx

you need to be sure you have compiled for relocatable code. With g++ you may need the -fPIC switch on Linux. So-called position independent code (PIC) is slower than position dependent code due to the ABI used by Linux, together with the x86_64 architecture. This problem may or may not arise on other platforms. Felix is very careful to distinguish object files generated for static linkage and those for dynamic linkage. When in doubt, use -fPIC because such code can usually also be statically linked.

Compiling Felix with added libraries

You can also tell Felix to link extra libraries into your program. The easiest way is to just put the filename of the library on the command line. Make sure you compile with the right model!

This method of linkage always works for static linkage:

flx --static libmylib.a myfelix.flx

should link your program against the give static link archive on Linux. On Windows you would use:

flx --static mylib.lib myfelix.flx

If you compile in dynamic mode, you can also give library names like this, they will just be passed as written to the C++ compiler. This is definitely NOT recommended because it probably will not work.

A better way is to pass specific linker switches:

flx --static -Llibdir -lmylib.a myfelix.flx

This should work for both dynamic and static linkage. On Unix, the switches shown are just passed directly to the C++ compiler in link mode.

On Windows, the toolchain drivers use ths same switches, but attempt to translate for MSVC++. For example:

flx --static -Llibdir -lmylib.lib myfelix.flx

should work on Windows. Note that on Unix, the system will look for libmylib.a whereas on Windows, it will look for just mylib.lib, without the lib prefix. MSVC++ uses different switches than Unix, but the toolchain knows what -L and -l mean and map these switches over to MSVC++ syntax.

Using specific switches like this is not recommended except briefly for experimentation. It is much better to register the library in the configuration database.

Compiling C++ only

flx can compile and run C++ programs, programs witten entirely without any Felix. For example:

flx --c++ --static needed.cpp mainline.cxx -- args

All you need is to add the --c++ switch. When you run C++ like this you must remember that the Felix configuration data base will not allow automatic linkage, as it does for Felix programs, unless you modify the source.

We need to use the special symbol – above separate the list of C++ files and the arguments to the program.

Specifying Header file search paths

In order to compile C++ code, or to compile Felix code which embeds C++ which requires header files, you can specify a search path on the flx command line by:

flx --static -Imydir myfile.cpp myfelix.flx

The -Imydir switch extends the search paths used for C++ compilation for the C++ source file myfile.cpp as well as for compiling the generated Felix C++ code. In addition it also adds the directory to the Felix library search path, so any Felix files in the specified directory will be found.

Output Object Type

The normal mode of operation of flx is to run specified program. Execution can be inhibited by using the -c switch.

By default, flx generates a dynamic library, this is a shared library on Unix with .so extension on Linux, or .dylib extenion on OSX, on Windows, you get a .dll.

The action of a Felix program is just the side effects of the initialisation of a library, that is, programs in Felix do not really exist. Thus, a generated dynamic library can act both as a program and also as an actual library.

Felix comes with two executables, flx_run and flx_arun which can be used to run any dynamic Felix library.

If the --static switch is set, then object files are generated for static linkage. Otherwise, object files are generated for dynamic linkage. Dynamic link object files on x86_64 Linux systems require position independent code. Shared libraries must be built from dynamic link object files.

If --static is set, then Felix links the object code for either flx_run or flx_arun together with a stub adaptor against the object file of your program, to produce a stand alone executable.

To generate a static archive, use the --staticlib switch. This produces an .a file on UNix systems and a .lib file on Windows. Note that this option implies --static. However, you can still make static link library from dynamic object files. You need to first compile a dynamic object file, and then on a separate command combine it with any other dynamic object files using --staticlib.

The --exe switch tells flx to produce a static link executable. This is only necessary in special circumstances.

The --nolink switch inhibts linking so that the output object is now an object file. It can be combined with –static to produce a non-position independent object file. Unless overriden, flx produces static link object files with the source basename suffixed by _static and dynamic link, position independent object files with suffix _dynamic.

The --nocc switch inhibits C++ compilation.

The --run-only switch inhits all compilation and just runs the program, ignoring any dependency checking. Obviously this will fail if there is no program to run.

Output Location

By default, the output object of a flx operation will be placed in the cache as $HOME/.felix/cache/binary/pathname where pathname is the absolute pathname of the source file with the extension replaced depending on the output type and OS conventions, as well as the suffix for object files if the output type is an object file produced for a Felix source program.

The output pathname can be changed with the -o pathname switch. The given pathname is used instead of the default. This is discouraged because it is not platform independent.

The output pathname can be changed with the -ox pathname switch. In this case the pathname specified is used, except that the appropriate extension is added automatically. This is prefered over the plain -o switch because it is platform independent.

The output pathname can also be changed with the -od dirname switch. In this case, the output object is placed in the specified directory, with the name of the basename of the input file, and the appropriate extension. This option is specifically design for use with batched compilations where the filename is not known, because the files to be processed are find by examining a directory and comparing filenames found in it with a regular expression. However this switch is also useful even if you know the filename because it avoid repeating it, and it is useful in a script, because it avoids the string processing required to remove the source extension.

When Felix translates a Felix program to C++ it normally puts the C++ files into the cache. You can override this with the --output_dir=dirname switch. This is primarily useful if you are cross compiling, where wish to capture the output files and ship them to another computer for C++ compilation.

The --bundle_dir=dirname switch bundles all the generated files for a program into a single directory. This includes resource control files, C++ output files, object files, executables, etc. This is sometimes useful when debugging, or when you need to ship some or all of the generated files to another computer.

The --cache_dir=dirname changes the location of the cache for this processing run. The cache is normally $HOME/.felix/cache. This is useful is you are running flx in a special mode, and it is essential if you are running flx simultaneously in multiple processes to avoid clobbering of cached files. Always use this if you are simultaneously building for different targets.

By default, Felix knows about targets and if you change targets the cache is cleaned automatically. Compiling from a clean cache takes considerable extra time, since the whole library has to be parsed and bound again.

Generic Performance Controls

flx provides several performance controls. The --usage=level control is a generic control over the compilation process. The level can be as follows:

hyperlight

Ultra fast performance, all run time checks stripped. Not recommended except for microbenchmarking tests.

production

For code to be shipped to clients. High performance run time at the expense of compile time, but includes run time checks.

prototype

For use developing a program, provides slightly faster compilation at the expense of some run time performance, and includes more run time checks and debugging controls.

debug, debugging

Provides the slowest output with the maximum debugging support. Object files should be produces with debugging information for debugger use. Comments in the generated C++ are expanded. Synthesised objects are reduced to make it easier to compare generated C++ with Felix sources.

Insecure run time debugging support is enabled. This includes run time UDP debugging traces on Unix platforms.

C++ compiler switches

Felix recognises certain switches and ships them to your C++ compiler. Only a fixed set of switches is recognised. In some cases, the switches may be translated by the underlying toolchain.

-Lword, -lword

Shipped to the linker.

-fword, -Wword

Shipped to the compiler. Sets warning controls and miscellaneous options. Compiler specific.

-Dword, -Dword=word

Shipped to the compiler. Sets macros. Translated for all compilers.

-O0, -O1, -O2, -O3

Shipped to the compiler. Tells the compiler which performance model to compile with. May interfere with instructions from Felix performance controls.

-Idir

Shipped to the compiler and also used by Felix. Specifies path for include file search.

–cflags=word

Shipped to compiler.

Debugging

The switch --debug-flx tells flx to emit progress and debugging information, especially about dependency checking.

The switch --compile-time tells the Felix compiler flxg to emit times for phases of execution. This is primarily useful to find exactly when a particular bug in Felix program is detected, since some error messages can be hard to understand.

The switch --debug-compiler turns on full debugging of the Felix compiler flxg. It is primarily for the developer of the compiler itself, not users.

The –echo switch tells flx to print commands it sends to the shell. You can also use the FLX_SHELL_ECHO=1 environment variable to do this. That variable affects all Felix programs, including both flx itself and also any program it runs.

The --force-compiler switch forces flx to send Felix code to the Felix compiler flxg even if flx thinks the program and its dependencies are unchanged. This switch usually fails to achieve its intent because flxg also does dependency checking.

The --clean switch wipes out the entire cache forcing all compilation to run from scratch.

The --nofelix switch is used to inhibit translation of Felix code to C++. It does not prevent the other steps. This switch is used so you can add diagnostic prints to generated C++ code and rerun your C++ compilation, linkage, and execution steps, without flxg clobbering your edits.

Test Suites

The --stdin=filename switch tells flx to that when it runs a Felix program, to redirect standard input so it comes from the specified file.

The --stdout=filename switch tells flx that when it runs a Felix program, to redirect standard output to the specified file.

The –expect=filename switch tells flx that the expected output of a program is in the specified file. After the program has run, Felix checks the output agrees with the expected output.

The --stdin, --stdout and --expect switch are similar but they use the pathname of the Felix program with the extension replaced by .input, .stdout and .expect respectively. These switches are used to run test suites along with batch mode compilation.

Batch Compilation

flx can run a command multiple times, replacing the primary Felix filename with a each name found in a directory which matches a regular expression.

The --indir=dirname switch sets the directory to be examined for filenames. The --regex=regexp sets the regular expression used to filter the filenames. This is a Google RE2 compilant regular expression. Make sure you get the command line quoting correct. The regexp must match the whole of the filename relative to the directory specified in --indir switch.

The --nonstop switch tells flx to run a batch of compilations without stopping. By default, it stops when an error is detected.

Felix compilation control

The --nostdlib switch prevents Felix from automatically including the Felix Standard Library. When you use this switch, Felix is said to be running raw. Raw operation is useful for teaching and experimentation because it removes types and functions defined in the standard library from consideration.

Note that the grammar, which is defined in the library, is not disabled by using this switch.

The --import=filename switch imports a file, as if you had written include “filename” in every file. This includes not just your main Felix program but every file it includes, directly or indirectly.

The import switch is used to import macros, because macros are lexically scoped to the file in which they are defined, and cannot be exported to another file. By using the import switch a file with macros in it is made available universally. It is used by flx itself, to import the macros which specify the host operating system, to enable platform dependent code to be generated.

By convention, macro definition files use the extension .flxh.

The switch may also be given in the form --import=@filename. In this case the named file contains a list of files to be imported.

Targetting

Felix has a number of switches to control targetting.

The --target-dir=dir switch sets the directory in which target subdirectories are located. It defaults to the Felix installation directory. The --target-subdir=dir switch sets the subdirectory of the target directory which contains the actual target configuration. It defaults to host.

If you have built a target for say iPhone you can build code for the iPhone by

flx --target-subdir=iPhone iphoneprogram.flx

This will compile the generated C++ with options and header files specified in the configuration database for that target, and link against libraries specified in that target. So for example, on a Mac, you will end up with the above setup with an ARM binary suitable for running on iOS, for the particular API for the version of iPhone you set up. Felix does not help you set up the environment, but once you have done so, flx will compile and link automatically for any target.

A popular target on Linux is clang. You will normally use the host target configured for g++ however if you also have the clang family of compilers you can target them instead of, or as well as, g++.

Be aware, that changing targets clobbers your cache, so if you are building for multiple targets it is a good idea to have separate cache set up for each one.

The --toolchain=toolchain switch can be used to change your toolchain without changing your target. You must take care with this option, because code generated by one toolchain may or may not be compatible with code generated by another.

The flx tool keeps track of the toolchain which is used to compile C++ codes. However, if you are supplying already compiled object files, it cannot report a mismatch.

The --pkgconfig_path+=dir switch prepends the specified directory to the search path used by the internal flx_pkgconfig database query tool. It can be used to enable searching for third party libraries which have configuration data in a location outside Felix. This is strongly recommended practice, since rebuilding Felix destroys all data in the installation directory before installing a clean upgraded copy. However the command line switch is not the best way to provide the location of this configuration database, you should use the $HOME/.felix/config/felix.fpc file instead.

Miscellaneous

The --help switch prints a list of switches.

The --where switch tells the computed location of the Felix installation directory.

The --time switch causes flx to report how long a program takes to run. The time does not include compilation time, only execution time.

The --version switch reports the current version of Felix for which flx was compiled. Be warned, flx can run other version of Felix. To find out the version of Felix source library being used, you have to run a program which prints the library version.

The --repl switch runs a rudimentary line at a time psuedo interpretive loop. You can use this for one liners. The repl accepts multiple lines up to a blank line, then compiles the code and runs it. The next paragraph of input is appended to the code you already supplied and the resulting text is compiled and run again.

The --felix=filename switch loads a configuration control file with a set of configuration settings. This can be used to provide detailed customisation of the configuration of the Felix system.

By default, flx looks for the file $HOME/.felix/config/felix.fpc and loads that if it is found, as if it were specified with the --felix switch.