The Winelib development toolkitWinemakerSupport for Visual C++ projects
Unfortunately Winemaker does not support the Visual C++ project
files, ...yet. Supporting Visual C++ project files (the
.dsp and some .mak files
for older versions of Visual C++) is definitely on
the list of important Winemaker improvements as it will allow it to
properly detect the defines to be used, any custom include path, the
list of libraries to link with, and exactly which source files to use
to build a specific target. All things that the current version of
Winemaker has to guess or that you have to tell it as will become
clear in the next section.
When the time comes Winemaker, and its associated build system, will
need some extensions to support:
per file defines and include paths. Visual C++ projects allow
the user to specify compiler options for each individual file
being compiled. But this is probably not very frequent so it
might not be that important.
multiple configurations. Visual C++ projects usually have at
least a 'Debug' and a 'Release' configuration which are compiled
with different compiler options. How exactly we deal with these
configurations remains to be determined.
Winemaker's source analysis
Winemaker can do its work even without a Windows makefile or a
Visual Studio project to start from (it would not know what to do
with a windows makefile anyway). This involves doing many educated
guesses which may be wrong. But by and large it works. The purpose
of this section is to describe in more details how winemaker
proceeds so that you can better understand why it gets things
wrong and how to fix it/avoid it.
At the core winemaker does a recursive traversal of
your source tree looking for targets (things to build) and source
files. Let's start with the targets.
First are executables and dlls. Each time it finds one of these in
a directory, winemaker puts it in the list of things to build and
will later generate a Makefile.in file in this
directory. Note that Winemaker also knows about the commonly used
Release and Debug
directories, so it will attribute the executables and libraries
found in these to their parent directory. When it finds an
executable or a dll winemaker is happy because these give it more
information than the other cases described below.
If it does not find any executable or dll winemaker will look for
files with a .mak extension. If they are not
disguised Visual C++ projects (and currently even if they are),
winemaker will assume that a target by that name should be built
in this directory. But it will not know whether this target is an
executable or a library. So it will assume it is of the default
type, i.e. a graphical application, which you can override by using
the and options.
Finally winemaker will check to see if there is a file called
makefile. If there is, then it will assume
that there is exactly one target to build for this directory. But
it will not know the name or type of this target. For the type it
will do as in the above case. And for the name it will use the
directory's name. Actually, if the directory starts with
src winemaker will try to make use of the name
of the parent directory instead.
Once the target list for a directory has been established,
winemaker will check whether it contains a mix of executables and
libraries. If it is so, then winemaker will make it so that each
executable is linked with all the libraries of that directory.
If the previous two steps don't produce the expected results (or
you think they will not) then you should put winemaker in
interactive mode (see ). This will allow you to specify the
target list (and more) for each directory.
In each directory winemaker also looks for source files: C, C++
or resource files. If it also found targets to build in this
directory it will then try to assign each source file to one of
these targets based on their names. Source files that do not seem
to match any specific target are put in a global list for this
directory, see the EXTRA_xxx variables in the
Makefile.in, and linked with each of the
targets. The assumption here is that these source files contain
common code which is shared by all the targets.
If no targets were found in the directory where these files are
located, then they are assigned to the parent's directory. So if a
target is found in the parent directory it will also 'inherit' the
source files found in its subdirectories.
Finally winemaker also looks for more exotic files like
.h headers, .inl files
containing inline functions and a few others. These are not put in
the regular source file lists since they are not compiled directly.
But winemaker will still remember them so that they are processed
when the time comes to fix the source files.
Fixing the source files is done as soon as winemaker has finished
its recursive directory traversal. The two main tasks in this step
are fixing the CRLF issues and verifying the case of the include
statements.
Winemaker makes a backup of each source file (in such a way that
symbolic links are preserved), then reads it fixing the CRLF
issues and the other issues as it goes. Once it has finished
working on a file it checks whether it has done any non
CRLF-related modification and deletes the backup file if it did
not (or if you used ).
Checking the case of the include statements (of any form,
including files referenced by resource files), is done in the
context of that source file's project. This way winemaker can use
the proper include path when looking for the file that is included.
If winemaker fails to find a file in any of the directories of the
include path, it will rename it to lowercase on the basis that it
is most likely a system header and that all system headers names
are lowercase (this can be overriden by using
).
Finally winemaker generates the Makefile.in
files and other support files (wrapper files, spec files,
configure.in,
Make.rules.in). From the above description
you can guess at the items that winemaker may get wrong in
this phase: macro definitions, include path, library path,
list of libraries to import. You can deal with these issues by
using winemaker's , ,
and options if they are
homogeneous enough between all your targets. Otherwise you may
want to use winemaker's interactive
mode so that you can specify different settings for each
project / target.
For instance, one of the problems you are likely to encounter is
that of the STRICT macro. Some programs will
not compile if STRICT is not turned on, and
others will not compile if it is. Fortunately all the files in a
given source tree use the same setting so that all you have to do
is add -DSTRICT on winemaker's command line
or in the Makefile.in file(s).
Finally the most likely reasons for missing or duplicate symbols
are:
The target is not being linked with the right set of libraries.
You can avoid this by using winemaker's and
options or adding these libraries to the
Makefile.in file.
Maybe you have multiple targets in a single directory and
winemaker guessed wrong when trying to match the source files
with the targets. The only way to fix this kind of problem is
to edit the Makefile.in file manually.
Winemaker assumes you have organized your source files
hierarchically. If a target uses source files that are in a
sibling directory, e.g. if you link with
../hello/world.o then you will get missing
symbols. Again the only solution is to manually edit the
Makefile.in file.
The interactive mode
what is it,
when to use it,
how to use it
The Makefile.in files
The Makefile.in is your makefile. More
precisely it is the template from which the actual makefile will
be generated by the configure script. It also
relies on the Make.rules file for most of
the actual logic. This way it only contains a relatively simple
description of what needs to be built, not the complex logic of
how things are actually built.
So this is the file to modify if you want to customize things.
Here's a detailed description of its content:
### Generic autoconf variables
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = .
SRCDIR = @srcdir@
VPATH = @srcdir@
The above is part of the standard autoconf boiler-plate. These
variables make it possible to have per-architecture directories for
compiled files and other similar goodies (But note that this kind
of functionality has not been tested with winemaker generated
Makefile.in files yet).
SUBDIRS =
DLLS =
EXES = hello
This is where the targets for this directory are listed. The names
are pretty self-explanatory. SUBDIRS is usually
only present in the top-level makefile. For libraries you should
put the full Unix name, e.g. libfoo.so.
### Global settings
DEFINES = -DSTRICT
INCLUDE_PATH =
LIBRARY_PATH =
LIBRARIES =
This section contains the global compilation settings: they apply
to all the targets in this makefile. The LIBRARIES
variable allows you to specify additional Unix libraries to link with.
Note that you would normally not specify Winelib libraries there. To
link with a Winelib library, one uses the 'import' statement of the
spec files. The exception is when you
have not explicitly exported the functions of a Winelib library. One
library you are likely to find here is mfc (note,
the '-l' is omitted).
The other variable
names should be self-explanatory. You can also use three additional
variables that are usually not present in the file:
CEXTRA, CXXEXTRA and
WRCEXTRA which allow you to specify additional
flags for, respectively, the C compiler, the C++ compiler and the
resource compiler. Finally note that all these variable contain
the option's name except IMPORTS. So you should
put -DSTRICT in DEFINES but
winmm in IMPORTS.
Then come one section per target, each describing the various
components that target is made of.
### hello sources and settings
hello_C_SRCS = hello.c
hello_CXX_SRCS =
hello_RC_SRCS =
hello_SPEC_SRCS = hello.spec
Each section will start with a comment indicating the name of the
target. Then come a series of variables prefixed with the name of
that target. Note that the name of the prefix may be slightly
different from that of the target because of restrictions on the
variable names.
The above variables list the sources that are used togenerate the
target. Note that there should only be one resource file in
RC_SRCS, and that SPEC_SRCS
will always contain a single spec file.
hello_LIBRARY_PATH =
hello_LIBRARIES =
hello_DEPENDS =
The above variables specify how to link the target. Note that they
add to the global settings we saw at the beginning of this file.
DEPENDS, when present, specifies a list of other
targets that this target depends on. Winemaker will automatically
fill this field, and the LIBRARIES field, when an
executable and a library are built in the same directory.
The reason why winemaker also links with libraries in the Unix sense
in the case above is because functions will not be properly exported.
Once you have exported all the functions in the library's spec file
you should remove them from the LIBRARIES field.
hello_OBJS = $(hello_C_SRCS:.c=.o) \
$(hello_CXX_SRCS:.cpp=.o) \
$(EXTRA_OBJS)
The above just builds a list of all the object files that
correspond to this target. This list is later used for the link
command.
### Global source lists
C_SRCS = $(hello_C_SRCS)
CXX_SRCS = $(hello_CXX_SRCS)
RC_SRCS = $(hello_RC_SRCS)
SPEC_SRCS = $(hello_SPEC_SRCS)
This section builds 'summary' lists of source files. These lists are
used by the Make.rules file.
### Generic autoconf targets
all: $(DLLS) $(EXES:%=%.so)
@MAKE_RULES@
install::
for i in $(EXES); do $(INSTALL_PROGRAM) $$i $(bindir); done
for i in $(EXES:%=%.so) $(DLLS); do $(INSTALL_LIBRARY) $$i $(libdir); done
uninstall::
for i in $(EXES); do $(RM) $(bindir)/$$i;done
for i in $(EXES:%=%.so) $(DLLS); do $(RM) $(libdir)/$$i;done
The above first defines the default target for this makefile. Here
it consists in trying to build all the targets. Then it includes
the Make.rules file which contains the build
logic, and provides a few more standard targets to install /
uninstall the targets.
### Target specific build rules
$(hello_SPEC_SRCS:.spec=.tmp.o): $(hello_OBJS)
$(LDCOMBINE) $(hello_OBJS) -o $@
-$(STRIP) $(STRIPFLAGS) $@
$(hello_SPEC_SRCS:.spec=.spec.c): $(hello_SPEC_SRCS:.spec) $(hello_SPEC_SRCS:.spec=.tmp.o) $(hello_RC_SRCS:.rc=.res)
$(WINEBUILD) -fPIC $(hello_LIBRARY_PATH) $(WINE_LIBRARY_PATH) -sym $(hello_SPEC_SRCS:.spec=.tmp.o) -o $@ -spec $(hello_SPEC_SRCS)
hello.so: $(hello_SPEC_SRCS:.spec=.spec.o) $(hello_OBJS) $(hello_DEP
ENDS)
$(LDSHARED) $(LDDLLFLAGS) -o $@ $(hello_OBJS) $(hello_SPEC_SRCS:.spec=.spec.o) $(hello_LIBRARY_PATH) $(hello_LIBRARIES:%=-l%) $(DLL_LINK) $(LIBS)
test -f hello || $(LN_S) $(WINE) hello
Then come additional directives to link the executables and
libraries. These are pretty much standard and you should not need
to modify them.
The Make.rules.in file
What's in the Make.rules.in...
The configure.in file
What's in the configure.in...
Compiling resource files: WRC
To compile resources you should use the Wine Resource Compiler,
wrc for short, which produces a binary .res
file. This resource file is then used by winebuild when compiling
the spec file (see ).
Again the makefiles generated by winemaker take care of this for you.
But if you were to write your own makefile you would put something
like the following:
WRC=$(WINE_DIR)/tools/wrc/wrc
WINELIB_FLAGS = -I$(WINE_DIR)/include -DWINELIB -D_REENTRANT
WRCFLAGS = -r -L
.SUFFIXES: .rc .res
.rc.res:
$(WRC) $(WRCFLAGS) $(WINELIB_FLAGS) -o $@ $<
There are two issues you are likely to encounter with resource files.
The first problem is with the C library headers. WRC does not know
where these headers are located. So if an RC file, of a file it
includes, references such a header you will get a 'file not found'
error from wrc. Here are a few ways to deal with this:
The solution traditionally used by the Winelib headers is to
enclose the offending include statement in an
#ifndef RC_INVOKED statement where
RC_INVOKED is a macro name which is
automatically defined by wrc.
Alternately you can add one or more directive
to your wrc command so that it finds you system files. For
instance you may add -I/usr/include
-I/usr/lib/gcc-lib/i386-linux/2.95.2/include to cater
to both C and C++ headers. But this supposes that you know where
these header files reside which decreases the portability of your
makefiles to other platforms (unless you automatically detect all
the necessary directories in the autoconf script).
Or you could use the C/C++ compiler to perform the preprocessing.
To do so, simply modify your makefile as follows:
.rc.res:
$(CC) $(CC_OPTS) -DRC_INVOKED -E -x c $< | $(WRC) -N $(WRCFLAGS) $(WINELIB_FLAGS) -o $@
The second problem is that the headers may contain constructs that
WRC fails to understand. A typical example is a function which return
a 'const' type. WRC expects a function to be two identifiers followed
by an opening parenthesis. With the const this is three identifiers
followed by a parenthesis and thus WRC is confused (note: WRC should
in fact ignore all this like the windows resource compiler does).
The current work-around is to enclose offending statement(s) in an
#ifndef RC_INVOKED.
Using GIF files in resources is problematic. For best results,
convert them to BMP and change your .res
file.
If you use common controls/dialogs in your resource files, you
will need to add #include <commctrl.h>
after the #include <windows.h> line,
so that wrc knows the values of control
specific flags.
Compiling message files: WMC
how does one use it???
The Spec fileIntroduction
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:
name
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').
modeinitmode 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.
import
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).
rsrc
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 ) 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: .
Compiling it
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.
More details
(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 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:
pascal16for a Win16 function returning a 16-bit valuepascalfor a Win16 function returning a 32-bit valueregisterfor a function using CPU register to pass argumentsinterruptfor a Win16 interrupt handler routinestdcallfor a normal Win32 functioncdeclfor a Win32 function using the C calling conventionvarargsfor a Win32 function taking a variable number of argumentsARGTYPE should be one of:
wordfor a 16 bit wordlonga 32 bit valueptrfor a linear pointerstrfor a linear pointer to a null-terminated strings_wordfor a 16 bit signed wordsegptrfor a segmented pointersegstrfor a segmented pointer to a null-terminated stringwstrfor a linear pointer to a null-terminated wide
(16-bit Unicode) string
Only ptr, str,
wstr 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.
Strings should almost always map to str,
wide strings - wstr.
As the general rule it depends on whether the
parameter is IN, OUT or IN/OUT.
IN: str/wstr
OUT: ptr
IN/OUT: str/wstr
It is for debug messages. If the parameter is OUT
it might not be initialized as thus it should not
be printed as a string.
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.
Linking it all together
To link an executable you need to link together: your object files,
the spec file, any Windows libraries that your application depends
on, gdi32 for instance, and any additional library that you use. All
the libraries you link with should be available as '.so' libraries.
If one of them is available only in '.dll' form then consult
.
It is also when attempting to link your executable that you will
discover whether you have missing symbols or not in your custom
libraries. On Windows when you build a library, the linker will
immediately tell you if a symbol it is supposed to export is
undefined. In Unix, and in Winelib, this is not the case. The symbol
will silently be marked as undefined and it is only when you try to
produce an executable that the linker will verify all the symbols are
accounted for.
So before declaring victory when first converting a library to
Winelib, you should first try to link it to an executable (but you
would have done that to test it anyway, right?). At this point you
may discover some undefined symbols that you thought were implemented
by the library. Then, you to the library sources and fix it. But you
may also discover that the missing symbols are defined in, say,
gdi32. This is because you did not link the said library with gdi32.
One way to fix it is to link this executable, and any other that also
uses your library, with gdi32. But it is better to go back to your
library's makefile and explicitly link it with gdi32.
As you will quickly notice, this has unfortunately not been
(completely) done for Winelib's own libraries. So if an application
must link with ole32, you will also need to link with advapi32,
rpcrt4 and others even if you don't use them directly. This can be
annoying and hopefully will be fixed soon (feel free to submit a
patch).