roboterclubaachen / xpcc

DEPRECATED, use our successor library https://modm.io instead
Other
173 stars 39 forks source link

Compiling native hosted Windows device w/ MinGW #201

Closed 7Kronos closed 7 years ago

7Kronos commented 7 years ago

Hi Guys,

Since yesterday, I'm trying to get a simple project compile on Windows which target device is "hosted". As a side note STM32 and AVR works fine and I plan to PR a doc on how to setup a complete native windows env. I know I could use a VM but hey, I love Visual Studio :)

Anyway, I have setup MinGW with g++. I made a simple project with a main inspired with one if the example linux projects. I feel stuck with a snprintf/vsnprintf issue where I don't have the background to figure out what is best to do there.

Here is what I found so far :

First I had to set an environment variable to add boost and SDL libraries : CPLUS_INCLUDE_PATH=C:\Repos\libs\boost_1_62_0;C:\Repos\libs\SDL2

Secondly, I added core/uart drivers to the windows.xml device file as follow :

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE rca SYSTEM "../devicefile.dtd">
<rca version="1.0">
  <device platform="hosted" family="windows">
    <naming-schema>{{ platform }}/{{ family }}</naming-schema>
    <driver type="graphics" name="hosted"/>
    <driver type="uart" name="hosted"/>
    <driver type="core" name="windows"/>
  </device>
</rca>

Then, I found a conflict with xpcc::log::Level enum and a define made in wsocket.h. There is a preprocessing define that use the label "ERROR". I temporally dirty fixed it with :

#pragma push_macro("ERROR")
#undef ERROR
...
        enum Level
        {
            DEBUG,
            INFO,
            WARNING,
            ERROR,
            DISABLED
        };
...
#pragma pop_macro("ERROR")

And finally I face some warning redefinitions and what I call know the "snprintf/vsnprintf incident".

iostream_float.cpp:82:51: error: 'snprintf' was not declared in this scope

main.cpp :

#include <xpcc/architecture.hpp>
#include <xpcc/debug/logger.hpp>
#include <xpcc_build_info.hpp>

#undef  XPCC_LOG_LEVEL
#define XPCC_LOG_LEVEL xpcc::log::INFO

int main()
{
    XPCC_LOG_INFO << "Machine:  " << XPCC_BUILD_MACHINE << xpcc::endl;
    XPCC_LOG_INFO << "User:     " << XPCC_BUILD_USER << xpcc::endl;
    XPCC_LOG_INFO << "Os:       " << XPCC_BUILD_OS << xpcc::endl;
    XPCC_LOG_INFO << "Compiler: " << XPCC_BUILD_COMPILER << xpcc::endl;

    return 0;
}

Do you feel like it is a waste of time or is it something that is easily fixable ?

salkinium commented 7 years ago

Interesting. So apparently snprintf does not exist on Windows/MinGW, since it's not part of ANSI C. I'd just use our manual implementation on Windows instead:

-#if defined(XPCC__CPU_CORTEX_M4) || defined(XPCC__CPU_CORTEX_M3) || defined(XPCC__CPU_CORTEX_M0)
+#if defined(XPCC__CPU_CORTEX_M4) || defined(XPCC__CPU_CORTEX_M3) || defined(XPCC__CPU_CORTEX_M0) || defined(XPCC__OS_WIN32)

I'm not sure what you're planning to do with xpcc on Windows, but please note that the hosted support only exists to compile our unit tests and a very limited subset of our robot and xpcc code on the PC for game and graphics simulation.

If you are interested in simulating ARM Cortex-M binaries, you can have a look at Qemu or even emul8.

We are going to remove the VM option, since it's unmaintained and difficult to reliably connect USB devices through to the VM on all platforms (#132, #133). So we'd very much appreciate a native Windows install guide for MinGW!

7Kronos commented 7 years ago

Exactly. I can't believe I missed this one, I should have inspected detect.hpp. My goal is to write unittests and graphics simulation natively as I work on Windows. Thanks for pointing me to Emul8, looks promising !

I'll definitely write a guide for a native Windows install (w/Qt Creator) !

I'll add an extra for Visual Studio adoption options, like running scons and add Intellisence (works pretty well already, have to double check it). Debugging might be a challenge without special plugins tho.

Meanwhile, I'll PR a compilable version with MinGW so you can review my tweaks.

        enum Level
        {
            LEVEL_DEBUG,
            LEVEL_INFO,
            LEVEL_WARNING,
            LEVEL_ERROR,
            LEVEL_DISABLED
        };
salkinium commented 7 years ago

What do you think about renaming Level enum labels (add prefix or use pascal case)?

I don't think thats feasible since this logger code is used quite extensively in our robot code and I don't want to refactor that. It's definitely an issue if wsocket.h decides to use such a top level define in its header file, but if your workaround works, then I'd prefer that.

Regarding SDL2: I have to check for what we use that inside of our robot code and who is a stakeholder in getting that upgrade. Don't hold your breath though, it's likely going to be complicatedto upgrade for us internally, so we may want to stick with what works.

7Kronos commented 7 years ago

For SDL2 I can try to make the upgrade.

Meanwhile, I fixed many things and what is left is some linking trouble I can't figure it out. I sorted already some of the boost lib specific dependencies for Windows. But I'm facing a wall where I can't understand why the static declarations in hosted/default_style.cpp are not resolved by the linker.

An "objdump -f build\libxpcc\src\libxpcc.a" shows that the file has been included during compilation.

