Archive for the ‘MinGW’ Category

porting resource compiler .rc files to windres

Thursday, January 31st, 2008

For MinGW, windres is the replacement for the rc resource compiler.  Given a random .rc file, to compile it with MinGW the trick seems to be to insert the following:

// for windres
#include “winresrc.h”
#define IDC_STATIC (-1)

Done.  Handy for cross-compiling these things from Linux.

compiling DirectShow with MinGW on Linux

Thursday, January 24th, 2008

First question: why on earth would you want to do this?  Are you quite mad?

Finding a reason to do this is the hard part, actually doing it is not that bad.  First, start using MinGW on Linux.  That’s fairly straightforward, on Debian/Ubuntu just do “apt-get install mingw32″, then use the i586-mingw32msvc-g++ compiler and its friends in place of regular gcc (this package also places a bunch of other helper programs in the slightly unusual path /usr/i586-mingw32msvc/bin).

Now, follow Samuel Audet’s instructions on using DirectShow from MinGW.

That gets us a lot of the way, but a few more issues show up:

  • Add a definition, _OBJBASE_H_, to your compiler flags
  • Remove superfluous CAggDirectDraw:: qualifier on CAggDirectDraw::~CAggDirectDraw()  in videoctl.h
  • Remove superfluous CTransInPlaceFilter:: qualifier on CTransInPlaceFilter::Copy() in transip.h

While Samuel Audet recycled a project file for compiling, I chose to use CMake.  This isn’t essential of course, but I’ll post the method anyway.  Suppose we want to compile the DirectShow “Ball” example.  I copied the Ball, BaseClasses, and Include directories of the DirectX 9.0 SDK into a common directory, and added a CMakeLists.txt file as follows:

directx_test/

CMakeLists.txt
Ball/
BaseClasses/
Include/

The Ball example generates an activex control, which is just a DLL.  Here is the CMakeLists.txt I used to get this done:

PROJECT(directshower)
FILE(GLOB_RECURSE folder_source *.cpp *.cc *.c)
FILE(GLOB_RECURSE folder_header *.h)
ADD_DEFINITIONS(-D_OBJBASE_H_)
SET(CMAKE_SHARED_LINKER_FLAGS “-Wl,–add-stdcall-alias”)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/Include
${PROJECT_SOURCE_DIR}/Ball
${PROJECT_SOURCE_DIR}/BaseClasses)
LINK_LIBRARIES(advapi32 gdi32 ole32 oleaut32 user32 winmm uuid strmiids)
ADD_LIBRARY(directshower SHARED ${folder_source} ${folder_header})

Other possible libraries to link can be found by inspecting the .dsp files in the project directories.

This compiles and produces a reasonable looking DLL file that, in my case, didn’t actually work straight away as an activex control.  We need to make sure that functions like DllMain, DllRegisterServer, etc are public and “unmangled” in the DLL.  We can check this by typing something like:

 /usr/i586-mingw32msvc/bin/objdump -x libdirectshower.dll | grep DllMain

We want this to give a result like this:

        [   4] DllMain
[   5] DllMain@12
[  8](sec  1)(fl 0×00)(ty  20)(scl   2) (nx 0) 0×000000c0 _DllMainCRTStartup@12
[3978](sec  1)(fl 0×00)(ty  20)(scl   2) (nx 1) 0×000366d0 _DllMain@12

That first line, where the symbol DllMain is present without an underscore before it and without an @ after it, is good, that’s what we want.  That shows that DllMain will be visible on Windows.  You can read about the details at Wu Yongwei’s page on calling conventions.

We need to make sure at least the following functions are visible:

  • DllMain
  • DllGetClassObject
  • DllCanUnloadNow
  • DllRegisterServer
  • DllUnregisterServer

Track all these functions down in the source code.  DllGetClassObject and DllCanUnloadNow are in BaseClasses/dllentry.cpp, the rest are in this case in Ball/fball.cpp.  We need to insert “__declspec(dllexport)” into the declarations of all these methods (there are other possibilities, but this will do for now.  Let’s do:

#define EXPORT __declspec(dllexport)
#define STDAPI_EXPORTED  EXTERN_C EXPORT HRESULT STDAPICALLTYPE

Now, change the signatures of these functions as follows:

STDAPI_EXPORTED DllRegisterServer()
STDAPI_EXPORTED DllUnregisterServer()
STDAPI_EXPORTED DllGetClassObject(REFCLSID rClsID,REFIID riid,void **pv)
STDAPI_EXPORTED DllCanUnloadNow()
EXTERN_C EXPORT BOOL STDAPICALLTYPE DllMain(HANDLE hModule, DWORD  dwReason, LPVOID lpReserved)

Recompile, check that the symbols are actually visible, copy your .dll to a windows machine, do:

regsvr32.exe  directshower.dll

And boom!  Success!

It seems wrong, somehow…  yet so, so right.

compiling ODE with mingw on linux

Wednesday, January 16th, 2008

The default stack size with mingw on linux seems smaller than the default on windows. This became a problem for me when working with ODE, a dynamics engine that can be a heavy user of the stack. To avoid program crashes on object collisions, I needed to add the following flags to gcc:

-Wl,–stack,0×2000000

This should give a 32M stack size, which I would have expected to be the default for windows.

I was using the mingw32 package on debian.

Update: sometimes the above is not enough, and I’ve had to edit the stack size of a program after it has been compiled, mingw doesn’t seem to set things up right. I’ve used:

editbin.exe /STACK:30000000 the_program.exe

where editbin.exe is a program microsoft supplies for this sort of thing (runs fine under wine). Not sure what a FOSS equivalent of this tool would be.

Touching Windows with a barge-pole

Saturday, November 24th, 2007

We are a Linux shop here at MakeSweet, but occasionally we need to distribute programs - and that means compiling for Windows. We’ve found that for the cleanest results, MinGW (Minimalist GNU for Windows) is hard to beat. It is useful even if you are compiling on Windows, but it is especially useful if you are cross-compiling from Linux.

Getting set up for cross-compiling for Windows is trivial to set up on Debian/Ubuntu, just do:

sudo apt-get install mingw32

For other Linux systems, you can follow some tips on the MinGW wiki: BuildMingwCross, Build-a-Win32-x-compiler-for-Linux.

Our favorite build system is CMake; there are tips on adapting CMake to MinGW on the CMake wiki at CMakeMingw.

One subtlety with MinGW is that after building, your program may depend on mingw10.dll. This is a freely distributable DLL (on Debian, you can find it in /usr/share/doc/mingw-runtime) but it can be nice to build programs with no extra DLL dependencies. To do that, make sure the “-mthreads” flag is not used during compilation, and remove it if it is. You should be aware of the consequences of removing the flag though, and it may not be a reasonable thing to do. In our experience, if you are not using exceptions, things seem ok without it.

For cross-compiling with MinGW on Linux, CMake helps a lot. See CMakeCrossCompiling for tips. At the time of writing, only the CVS version of CMake supports cross-compiling. You just need to set up a “toolchain” file describing your environment, for me I called it ~/mingwin.cmake and it looked like this:

SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_C_COMPILER /usr/bin/i586-mingw32msvc-gcc)
SET(CMAKE_CXX_COMPILER /usr/bin/i586-mingw32msvc-g++)
SET(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc /home/bozo/mingw/install)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Then, when configuring a project, the first call to CMake would be like this:

cmake -DCMAKE_TOOLCHAIN_FILE=~/mingwin.cmake .