Monday, August 25, 2014

Dominator Update..

I still haven't found the time to get back to the Dominator, but here is a little animation that I made from the first run I did a couple of months ago.


The animation shows streamlines over the vehicle as it is rotated through (almost) 360 degrees.  The inputs to the simulation are fairly arbitrary at this point, so I'm not claiming that any of this is very accurate.  That said, here are the lift and drag coefficients plotted vs simulation time.



 

Here are a few observations..
  • The lift and drag forces are many times higher when the wind is incident on the sides of the vehicle.  Not surprising seeing how cars are designed to go forward, not sideways.  However, it does provoke some thoughts as to how you might design a vehicle that minimizes forces over the entire range of possible wind directions.
  • There is no orientation that produces any sort of down force.  In fact, the lift is always at least equal to, and in many cases significantly greater than the drag.  It's possible that this model is missing any effects due to flow moving under the chassis in the real world. 
  • The rotation rate that I used is probably influencing the results since the symmetric model should produce identical force profiles if each incidence was run as a steady state solution.  It was just the easiest way to get the flow solver to give me a nice set of data for the animation. :)
 At some point I'd like to re-run this case at a higher resolution and then plot the results in physical units.


Wednesday, May 7, 2014

Dominator! Part 1: Introduction and CAD Modeling

Ok.  So it's been over a year since my last post and all of my posts for the year before that were about programming on Android.  Well, I can only say that I've been busy with my day job (and a new baby!), so there really hasn't been much time for anything else.

That said, I do have a few things that I'd like to share, so I'll start with what is probably the coolest.
If you know what this is already, then I doubt that I need to explain too much more about what I'm trying to do here.  If you don't know what it is, then here are a few more pictures to fill you in.
http://en.wikipedia.org/wiki/SRV_Dominator
This is the latest 'Dominator' storm chasing vehicle developed by meteorologist Reed Timmer.  It is basically an armored Ford Super Duty pickup that is intended to allow storm chasers to get really close to a tornado with minimum risk.  I've personally never chased a storm, but living here in Norman Oklahoma, I know that it is something people do, and who knows, maybe I'll give it a try sometime to see how bad it is.. just once. ;)

Last year we had by far the scariest severe weather season in the nearly ten years that I've lived in Norman with the May 20th and May 31st tornadoes.  The destruction in some parts of Moore was nearly total and more than two dozen lives were lost in the storms including, tragically, children who were at their elementary school.  As terrible as that was, the general consensus is that things could have been much worse without the advance warning that was given in part due to the efforts of Mr. Timmer and others.

Ever since then, it's been in the back of my mind to do something with one of these chase vehicles.  I chose the Dominator 3 for a few different reasons, but mostly because it is one that I might actually get to see up close at some point and it looked reasonably easy to build a 3D model of.

As a personal challenge, I decided to see what I could do with just the pictures of the truck that I have posted above.  Well, maybe I'm a little bit lazy and didn't want to take the time to bug the guys who built it for more information.

So, given just a few pictures of something, how do we go about turning that into a 3D model?  Well, it's actually not that difficult if you have a little patience and the right tools.  Honestly, my CAD skills have atrophied a lot over the years, so I'm sure that any number of people I know could have done this part better, but I suppose I got the job done.

Here's how..

Find an image that is reasonably close to a 2D projection of the object.  I started with this front view.
In a perfect world this would be an image taken from a distance with a telephoto lens to minimize perspective distortion, but I think this one is a decent starting point.  The next piece of the puzzle is a good vector drawing program.  Adobe Illustrator would be a candidate if I had it, but luckily for me, the open source Inkscape program does the job nicely.
It should be obvious why I though this geometry would be fairly easy to work with.  Most of the surfaces are planar, so it was no problem tracing lines over the welds that keep all those nice armor plates together.  The vector drawing program then spits the traced lines out as a CAD friendly .dxf file that drops right into the ten year old seat of Pro Engineer that I keep around for just these sorts of things.
Honestly, I have a long term goal of finding a good open source CAD package for these occasions, but there are very few non-commercial options right now.  Before anyone says Blender I just want to point out that it doesn't really do NURBS, or IGES output, so it can't provide what I need (yet).  The Open Cascade based package Salome might actually have all of the necessary bits, but I'm too far down the learning curve at the moment to use it effectively.

I also did some work in Inkscape on the rear quarter view.
Here is a good example of why perspective throws such a big wrench in things.  If it was a good parallel projection then I could have made a matching view plane in CAD and then projected that into a side view and got some useful information.  As it is, the only thing it was really good for was to allow me to count the number and relative placement of the weld lines on the rear of the vehicle.  Close enough for government work, as my dad used to say.  No offense to my friends at NASA ;)

This is where things get a little dicey.  Without a good side view, I was forced to estimate how far to push all of the vertices from the Inkscape lines to create the final 3D geometry.  I basically worked on it one night until I got too tired to keep going and called it good.
Once I had that, the rest wasn't bad at all.
TA-DA!

