[Insight-users] ITK 4 on iOS and Android

Shashwath T.R. trshash at gmail.com
Sat Apr 14 03:28:54 EDT 2012


Hi everyone,

I've been trying to get ITK 4 master to compile on iOS and the Android NDK.
This is just a short account of all the problems I faced, and how I worked
around them.

The SDK versions I'm using are the iOS 5.0 (iPhoneOS5.0.sdk and
iPhoneSimulator5.0.sdk), and r7 of the Android NDK. For iOS, my IDE is
XCode 4.2, and for Android, it's Eclipse. I'm not sure how other IDEs or
SDK versions will impact what I've done.

First, the instructions given at
http://www.midasjournal.org/browse/publication/755 seem to be outdated.
They may work on 3.20, but on 4.x, they fall flat. Most of the
modifications suggested are different, and much better accomplished using a
CMake toolchain. Also, XCode 4.2 looks very different from the screenshots
in the paper. For example, the modification suggested in vnl_math.cxx is
just not required. But this paper provides a good starting point to
understanding how to do it all.

I chose to do it all using Makefiles instead of XCode or Eclipse projects.
This makes it easier to debug the console output. Also, I used toolchain
files for each of the builds. So, here's my procedure:

1. Build everything on OSX; this is mostly a sanity check to ensure that
the code-base is compilable in its pristine form.
2. Use the attached toolchain files to configure ITK.
3. Disable some modules that don't compile - primarily, the ITK-VTK glue,
GDCM TIFF and HDF5. I think I know how to solve the first two, at least -
the ITK-VTK glue should compile against vtk-modular, which VES for example
is using, and TIFF should work with the version of itkmkg3states, as
suggested in the paper. But I haven't tried that myself. I don't know how
to work with HDF5, and since I'm not using it, it's not my priority.
4. There are a few changes required to the code, in
itkFloatingPointExceptions.cxx and itkMutexLockNoThreads.cxx, because the
#ifdefs required there are not auto-detected by CMake properly.
5. Run make

Specific to iOS:
I used a toolchain, and a build script (runner.sh) which defines CFLAGS and
CXXFLAGS. Mostly, it's copied from here:
http://stackoverflow.com/a/6477393/11684 and modified a bit because it was
written for Bullet. Runner.sh itself tries to use the default configuration
(ITK_BUILD_ALL_MODULES is ON), so after it finished with errors, I went in
with cmake-gui and tweaked the modules to the list that would compile (see
above).

I'm not able to figure out if clang defines any iOS specific macros that I
can use to conditionally compile code, so I defined -D__APPLE_IOS__ in
CFLAGS and CXXFLAGS so that I could make code modifications to itk that
would be reasonably portable.

The modification I had to make to the source code itself is in
itkFloatingPointExceptions.cxx. The iOS API doesn't define feenableexcept
and fedisableexcept (I think those are not part of C99?). So I just defined
empty functions returning 0, as under "#if defined(__sun)" in the same
file. My modifications look something like this:

diff --git a/Modules/Core/Common/src/itkFloatingPointExceptions.cxx
b/Modules/Core/Common/src/itkFloatingPointExceptions.cxx
index 0bce9ce..7115c42 100644
--- a/Modules/Core/Common/src/itkFloatingPointExceptions.cxx
+++ b/Modules/Core/Common/src/itkFloatingPointExceptions.cxx
@@ -55,12 +55,7 @@
http://graphviz.sourcearchive.com/documentation/2.16/gvrender__pango_8c-source.h
 #endif // LINUX


@@ -427,6 +422,20 @@ void FloatingPointExceptions

 #else // defined( _WIN32 )

+#if defined(__APPLE_IOS__)
+// Added for iOS
+int feenableexcept(unsigned int)
+{
+  return 0;
+}
+
+int fedisableexcept(unsigned int)
+{
+  return 0;
+}
+
+#endif // __APPLE_IOS__
+
 void
 FloatingPointExceptions
 ::Enable()

Apart from this, no problems with iOS. It builds fine, and just works.

Specific to the iOS simulator:
The iOS simulator is actually an x86 native platform, and should be built
with the appropriate options. The only change from the iOS instructions is
to change CFLAGS in runner.sh to 'CFLAGS="-arch i386 -isysroot $SYSROOT
-miphoneos-version-min=4.0 -D__APPLE_IOS__"'. Otherwise, everything works
just fine.

