Search code examples
c++windowswinapiwinewinelib

Problems compiling C++ programs with wineg++/winelib


I am having trouble compiling C++ programs with wineg++. To illustrate my problem, I have written two test programs.

msgbox.cpp

#include <algorithm>
#include <iterator>
#include <cstdio>

#include <windows.h>

int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    char buf[30], *pos = buf;
    int xs[] = {1,3,2,4,3,5,4,6,5,7,6,8,7,9};

    std::sort( std::begin(xs), std::end(xs) );
    for (int x : xs) {
        pos += std::sprintf(pos, "%d ", x);
    }

    MessageBox(0, buf, "Hello", 0);
    return 0;
}

frame.cpp

#include "../win32xx/include/wxx_wincore.h"
#include "../win32xx/include/wxx_frame.h"

int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    CWinApp winApp;
    CFrame frame;
    CWnd view;
    frame.SetView(view);
    frame.Create();
    winApp.Run();
}

The second program uses the Win32++ library, which I can't recommend enough.

Both programs compile and run just fine using a cross-compiler:

okuu% x86_64-w64-mingw32-g++ msgbox.cpp -o msgbox.exe
okuu% wine ./msgbox.exe
okuu% x86_64-w64-mingw32-g++ frame.cpp -o frame.exe -lgdi32 -lcomctl32 -static
okuu% wine ./frame.exe
okuu% rm *exe*

But I want to use winelib so that I can use both the Windows API and Unix libraries. This is what I tried first:

okuu% wineg++ msgbox.cpp -o msgbox.exe
okuu% ./msgbox.exe
okuu% wineg++ frame.cpp -o frame.exe -mwindows
In file included from ../win32xx/include/wxx_appcore.h:57:0,
                 from ../win32xx/include/wxx_wincore.h:96,
                 from frame.cpp:1:
../win32xx/include/wxx_appcore0.h:120:12: fatal error: process.h: No such file or directory
   #include <process.h>
            ^~~~~~~~~~~
compilation terminated.
winegcc: g++ failed

Then I read wineg++'s man page, which says:

-mno-cygwin
Use Wine implementation of MSVCRT, instead of linking against the host system libc. This is necessary for the vast majority of Win32 applications, as they typically depend on various features of MSVCRT. This switch is also used by the MinGW compiler to link against MSVCRT on Windows, instead of linking against Cygwin libc. Sharing the syntax with MinGW makes it very easy to write Makefiles that work under Wine, MinGW+MSYS, or MinGW+Cygwin.

So I tried again with -mno-cygwin, and got a 2000-line error message that begins with:

okuu% wineg++ frame.cpp -o frame.exe -mwindows -mno-cygwin
In file included from /usr/include/c++/7.2.1/cstdlib:75:0,
                 from /usr/include/c++/7.2.1/bits/stl_algo.h:59,
                 from /usr/include/c++/7.2.1/algorithm:62,
                 from ../win32xx/include/wxx_appcore0.h:110,
                 from ../win32xx/include/wxx_appcore.h:57,
                 from ../win32xx/include/wxx_wincore.h:96,
                 from frame.cpp:1:
/usr/include/stdlib.h:310:5: error: ‘int32_t’ does not name a type; did you mean ‘wint_t’?
     int32_t *fptr;  /* Front pointer.  */
     ^~~~~~~
     wint_t
/usr/include/stdlib.h:311:5: error: ‘int32_t’ does not name a type; did you mean ‘wint_t’?
     int32_t *rptr;  /* Rear pointer.  */
     ^~~~~~~
     wint_t
/usr/include/stdlib.h:312:5: error: ‘int32_t’ does not name a type; did you mean ‘wint_t’?
     int32_t *state;  /* Array of state values.  */
     ^~~~~~~
     wint_t
/usr/include/stdlib.h:316:5: error: ‘int32_t’ does not name a type; did you mean ‘wint_t’?
     int32_t *end_ptr;  /* Pointer behind state table.  */
     ^~~~~~~
     wint_t
/usr/include/stdlib.h:320:8: error: ‘int32_t’ has not been declared
        int32_t *__restrict __result) __THROW __nonnull ((1, 2));
        ^~~~~~~

So it seems C99's fixed-size integer types are not available. That seems easy enough to solve:

frame.cpp

#include <stdint.h>
#include "../win32xx/include/wxx_wincore.h"
#include "../win32xx/include/wxx_frame.h"
// etc. etc. etc.

And I tried again, but got a different 2000-line error message that begins with:

okuu% wineg++ frame.cpp -o frame.exe -mwindows -mno-cygwin
In file included from /usr/include/c++/7.2.1/cwchar:44:0,
                 from /usr/include/c++/7.2.1/bits/postypes.h:40,
                 from /usr/include/c++/7.2.1/bits/char_traits.h:40,
                 from /usr/include/c++/7.2.1/string:40,
                 from ../win32xx/include/wxx_appcore0.h:111,
                 from ../win32xx/include/wxx_appcore.h:57,
                 from ../win32xx/include/wxx_wincore.h:96,
                 from frame.cpp:2:
/usr/local/include/wine/msvcrt/wchar.h:398:23: error: conflicting declaration of C function ‘size_t mbstowcs(wchar_t*, const char*, size_t)’
 size_t        __cdecl mbstowcs(wchar_t*,const char*,size_t);
                       ^~~~~~~~

At this point I have run out of ideas. This is what I have understood so far:

  • My system's libc and Wine's MSVCRT have conflicting definitions. (This was probably to be expected.)
  • My system's libc++ is hardwired to work with my system's libc.
  • Wine comes with a MSVCRT, but not with a C++ standard library implementation.

The logical course of action with the information I have so far would be to look for a C++ standard library implementation that's compatible with Wine's MSVCRT, but I don't know of one. Does anybody here know of one?


Solution

  • The only solution I can think of is to stick with the system libc and write your own process.h. This file should either #include the standard header files that have the functions Win32++ needs or provide its own implementations of those functions. If Win32++ won't compile without a particular function but your program does not actually depend on that function, the implementation of that function can simply return 0 or another fake value.

    If the system libc has a header file that Win32++ asks for, but the file does not declare all of the functions that Win32++ expects, you'll have to write a header file such as win32xx-compat.h that defines those functions and #include it before any Win32++ header.