Archived

This forum has been archived. Please start a new discussion on GitHub.

Ice build for ARM architecture

Has anyone has experience at cross-compiling Ice for the ARM CPU?

By default, it gets upset because this is not one of the listed CPU architecture options for endian-ness in Ice/Util/Config.h

If it helps, I can edit this file to fix it & then send it in once I have been able to build the library and test that it works.

For the GNU C compiler, you can always rely on __BYTE_ORDER being defined by include/bits/endian.h as __LITTLE_ENDIAN or __BIG_ENDIAN. This would be a more portable way of doing it (for the GCC world at least).

Regards,
Jeff Gray

Comments

  • matthew
    matthew NL, Canada
    I don't think Ice has ever been built for ARM. We've built IceE for ARM in the past, however, so taking a look there might be helpful.

    As to endian.h, I don't think its all that helpful. The header isn't part of glibc, and is not part of any any standard that I'm aware of. Also endianess is hardly the primary stopper in porting to a new OS and architecture :)
  • endian.h is part of glibc (in 2.3 and 2.7 that I've checked) and can be found in the /include directory. It typically includes bits/endian.h, which in turn references system dependent files deeper down.

    I have modified cpp/include/IceUtil/Config.h to reflect the constants defined in endian.h. This compiles the files - I still have to get all the 3rd party libraries built, so I can't link it yet. But I think this is heading in the right direction.

    I'll complete the work & let you know it goes. Are there any documents to help me with cross-compiling Ice? I've a lot of experience at doing it with fairly tricky apps, like Python & ACE, but it always helps if there's some specific documentation.

    My cross development environment is GCC-4.2.3, GLIBC-2.7 with NPTL & TLS.

    Regards,
    Jeff Gray

    //
    // Endianness
    //
    // Most CPUs support only one endianness, with the notable exceptions
    // of Itanium (IA64) and MIPS.
    //
    #ifdef __GLIBC__
    # include <endian.h>
    #endif

    #if defined(__i386) || defined(_M_IX86) || defined(__x86_64) || \
    defined(_M_X64) || defined(_M_IA64) || defined(__alpha__) || \
    (__BYTE_ORDER == __LITTLE_ENDIAN) || defined(__MIPSEL__)
    # define ICE_LITTLE_ENDIAN
    #elif defined(__sparc) || defined(__sparc__) || defined(__hppa) || \
    defined(__ppc__) || defined(__powerpc) || defined(_ARCH_COM) || \
    (__BYTE_ORDER == __BIG_ENDIAN) || defined(__MIPSEB__)
    # define ICE_BIG_ENDIAN
    #else
    # error "Unknown architecture"
    #endif
  • bernard
    bernard Jupiter, FL
    Hi Jeff,

    Thanks, this glibc-endianness check is a good idea and we'll incorporate it in a future release.
    You probably want to add a "if defined(__BYTE_ORDER)", in case you ever compile this code with a compiler other than GCC.

    We currently don't support cross-compiling for Ice, and there is no special cross-compiling support in the Ice build system, or associated documentation. We expect that you build Ice directly on your target.

    On the other hand, Ice-E supports both ARM and cross-compiling, and doesn't depend on any third-parties. Is there any feature in Ice and not Ice-E that you need for your application?

    Best regards,
    Bernard
  • I need Ice, because I need the Python target as well.

    My target is a smallish device (ARM9 180MHz, 64MB RAM, 64MB Flash) & not the best for running builds on. It's fine for running an Ice based app, but a bit slow for GCC...

    To date, I have been using a crosstool build set to cross compile apps on my Linux based PC. An alternative, which makes the setup much easier for many apps is to run Qemu on Linux, which allows me to run a virtual ARM machine on my PC. I might look at this in more detail so I can build Ice 'on the target'.

    From what I've seen in the Ice source, I don't see anything that should prevent it running on ARM. You've done the hard work of minimising platform specifics. As long as I set the platform specific things like byte order and int size properly, then it should be fine because the Linux kernel & GCC/GLIBC aid portability as well. I'll let you know in a while how it goes.

    Thanks,
    Jeff Gray
  • bernard
    bernard Jupiter, FL
    Hi Jeff,

    The only ARM-specific "feature" I am aware of is the double representation, and consequently marshaling/unmarshaling code.

    While porting Ice to ARM, I recommend to look for "__arm__" in Ice-E's BasicStream.cpp, and make the same adjustments to Ice's BasicStream.cpp.

    Please let us know of it goes.

    Best regards,
    Bernard
  • All,
    I just so happened to be attempting this (Ice on arm) when I ran across your posts. Using the changes in BasicStream.cpp from IceE as a guide I was able to get everything compilied. Most of the test suite successfully ran, except the following:
    • IceUtil/unicode (seems to be a byte order error)
    • Slice/errorDetection (this error simply failed with exit code 256)
    • IceStorm/single (see below for details)
    • FreezeScript/dbmap (failed with exit code 256)
    • FreezeScript/evictor (failed with exit code 256)
    • IceGrid/* (the test here just didn't run, and as I don't need it I didn't fix the tests)

    I found that qemu did not handle exceptions correctly, so I had to run all the test cases on my device (a Nokia N800 for reference). The IceStorm/single test was an interesting failure, especially as the other IceStorm tests passed. I am going to look into the cause a bit further later, but (for reference again) here is the output from the test:
    *** running tests in ./test/IceStorm/single
    starting icestorm service... ./bin/icebox --Ice.Default.Host=127.0.0.1 --Ice.PrintProcessId --Ice.PrintAdapterReady --Ice.NullHandleAbort --Ice.Warn.Connections --Ice.ServerIdleTime=30 --Ice.ThreadPool.Server.Size=1 --Ice.ThreadPool.Server.SizeMax=3 --Ice.ThreadPool.Server.SizeWarn=0 --IceBox.ServiceManager.Endpoints="default -p 12010" --Ice.Default.Locator= --IceBox.Service.IceStorm=IceStormService,32:createIceStorm --IceStorm.TopicManager.Endpoints="default -p 12011" --IceStorm.Publish.Endpoints="default:udp" --IceBox.PrintServicesReady=IceStorm --IceBox.InheritProperties=1 --Freeze.DbEnv.IceStorm.DbHome=./test/IceStorm/single/db
    ok
    creating topic... ./bin/icestormadmin --Ice.Default.Host=127.0.0.1 --Ice.NullHandleAbort --Ice.Warn.Connections --IceStorm.TopicManager.Proxy="IceStorm/TopicManager:default -p 12011" -e "create single"
    ok
    starting subscriber... ok
    starting publisher... ok
    testing default reliability... ok
    testing oneway reliability... ok
    testing twoway reliability... failed!
    Subscriber.cpp:90: assertion `false' failed
    05/11/08 22:00:31.560 warning: connection exception:
    TcpTransceiver.cpp:223: Ice::ConnectionLostException:
    connection lost: recv() returned zero
    local address = 127.0.0.1:12011
    remote address = 127.0.0.1:57028
    Aborted
    05/11/08 22:00:31.584 warning: connection exception:
    TcpTransceiver.cpp:223: Ice::ConnectionLostException:
    connection lost: recv() returned zero
    local address = 127.0.0.1:54104
    remote address = 127.0.0.1:50339
    destroying topic... ok
    shutting down icestorm service... ok
    *** test in ./test/IceStorm/single failed with exit status 256
    

    I am now trying to get IcePy working, but the first test has failed, I will investigate further and let you all know what I find. If anyone has any thoughts about possible arm and IcePy issues I would appreciate it.

    Below is the patch of my BasicStream.cpp:
    --- Ice-3.2.1/src/Ice/BasicStream.cpp   2007-08-08 14:00:54.000000000 -0500
    +++ src/Ice/BasicStream.cpp     2008-05-15 16:24:17.000000000 -0500
    @@ -1161,6 +1161,16 @@
         *dest = *src;
     #else
         const Byte* src = reinterpret_cast<const Byte*>(&v);
    +#  if defined(__arm__) && defined(__linux)
    +    dest[4] = *src++;
    +    dest[5] = *src++;
    +    dest[6] = *src++;
    +    dest[7] = *src++;
    +    dest[0] = *src++;
    +    dest[1] = *src++;
    +    dest[2] = *src++;
    +    dest[3] = *src;
    +#  else
         *dest++ = *src++;
         *dest++ = *src++;
         *dest++ = *src++;
    @@ -1169,6 +1179,7 @@
         *dest++ = *src++;
         *dest++ = *src++;
         *dest = *src;
    +# endif
     #endif
     }
    
    @@ -1196,6 +1207,21 @@
                 *dest++ = *src--;
                 src += 2 * sizeof(Double);
             }
    +#elif defined(__arm__) && defined(__linux)
    +        const Byte* src = reinterpret_cast<const Byte*>(begin);
    +        Byte* dest = &(*(b.begin() + pos));
    +        for(int j = 0 ; j < sz ; ++j)
    +        {
    +            dest[4] = *src++;
    +            dest[5] = *src++;
    +            dest[6] = *src++;
    +            dest[7] = *src++;
    +            dest[0] = *src++;
    +            dest[1] = *src++;
    +            dest[2] = *src++;
    +            dest[3] = *src++;
    +            dest += sizeof(Double);
    +        }
     #else
             memcpy(&b[pos], reinterpret_cast<const Byte*>(begin), sz * sizeof(Double));
     #endif
    @@ -1223,6 +1249,16 @@
         *dest = *src;
     #else
         Byte* dest = reinterpret_cast<Byte*>(&v);
    +#  if defined(__arm__) && defined(__linux)
    +    dest[4] = *src++;
    +    dest[5] = *src++;
    +    dest[6] = *src++;
    +    dest[7] = *src++;
    +    dest[0] = *src++;
    +    dest[1] = *src++;
    +    dest[2] = *src++;
    +    dest[3] = *src;
    +#  else
         *dest++ = *src++;
         *dest++ = *src++;
         *dest++ = *src++;
    @@ -1231,6 +1267,7 @@
         *dest++ = *src++;
         *dest++ = *src++;
         *dest = *src;
    +# endif
     #endif
     }
    
    @@ -1260,6 +1297,21 @@
                 *dest-- = *src++;
                 dest += 2 * sizeof(Double);
             }
    +#elif defined(__arm__) && defined(__linux)
    +        const Byte* src = &(*begin);
    +        Byte* dest = reinterpret_cast<Byte*>(&v[0]);
    +        for(int j = 0 ; j < sz ; ++j)
    +        {
    +            dest[4] = *src++;
    +            dest[5] = *src++;
    +            dest[6] = *src++;
    +            dest[7] = *src++;
    +            dest[0] = *src++;
    +            dest[1] = *src++;
    +            dest[2] = *src++;
    +            dest[3] = *src++;
    +            dest += sizeof(Double);
    +        }
     #else
             copy(begin, i, reinterpret_cast<Byte*>(&v[0]));
     #endif
    

    If anyone needs any other information, or has any ideas about how to get IcePy working, or needs me to test something on arm just let me know.

    Thanks!