Linking: build\win32_tests.exe
build\main.o: In function `ZN4xpcc3log6LoggerlsIA11_cEERS1_RKT_':
C:/Projets/onevape/xpcc/src/xpcc/debug/logger/logger.hpp:95: undefined reference to `xpcc::log::info'
build\main.o: In function `ZN4xpcc3log6LoggerlsIA10_cEERS1_RKT_':
C:/Projets/onevape/xpcc/src/xpcc/debug/logger/logger.hpp:95: undefined reference to `xpcc::log::info'
build\main.o: In function `ZN4xpcc8IOStreamlsEPFRS0_S1_E':
C:/Projets/onevape/xpcc/src/xpcc/io/iostream.hpp:359: undefined reference to `xpcc::log::info'
build\main.o: In function `ZN4xpcc3log6LoggerlsIA11_cEERS1_RKT_':
C:/Projets/onevape/xpcc/src/xpcc/debug/logger/logger.hpp:95: undefined reference to `xpcc::log::info'
build\main.o: In function `ZN4xpcc3log6LoggerlsIA7_cEERS1_RKT_':
C:/Projets/onevape/xpcc/src/xpcc/debug/logger/logger.hpp:95: undefined reference to `xpcc::log::info'
build\main.o:C:/Projets/onevape/xpcc/src/xpcc/io/iostream.hpp:359: more undefined references to `xpcc::log::info' follow
c:/mingw/bin/../lib/gcc/mingw32/5.3.0/../../../libmingw32.a(main.o):(.text.startup+0xa0): undefined reference to `WinMain@16'
collect2.exe: error: ld returned 1 exit status
scons: *** [build\win32_tests.exe] Error 1
scons: building terminated because of errors.

The last undefined reference must be a simple MinGW define missing. It thinks I'm compiling a windowed program. I'll figure this out.

salkinium commented 7 years ago

Meanwhile, I fixed many things and what is left is some linking trouble I can't figure it out.

I believe this is an issue with weak linking with MinGW (the symbols are all declared xpcc_weak). My quick googling couldn't find any immediately obvious solution, and I don't have a Windows system to test anyways.

static Wrapper< char[10], TURQUOISE, NONE > debugWrapper("Debug:   ", device);
Logger xpcc_weak debug(debugWrapper);

The last undefined reference must be a simple MinGW define missing.

Probably the int main(void) signature is different. Try the standard int main( int argc, char* argv[] ) signature, maybe that's the issue.

When I compiled xpcc a year ago for a Qt 5 Windows application (for which I didn't use xpcc's logger), I had to add a compiler flag to enable correct __attribute__((packed)) operation. Maybe something similar needs to be set for weak linking? Maybe weak linking only works with GNU ld?

7Kronos commented 7 years ago

Probably the int main(void) signature is different. Try the standard int main( int argc, char* argv[] ) signature, maybe that's the issue.

Indeed signature int main(int argc, char** argv) works but more importantly I had to link SDLMain and SDL lib.

Anyways, I have successfully built the sample above with minimal isolated changes.

I can't get around the weak symbol, don't know why, but I did a lot of research and I think it's simply a bug in MinGW's Binutils. I will try MinGW-w64 to check this assumption (anyway w64 seems more maintained to me).

Another issue is that how boost lib compile and install, it add suffix with meta info, I end up with this in project.cfg :

[environment]
LINKCOM* = -lboost_thread-mgw53-mt-sd-1_62 -lboost_system-mgw53-mt-sd-1_62

We don't have symlinks on Windows :)

Another issue is that with SDL linked, I have to redirect the stolen console from it :

    // ensure the console has been allocated
    AllocConsole();

    freopen( "CON", "w", stdout );
    freopen( "CON", "w", stderr );

    /* Linux useful ?
    freopen("/dev/tty", "w", stdout);
    freopen("/dev/tty", "w", stderr);
    */

Lastly, SDL.dll is needed, I can't static link it.

If you have the time, I can PR you a proposal to review !

salkinium commented 7 years ago

I can't get around the weak symbol

Defining xpcc_weak as empty will likely lead to "multiple declaration" warnings later on when some code tries to overwrite these functions.

Another issue is that how boost lib

Yeah, I've heard friends mutter expletives mixed with "symlinks", "long paths" and "windows" under their breath 😛. If there is no other solution, I think it's perfectly fine to put this in the project.cfg, it just has to be pointed out in the install instructions.

Another issue is that with SDL linked, I have to redirect the stolen console from it : Lastly, SDL.dll is needed, I can't static link it.

No clue, sorry. If that makes it work, fine with me 👍.

If you have the time, I can PR you a proposal to review !

Yes, but use a feature branch for the PR please.

7Kronos commented 7 years ago

Just a quick update. I'm still on this. Took me time to test alternatives like Cyg/Mys2 (witch contain precompiled boost/SDL libs). I may be able to PR my best and final proposal today or tomorrow :)

7Kronos commented 7 years ago

PR created, to sum it up, compilation works on Cygwin, Msys2 and native MinGW native install. Cygwin is definitely the recommended method as it is the only one that provide a working env with SCons+Jinja2+Boost+SDL static linking out of the box. Msys2 has conflicting python packages between SCons and Jinja2. Both 32 and 64 bits MinGW-w64 g++ compilers work fine.

Info: Machine: Kronos-PC Info: User: Kronos Info: Os: CYGWIN_NT-10.0 Info: Compiler: x86_64-w64-mingw32-g++ (GCC) 5.4.0

xpcc_weak is still an issue and I had to suppress the macro for Windows compilation. We can expect some conflicting. User can't hard link his methods :'(

Last frustrating issue is that the recover stolen console from SDL does not work on Minitty (freopen of /dev/tty seems do not work). So logger to console works only on Bash and Cmd.