Portability of WSTP Programs

The Wolfram Language side of a Wolfram Symbolic Transfer Protocol (WSTP) connection is set up to work exactly the same on all computer systems. But inevitably there are differences between external programs on different computer systems.
For a start, different computer systems almost always require different executable binaries. When you call Install["prog"], therefore, you must be sure that prog corresponds to a program that can be executed on your particular computer system.
Install["file"]
try to execute file directly
Install["file",LinkProtocol->"type"]
use the specified protocol for lowlevel data transport
$SystemID
identify the type of computer system being used
Install["dir"]
try to execute a file with a name of the form dir/$SystemID/dir
Installing programs on different computer systems.
The Wolfram Language follows the convention that if prog is an ordinary file, then Install["prog"] will just try to execute it. But if prog is a directory, then the Wolfram Language will look for a subdirectory of that directory whose name agrees with the current value of $SystemID and will then try to execute a file named prog within that subdirectory.
mcc -o prog
put compiled code in the file prog in the current directory
mcc -xo prog
put compiled code in prog/$SystemID/prog
Typical Unix commands for compiling external programs.
Even though the executable binary of an external program is inevitably different on different computer systems, it can still be the case that the source code in a language such as C from which this binary is obtained can be essentially the same.
But to achieve portability in your C source code, there are several points that you need to watch.
For a start, you should never make use of extra features of the C language or C runtime libraries that happen to be provided on a particular system, but are not part of standard C. In addition, you should try to avoid dealing with segmented or otherwise special memory models.
The include file wstp.h contains standard C prototypes for all the functions in the WSTP library.
WSPutInteger32()WSGetInteger32()
integer corresponding to C type int, that is, 32 bits
WSPutInteger16()WSGetInteger16()
integer of type short, that is, 16 bits
WSPutInteger64()WSGetInteger64()
64-bit integer
WSPutReal64()WSGetReal64()
IEEE double-precision real number, corresponding to the C-language type double
WSPutReal32()WSGetReal32()
IEEE singleprecision real number, corresponding to the C-language type float
WSPutReal128()WSGetReal128()
IEEE quadprecision real number
WSTP functions that use specific C types.
If you are going to call WSTP library functions in a portable way, it is essential that you use the same types as they do.
If your programs correctly match the argument types for the WSTP library functions, you do not have to worry about C type differences between computer systems. WSTP automatically converts the C types to the appropriate sizes for each platform. WSTP also swaps bytes as needed to correctly transfer numbers across platforms and it converts between floating-point number formats with the smallest possible loss of precision.
WSPutString(stdlink,char*s)
put a null-terminated C character string
WSPutUnicodeString(stdlink,unsigned short*s,int n)
put a string encoded in terms of 16bit UCS-2 Unicode characters
WSPutByteString(stdlink,unsigned char*s,int n)
put a string containing only 8bit character codes
WSPutUTF8String(stdlink, const unsigned char*s,int n)
put a string of UTF-8 encoded Unicode characters
WSPutUTF16String(stdlink, const unsigned short*s,int n)
put a string of UTF-16 encoded Unicode characters
WSPutUTF32String(stdlink, const unsigned int*s,int n)
put a string of UTF-32 encoded Unicode characters
WSGetString(stdlink,char**s)
get a null-terminated C character string
WSGetUnicodeString(stdlink,unsigned short**s,long*n)
get a string encoded in terms of 16bit UCS-2 Unicode characters
WSGetByteString(stdlink,unsigned char**s,long*n,long spec)
get a string containing only 8bit character codes, using spec as the code for all 16bit characters
WSGetUTF8String(stdlink, const unsigned char**s,int*m,int*n)
get a string of UTF-8 encoded Unicode characters
WSGetUTF16String(stdlink, const unsigned short**s,int*m,int*n)
get a string of UTF-16 encoded Unicode characters
WSGetUTF32String(stdlink, const unsigned int**s,int*n)
get a string of UTF-32 encoded Unicode characters
Manipulating general strings.
In simple C programs, it is typical to use strings that contain only ordinary ASCII characters. But in the Wolfram Language, it is possible to have strings containing all sorts of special characters. These characters are specified within the Wolfram Language using Unicode character codes, as discussed in "Raw Character Encodings".
C language char* strings typically use only 8 bits to store the code for each character. UCS-2 encoded strings, however, require 16 bits. As a result, the functions WSPutUnicodeString() and WSGetUnicodeString() work with arrays of unsignedshort integers. The same is true of UTF-16 encoded strings and the corresponding functions WSPutUTF16String() and WSGetUTF16String().
UTF-32 encoded strings require 32 bits for each character, and the corresponding functions WSPutUTF32String() and WSGetUTF32String() work with arrays of unsigned int integers.
If you know that your program will not have to handle special characters, then you may find it convenient to use WSPutByteString() and WSGetByteString(). These functions represent all characters directly using 8bit character codes. If a special character is sent from the Wolfram Language, then it will be converted by WSGetByteString() to a fixed code that you specify.
main() may need to be different on different computer systems
A point to watch in creating portable WSTP programs.
Computer systems and compilers that have C runtime libraries based on the Unix model allow WSTP programs to have a main program of the form main(argc,argv) that simply calls WSMain(argc,argv).
Some computer systems or compilers may, however, require main programs of a different form. You should realize that you can do whatever initialization you want inside main() before calling WSMain(). Once you have called WSMain(), however, your program will effectively go into an infinite loop, responding to requests from the Wolfram Language until the link to it is closed.