Expand/Shrink

format directive

The primary purpose of the format directive is cross-compilation, ie 32<->64 and pe<->elf (aka Windows<->Linux).

If the format directive is completely omitted then suitable defaults for all values are provided, largely based on the compiler being run. For example, assuming -c, running the console version (p.exe) creates a console executable whereas running pw.exe creates a gui executable. Likewise running a 32-bit version of Phix by default creates a 32-bit executable whereas a 64-bit version creates a 64-bit executable. And of course running a Windows version of Phix on a Windows machine by default creates a Windows PE format executable, whereas a Linux version on a Linux machine creates a Linux ELF format executable (but running a PE format Phix under Wine will create a PE format output suitable for running under Wine). The format directive allows you to override that default behaviour and has the following formal syntax:
    format "redirect.file"|
           (PE32|PE64) [GUI|console] [3.10|4.0|5.0] [DLL] [icons] [version] [manifest]|
           (ELF32|ELF64) [SO] | ARM
As a simple example, you could just use ("-c" and) "format PE32".

When DLL/SO is specified, the compiler collects export statements in the top-level file and uses that list (of symtab entry indexes) to construct the required export section. Note that constants (and enums) cannot be exported, and routines are subject to the same restrictions as call_back routines. You should also note that DLL/SO mandates the use of "-c -norun" on the command line, there is no interpret (or trace) mode, and further that "-c -nodiag -norun" (or the shorter/easier but equivalent "-dll") is recommended once things have been adequately tested.

Note that instead of a format directive, requires() and/or with/without javascript_semantics should be used to limit the platform(s) that Phix should attempt to run on/compile/transpile for, and prevent time being wasted on those you know it will not work on (at least not without further effort).

At the time of writing, SO are in progress/not yet supported. [DEV]

Note that, as a relatively new addition, the format directive is subject to frequent change. One possible (but untried) use for the format directive might be for a library to assert that the target architecture is properly supported/tested, eg arwen.ew could begin with the line "format PE32|PE64" (literally including the "|") to assert that it does not run on ELF/ARM, or another component could have all four currently supported targets, as a safety measure against some other target being added in the future. (Note that arwen.ew is currently 32 bit only and I have no plans to attempt a 64 bit version of it.) Consequently this section is likely to be updated as/when things get implemented/fixed.

The format directive should be at the start of the main file, before any constant, variable, or routine definitions, or any executable code or include statements, but can be after namespace and with/without directives. To get technical for a moment, the real issue is that any #ilASM statements, as very commonly occuring in the builtins directory, are, before a format directive, rather likely to target the wrong architecture. Some special handling has been added to pmain.e (see Z_format) to allow trace() and profile() to precede a format statement, however it may not work in all cases. Likewise you may also get away with a few simple constants, etc. Otherwise once any "prohibited code" has been processed the compiler simply issues an "invalid" error against the word "format".

At most two redirects are permitted. For example, p.exw has the directive 'format "p.fmt"'; p.fmt is intended to contain one of 'format "pe32.fmt"', 'format "pe64.fmt"', 'format "elf32.fmt"', or 'format "elf64.fmt"', and finally pe32.fmt (etc) contains the actual format directive. This allows me to work on the compiler and/or the test harness without keeping several such directives in step, and also permits the build process to replace (and later restore) p.fmt for cross-compilation etc. A redirected file cannot contain anything other than a format directive; pmain.e/DoFormat() issues a compilation error if it does not reach EOF. In case you have not guessed, if the token following the format keyword is a string, it is a filename. In fact, a format "filename" directive is almost identical to an include filename statement, except that the former expressly prohibits anything other than a format directive in the target file. Also, redirects are ignored during interpretation, whereas an "inline" format directive that specifies an incompatible architecture for interpretation causes a compilation error.

As an example, the file pe32.fmt distributed with Phix contains:
format PE32 4.0
icons {"ok.ico",{0,1}}
version { "FileDescription","Phix Programming Language",
          "LegalCopyright","Pete Lomax",
          "FileVersion","0.6.3",
          "ProductName","Phix Programming Language",
          "ProductVersion","0.6.3",
          "OriginalFilename","pw.exe" }
manifest `
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <assemblyIdentity name="x.x.x" processorArchitecture="x86" version="5.1.0.0" type="win32"/>
 <description>no</description>
 <dependency>
  <dependentAssembly>
   <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" 
                     processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*" />
  </dependentAssembly>
 </dependency>
</assembly>`
 
Unusually, perhaps, p.exw does not specify either GUI or console since it always creates p.exe and pw.exe anyway. Subsystem version 4.0 is the default for 32-bit executables and 5.0 the default for 64-bit files (for PE format files, that is). Note that (the older) with/without console/gui affect exactly the same settings (variables OptConsole and subvers, which are defined in pglobals.e).

The values shown above for icons and manifest coincide with the defaults (see pglobals.e). If the version details (which must be an even number of strings) are omitted, then no version information is output in the resulting executable file. There is no way to dynamically set any values during compilation, though it should be trivial to (programmatically) create such a file beforehand.

I believe (but I’m not an expert) that a processorArchitecture of "*" would be best for PE32/PE64 compatibility. Since I encountered a problem trying to compile "x86" to PE64, I expect others will probably do so as well, and hence have implemented the following solution:

Any "x86" in the manifest are automatically replaced with "amd64" (including the quotes) when PE64 is in force, as it seems that doing so is necessary to properly initialise the common controls (without manually invoking InitCommonControlsEx). This was originally only intended to apply to the default rather than any explicit replacement, but since it is an easy fix to a possibly fairly common mistake that would otherwise completely hose an application, it has been deliberately left like that (applying across the board to everything). There is, however, no equivalent substitution of "amd64" with "x86" when PE32 is in force.

Lastly, when using a 32-bit compiler to create a 64-bit executable, be aware that the integer range is redefined as +/-#FFFF_FFFF rather than -#4000_0000_0000_0000 to #3FFF_FFFF_FFFF_FFFF. See ptok.e/setFLOAT() for all the nitty-gritty details. It is also true that the value of PI, and possibly some other constants, will be slightly out, by about one trillionth of one percent, when performing such cross-compilations.

pwa/p2js: Ignored/Not supported. On desktop/Phix, a format directive does not change interpretation one iota, except for DLL/SO which trigger an error if -c (or -dll) was not specified on the command line. There is no -c option in p2js (as yet), otherwise that handling is the same, and just like desktop/Phix without -c the format directive is largely ignored. Plus of course there is no sensible/practical way a browser could write an executable file anyway, at least not without a bit of server-side code [as yet not even planned].