As a part of the Columbus Project (Colby’s Robot Remote Controller for iPhone), I had to devise a way of tapping into existing communication protocol. Since the ecosystem (GCM and nav-devel) used to steer and communicate with the robots is built atop IPC by Carnegie Mellon, the easiest way would be to incorporate the IPC source into the iPhone source.
Having a lot of problems with compiling IPC into iPhone app, I planned to just write a wrapper that would run alongside IPC on a robot development system. On January 19, while I was cleaning up the files, including IPC trunk and I noticed the lib/ folder. It turns out that as a side effect of Make, a .a file is created, namely libipc.a - that contains a complete IPC library with all features packed into a single file. After a few hours of messing with the code, Makefiles, iPhone simulator and a dozen of coffees, I managed to get a libipc.a that works fine on iPhone.
Some hints for anyone who tries to accomplish anything similar, or has to deal with something that does not support autoconf are below.
First problem, is that Apple deprecated (probably) support for some code used by logging procedures in IPC. The easiest solution is to open src/logging.c file and comment out a section from lines 445 to 463. It regards obtaining time when data is saved to the log, something that will be abundant on iPhone anyway. After that, the compilation (without any further changes described below, i.e. for Darwin or Mac OS X desktop) should run just fine.
Then, to create IPC library, make sure to find the right Makefile containing the CC and CPP references. In this case, they are contained in etc/ and we are interested particularly in GNUmakefile.defs. You have to edit the defs file to relate to the right GCC and G++ compilers on your development Mac, since using ARM flags on default GCC/G++ will crash them (Apple axed ARM support from default installation). You will find right compilers in (/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin). You will need to configure the compiler with a -arch armv6 flag, as follows (lines 252 and 253):
CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc -arch armv6 CCC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/g++ -arch armv6
However, with such settings, the system libraries and includes (i.e. stdio or math.h) may not link properly, so to replace them in your GNUmakefile.defs (lines 215 and 216):
PUBLIC_INC_DIR = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.2.sdk/usr/include PUBLIC_LIB_DIR = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.2.sdk/usr/lib
Afterwards, just a normal make should suffice, but I came across a missing header, namely stdarg.h. Copying it from /Developer/Platforms/iPhoneOS.platform/Developer/usr/lib/gcc/arm-apple-darwin9/4.2.1/include into the IPC’s src folder was the quickest solution and worked just fine.
The compilation will crash on the way (remember to do a make in src/), due to impossibility of compiling Java libraries and some XDR problems. However, at this point, inside src/lib/Darwin-10.2.0 you should be able to find a complete ARM version of your library. (easy way to check it, is by running the central located in the src/bin/Darwin-10.2.0 folder - if it crashes due to architecture, you are golden).
For ease of development I recommend to do at least one more compilation with i386 flag for architecture (now, just normal gcc and standard libraries will suffice), since the simulator (Aspen) and real device use the same codebase, and ARM version will not run inside aspen. (note - on 64-bit enabled OS X the libipc.a will by default compile for x86_64) After compilations, you should merge them into a fat library using following command:
lipo -output libipc.a -create arm/libipc.a i386/libipc.a x86_64/libipc.a
Result should be a single libipc.a file, that when queried with file command in terminal, should return a following list:
libipc.a: Mach-O universal binary with 3 architectures libipc.a (for architecture armv6): current ar archive random library libipc.a (for architecture i386): current ar archive random library libipc.a (for architecture x86_64): current ar archive random library
Note: using libipc.a on your iPhone will actually not occupy more runtime memory, since the x86_64 and i386 architectures will be automatically stripped as a part of runtime.
After libipc is compiled and merged, it is time to use it inside the project and confirm everything is fine. Open Xcode (and create iPhone project for Window-based Application if not created yet), and drag libipc.a into Frameworks folder of your project, and libipc.h (placed in main IPC /include folder) into Other Sources. If queried, copy the file into the project. Result should look as on the left.
Then, open the Appdelegate.m file and import the IPC header on the top:
Next, in applicationDidFinishLaunching method add following, after making window visible:
IPC_connectModule("Hello, world", "YOUR_IP");
Note: since IPC_connect requires environmental variable CENTRALHOST, and there is no comfortable way of configuring env variables on iPhone, it is better to use a backup method for this. Furthermore, IPC_connectModule it allows one to use dictionary settings or Bonjour for detecting devices on the network (as host can be changed dynamically)
Building and running this, should effect in what is shown on the top of the page. If the build crashes, it will be due to the fact that unsupported library architecture is run (i.e. ARM on i386 or i386 on ARM) - then check, if the libipc.a copied into the project really contains the required architectures.
Further trials can be done by copying ipcTest1 content into the AppDelegate, modifying it to use connectModule, and referencing it from applicationDidFinishLaunching - when run, it will subscribe to central running on a main computer and work fine.
Similar regime can be followed for other libraries built atop IPC (svm, nav, gcm) - which indeed were compiled successfully and were used later to create the robot controller. At the moment, compiled a version 1.0 of fat versions of libraries can be downloaded directly from this page. Each of them contains x86_64 i386 and ARM v6 architectures. GCM does not play well in i386 architecture, but this should be fixed in a future release.
Last friendly hint - IPC Makefiles do not like spaces in the full directory names. So, if the IPC is placed in JanPlan 2010, it will not compile - but in JanPlan2010, it will.
Now IPC works completely!