Design considerations for using the C-API Foundation
Since you will hardly write plain C-code, you need to use the C-runtime functionality. The problem is in this case that some functions need an initialization.
Also, if you write C++ code, you are forced to let the C-runtime initialize several things for you. Initialization can be accomplished in two ways:
The easiest way is linking the C-runtime import library to your EXE. You only need to specify it in your link directive:
alink <options> <OBJ files> msvcrt.lib
This way, the C-runtime DLL will be initialized automatically when the Xbase++ application is started. However, there is a slight disadvantage due to a larger overhead at program startup and, of course, you have to distribute the C-runtime DLL(s) along with your application.
The second possibility also uses DLLs. However, they are created from different "types" of C-code. If you separate the actual C-code from the C-API code, you can build a DLL for the C-sources which access the C-runtime functions. The C-API is then used to program wrapper functions which call the C-functions.
When you use this possibility, you are required to create an import library for the DLL which contains C-functions and link it together with the modules containing Xbase++ code and the C-API functions to the EXE file. In this scenario, your program consists of three layers:
PRG code which calls functions programmed with the C-API (OBJ module).
C-API code which calls functions programmed in C (OBJ module).
C code which uses C-runtime functionality (separated in DLL).
The advantage is that you can use functions like sprintf(), strcpy() and so on in your C-code and can debug it prior to including it into your Xbase++ application.
Due to the different language levels, you must use the appropriate linker and debugger.
If you want to debug the C-API functions at the Xbase++ level, you must use ALINK to link and XPPDBG to debug.
If you want to debug the C-code, you can use the linker and debugger that comes with Visual C++.
The C-compiler mangles all __cdecl functions with a leading underscore. If you link statically, you must use these mangled function names in your Xbase++ code. With some C-compilers you are able to turn off this behaviour. However, you can map function names used in the Xbase++ code to the mangled C-function names. The Xbase++ compiler uses the directive #pragma map for that purpose:
#pragma map(<funcname in PRG>,"<funcname in C>")
This maps an implemented or referenced function name to a new name for the current source file. Note that the second function name must be enclosed in double quotes while the first one is not. Also, be aware that this may also map an Xbase++ function name.
If you create a DLL which isolates the C-functionality, you can change the function names already by mapping them in a DEF-file. Then the import library contains the mapped function names. The file F2BIN.DEF for the example discussed in the previous section would look like this:
LIBRARY F2Bin.Dll
EXPORTS
F2BIN = _F2BIN
BIN2F = _BIN2F
From this DEF file, you create an import library and a binary export definition file with AImplib:
aimplib f2bin.def
At this stage, you should delete all previously declared #pragma mapdirectives from your Xbase++ code.
Finally, your makefile must be modified to reflect the correct build rules:
CC = cl /LD /Tc
LINK = alink /DE
sample.exe: sample.obj f2bin.lib f2bin.dll
$(LINK) sample.obj f2bin.lib
sample.obj: sample.prg
xpp /b /q $*
f2bin.dll: f2bin.c f2bin.exp
$(CC) f2bin.c /link xpprt1.lib f2bin.exp
f2bin.exp f2bin.lib: f2bin.def
aimplib $*.def
This makefile creates a SAMPLE.EXE file, which uses the F2BIN.DLL file.
The following table summarizes all compile and link options which must be used at different stages of a C-API project:
Tool | Option | Meaning | Use when |
---|---|---|---|
alink | /DE | include debug info | debugging Xbase++ code |
xpp | /b | include debug info | debugging Xbase++ code |
cl | /c | compile only | you link with ALINK |
cl | /LD | compile for DLL | separating C-code in a DLL |
cl | /link | specify link option | separating C-code in a DLL |
cl | /Tc | compile as plain C | |
cl | /Zl | no default libs | no C-runtime functions are used |
cl | /Z7 | include debug info | debugging C code |
If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.