Faking in the mirror, windows and grill details actually took a lot less time than getting the surfaces where I was happy (enough) with them.  As you can see, symmetry is our friend.  If I had to guess, I would say that I missed the windshield rake by 10 or 15 degrees and the hood seems too short looking at it now, but overall I think it turned out decent.

Stay tuned for part two where I'll talk about generating the computational grid and setting up the flow solver.

...


Tuesday, September 11, 2012

Android Rotation Exploitation...

Here is something that took me a whole week of late night head scratching, so I thought I would put it out here just in case someone else needs it (and so I won't forget how I did it).

The Goal:

"Figure out which way is down on an Android tablet"

The Challenge:

"Down means something different to a tablet and a phone"

The Problem:

Android says.. "NONE SHALL PASS (without JNI)"

Well, just paraphrasing that last part, but that's how I felt after about twenty hours of pain.  The funny part of all of this is that, according to the Android documentation:

DEFINITION: NativeActivity
Convenience for implementing an activity that will be implemented purely in native code. That is, a game (or game-like thing). There is no need to derive from this class; you can simply declare it in your manifest, and use the NDK APIs from there.

Hmm... a game (or game-like thing).  No need to derive from this class, you simply use the NDK APIs from there.  Seems reasonable to me that a game might need to know which way the screen is turned.  Forgive me if I am mistaken, but.. THERE IS NO NDK API THAT WILL TELL ME THE DEFAULT SCREEN ORIENTATION FOR MY DEVICE.

Of course, if you are writing your code in Java then your life is good (well you've got other problems, just not this particular one):

http://developer.android.com/reference/android/view/Display.html#getRotation()

This nice little function gives you a number from 0-3, which tells you exactly what the current screen rotation is compared to the default for the device.  Since I've been working on an app that uses the accelerometers along with landscape orientation whether running on a phone or a tablet, I kind of need that little bit of information.  I won't bore you with the details of all of the blind alleys I went down getting this to work, but things started looking up when I came across:

http://stackoverflow.com/questions/6838397/how-do-i-load-my-own-java-class-in-c-on-android

Since I know very little Java (and only a little more C++), this has been a true education.  If you want the same education, then go ahead and add getRotation() to the native-activity example that comes with the NDK.  If you can do it in fewer than 50 lines of code then you've earned my respect and admiration... also, do you mind if I use your code?

Here is the final procedure that worked for me:
  1. Add a Java file that extends the NativeActivity class that is instantiated when the app is launched.
  2. Override the NativeActivity class onCreate method to call getRotation() and store the result in a public static variable that will be exposed through JNI.
  3. Modify AndroidManifest.xml to reference the new Java class instead of the original android.app.NativeActivity
  4. Add a JNI_OnLoad function to the native code in jni/main.c so it can cache a handle to the virtual machine and references to the objects that will be called back through JNI.
  5. Add a new function to main.c that attaches the native activity thread to the virtual machine, calls back for the getRotation value, and then detaches the thread.
  6. Call the new function AFTER initializing the screen in native code.  I found this out the hard way.. since the native activity is in its own thread, the JNI_OnLoad function call can lag behind the native activity, resulting in bogus getRotation results on startup.
All that to get a simple 0 or 1.. well, it's actually 0, 1, 2, or 3, but I only care about the first two right now.

... and Google seems to wonder why people prefer to develop for that other (i)OS

If you want to see the gory details, this link contains the whole Android project:

https://dl.dropbox.com/u/97874334/Native_getRotation.tgz

or, if you just want to play with the app..

https://dl.dropbox.com/u/97874334/NativeRotation-debug.apk




Thursday, August 16, 2012

Something Borrowed... (Android Fortran)


OK.. I think I need to apologize to some people who have been trying to re-create the Android Fortran compiler for themselves with varying degrees of success.  I should also heartily congratulate those who have managed it.  As it turns out, I had unintentionally provided a single point failure in one of the steps and did not catch it until I tried to recreate the toolchain from scratch myself.

So.. um.. sorry.

As penance, I decided to torture myself with a couple of days in bash script hell with the goal of creating a fully automated installer for the Fortran enabled NDK.

And so, I present to you:

A lovely bunch of coconuts

Android_Fortran_NDK_Installer_r8b.sh

Android_Fortran_NDK_Installer_r8d.sh


I've only tested it under Ubuntu 12.04 and Fedora 16/17/18, but it should *theoretically* work with other Linux distributions.

...and, so you have something to try it out on, here is a ready to go command line version of Linpack to shake down your new compiler.

Linpack_Android.tgz

Instructions:
  1. Right click and save the script at the link above (the first one)
  2. Open a terminal
  3. cd to where you want the NDK to live
  4. Run it!
    • /bin/bash ~/Downloads/Android_Fortran_NDK_Installer_r8b.sh
  5. Follow the prompt to install dependencies
  6. Wait for it to download and build everything
  7. Wait...
  8. Wait...
  9. Wait...
 You should now be able to find the shiny new compilers here:

{install-path}/android-ndk-r8b/toolchains/arm-linux-androideabi-4.8.0/prebuilt/linux-x86/bin

Little Notes:
  • You do not need to download the NDK.. the script will do it for you.
  • You mush have an active Internet connection.
  • Right now, only the arm compiler is built.  If you want x86 or MIPS it probably wouldn't be that much extra work, but I don't really see the point right now.
  • It needs to be run somewhere you have write permissions.. do not sudo it or install it as root user.
  • It looks for evidence that it has been installed in your .bashrc file before adding itself to it.  You should probably remove any existing NDK references from your .bashrc before you run the script.
  • It tries to detect whether the host OS is 32 or 64 bits and adjusts a couple of things accordingly.
  • The GCC sources are HUGE.. you can safely remove them if the script finishes successfully... rm -rf android-ndk-r8b/src
  • It relies on some files I put on Dropbox.. if you don't trust me then don't run it.. ;)
  • Seriously.. you should never run a script you got from some guys blog.
  • No warranty expressed or implied.
BIG NOTES:

This script will not install the Android SDK or Eclispe, or ADB, or Netflix, and it will definitely not write Fortran enabled Android apps for you.  The important thing here is that you will have Fortran in your NDK.  How you use it is between you and your therapist.  As I've said before, there are some workarounds in the NDK build scripts that are very hackerlicious and have been rejected by Google for inclusion in the official NDK. (or so I've been told, I never submitted them myself)