Specific to Android:
I hunted around for a good toolchain I could use for Android, and finally
after several failures, I tried the one distributed with VES, which itself
comes from OpenCV, and this one works out of the box. The other toolchains
I found online (http://code.google.com/p/android-cmake/ for example) fail
when testing for endianness, which had me stuck for a very long time. But
the OpenCV toolchain works fine. To use this toolchain, one exports
NDK_TOOLCHAIN_ROOT=/path/to/android/ndk in the shell, and then runs cmake
with the usual options. Again, I went in and disabled those modules that
wouldn't compile - the same ones as for iOS.

Two code changes are required. In itkMutexLockNoThreads.cxx. I don't think
this is Android specific; this file seems to doubly define stuff that's
already defined in itkMutexLock.cxx. It's out of sync with the other
platform-specific itkMutexLock*.cxx files which are its siblings. The code
change is below:

diff --git a/Modules/Core/Common/src/itkMutexLockNoThreads.cxx
b/Modules/Core/Common/src/itkMutexLockNoThreads.cxx
index b38c2dc..0bb3ead 100644
--- a/Modules/Core/Common/src/itkMutexLockNoThreads.cxx
+++ b/Modules/Core/Common/src/itkMutexLockNoThreads.cxx
@@ -29,12 +29,6 @@

 namespace itk
 {
-// New for the SimpleMutex
-SimpleMutexLock * SimpleMutexLock::New()
-{
-  return new SimpleMutexLock;
-}
-
 // Construct a new MutexLock
 SimpleMutexLock::SimpleMutexLock()
 {
@@ -87,8 +81,4 @@ void SimpleMutexLock::Unlock()
 #endif
 }

-void MutexLock::PrintSelf(std::ostream & os, Indent indent) const
-{
-  Superclass::PrintSelf(os, indent);
-}
 } //end namespace itk

The other code change is in itkFloatingPointExceptions.cxx, to work around
a rather strange bug in the Android NDK. In fenv.h, the code starts wtih
__BEGIN_DECLS and ends with __END_DECLS, which should be defined to an
'extern "C" {' and '}' when compiling with C++. This is defined in
sys/cdefs.h in the NDK include directory
($NDK_ROOT/platforms/android-8/arch-arm/usr/include/sys/cdefs.h in my
case). This is not included in fenv.h, so we don't get these definitions,
and so when CMake tries to detect the presence of fenv.h, its test compile
fails and it sets ITK_HAVE_FENV_H to FALSE. Fixing this would either
require changes to the NDK or to CMake, so instead, I just removed the
conditional ITK_HAVE_FENV_H  in itkFloatingPointExceptions.cxx as below
(yeah, it should really be macro based like I did for iOS above, but I got
lazy towards the end):

diff --git a/Modules/Core/Common/src/itkFloatingPointExceptions.cxx
b/Modules/Core/Common/src/itkFloatingPointExceptions.cxx
index 0bce9ce..7115c42 100644
--- a/Modules/Core/Common/src/itkFloatingPointExceptions.cxx
+++ b/Modules/Core/Common/src/itkFloatingPointExceptions.cxx
@@ -55,12 +55,7 @@
http://graphviz.sourcearchive.com/documentation/2.16/gvrender__pango_8c-source.h
 #endif // LINUX


-#ifdef ITK_HAVE_FENV_H
-#include <stdio.h> // needed on Solaris
 #include <fenv.h>
-#else
-#error "fenv.h required for floating point exception handling"
-#endif

 #define DEFINED_PPC      (defined(__ppc__) || defined(__ppc64__))
 #define DEFINED_INTEL    (defined(__i386__) || defined(__x86_64__))

With these changes, everything compiles!

Testing and using my builds:

For iOS, I've compiled a simple program that just allocates an
itk::Image<unsigned char> on a button click. Just a canonical hello
world... I've run this on the simulator, but not on the device as of now
(I'm yet to pay the $99 Apple Tax).

A small note: The UIImage import/export classes at
http://www.midasjournal.org/browse/publication/760 seem to be a rather
roundabout way of doing things! Here's a code example from that paper:

		grayReader->SetImageIO(imageIO1);
		imageIO1->SetFileName(image.image);
		grayReader->SetFileName("UIImage");
		grayReader->Update();

Setting a file name as "UIImage" to a reader object?

I'd suggest that doing something like what the itk-vtk glue does would be
much better. Having an itk::ImageToUIImage and an itk::UIImageToImage pair
would be a lot more symmetric in my opinion. I'm going to try that sometime.

I haven't yet tried it out on Android. Once I write a more substantial
application, I'll post again.

So, summing up, some observations and questions:
1. Cross-compilation was actually _easier_ than I expected, as long as
toolchains were used. But it could be easier. Maybe we should have the
toolchains included with ITK, like VES is doing?
2. The resources on the web are outdated! They need to be updated...
3. Some code changes are required, which need to be reviewed.
4. What does itkmkg3states in itkTIFF actually do? Can we find another way
to do what it does while cross-compiling? It seems to me that this would be
a persistent problem for all cross-compiled builds (even, for example,
MinGW compiling on a Linux host).
5. We should try with vtk-modular and see if the itk-vtk glue can't be
coaxed to compile.
6. What about VES integration?
7. In general, I suggest setting CMAKE_INSTALL_PREFIX and installing the
headers and libraries. This makes it MUCH easier to configure XCode (and
I'm sure, the Android NDK also).

In all the above, I was just following from one step to another. I'm sure
the process could be simplified and improved. Anyone else have ideas on
this account?

One thing I should really do is go back and edit the iOS toolchain to
include CFLAGS and CXXFLAGS like the Android one does. This makes things a
LOT simpler. Also, it would be good if we could auto-detect those modules
that cannot compile, and disable them. It's a pain, having to go back and
reconfigure everything.

Maybe we should write this up as a Wiki article? I'd like it if someone
else could replicate these results, so that I know that they are repeatable.

Hope this helps others...

Shash
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.itk.org/pipermail/insight-users/attachments/20120414/6e47528a/attachment.htm>


More information about the Insight-users mailing list