Linking Quintus with foreign code on Microsoft Windows Last update 2001-10-04 Author: Per.Mildner@sics.se Contact Quintus support if you have further questions (qpsupport@sics.se) . You should upgrade to the latest version of quintus 3.4. (available from where you obtained the original 3.4 version). . The documentation on foreign resources is not at all clear. Especially for windows. Some more information is in the release notes, especially for recent versions of Quintus 3.4. . Never use /nodefaultlib. If the linker complains about conflicting libraries then, in all likelihood, there is a problem that must be resolved. (Problems related to this have been fixed in recent versions of Quintus 3.4). If a library conflict is ignored by using /nodefaultlib you may sometimes call another procedure , e.g., from the C run-time library, than what was intended (calling printf when the source code calls malloc will give very mysterious bugs....). Example 1 shows how to call foreign code (the C procedure "test_procedure") from a run-time system. Both the foreign code and the Quintus libraries are DLLs. This is the recommended way to link foreign code with Quintus. Notes: All examples assume that you have the environment set-up appropriately for using Quintus and Microsoft Visual Studio. The easiest way is to run the BAT files supplied, e.g. d:\qpdev\qprm281>"C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT" ... d:\qpdev\qprm281>C:\quintus\bin\ix86\qpvars.bat ... The -v (verbose) flag is optional, it is just to make it simpler to see what is going on. When qld sees the load_foreign_executable('test_foreign') it will try to link with an import library (test_foreign.lib) if it exists. An import library *must* exist, if the import library does not exists qld will (incorrectly) pass the DLL itself to LINK.EXE. As can be seen from the dumpbin output, test.exe depends both on the quintus run-time DLLs (qpeng.dll, libqp.dll) and the foreign code DLL (test_foreign.dll). #### START EXAMPLE 1 D:\qpdev\qprm281>type test_foreign.c type test_foreign.c /* __cdecl is the default but specifying it ensures everything works if you change the default. */ extern __declspec(dllexport) int __cdecl test_procedure(double d1, double *d2); int test_procedure(double d1, double *d2) { *d2 = d1; return 1; } D:\qpdev\qprm281>cl /MD -LD test_foreign.c cl /MD -LD test_foreign.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86 Copyright (C) Microsoft Corp 1984-1998. All rights reserved. test_foreign.c Microsoft (R) Incremental Linker Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. /out:test_foreign.dll /dll /implib:test_foreign.lib test_foreign.obj Creating library test_foreign.lib and object test_foreign.exp D:\qpdev\qprm281>type test.pl type test.pl foreign_file('test_foreign',[test_procedure]). foreign(test_procedure,c,test_predicate(+double,-double,[-integer])). %% making load_foreign_executable a top-level directive ensures that %% qld and qpc does the right thing. Note that you cannot call %% load_foreign_executable from a run-time executable. :- load_foreign_executable('test_foreign'). test(D1):- write('Calling foreign (C) function test_procedure via'), nl, write('(Prolog) glue predicate test_predicate'),nl, test_predicate(D1,D2,Result), write('D1 (input): '),write(D1),nl, write('D2 (output): '),write(D2),nl, write('Result: '),write(Result),nl. runtime_entry(start) :- unix(argv(Argv)), ( Argv = [A1] -> %% Calling load_foreign_executable here would work in a %% development system but not in a run-time system. %% load_foreign_executable('test_foreign'), test(A1) ; otherwise -> format(user_error, 'Wrong number of arguments. One float required~n', []), halt(1) ). D:\qpdev\qprm281>qpc -v -c test.pl qpc -v -c test.pl Quintus Prolog Release 3.4 (iX86, Windows NT, June 27 2000) Originally developed by Quintus Corporation, USA. Copyright (C) 1998, Swedish Institute of Computer Science. All rights reserved. PO Box 1263, SE-164 29 Kista, Sweden. +46 8 633 1500 Email: qpsupport@sics.se WWW: http://www.sics.se/ Licensed to Dr Per Mildner % compiling D:/qpdev/qprm281/test.pl... % dependency on foreign file test_foreign recorded % test.pl compiled into test.qof in module user, 0.000 seconds D:\qpdev\qprm281>dir test_foreign* dir test_foreign* Volume in drive D has no label. Volume Serial Number is 4C59-7274 Directory of D:\qpdev\qprm281 10/04/2001 11:24a 253 test_foreign.c 10/04/2001 11:33a 20,480 test_foreign.dll 10/04/2001 11:33a 587 test_foreign.exp 10/04/2001 11:33a 2,050 test_foreign.lib 10/04/2001 11:33a 564 test_foreign.obj 5 File(s) 23,934 bytes 0 Dir(s) 19,870,325,248 bytes free D:\qpdev\qprm281>dir test.* dir test.* Volume in drive D has no label. Volume Serial Number is 4C59-7274 Directory of D:\qpdev\qprm281 10/04/2001 11:29a 1,089 test.pl 10/04/2001 11:33a 2,048 test.qof 2 File(s) 3,137 bytes 0 Dir(s) 19,870,325,248 bytes free D:\qpdev\qprm281>qld -v -d -o test.exe test.qof qld -v -d -o test.exe test.qof Microsoft (R) Incremental Linker Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. Quintus Link Editor, Release 3.4 Copyright (C) 1998, Swedish Institute of Computer Science. All rights reserved. C:/quintus/lib/ix86/qprte.qof: D:/qpdev/qprm281/test.qof: C:\quintus\bin\ix86\qcon.exe C:/temp/qpa02124.qof -o C:/temp/qpa02124.obj File deleted: C:/temp/qpa02124.qof link -out:test.exe C:/temp/qpa02124.obj C:/quintus/lib/ix86/qpeng.lib C:/quintus/lib/ix86/qprte.lib D:/qpdev/qprm281/test_foreign.lib C:/quintus/lib/ix86/libqp.lib -defaultlib:MSVCRT -subsystem:console File deleted: C:/temp/qpa02124.obj D:\qpdev\qprm281>.\test.exe 42.0 .\test.exe 42.0 Calling foreign (C) function test_procedure via (Prolog) glue predicate test_predicate D1 (input): 42.0 D2 (output): 42.0 Result: 1 D:\qpdev\qprm281>dumpbin /DEPENDENTS test.exe dumpbin /DEPENDENTS test.exe Microsoft (R) COFF Binary File Dumper Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. Dump of file test.exe File Type: EXECUTABLE IMAGE Image has the following dependencies: qpeng.dll test_foreign.dll MSVCRT.dll libqp.dll Summary 30000 .data 2000 .rdata 43000 .text #### END EXAMPLE 1 Example 2 shows how to create a run-time system that statically link to both the Quintus run-time and the foreign code. Notes: test.pl and test_foreign.c are as in Example 1. For compiling C-code that will be used for static linking with the static version of the Quintus libraries you should use the /MT flag (static multi threaded C run-time library). Failure to do so will lead to subtle errors and the linker warning LNK4098. Quintus uses the convention that a suffix of 's' indicate a library for static linking. This is to distinguish static libraries from import libraries since both have the file type ".lib". In the example this convention is followed for the object file (test_foreigns.obj) as well, this is not necessary. As in Example 1, the -v flag is optional. The linker warning LNK4049 can be ignored. As can be seen from the dumpbin output, test_static.exe only depends on Windows system DLLs. It does not depend on any Quintus files nor on any foreign function file. #### START EXAMPLE 2 D:\qpdev\qprm281>qpc -c test.pl qpc -c test.pl % D:/qpdev/qprm281/test.pl: test.qof D:\qpdev\qprm281>cl /MT -c test_foreign.c -Fotest_foreigns.obj cl /MT -c test_foreign.c -Fotest_foreigns.obj Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86 Copyright (C) Microsoft Corp 1984-1998. All rights reserved. test_foreign.c D:\qpdev\qprm281>lib -out:test_foreigns.lib test_foreigns.obj lib -out:test_foreigns.lib test_foreigns.obj Microsoft (R) Library Manager Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. D:\qpdev\qprm281>dir test_foreigns.* dir test_foreigns.* Volume in drive D has no label. Volume Serial Number is 4C59-7274 Directory of D:\qpdev\qprm281 10/04/2001 11:58a 886 test_foreigns.lib 10/04/2001 11:58a 565 test_foreigns.obj 2 File(s) 1,451 bytes 0 Dir(s) 19,870,384,640 bytes free D:\qpdev\qprm281>qld -v -S -d -o test_static.exe test.qof -LD qpconsoles.lib user32.lib comdlg32.lib gdi32.lib qld -v -S -d -o test_static.exe test.qof -LD qpconsoles.lib user32.lib comdlg32.lib gdi32.lib Microsoft (R) Incremental Linker Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. Creating library test_static.lib and object test_static.exp LINK : warning LNK4049: locally defined symbol "_Q9PSEUDO_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9ForeignSyms_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9Dbrefs_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9FileAtoms_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9MFile_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9HITEXT_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9LOTEXT_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9HIDATA_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9LODATA_ptr" imported LINK : warning LNK4049: locally defined symbol "_QP_pc_handler" imported LINK : warning LNK4049: locally defined symbol "_QP_handler_sig" imported LINK : warning LNK4049: locally defined symbol "_QP_interrupt_handled_event" imported LINK : warning LNK4049: locally defined symbol "_QP_pc_set_handler" imported LINK : warning LNK4049: locally defined symbol "_QP_interrupt_pending_event" imported Quintus Link Editor, Release 3.4 Copyright (C) 1998, Swedish Institute of Computer Science. All rights reserved. C:/quintus/lib/ix86/qprte.qof: D:/qpdev/qprm281/test.qof: C:\quintus\bin\ix86\qcon.exe C:/temp/qpa02472.qof -o C:/temp/qpa02472.obj File deleted: C:/temp/qpa02472.qof link -out:test_static.exe C:/temp/qpa02472.obj C:/quintus/lib/ix86/qpengs.lib C:/quintus/lib/ix86/qprtes.lib D:/qpdev/qprm281/test_foreigns.lib C:/quintus/lib/ix86/libqps.lib -defaultlib:LIBCMT -subsystem:console qpconsoles.lib user32.lib comdlg32.lib gdi32.lib File deleted: C:/temp/qpa02472.obj D:\qpdev\qprm281>.\test_static 43.0 .\test_static 43.0 Calling foreign (C) function test_procedure via (Prolog) glue predicate test_predicate D1 (input): 43.0 D2 (output): 43.0 Result: 1 D:\qpdev\qprm281>dumpbin /DEPENDENTS test_static.exe dumpbin /DEPENDENTS test_static.exe Microsoft (R) COFF Binary File Dumper Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. Dump of file test_static.exe File Type: EXECUTABLE IMAGE Image has the following dependencies: USER32.dll comdlg32.dll GDI32.dll KERNEL32.dll Summary 3F000 .data 3000 .rdata A0000 .text D:\qpdev\qprm281> #### END EXAMPLE 2 The third example shows how to link statically with foreign code, while still using the DLL version of the Quintus libraries Notes: test.pl and test_foreign.c are as in Example 1. For compiling C-code that will be used for dynamic linked Quintus run-time you should use the /MD flag (dynamic multi threaded C run-time library). Failure to do so will lead to subtle errors and the linker warning LNK4098. As in Example 1, the -v flag is optional. As can be seen from the dumpbin output, test_foreign_static.exe only depends on the Quintus DLLs while the foreign code is statically linked. #### START EXAMPLE 3 D:\qpdev\qprm281>qpc -c test.pl qpc -c test.pl % D:/qpdev/qprm281/test.pl: test.qof D:\qpdev\qprm281>cl /MD -c test_foreign.c cl /MD -c test_foreign.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86 Copyright (C) Microsoft Corp 1984-1998. All rights reserved. test_foreign.c D:\qpdev\qprm281>dir test_foreign.* dir test_foreign.* Volume in drive D has no label. Volume Serial Number is 4C59-7274 Directory of D:\qpdev\qprm281 10/04/2001 11:24a 253 test_foreign.c 10/04/2001 12:48p 564 test_foreign.obj 2 File(s) 817 bytes 0 Dir(s) 19,870,315,520 bytes free D:\qpdev\qprm281>lib -out:test_foreign.lib test_foreign.obj lib -out:test_foreign.lib test_foreign.obj Microsoft (R) Library Manager Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. D:\qpdev\qprm281>dir test_foreign.* dir test_foreign.* Volume in drive D has no label. Volume Serial Number is 4C59-7274 Directory of D:\qpdev\qprm281 10/04/2001 11:24a 253 test_foreign.c 10/04/2001 12:49p 884 test_foreign.lib 10/04/2001 12:48p 564 test_foreign.obj 3 File(s) 1,701 bytes 0 Dir(s) 19,870,314,496 bytes free D:\qpdev\qprm281>qld -v -d -o test_foreign_static.exe test.qof qld -v -d -o test_foreign_static.exe test.qof Microsoft (R) Incremental Linker Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. Creating library test_foreign_static.lib and object test_foreign_static.exp Quintus Link Editor, Release 3.4 Copyright (C) 1998, Swedish Institute of Computer Science. All rights reserved. C:/quintus/lib/ix86/qprte.qof: D:/qpdev/qprm281/test.qof: C:\quintus\bin\ix86\qcon.exe C:/temp/qpa02528.qof -o C:/temp/qpa02528.obj File deleted: C:/temp/qpa02528.qof link -out:test_foreign_static.exe C:/temp/qpa02528.obj C:/quintus/lib/ix86/qpeng.lib C:/quintus/lib/ix86/qprte.lib D:/qpdev/qprm281/test_foreign.lib C:/quintus/lib/ix86/libqp.lib -defaultlib:MSVCRT -subsystem:console File deleted: C:/temp/qpa02528.obj D:\qpdev\qprm281>.\test_foreign_static.exe 44.0 .\test_foreign_static.exe 44.0 Calling foreign (C) function test_procedure via (Prolog) glue predicate test_predicate D1 (input): 44.0 D2 (output): 44.0 Result: 1 D:\qpdev\qprm281>dumpbin /DEPENDENTS test_foreign_static.exe dumpbin /DEPENDENTS test_foreign_static.exe Microsoft (R) COFF Binary File Dumper Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. Dump of file test_foreign_static.exe File Type: EXECUTABLE IMAGE Image has the following dependencies: qpeng.dll MSVCRT.dll libqp.dll Summary 30000 .data 2000 .rdata 44000 .text D:\qpdev\qprm281> #### END EXAMPLE 3 The fourth example shows how to link statically with the Quintus run-time while linking dynamically with the foreign code. Notes: This is not recommended. The static version of the Quintus run-time is statically linked with the C run-time library (using cl /MT), however, there is no way that dynamically loaded foreign code can be made to use the same instance of the C run-time library. Either the foreign code can be compiled with /MT, leading to multiple copies of the static C run-time library, or the foreign code can be compiled with /MD, making all such dynamic code share C run-time library while the Quintus run-time will still use its own copy of the static C run-time library. In the future probably both static and dynamic versions of the Quintus run-time system will use the DLL version of the C run-time (using /MD). The example below use /MT for compiling the test_foreign.dll but it could have used /MD instead. test.pl and test_foreign.c are as in Example 1. As in Example 1, the -v flag is optional. The linker warning LNK4049 can be ignored. As can be seen from the dumpbin output, test_static_foreign_dynamic.exe only depends on the foreign code DLL test_foreign.dll (and the Windows system DLLs). It does not depend on any Quintus files. #### BEGIN EXAMPLE 4 D:\qpdev\qprm281>qpc -c test.pl qpc -c test.pl % D:/qpdev/qprm281/test.pl: test.qof D:\qpdev\qprm281>cl -LD /MT test_foreign.c -link -IMPLIB:test_foreigns.lib cl -LD /MT test_foreign.c -link -IMPLIB:test_foreigns.lib Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86 Copyright (C) Microsoft Corp 1984-1998. All rights reserved. test_foreign.c Microsoft (R) Incremental Linker Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. /out:test_foreign.dll /dll /implib:test_foreign.lib -IMPLIB:test_foreigns.lib test_foreign.obj Creating library test_foreigns.lib and object test_foreigns.exp D:\qpdev\qprm281>dir test_foreign.* test_foreigns.* dir test_foreign.* test_foreigns.* Volume in drive D has no label. Volume Serial Number is 4C59-7274 Directory of D:\qpdev\qprm281 10/04/2001 11:24a 253 test_foreign.c 10/04/2001 01:20p 49,152 test_foreign.dll 10/04/2001 01:20p 587 test_foreign.exp 10/04/2001 01:20p 2,050 test_foreign.lib 10/04/2001 01:20p 564 test_foreign.obj Directory of D:\qpdev\qprm281 10/04/2001 01:20p 588 test_foreigns.exp 10/04/2001 01:20p 2,050 test_foreigns.lib 7 File(s) 55,244 bytes 0 Dir(s) 19,870,254,592 bytes free D:\qpdev\qprm281>qld -v -S -d -o test_static_foreign_dynamic.exe test.qof -LD qpconsoles.lib user32.lib comdlg32.lib gdi32.lib qld -v -S -d -o test_static_foreign_dynamic.exe test.qof -LD qpconsoles.lib user32.lib comdlg32.lib gdi32.lib Microsoft (R) Incremental Linker Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. Creating library test_static_foreign_dynamic.lib and object test_static_foreign_dynamic.exp LINK : warning LNK4049: locally defined symbol "_Q9PSEUDO_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9ForeignSyms_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9Dbrefs_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9FileAtoms_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9MFile_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9HITEXT_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9LOTEXT_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9HIDATA_ptr" imported LINK : warning LNK4049: locally defined symbol "_Q9LODATA_ptr" imported LINK : warning LNK4049: locally defined symbol "_QP_pc_handler" imported LINK : warning LNK4049: locally defined symbol "_QP_handler_sig" imported LINK : warning LNK4049: locally defined symbol "_QP_interrupt_handled_event" imported LINK : warning LNK4049: locally defined symbol "_QP_pc_set_handler" imported LINK : warning LNK4049: locally defined symbol "_QP_interrupt_pending_event" imported Quintus Link Editor, Release 3.4 Copyright (C) 1998, Swedish Institute of Computer Science. All rights reserved. C:/quintus/lib/ix86/qprte.qof: D:/qpdev/qprm281/test.qof: C:\quintus\bin\ix86\qcon.exe C:/temp/qpa01916.qof -o C:/temp/qpa01916.obj File deleted: C:/temp/qpa01916.qof link -out:test_static_foreign_dynamic.exe C:/temp/qpa01916.obj C:/quintus/lib/ix86/qpengs.lib C:/quintus/lib/ix86/qprtes.lib D:/qpdev/qprm281/test_foreigns.lib C:/quintus/lib/ix86/libqps.lib -defaultlib:LIBCMT -subsystem:console qpconsoles.lib user32.lib comdlg32.lib gdi32.lib File deleted: C:/temp/qpa01916.obj D:\qpdev\qprm281>.\test_static_foreign_dynamic.exe 45.0 .\test_static_foreign_dynamic.exe 45.0 Calling foreign (C) function test_procedure via (Prolog) glue predicate test_predicate D1 (input): 45.0 D2 (output): 45.0 Result: 1 D:\qpdev\qprm281>dumpbin /DEPENDENTS test_static_foreign_dynamic.exe dumpbin /DEPENDENTS test_static_foreign_dynamic.exe Microsoft (R) COFF Binary File Dumper Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. Dump of file test_static_foreign_dynamic.exe File Type: EXECUTABLE IMAGE Image has the following dependencies: test_foreign.dll USER32.dll comdlg32.dll GDI32.dll KERNEL32.dll Summary 3F000 .data 3000 .rdata A0000 .text D:\qpdev\qprm281> #### END EXAMPLE 4 If the foreign code need to use the Quintus API, e.g., to call prolog code then the recommended way is that both foreign code and quintus run-time libraries should use dynamic linking (as in Example 1). Alternatively, both the foreign code and the Quintus libraries should be statically linked (as in Example 2). If you intend to use Microsoft Foundation Classes (MFC) you should probably read TN011 "Using MFC as Part of a DLL" available at