In Windows the program's life starts either when its
main
is called, for console applications, or
when its WinMain
is called, for windows
applications in the 'windows' subsystem. On Unix it is always
main
that is called. Furthermore in Winelib it
has some special tasks to accomplish, such as initializing Winelib,
that a normal main
does not have to do.
Furthermore windows applications and libraries contain some
information which are necessary to make APIs such as
GetProcAddress
work. So it is necessary to
duplicate these data structures in the Unix world to make these
same APIs work with Winelib applications and libraries.
The spec file is there to solve the semantic gap described above.
It provides the main
function that initializes
Winelib and calls the module's WinMain
/
DllMain
, and it contains information about
each API exported from a Dll so that the appropriate tables can be
generated.
A typical spec file will look something like this:
name hello type win32 mode guiexe init WinMain rsrc resource.res import winmm.dll |
And here are the entries you will probably want to change:
This is the name of the Win32 module. Usually this is the same as that of the application or library (but without the 'lib' and the '.so').
mode defines whether what you are building is a library, dll, a console application, cuiexe or a regular graphical application guiexe. Then init defines what is the entry point of that module. For a library this is customarily set to DllMain, for a console application this is main and for a graphical application this is WinMain.
Add an 'import' statement for each library that this executable depends on. If you don't, these libraries will not get initialized in which case they may very well not work (e.g. winmm).
This item specifies the name of the compiled resource file to link with your module. If your resource file is called hello.rc then the wrc compilation step (see Compiling resource files: WRC) will generate a file called hello.res. This is the name you must provide here. Note that because of this you cannot compile the spec file before you have compiled the resource file. So you should put a rule like the following in your makefile:
hello.spec.c: hello.res |
If your project does not have a resource file then you must omit this entry altogether.
This entry is not shown above because it is not always
necessary. In fact it is only necessary to export functions
when you plan to dynamically load the library with
LoadLibrary
and then do a
GetProcAddress
on these functions.
This is not necessary if you just plan on linking with the
library and calling the functions normally. For more details
about this see: More details.
Compiling a spec file is a two step process. It is first converted into a C file by winebuild, and then compiled into an object file using your regular C compiler. This is all taken care of by the winemaker generated makefiles of course. But here's what it would like if you had to do it by hand:
WINEBUILD=$(WINE_DIR)/tools/winebuild .SUFFIXES: .spec .spec.c .spec.o .spec.spec.c: $(WINEBUILD) -fPIC -o $@ -spec $< .spec.c.spec.o: $(CC) -c -o $*.spec.o $< |
Nothing really complex there. Just don't forget the .SUFFIXES statement, and beware of the tab if you copy this straight to your Makefile.
(Extracted from tools/winebuild/README)
Here is a more detailed description of the spec file's format.
# comment text |
Anything after a '#' will be ignored as comments.
name NAME type win16|win32 <--- the |'s mean it's one or the other |
These two fields are mandatory. name defines the name of your module and type whether it is a Win16 or Win32 module. Note that for Winelib you should only be using Win32 modules.
file WINFILENAME |
This field is optional. It gives the name of the Windows file that is replaced by the builtin. <name>.DLL is assumed if none is given. This is important for kernel, which lives in the Windows file KRNL386.EXE.
heap SIZE |
This field is optional and specific to Win16 modules. It defines the size of the module local heap. The default is no local heap.
mode dll|cuiexe|guiexe |
This field is optional. It specifies specifies whether it is the spec file for a dll or the main exe. This is only valid for Win32 spec files.
init FUNCTION |
This field is optional and specific to Win32 modules. It specifies a function which will be called when the dll is loaded or the executable started.
import DLL |
This field can be present zero or more times. Each instance names a dll that this module depends on (only for Win32 modules at the present).
rsrc RES_FILE |
This field is optional. If present it specifies the name of the .res file containing the compiled resources. See Compiling resource files: WRC for details on compiling a resource file.
ORDINAL VARTYPE EXPORTNAME (DATA [DATA [DATA [...]]]) 2 byte Variable(-1 0xff 0 0) |
This field can be present zero or more times. Each instance defines data storage at the ordinal specified. You may store items as bytes, 16-bit words, or 32-bit words. ORDINAL is replaced by the ordinal number corresponding to the variable. VARTYPE should be byte, word or long for 8, 16, or 32 bits respectively. EXPORTNAME will be the name available for dynamic linking. DATA can be a decimal number or a hex number preceeded by "0x". The example defines the variable Variable at ordinal 2 and containing 4 bytes.
ORDINAL equate EXPORTNAME DATA |
This field can be present zero or more times. Each instance defines an ordinal as an absolute value. ORDINAL is replaced by the ordinal number corresponding to the variable. EXPORTNAME will be the name available for dynamic linking. DATA can be a decimal number or a hex number preceeded by "0x".
ORDINAL FUNCTYPE EXPORTNAME([ARGTYPE [ARGTYPE [...]]]) HANDLERNAME 100 pascal CreateWindow(ptr ptr long s_word s_word s_word s_word word word word ptr) WIN_CreateWindow 101 pascal GetFocus() WIN_GetFocus() |
This field can be present zero or more times. Each instance defines a function entry point. The prototype defined by EXPORTNAME ([ARGTYPE [ARGTYPE [...]]]) specifies the name available for dynamic linking and the format of the arguments. "ORDINAL" is replaced by the ordinal number corresponding to the function, or @ for automatic ordinal allocation (Win32 only).
FUNCTYPE should be one of:
for a Win16 function returning a 16-bit value
for a Win16 function returning a 32-bit value
for a function using CPU register to pass arguments
for a Win16 interrupt handler routine
for a normal Win32 function
for a Win32 function using the C calling convention
for a Win32 function taking a variable number of arguments
ARGTYPE should be one of:
for a 16 bit word
a 32 bit value
for a linear pointer
for a linear pointer to a null-terminated string
for a 16 bit signed word
for a segmented pointer
for a segmented pointer to a null-terminated string
Only ptr, str and long are valid for Win32 functions. HANDLERNAME is the name of the actual Wine function that will process the request in 32-bit mode.
The two examples define an entry point for the
CreateWindow
and GetFocus
calls respectively. The ordinals used are just examples.
To declare a function using a variable number of arguments in Win16, specify the function as taking no arguments. The arguments are then available with CURRENT_STACK16->args. In Win32, specify the function as varargs and declare it with a '...' parameter in the C file. See the wsprintf* functions in user.spec and user32.spec for an example.
ORDINAL stub EXPORTNAME |
This field can be present zero or more times. Each instance defines a stub function. It makes the ordinal available for dynamic linking, but will terminate execution with an error message if the function is ever called.
ORDINAL extern EXPORTNAME SYMBOLNAME |
This field can be present zero or more times. Each instance defines an entry that simply maps to a Wine symbol (variable or function); EXPORTNAME will point to the symbol SYMBOLNAME that must be defined in C code. This type only works with Win32.
ORDINAL forward EXPORTNAME SYMBOLNAME |
This field can be present zero or more times. Each instance defines an entry that is forwarded to another entry point (kind of a symbolic link). EXPORTNAME will forward to the entry point SYMBOLNAME that must be of the form DLL.Function. This type only works with Win32.