I'd like to mention here that I never intended to become the de facto, ipso facto (or any other facto) subject matter expert on running Fortran on Android.  However, as it appears that is exactly what I have become, I think would be great to put some pressure on Google to do this so it gets done "right" (and so I don't have to anymore).

Here is how they can partially atone for their love of Java:
  • Add --enable-languages support to the NDK build-gcc.sh script.  I've looked at the helper scripts and they've already started putting in the dependencies for graphite loop optimizations.  There used to be issues with the upstream gfortran sources, but those are fixed.. Fortran is seriously a gimme!  I'm also suspecting that they are working toward adding OpenMP support soon.. at that point Fortran starts looking very interesting to us engineer types.  Not to mention all of the other languages that are 100% working in GCC!
  • Add some sort of generic flag passing for 'unsupported' compilers.  Right now I'm hijacking some of the code they put in for C/C++ but it ain't pretty.
  • Make Eclipse conscious of when the native code changes.. or at least put in a f***ing button to build the native library!  Update: OK.. this does work, at least with Eclipse Juno and ADT 20.0.3.  The Eclipse Photran plug-in even works with it.  I can build and deploy an entire Fortran enabled app directly from Eclipse! WHOO-HOO!!!  As bad as Eclipse is.. I believe it now finally edges out my previous workflow, which was a bunch of terminals and Vim windows. +1 Google
I've accepted (and am learning to live with) the Java container that my code has to run in to be an actual 'App'.  HOWEVER, I have to say that I've learned far more from looking at the platform header files than I have from the documentation that is provided by Google.  As a Android developer, I would like to feel like Google is standing behind me, offering support and guidance.  Unfortunately, as an Android *NDK* developer I feel like they just came up and shoved me off the diving board without my floaties on!  And it ain't the Fortran either, believe me.  Talk to anyone who has tried to do this in C or C++.




Thursday, May 17, 2012

Finally... My First Android/Fortran App!




I'm trying out Google Drive for the first time, so hopefully, you can download the Android project files for this app here

Or just grab the app here and let me know in the comments if it works for you.  The app is the result of porting the Julia set fractal Fortran code from this page.  I added a simple OpenGL rendering capability along with a little randomization of the control parameters so it generates something different each time the screen is touched.  The video above shows it running on my Droid Bionic.  The render time can vary drastically depending on the complexity of the fractal.  After running it a few times, I realized that it actually makes a very convincing image of a migraine aura.  That's a bummer too, since it almost gives me a headache looking at it now!

I know it was quite a while ago that I promised to post an example of how to build and actual Android application using Fortran.  As usual, getting the app built was the easy part while finding the discipline to sit down and type up this post has turned out to be the hard part.

