An example showing how to build a dynamic foreign resource, with and without using the command 'splfr'. 'cplus' is a simple test program for using C++ with the FLI. Last updated for SICStus 4.0.1 and Visual Studio 2005 SP1 sicstus-support@sics.se NOTE: The details below are subject to change without notice. Use splfr --verbose --keep each time you upgrade to new version of SICStus to see if anything has changed. Options --verbose will show details on what is going on and --keep ensures that generated C files are not deleted. This example assumes that you are familiar with using the Microsoft C compiler (cl.exe) from the command line and from within Visual Studio. Start by opening a command window (run cmd.exe from the Start menu), then run the Visual Studio setup script to ensure that the C compiler can be found: ##### TRANSCRIPT BEGIN Microsoft Windows [Version 6.0.6000] Copyright (c) 2006 Microsoft Corporation. All rights reserved. c:\cplusplus>"%PROGRAMFILES%/Microsoft Visual Studio 8/VC/bin/vcvars32.bat" "%PROGRAMFILES%/Microsoft Visual Studio 8/VC/bin/vcvars32.bat" c:\cplusplus>"C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat" Setting environment for using Microsoft Visual Studio 2005 x86 tools. c:\cplusplus> ##### TRANSCRIPT END (By using environment variables, like %PROGRAMFILES%, we ensure that these examples will work on most Windows variants. The transcripts are from Windows Vista x64, the paths may differ on other Windows variants.) Then, add the SICStus bin\ folder to the PATH so that all SICStus tools can be found and so that the SICStus runtime libraries can be found. ##### TRANSCRIPT BEGIN c:\cplusplus>SET PATH=%PATH%;%PROGRAMFILES%\SICStus Prolog 4.0.1\bin SET PATH=%PATH%;%PROGRAMFILES%\SICStus Prolog 4.0.1\bin c:\cplusplus> ##### TRANSCRIPT END Now you should be able to run sicstus like so: ### TRANSCRIPT START c:\cplusplus>sicstus -i -f sicstus -i -f SICStus 4.0.1 (x86-win32-nt-4): Tue May 15 21:17:49 WEST 2007 Licensed to SICS | ?- halt. ### TRANSCRIPT END (The example above represents the default installation folder for SICStus 4.0.1.) --------------------------------------------------------------------- Building the resource using 'splfr'. (A) Create the foreign resource: ==================== splfr cplus.pl cplus.cpp This creates cplus.dll and cplus_glue.h. The latter contains C declarations corresponding to the foreign/2 declarations in cplus.pl. All foreign resource code should include the header file generated by splfr. Note that cplus_glue.h will be deleted, along with all other temporary files, when splfr finishes, unless you also specify the --keep flag. Alternatively you could compile the C++ file separately and pass cplus.obj instead of cplus.cpp to splfr. However, when compiling your C or C++ code you must pass the same options to the compiler as those passed by splfr. The options used by splfr are subject to change without notice and are (intentionally) not documented. To figure out what options are used you should do as (A) above, that is, let splfr compile the code and pass the flags --verbose and --keep to splfr. This will show all steps performed by splfr, including the options passed to the compiler when compiling your C or C++ code. By passing --keep it will also keep all generated C code, such as the cplus_glue.h. You will have to repeat this step for each new version of SICStus. In 4.0.1 the output from (A), with --verbose and --keep added, looks something like: #### (B) TRANSCRIPT BEGIN c:\cplusplus>splfr --verbose --keep cplus.pl cplus.cpp splfr --verbose --keep cplus.pl cplus.cpp splfr (SICStus Prolog 4.0.1) SICStus Prolog Release 4.0.1 Copyright (c) 1998-2007 Swedish Institute of Computer Science Report bugs at: http://www.sics.se/sicstus/bugreport/bugreport.html % Handling non-option arg cplus.pl ... as Prolog source file % Handling non-option arg cplus.cpp ... as C/C++ source file % Reading configuration file "C:/PROGRA~2/SICSTU~1.1/bin/spconfig-4.0.1" C:\PROGRA~2\SICSTU~1.1\bin\sicstus -f --goal "prolog:splfr_prepare_foreign_resource('cplus','cplus.pl','cplus_glue.c','cplus_glue.h', [])." SICStus 4.0.1 (x86-win32-nt-4): Tue May 15 21:17:49 WEST 2007 Licensed to SICS % c:/cplusplus/cplus_glue.h generated, 0 msec % c:/cplusplus/cplus_glue.c generated, 0 msec % Compiling cplus.cpp... cl.exe -I"C:\PROGRA~2\SICSTU~1.1/include" -I. /MD /Z7 /GF /Ox -DSPDLL /MD -DSP_RESNAME=cplus -c cplus.cpp -Focplus.obj Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. cplus.cpp % Compiling cplus_glue.c... cl.exe -I"C:\PROGRA~2\SICSTU~1.1/include" -I. /MD /Z7 /GF /Ox -DSPDLL /MD -DSP_RESNAME=cplus -c cplus_glue.c -Focplus_glue.obj Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. cplus_glue.c % Building foreign resource "cplus"... link.exe -nologo -dll /INCREMENTAL:NO /SAFESEH /NXCOMPAT kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib -debug cplus.obj cplus_glue.obj -OUT:cplus.dll kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib -IMPLIB:dummy.lib Creating library dummy.lib and object dummy.exp mt.exe /manifest cplus.dll.manifest /outputresource:cplus.dll;#2 Microsoft (R) Manifest Tool version 5.2.3790.2075 Copyright (c) Microsoft Corporation 2005. All rights reserved. % Keeping temporary files... cplus_glue.c (symbolic name is cplus_glue.c) cplus_glue.h (symbolic name is cplus_glue.h) #### TRANSCRIPT END (The link line has all .lib files duplicated, this is redundant but harmless.) The information we are looking for is the line after "% Compiling cplus.cpp...", that is: cl.exe -I"C:\PROGRA~2\SICSTU~1.1/include" -I. /MD /Z7 /GF /Ox -DSPDLL /MD -DSP_RESNAME=cplus -c cplus.cpp -Focplus.obj The -I options are there so that the sicstus.h include file can be found, if you are compiling from within Microsoft Visual C++ you should add the sicstus include directory to the list of include file directories. The -D are the important ones here, apparently -DSPDLL and -DSP_RESNAME=cplus should be used. The other options tells cl about optimizations, debug information etc, except for /MD, these are not very important. We use the term "apparently" here to stress that this information *must* be re-confirmed with whatever versions of SICStus you are using. (C) So, to compile a C or C++ file for a resource named cplus you should do something like (substituting %PROGRAMFILES% to make this work on most installations): cl.exe -I"%PROGRAMFILES%\SICSTUS Prolog 4.0.1\include" /MD /Ox -DSPDLL -DSP_RESNAME=cplus -c cplus.cpp -Focplus.obj Each time you change the foreign/2 declarations in cplus.pl you need to re-create cplus_glue.h and re-compile cplus.cpp. To recreate cplus_glue.h without creating a foreign resource you can do: #### (D) TRANSCRIPT BEGIN c:\cplusplus>splfr --nocompile --keep cplus.pl splfr --nocompile --keep cplus.pl % Keeping temporary files... cplus_glue.c (symbolic name is cplus_glue.c) cplus_glue.h (symbolic name is cplus_glue.h) #### TRANSCRIPT END Note that you only need to pass the prolog file to splfr. The --keep flag ensures that all generated files remains and get sensible names. (E) Finally, to create the foreign resource you would do: c:\cplusplus>splfr --header=dummy.h cplus.pl cplus.obj The --header=dummy.h is so that the cplus_glue.h file generated in steps (B) or (D) above, will not be overwritten. (F) Compile the prolog code ==================== c:\cplusplus>sicstus --goal "compile(cplus),save_files(['cplus.pl'],cplus),halt." This tells sicstus to compile cplus.pl and save the result in cplus.po and finally halt. Alternatively you can perform these step interactively: #### (G) TRANSCRIPT BEGIN c:\cplusplus>sicstus -i -f sicstus -i -f SICStus 4.0.1 (x86-win32-nt-4): Tue May 15 21:17:49 WEST 2007 Licensed to SICS | ?- compile(cplus). % compiling c:/cplusplus/cplus.pl... % loading foreign resource c:/cplusplus/cplus.dll in module user % compiled c:/cplusplus/cplus.pl in module user, 16 msec 5556 bytes yes | ?- save_files(['cplus.pl'],cplus). % c:/cplusplus/cplus.po created in 0 msec yes | ?- halt. #### TRANSCRIPT END You could also do this from within spwin.exe. The -i is only needed if you start sicstus.exe from a *shell* buffer within emacs where sicstus cannot figure out that it should run interactively. The -f is so that no .sicstusrc file is read. Note that the foreign resource cplus.dll must exist when cplus.pl is compiled. --------------------------------------------------------------------- Same example but not using 'splfr': Create the glue code and the glue header file: ========================= c:\cplusplus>splfr --nocompile --keep cplus.pl See (D) above. This creates cplus_glue.h and cplus_glue.c. Compile the C++ file cplus.cpp: ===================== cl.exe -I"%PROGRAMFILES%\SICSTUS Prolog 4.0.1\include" /MD /Ox -DSPDLL -DSP_RESNAME=cplus -c cplus.cpp -Focplus.obj See (B) and (C) above. Compile the C glue file cplus_glue.c: ===================== See (B) and (C) for how to figure out the command to use. In SICStus 4.0.1 it would be something like: cl.exe -I"%PROGRAMFILES%\SICStus Prolog 4.0.1\include" -I. /MD /Ox -DSPDLL -DSP_RESNAME=cplus -c cplus_glue.c -Focplus_glue.obj Link the object files to create a foreign resource: ==================================== See (B) and (C) for how to figure out the command to use. In SICStus 4.0.1 it would be something like: link.exe -nologo -dll /SAFESEH /NXCOMPAT kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib -debug cplus.obj cplus_glue.obj -OUT:cplus.dll (The /SAFESEH and /NXCOMPAT are optional, security-related flags). Alternatively you could use cl.exe for linking, something like: cl -nologo /MD /LD /Zi kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib cplus.obj cplus_glue.obj -Fecplus.dll /link /SAFESEH /NXCOMPAT We need to embed the manifest created by the Visual Studio linker ============================ mt.exe /manifest cplus.dll.manifest /outputresource:cplus.dll;#2 This step embeds information about what version of the C runtime library that is used by cplus.dll. We don't need any import lib: ============================ del cplus.lib cplus.exp These files are harmless but will not be used. --------------------------------------------------------------------- Testing: ======== #### TRANSCRIPT BEGIN c:\cplusplus>sicstus -i -f sicstus -i -f SICStus 4.0.1 (x86-win32-nt-4): Tue May 15 21:17:49 WEST 2007 Licensed to SICS | ?- [cplus]. % loading c:/cplusplus/cplus.po... % loading foreign resource c:/cplusplus/cplus.dll in module user % loaded c:/cplusplus/cplus.po in module user, 0 msec 5672 bytes yes | ?- main. Testing creating and accessing a dynamic C++ object Testing setting a C "long" value as a long and reading it as long and as a term Calling Obj.set_i(4711) Calling Obj.get_i()... got back the (C long) 4711....OK Calling Obj.get_t()... got back the (term) 4711....OK Testing setting a C "long" value as a term and reading it as long and as a term Calling Obj.set_t(-59837) Calling Obj.get_t()... got back the (term) -59837....OK Calling Obj.get_i()... got back the (C long) -59837....OK Testing accessing a static C++ object Testing setting a C "long" value as a long and reading it as long and as a term Calling Obj.set_i(4711) Calling Obj.get_i()... got back the (C long) 4711....OK Calling Obj.get_t()... got back the (term) 4711....OK Testing setting a C "long" value as a term and reading it as long and as a term Calling Obj.set_t(-59837) Calling Obj.get_t()... got back the (term) -59837....OK Calling Obj.get_i()... got back the (C long) -59837....OK yes | ?- halt. &stat_obj == 0x1e51b8 c:\cplusplus> #### TRANSCRIPT END The next step is to use this foreign resource from a SICStus runtime system, see README_RUNTIME.txt.