Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix Windows cross-compilation on Linux using mingw-w64 #688

Merged
merged 9 commits into from
Aug 9, 2015

Conversation

smcv
Copy link
Contributor

@smcv smcv commented Jul 29, 2015

mingw-w64 is a way to compile native 32- or 64-bit Windows executables using gcc/g++, compiling on either Linux (with a cross-compiler that targets mingw-w64) or Windows. The resulting binaries do not depend on a special platform layer like Cygwin: they use the normal Win32 API, with Microsoft's msvcrt.dll as their C runtime.

Previous versions of OpenJK needed significant changes for mingw, which is presumably why it isn't currently supported, but current git master can cross-compile under mingw on Linux with only minor modifications: the general theme is that it becomes necessary to distinguish between MSVC-only code, and Windows-only code (which were previously the same thing). These changes hopefully don't break MSVC builds, but I'd appreciate it if someone could test that.

So far, I've only tried compiling 32-bit debug and release builds on Linux. My planned next steps are: test those builds on native Windows; test on Wine; try Win64 builds.

Travis-CI has a mingw-w64 cross-compiler available, which ioquake3 uses for snapshot builds. I'm going to look into setting this up for my own OpenJK branches, and I hope to be able to provide a pull request soon if the OpenJK developers would be interested in doing the same. Unlike the buildbot, Travis-CI can be run automatically for every commit and every pull request, making it easy to detect pull requests from a Linux user that would break the Windows build, or vice versa. You could continue to use OpenJK's current buildbot infrastructure to produce the official snapshots if you prefer that (and it does have the advantage of covering OS X, which needs special setup for Travis-CI).

@xycaleth
Copy link
Member

A quick look at your changes looks good. I'm a little worried about your changes in 1a9b48184ece to files in the code/win32/ folder though. Were you seeing compile errors from these files, or did you simply go through all the files? That folder is no longer (or at least, should no longer) be used by any of the executables, so there shouldn't be any need to update them.

We should delete the folder at some point :)

@smcv
Copy link
Contributor Author

smcv commented Jul 31, 2015

Were you seeing compile errors from these files, or did you simply go through all the files?

I'm not sure; I started the branch a while ago, but I didn't push it, partly because linking failed with the bundled SDL (I think it might only work for MSVC, I'm using a separate SDL binary now) and partly because the diff was a lot larger back then. It's possible that it broke the build when I started, but doesn't any more.

xinput.h is what mingw-w64 calls that header, and altering the case should be harmless on Windows, even if it isn't actually any help either :-)

We should delete the folder at some point :)

One of my ulterior motives in trying to set up a working autobuild environment for mingw is that I can try out changes like "delete code*/win32 and see what happens" and know that if it builds on all the platforms, it's probably good :-)

@smcv
Copy link
Contributor Author

smcv commented Jul 31, 2015

the diff was a lot larger back then

I've benefited from some cleanup done by other people within OpenJK, and also some fixes in the mingw-w64 headers (for which I previously had a somewhat nasty workaround).

@smcv
Copy link
Contributor Author

smcv commented Jul 31, 2015

You are right that not all of 1a9b481 is necessary now; the only parts that actually break compilation are the various inclusions of Windows.h and gl/gl.h, and one ShlObj.h in shared/. But I'm fairly sure the rest is right, and some of it might be necessary with different compilation options. At worst, it's harmless on case-insensitive OSs.

@smcv
Copy link
Contributor Author

smcv commented Aug 2, 2015

I've updated the branch to stop patching code*/win32.

There are a few fixes in code paths which are only taken with OPENAL and/or USE_OPENAL defined, which we don't (or at least my test builds don't). I've left those in, but split them into their own commit so they're easy to discard if desired.

@smcv
Copy link
Contributor Author

smcv commented Aug 3, 2015

Updated the branch again to be able to use the bundled SDL2 library rather than an external one. It turned out to be a library-order issue.