As a happy side-benefit of my procrastination, I've managed to update my toolbox to the latest Android NDK version (r7).  Also, in the meantime, the very smart people over at the GCC project have improved their support for building the compilers, so it is much easier to get the job done now.  As a matter of fact, the job is so easy now that I've decided to make a little patch file that should take care of fixing the few things that are left in the NDK package itself.  update -- as a side-benefit of my further procrastination, NDK r8 is now out... :(

To recap:

Set up your build machine.
Build your custom android compiler.
Configure the NDK build tools.

Now that we have a working tool set, it's finally time to talk about how we will make our Fortran code talk to the Android system.
This is where the magic of iso_c_binding comes in.  The example below is a bit of the 'glue' that I am using to draw via OpenGL ES directly to a context on the device that is set up using C code derived from the "NativeActivity" example in the Android NDK.  I would like to thank the people behind the F03GL project since the code that they provide for binding the older desktop OpenGL to Fortran required only a couple of simple tweaks to work with the OpenGL ES 1 version that is part of the NDK.  I've also started building interfaces for the ES 2.0 functions and have most of the basic ones working.  Once I have a more complete set, I'll post that as well.

Have a look at this code..


MODULE OpenGL_GL
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
PUBLIC
INTEGER, PARAMETER :: GLenum=C_INT, GLfloat=C_FLOAT

INTEGER(GLenum), PARAMETER :: GL_NEVER                 = z'0200' ! 0x0200
INTEGER(GLenum), PARAMETER :: GL_LESS                  = z'0201' ! 0x0201

INTERFACE
  SUBROUTINE glTranslatef(x, y, z) BIND(C,NAME="glTranslatef")
  IMPORT
  REAL(GLfloat), VALUE :: x, y, z
  END SUBROUTINE glTranslatef
END INTERFACE
END MODULE

The basic idea is this:

  1. Create a module to hold all of your C interfaces
  2. If your targeted C library (in this case OpenGL) requires special types then define those first.. in this case it is the GLenum and GLfloat types that are used all over OpenGL code.  Of course there are many others, so see the source code for more examples.
  3. If your targeted C library uses enumerators (OpenGL uses tons!) define the enumerators as parameters (using the special types if applicable).  Examples are GL_NEVER and GL_LESS above.
  4. Create interface blocks for each C library function that you want to use.  If you don't need every function in a library then don't feel obligated to expose it with an interface.  Of course, while you're in there you might as well do as many as you can, right? ;)
  5. Use the module in your Fortran code.
  6. Link the C library to your executable at compile time ( -lGL or whatever).
  7. Marvel at the vast new capabilities that you will now be able to wield along with your Fortran kung-fu.
The above code is actually a really nice example of how the iso_c_binding module can be used to talk to most any C library function.  This is something that has been possible in Fortran in the past, but was much more difficult (and buggier).  It also makes it convenient to go the other way, making a Fortran function callable from C/C++... I use this too ;)

! in the Fortran code, do this... 
use iso_c_binding 
integer(c_int) function fortran_add(variable1,variable2) bind(c)
  integer(c_int), intent(in), value :: variable1,variable2
  fortran_add = variable1 + variable2
end function fortran_add

! in the C code, call it like any other function..
 int cvariable1 = 2;
 int cvariable2 = 2;
 int cvariable3 = fortran_add(variable1,variable2);
! cvariable3 should now be 4
! wasn't that easy...

This is exactly how I pass the screen dimensions from the Android virtual machine to the Fortran functions in the example app.  See the call to "fortran_init_gl" in jni/main.c file in the example source.

The rest is really just standard Android NDK, which isn't documented particularly well, but should be google-able enough by now for most issues that you might run into.  The procedure goes something like this:

  1. Put your C and Fortran sources in the jni folder in your project.
  2. Add your C and Fortran sources to the jni/Android.mk makefile
  3. Set appropriate compiler flags in jni/Application.mk.  I didn't add any options for specific build levels (debug, release, etc.) to the NDK toolchain for Fortran, so you need to put them in here.
  4. Run ndk-build in your project folder
  5. Deploy the app to your device the usual way (ant or eclipse).
I hope someone out there besides me finds this useful!  With any luck, I'll be able to start talking about the super-secret project that has been the motivation behind all of this insanity from the start.  Please feel free to bug me in the comments if I don't get something posted in a month or two...

Friday, October 21, 2011

Android Fortran Step-by-Step Part 3: Bringing it All Together

*** There is now a better way! ***
***UPDATED For NDK-r7***
Now that we have a working Fortran compiler for our Android hardware, it's time to show the NDK tools how to use it to build native applications.  Be warned:  I am not pretending to be a master of the GNU make system and I have done the minimum amount of hacking required so this will work for my own use... YMMV

If you haven't spent any time using the Android NDK then this will probably not be very informative.  Still, I am guessing that anyone who has gotten this far probably has at least tried to build the example applications that come with the development kit.  Specifically, I am referring to the Native Activity example, which is the only one I've seen so far that uses 0% Java and 100% native C code.  My original plan was to gut most of the C and replace it with calls to Fortran routines packaged as a library with interfaces bound to the skeleton C code via ISO_C_BINDING.  As I'm planning to demonstrate in the near future, this works well within reason.

I've also decided to avoid using Eclipse for the time being and stick to doing everything with text editors (gvim) and the command line.  The main reasons for this is that the Fortran plugins for Eclipse are not great and the apk package refuses to rebuild when changes are made to the native source files... I've really tried to like Eclipse, but I just can't shake the opinion that it's difficult to install, bloated, buggy and really only meant for Java programming.  I suppose if I was a computer science major in college then I would probably be hooked on some IDE or other, but I wasn't, so I'm not.  Give me a text editor with decent syntax highlighting and a compiler that produces reasonable debugging information and I'm happy.

On with the show...

Step 1:  Prep the new toolchain for the ndk-build script

The GNU Make based native build system needs a couple of things before it will recognize the new compiler.  The first thing to do is to copy two files from the old toolchain directory into the new one:

Starting in the NDK toolchains directory; if you are following the previous instructions, that will be here:

/opt/Android/android-ndk-r7/toolchains

cp arm-linux-androideabi-4.4.3/config.mk arm-linux-androideabi-4.7.0/
cp arm-linux-androideabi-4.4.3/setup.mk arm-linux-androideabi-4.7.0/

Now, if you built the 64-bit versions of the compiler executables, you will need to fake out the build script by making a symbolic link from the (non-existant) 32-bit tools to the 64-bit ones.

cd arm-linux-androideabi-4.7.0/prebuilt
ln -s linux-x86_64 linux-x86

Step 2: Add gfortran support to ndk-build

This was by far the hardest part for me since I am not a shell scripting master and definitely not a Make system master, but the result works well enough, although it could be much better I'm certain.  I would just make some diff patches, but I don't have a reliable way to post them here, so I'll just put the text of the changes in their entirety with instructions as to where to put them.

The first thing to do is to set an environment variable that tells the NDK which toolchain to use.  Add the following to your ~/.bashrc file:

export NDK_TOOLCHAIN=arm-linux-androideabi-4.7.0

(remember that you need to start a new terminal for the variable to be used)

UPDATE: If you followed the new instructions in the previous post then skip the next section and go straight to the bottom.. you're done!


Edit this file:

/opt/Android/android-ndk-r6b/build/core/build-binary.mk
Change line 195 to this:

all_source_extensions := .c .s .S $(LOCAL_CPP_EXTENSION) .f .f90

Add these lines starting at line 223:

# handle free-form Fortran (.f90)
$(foreach src,$(filter %.f90,$(LOCAL_SRC_FILES)), $(call compile-f90-source,$(src)))
# handle fixed form Fortran (.f)
$(foreach src,$(filter %.f,$(LOCAL_SRC_FILES)), $(call compile-fc-source,$(src)))

Edit this file:

/opt/Android/android-ndk-r6b/build/core/default-build-commands.mk

Add these lines starting at line 93:

TARGET_FC       = $(TOOLCHAIN_PREFIX)gfortran
TARGET_FFLAGS   =

Now for the big one...

Edit this file:

/opt/Android/android-ndk-r6b/build/core/definitions.mk

Add this chunk starting at line 1040:

# slightly modified version for Fortran source files
define ev-build-fc-file
$$(_OBJ): PRIVATE_SRC      := $$(_SRC)
$$(_OBJ): PRIVATE_OBJ      := $$(_OBJ)
$$(_OBJ): PRIVATE_DEPS     := $$(call host-path,$$(_OBJ).d)
$$(_OBJ): PRIVATE_MODULE   := $$(LOCAL_MODULE)
$$(_OBJ): PRIVATE_TEXT     := "$$(_TEXT)"
$$(_OBJ): PRIVATE_CC       := $$(_CC)
$$(_OBJ): PRIVATE_CFLAGS   := $$(_FLAGS)
$$(_OBJ): $$(_SRC) $$(LOCAL_MAKEFILE) $$(NDK_APP_APPLICATION_MK)
    @mkdir -p $$(dir $$(PRIVATE_OBJ))
    @echo "$$(PRIVATE_TEXT)  : $$(PRIVATE_MODULE) <= $$(notdir $$(PRIVATE_SRC))"
    $(hide) $$(PRIVATE_CC) $$(PRIVATE_CFLAGS) $$(call host-path,$$(PRIVATE_SRC)) -o $$(call host-path,$$(PRIVATE_OBJ))
endef

# This assumes the same things than ev-build-fc-file, but will handle
# the definition of LOCAL_FILTER_ASM as well.
define ev-build-fc-source-file
LOCAL_DEPENDENCY_DIRS += $$(dir $$(_OBJ))
ifndef LOCAL_FILTER_ASM
  # Trivial case: Directly generate an object file
  $$(eval $$(call ev-build-fc-file))
else
  # This is where things get hairy, we first transform
  # the source into an assembler file, send it to the
  # filter, then generate a final object file from it.
  #

  # First, remember the original settings and compute
  # the location of our temporary files.
  #
  _ORG_SRC := $$(_SRC)
  _ORG_OBJ := $$(_OBJ)
  _ORG_FLAGS := $$(_FLAGS)
  _ORG_TEXT  := $$(_TEXT)

  _OBJ_ASM_ORIGINAL := $$(patsubst %.o,%.s,$$(_ORG_OBJ))
  _OBJ_ASM_FILTERED := $$(patsubst %.o,%.filtered.s,$$(_ORG_OBJ))

  # If the source file is a plain assembler file, we're going to
  # use it directly in our filter.
  ifneq (,$$(filter %.s,$$(_SRC)))
    _OBJ_ASM_ORIGINAL := $$(_SRC)
  endif

  #$$(info SRC=$$(_SRC) OBJ=$$(_OBJ) OBJ_ORIGINAL=$$(_OBJ_ASM_ORIGINAL) OBJ_FILTERED=$$(_OBJ_ASM_FILTERED))

  # We need to transform the source into an assembly file, instead of
  # an object. The proper way to do that depends on the file extension.
  #
  # For C and C++ source files, simply replace the -c by an -S in the
  # compilation command (this forces the compiler to generate an
  # assembly file).
  #
  # For assembler templates (which end in .S), replace the -c with -E
  # to send it to the preprocessor instead.
  #
  # Don't do anything for plain assembly files (which end in .s)
  #
  ifeq (,$$(filter %.s,$$(_SRC)))
    _OBJ   := $$(_OBJ_ASM_ORIGINAL)
    ifneq (,$$(filter %.S,$$(_SRC)))
      _FLAGS := $$(patsubst -c,-E,$$(_ORG_FLAGS))
    else
      _FLAGS := $$(patsubst -c,-S,$$(_ORG_FLAGS))
    endif
    $$(eval $$(call ev-build-fc-file))
  endif

  # Next, process the assembly file with the filter
  $$(_OBJ_ASM_FILTERED): PRIVATE_SRC    := $$(_OBJ_ASM_ORIGINAL)
  $$(_OBJ_ASM_FILTERED): PRIVATE_DST    := $$(_OBJ_ASM_FILTERED)
  $$(_OBJ_ASM_FILTERED): PRIVATE_FILTER := $$(LOCAL_FILTER_ASM)
  $$(_OBJ_ASM_FILTERED): PRIVATE_MODULE := $$(LOCAL_MODULE)
  $$(_OBJ_ASM_FILTERED): $$(_OBJ_ASM_ORIGINAL)
    @echo "AsmFilter      : $$(PRIVATE_MODULE) <= $$(notdir $$(PRIVATE_SRC))"
    $(hide) $$(PRIVATE_FILTER) $$(PRIVATE_SRC) $$(PRIVATE_DST)

  # Then, generate the final object, we need to keep assembler-specific
  # flags which look like -Wa,
  _SRC   := $$(_OBJ_ASM_FILTERED)
  _OBJ   := $$(_ORG_OBJ)
  _FLAGS := $$(filter -Wa%,$$(_ORG_FLAGS)) -c
  _TEXT  := "Assembly     "
  $$(eval $$(call ev-build-fc-file))
endif
endef

...And this chunk at line 1213:

# -----------------------------------------------------------------------------
# Template  : ev-compile-fc-source
# Arguments : 1: single Fortran source file name (relative to LOCAL_PATH)
#             2: target object file (without path)
# Returns   : None
# Usage     : $(eval $(call ev-compile-fc-source,,)
# Rationale : Internal template evaluated by compile-fc-source
# -----------------------------------------------------------------------------

define  ev-compile-fc-source
_SRC:=$$(LOCAL_PATH)/$(1)
_OBJ:=$$(LOCAL_OBJS_DIR)/$(2)
_FLAGS := $$($$(my)FFLAGS) \
          $$(call get-src-file-target-cflags,$(1)) \
          $$(call host-c-includes, $$(LOCAL_C_INCLUDES) $$(LOCAL_PATH)) \
                     $$(LOCAL_CFLAGS) \
                    $$(NDK_APP_CFLAGS) \
          $$(LOCAL_FFLAGS) \
          $$(NDK_APP_FFLAGS) \
          $$(call host-c-includes,$$($(my)C_INCLUDES)) \
          -c \

_CC   := $$(TARGET_FC)
_TEXT := "Compile-fortran $$(call get-src-file-text,$1)"

$$(eval $$(call ev-build-fc-source-file))
endef

# -----------------------------------------------------------------------------
# Function  : compile-fc-source
# Arguments : 1: single Fortran source file name (relative to LOCAL_PATH)
# Returns   : None
# Usage     : $(call compile-fc-source,)
# Rationale : Setup everything required to build a single Fortran source file
# -----------------------------------------------------------------------------
compile-fc-source = $(eval $(call ev-compile-fc-source,$1,$(1:%.f=%.o)))
compile-f90-source = $(eval $(call ev-compile-fc-source,$1,$(1:%.f90=%.o)))

These are just slightly modified versions of the functions that handle C/C++ source code.  Once this is done, you should be able to put fixed form (.f) and free-form (.f90) Fortran source files in the jni folder of your native application, add them to LOCAL_SRC_FILES in ./jni/Android.mk, and then run ndk-build like normal to compile your Fortran into the shared library for your Android application.  If you are using Eclipse you should be able to build and deploy directly to your device, but remember that it will not regenerate the apk if you make changes to the source code (at least that's what happened to me).  If you are on the command line then you can use ant to build the apk and deploy it from within the project folder:

ndk-build -B V=1
ant release
ant install

When I find some more time, I'll put up an example of a working native application that demonstrates how to package some assets, move them to the device SD card and then use them to do something fun in Fortran using OpenGLES and the device sensors.

Thursday, October 20, 2011

Android Fortran Step-by-Step Part 2: Building a Custom GCC Toolchain

***There is now a better way!***
***Updated for NDK-r7*** 
 This part is relatively tricky.  I would never have gotten this far without the help of another clever person who needed a newer GCC toolchain for Android, but for a completely different set of reasons.

Thank you: http://glandium.org/blog/?p=2146

There are a lot of steps here, so I'll try not to clutter it up with jabber.  If you have completed Part 1, then you should be ready to dive right in and start cutting and pasting the following commands.  Maybe if I find some time, I'll make this into a shell or Python script that will automate the process, maybe not.

Step 0:  Get a few more required packages

sudo yum install subversion ncurses-devel flex bison texinfo

Step 1:  Get the NDK build package

This would normally be installed by the ./build/tools/download-toolchain-sources.sh script included with the NDK, but since kernel.org was hacked a couple of months ago that doesn't seem to be working.  Luckily it is available from the glandium.org post, so get it here:

https://bugzilla.mozilla.org/attachment.cgi?id=549787

Copy the ndk-build-r6.tar.gz2 file into /opt/Android/android-ndk-r6b and extract it there:
 tar jxvf ndk-build-r6.tar.bz2
You should now have a directory called:
 /opt/Android/android-ndk-r6b/src/build

UPDATE: The google source repositories are back, so you don't need to use the download-toolchain-sources.sh script.  Simply use git (yum install git if you don't have it already):

mkdir src
git clone https://android.googlesource.com/toolchain/build src/build

Step 2:  Put the GCC sources into your Android NDK install

cd /opt/Android/android-ndk-r7
mkdir -p src/gcc
svn export -r182917 svn://gcc.gnu.org/svn/gcc/trunk src/gcc/gcc-4.7.0
This will give you the exact set of sources that I used.  Depending on your connection speed this could also take some time to finish.  If you want to be adventurous, you can get the bleeding edge sources by omitting the -r182917 from the command above.  You can also use checkout instead of export if you want to be able to keep your sources up-to-date via 'svn update'.  Of course, as of the date of this post, this version IS the bleeding edge ;)

Step 3: Patch the GCC sources

There is an anoying 'bug' in the GCC gfortran configure process when building a cross-compiler (at least this one anyway).  Fortunately, this is much easier with the latest sources than it was the first time I tried it, but it still is a bit of a hack.

Open this file:


/opt/Android/android-ndk-r6b/src/gcc/gcc-4.7.0/libgfortran/configure
Change 'exit $1' on lines 279 and 26306 to 'echo $1'
This will keep the configure script from crashing because of a link test that can't be done for the cross-compiler.  If anyone has a more elegant solution to this then please post it in the comments!

Now open this file:


/opt/Android/android-ndk-r6b/src/gcc/gcc-4.7.0/libgfortran/io/unix.c
Add the following starting on line 1113:
#if !defined(S_IREAD) && defined(S_IRUSR)
#define S_IREAD  S_IRUSR
#define S_IWRITE S_IRUSR
#endif

This fixes a file permission issue when linking against the Android Bionic C library instead of the normal glibc.

Step 4: Get all of the extra sources you will need

There are a number of extra packages that are required in order to build a fully functional GCC cross-compiler.  These also need to be put in the right location for the Android helper script to use.  Note that the sources for gcc binutils and gdb need to be extracted, the others can stay packed up.

cd src
mkdir binutils
cd binutils
wget http://sourceware.mirrors.tds.net/pub/sourceware.org/binutils/snapshots/binutils-2.22.51.tar.bz2
tar -jxvf binutils-2.22.51.tar.bz2
cd ..
mkdir gmp
cd gmp
wget http://ftp.gnu.org/gnu/gmp/gmp-5.0.2.tar.bz2
cd ..
mkdir mpfr
cd mpfr
wget http://ftp.gnu.org/gnu/mpfr/mpfr-3.0.1.tar.bz2
cd ..
mkdir mpc
cd mpc
wget http://www.multiprecision.org/mpc/download/mpc-0.9.tar.gz
cd ..
mkdir gdb
cd gdb
wget http://ftp.gnu.org/gnu/gdb/gdb-7.3a.tar.bz2
tar -jxvf gdb-7.3a.tar.bz2
cd ..

!!!IMPORTANT!!!
Use the exact versions of each of the above that are shown.  There is a problem building with mpfr-3.1 and it will make it a lot harder for me to help you if you are using other versions!

You should now have a directory structure like this:

/opt/Android/android-ndk-r7/src:

ls *
src/binutils:
binutils-2.22.51  binutils-2.22.51.tar.bz2

src/build:
build-sysroot.sh  config.guess  configure     COPYING      dejagnu     Makefile.in
clear_header.sh   config.sub    configure.ac  COPYING.LIB  install-sh  README

src/gcc:
gcc-4.7.0

src/gdb:
gdb-7.3  gdb-7.3a.tar.bz2

src/gmp:
gmp-5.0.2.tar.bz2

src/mpc:
mpc-0.9.tar.gz

src/mpfr:
mpfr-3.0.1.tar.bz2


Step 5: Setting up the NDK helper script

The Android NDK comes with a nice script that takes care of most of the build process, as long as it knows where to find what it needs.  That requires a little bit of editing...

Open up:


/opt/Android/android-ndk-r6b/build/tools/build-gcc.sh

and make the following changes:


GDB_VERSION=7.3
BINUTILS_VERSION=2.22.51
GMP_VERSION=5.0.2
MPFR_VERSION=3.0.1

Add a new definition for MPC just below the one for GDB:


MPC_VERSION=0.9
register_var_option "--mpc-version=" MPC_VERSION "Specify mpc version"

Add a new option to control the languages that are to be built.  This can be placed anywhere in the upper portion of the script.  I placed it right under the line that starts: register_var_option "--keep-libstdcxx"


ENABLE_LANGUAGES="c,c++,fortran"
register_var_option "--enable-languages=" ENABLE_LANGUAGES "Experimental: specify which languages to build"

Now add the new definitions to the configure command about 2/3rds down in the script:


mkdir -p $BUILD_OUT && cd $BUILD_OUT && run \
$BUILD_SRCDIR/configure --target=$ABI_CONFIGURE_TARGET \
                        --enable-initfini-array \
                        --host=$ABI_CONFIGURE_HOST \
                        --build=$ABI_CONFIGURE_BUILD \
                        --disable-nls \
                        --prefix=$TOOLCHAIN_PATH \
                        --with-sysroot=$TOOLCHAIN_SYSROOT \
                        --with-binutils-version=$BINUTILS_VERSION \
                        --with-mpfr-version=$MPFR_VERSION \
                        --with-gmp-version=$GMP_VERSION \
                        --with-mpc-version=$MPC_VERSION \
                        --with-gcc-version=$GCC_VERSION \
                        --with-gdb-version=$GDB_VERSION \
                        --enable-languages=$ENABLE_LANGUAGES \
                        $ABI_CONFIGURE_EXTRA_FLAGS

UPDATE:
Since makefiles are notorious for crapping out due to invisible typos, I've decided to post a patch that should get your ndk-r7 directory all fixed up.

This patch for ndk-r7
or
This patch for ndk-r7b

Copy the above patch into your android-ndk-r7 directory and then patch as follows:

patch -p1 -i ndk-r7-fortran.patch

If it patches five files successfully then you should be ready to start the build...

Make sure you are in the NDK base directory:
cd /opt/Android/android-ndk-r7

Start the script and go to bed.. :)
./build/tools/build-gcc.sh --try-64 $PWD/src $PWD arm-linux-androideabi-4.7.0

If everything goes ok, this will take quite a while, possibly an hour or more. When it finishes, your shiny new Fortran enabled compiler suite will be here:
/opt/Android/android-ndk-r7/toolchains/arm-linux-androideabi-4.7.0/prebuilt/linux-x86_64/bin

Now you can remove the old compiler from your ~/.bashrc file and replace it with the new one (see the last post).
[mike@fedorocks bin]$ arm-linux-androideabi-gfortran --version
GNU Fortran (GCC) 4.7.0 20111019 (experimental)
Copyright (C) 2011 Free Software Foundation, Inc.

GNU Fortran comes with NO WARRANTY, to the extent permitted by law.
You may redistribute copies of GNU Fortran
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING

If you've made it this far then congratulations! You can now use your shiny new Arm enabled Fortran compiler just as you would your regular Fortran compiler.  I've already tested this with the Linpack benchmark as well as several other codes, so I am confident that it works.  While that is all well and good, our ultimate goal is to fix up the Android build system so we can put Fortran native code in our Android applications and pack them up for distribution on the Android Market.

Stay tuned...

Dominator Update..

I still haven't found the time to get back to the Dominator, but here is a little animation that I made from the first run I did a coupl...