The FLI macros such as define-foreign-function and define-foreign-callable take a keyword
:calling-convention. Apart from on 32-bit Windows and on the ARM architectures, there is only one calling convention and in most cases you do not need to specify it.
The common case when you need to specify the calling convention is on 32-bit Windows where the default LispWorks calling convention is
__stdcall. This matches the Win32 API functions, but compilers typically produce
__cdecl by default (which is the same as the non-Windows x86 systems).
ARM (both 32-bit and 64-bit) also has more than one calling convention, but it should be rare (in 32-bit) or extremely rare (in 64-bit) that you need to specify the convention. Note however that, on ARM, failing to specify that a function is variadic (by the keyword
:variadic-num-of-fixed) is more likely to cause crashes than on the other architectures.
The Win32 API functions in 32-bit Windows applications are compiled using the
__stdcall calling convention, but compilers normally use
__cdecl by default. Thus if you call functions that are not part of the Win32 API from 32-bit LispWorks then you need to check the calling convention and in most cases you need to specify it as
__cdecl by passing
:calling-convention :cdecl. To specify
:calling-convention :stdcall, which is the default so is not really needed.
Since whole libraries are normally compiled with the same calling convention, it is usually convenient to define your own defining macro that expands to the FLI defining macro and passes it the calling convention. For example, LispWorks itself uses the following defining macro to define foreign calls to the MySQL library:
32-bit ARM systems have two calling conventions: hard float and soft float. These calling conventions are binary incompatible, and operating systems generally support only one or the other. Currently, Android and iOS are both soft float but Android is now starting to support hard float code, while ARM Linux distributions are now almost always hard float, but used to be soft float. Moreover, iOS has a calling convention which is soft, and somewhat different from the Android/old-Linux soft float, so these are also binary incompatible.
The calling convention that is used by iOS.
The calling convention that is used by Android, and was used by old Linux systems.
The calling convention used by newer Linux systems.
When LispWorks compiles a foreign call or callable function, it (by default) generates "tri-compatible" code that can interface with either hard float, soft Linux or iOS foreign code. At run time, the code checks an internal flag and uses the appropriate calling convention. The internal flag is set to the correct value on start-up. The tri-compatible code is needed only for functions where the calling conventions differ, and when 2 or more of the conventions need the same code LispWorks avoids duplicating code, while remaining compatible with all 3 conventions.
Because of the tri-compatible code, LispWorks binaries (fasl files) are compatible with all the conventions. The compiled Lisp code is also compatible with all conventions. However, LispWorks executables (including LispWorks as a shared library) have a small C program that starts Lisp (the "xstarter"), and this is either hard float, soft Linux or iOS. Therefore, a LispWorks executable can run only on one calling convention, but the code that LispWorks compiles can run on all of them.
In particular, that means that it is possible to compile and build runtimes for Android and iOS on either soft float or hard float systems, because the runtime is created using the appropriate xstarter for the target OS.
Android. Currently that is an alias to :soft-linux.
Code that selects between
Note that variadic functions (for example
sscanf) are always soft float, which means that when compiling calls to such functions it is essential to specify that they are variadic (by passing
:variadic-num-of-fixed) to ensure that LispWorks does not try to pass the arguments as hard float.
Compatibility note: in LispWorks 7.0, you had to pass
:calling-convention :soft-float for variadic functions. This still works, but passing
:variadic-num-of-fixed is more correct and will make it work properly on other architectures, (in particular 64-bit ARM).
By default, LispWorks compiles code that selects which convention to use at run time. However, the difference between the conventions is quite minor and affects only a small number of functions, so the code is the same for most functions. Thus the overhead is quite small and you will not normally have a reason to pass
:calling-convention for 64-bit ARM.
Compile only the iOS convention.
Compile only the standard convention.
Note that all the keywords used for 32-bit ARM (see ARM 32-bit calling conventions), with the exception of
:ios, are treated as the default on 64-bit ARM.
On 32-bit x86 platforms, the C compilers have a fastcall calling convention. In Visual C and the GNU C compiler, this it is specified by the
__fastcall qualifier. If you call a foreign function that is compiled as a fastcall, you must specify the calling convention
LispWorks Foreign Language Interface User Guide and Reference Manual - 29 Sep 2017