The change to fix that should be harmless on MSVC (but please test!), because the MSVC linker prefers to resolve symbols in the same way gcc would, but unlike gcc it tries to cope with incorrect library order by falling back to libraries earlier in the command line: The MSVC linker is less sensitive to this issue because it will search all libraries for an unreferenced symbol. Library order still can affect which symbol gets resolved if more than one library have the symbol.

@smcv
Copy link
Contributor Author

smcv commented Aug 9, 2015

This seems to compile fine when including cmath all the time. Could you change it #include all the time?

Sure. I didn't want to change what happens on MSVC until someone could test there; but if you have now, that's fine.

Out of curiosity, what happens when this check [for sizeof(void *)] fails?

If the check isn't done (on Windows), then CMAKE_SIZEOF_VOID_P is unset and so doesn't match 8, Architecture is set to x86, and we produce a jagamex86.dll that is actually 64-bit code; and the cmake variable WIN64 isn't set, although that doesn't currently seem to have any practical effect on non-MSVC other than not installing DLLs to base/.

I don't think the check can fail (as in produce no result), assuming you have a working C compiler. It compiles a simple executable that encodes the size into a string, then looks for the string in the binary (to avoid having to run it, which would fail when cross-compiling).

MSVC doesn't object to this, but mingw gcc does. OpenAL-Soft already
had this fix applied in its initial commit (kcat/openal-soft@ae5f4e9).
On gcc, the floating-point overloads of abs() are only available
after including <cmath>. On MSVC it seems to be unnecessary but
harmless.
On Windows, header files' case and forward- vs. backslashes don't
matter, but when cross-compiling for Windows on a case-sensitive
platform like Linux it does matter. This case combination works
on mingw-w64.
This gets set with native gcc on Linux, and presumably also with
MSVC judging by its use in OpenJK, but doesn't seem to be set
when cross-compiling with the mingw-w64 toolchain.
Order is significant when using traditional Unix linkers like GNU ld:
libraries later in the link line can provide symbols required by
libraries earlier in the link line, but the opposite is not true.
When using an external SDL2, FindSDL2.cmake puts SDL2main before SDL2,
because SDL2main uses symbols from SDL2. Do the same for the bundled
SDL2 library.

This fixes the following link errors:

.../lib/SDL2/lib/x86/SDL2main.lib(./Release/SDL_windows_main.obj):(.text[_main]+0x5): undefined reference to `SDL_SetMainReady'
.../lib/SDL2/lib/x86/SDL2main.lib(./Release/SDL_windows_main.obj):(.text[_WinMain@16]+0x14): undefined reference to `SDL_wcslen'
.../lib/SDL2/lib/x86/SDL2main.lib(./Release/SDL_windows_main.obj):(.text[_WinMain@16]+0x2f): undefined reference to `SDL_iconv_string'
.../lib/SDL2/lib/x86/SDL2main.lib(./Release/SDL_windows_main.obj):(.text[_WinMain@16]+0x63): undefined reference to `SDL_malloc'
.../lib/SDL2/lib/x86/SDL2main.lib(./Release/SDL_windows_main.obj):(.text[_ParseCommandLine]+0x36): undefined reference to `SDL_isspace'
.../lib/SDL2/lib/x86/SDL2main.lib(./Release/SDL_windows_main.obj):(.text[_ParseCommandLine]+0xf5): undefined reference to `SDL_isspace'
collect2: error: ld returned 1 exit status
These assume that the compiler is in $PATH, and is named like the
ones in Debian/Ubuntu.
gcc/g++ link with support libraries: libgcc is a support library for
executables generated by gcc/g++, and libstdc++ is the GNU
implementation of Standard C++. Linking them statically means we don't
need to distribute separate libgcc_s_sjlj-1.dll and libstdc++-6.dll
binaries alongside OpenJK.
@xycaleth
Copy link
Member

xycaleth commented Aug 9, 2015

Looks good. Thanks smcv.

xycaleth added a commit that referenced this pull request Aug 9, 2015
fix Windows cross-compilation on Linux using mingw-w64
@xycaleth xycaleth merged commit 6201bf3 into JACoders:master Aug 9, 2015
@smcv smcv deleted the mingw branch August 9, 2015 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants