Thursday, September 20, 2012

Hacking Static Libraries for iOS 6 with lipo and hex editing

I always seem to find myself compiling for a new version of iOS right before a release and without fail it always causes me to completely adjust how I was doing something.

This time around, it was iOS 6 and the armv7s instruction set:


ld: file is universal (3 slices) but does not contain a(n) armv7s slice


What the What?

What this linker error means is that your compiled static library isn't 'fat' enough. In plain terms, it means that when it was built, it wasn't built for (one of) your specified architectures, and it can't be applied to your project. This also occurred when the armv7 was introduced.

The Good News


Now, if you're in charge of that static library, you just need to add 'armv7s' in Build Settings -> Valid Architectures and you're ready to go! If you aren't, it get a little more hazy.

Given that it's an incremental release, the armv7s is completely backwards compatible (as of speculatory writing!) and can easily run armv7-compiled code. This means that it isn't strictly necessary to go about recompiling the code, but that it won't be able to use any fixes or speed increases that may be present in the new instruction set.

The Bad News

You can't specify mixing version types. In older versions of Xcode, that was something that could be set, but it's been a while since Apple made anything that easy.

In fact, Xcode is notorious for making lives hard when it really doesn't need to be. It seems that every version of Xcode, incremental or otherwise, comes with major shifts in implementation or distributed SDK's. Anyone who has tried to run Xcode 4 on Snow Leopard will know that without me needing to tell them that it is an arm-twisting mess. Being backwards compatible, being forward compatible, you name it, if it's not 'current' in the Apple development world, you'll jump flaming hoop after flaming hoop. iOS 6 is no different.

Compiling for iOS 6 automatically adds the 'armv7s' flag to your valid architectures. For those not using 3rd party libraries, that is not an inherently bad thing, and in fact is very likely the 'right' way to go about things. Those who make 3rd-party libraries are tasked with maintaining this compatibility and from what I've seen, are timely about doing it, but what happens when you're using something... a little outdated?

The Correct Way

As you may already guess, the 'right way' of doing things is to remove armv7s from your valid architectures and go about your business. If you guessed that, you'd be right! As I mentioned before, the armv7s is backwards compatible and as-of this writing, there is nothing stating that your armv7 code won't work!

But what if you need to use iOS 6 and you aren't in a position to fall back to armv7 only? What if you're unable to re-compile the static library including that architecture? Well, here's a solution, complete with total lack of guarantees!

The Workaround

As a forewarning, this gets a little technical, but I'm going to attempt to be as straightforward as possible  in delivering these instructions. They are compiled from about five different sources or so and frankensteined together to form a comprehensive solution.

Step 1: Gather Your Materials

What you'll need:

  • the static library you need to use
  • the latest build of Xcode (4.5)
  • the latest iOS SDK (6.0)
  • a hex editor (such as Hex Fiend)
  • Terminal
It should go without saying that travelling this route requires, and is due to updating to, the most recent version of Xcode and the iOS 6 SDK. You'll know you have this when that linker error I put at the beginning of the article shows up when you build.

In this, I've recommended Hex Fiend as a hex editor, but really, it's whatever you want to use. You'll also need Terminal, which is in Applications -> Utilities on your Mac.

Step 2: Terminal and lipo

I mentioned earlier that your issue was your 'fat' library. To fix the 'fat', we'll need some
lipo.

First, let's check on our library to see what's supported in it. To check on the supported architectures in your library, enter the following into Terminal:

lipo -info libMYLIB.a

Note: If you didn't cd into your library's containing folder, you can navigate to it in Finder and drag-and-drop it into Terminal. Doing that will autocomplete the correct path.

Doing this will output something like the following:

Architectures in the fat file: libMYLIB.a are: armv6 armv7 i386 

Here we see that armv7s is not listed. We'll fix that.

The next command you'll need is -extract.

lipo libMYLIB.a -extract armv7 -output libMYLIB7s.a

In this command, the first file is your source file (the one that is missing the armv7s). What we're saying here is that we're extracting the armv7 architecture. The -output flag specifies where to place it. Again, if you don't cd to a specific directory, you'll need to specify the path along with the file here.

We have one more thing to do before we get down to the hex editing:

lipo libMYLIB7s.a -thin armv7 -output libMYLIB7sthin.a

This will ensure that your file is stripped to the bare minimum for your architecture! Checking its info as in the first part of step 2 should result in the following:


lipo -info libMYLIB7sthin.a 

input file libMYLIB7sthin.a is not a fat file


Check to make sure your output file was created and we're ready for step 3!

Step 3: Armv7s Bluffing

I need to emphasize that this doesn't actually make the code compiled for armv7s. It is merely bluffing. Here's how we do it.

Fire up Hex Fiend (or your preferred choice) and open your extracted libMYLIB7s.a. F to get your find/replace prompt up and input the following:

CEFAEDFE 0C000000 09000000
into your 'find' and
CEFAEDFE 0C000000 0B000000
into the replace.

Let's ignore the filename here, haha!

Save your new file (back up the previous, just in case!) and we're ready to move onto the last step!

Step 4: Repackaging the Library

Hope you still have Terminal open! This is the last line for us!

lipo -output libMYLIBfinal.a -create libMYLIB.a libMYLIB7sthin.a 

And... you're done! Put that new static library into your project and you should see it compile without issues!

I'm in the process of doing this with a couple of our legacy libs, so I'll report later on if there are any caveats to this method, but so far so good! Have fun everyone!

Thursday, June 7, 2012

CODE SNIPPET: Modal UIAlertView for Password Entry

After a few days, I finally managed to solve a problem that has been bothering me for a while. In iOS, UIAlertView is a non-modal way of displaying a message. This works fine for most circumstances, as majority of code can easily be broken up to accommodate the UIAlertView delegate methods, however sometimes you just need to sit down and block all further instructions until you get an answer.

Getting a password on the fly is one of those times.

This snippet was put together as a utility function, independent of class, implementation and delegate methods.  Feel free to use it and adapt it as you see fit, and it would be nice if you'd toss a line of credit in there somewhere.

NSString * DisplayModalPasswordEntry (NSString *szTitle, NSString *szMessage)
{
    // First, initialize the alert with our desired title and message
    // The delegate is nil because we will not be allowing delegate methods
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:szTitle 
                                                message:szMessage
                                                delegate:nil 
                                                cancelButtonTitle:@"Cancel" 
                                                otherButtonTitles:@"OK", 
                                                nil];

    // Make the entry secure
    [alert setAlertViewStyle:UIAlertViewStyleSecureTextInput];
    
    // Show our alert
    [alert show];

    // NSRunLoop will handle our blocking without explicitly blocking
    // NSDate will provide us with a condition for the NSRunLoop
    // UITextField and UIButton are for editing purposes during the loop
    NSRunLoop *rl = [NSRunLoop currentRunLoop];
    NSDate *d;
    UITextField *pTextField = [alert textFieldAtIndex:0];
    UIButton *pOKButton;
    
    // This loop goes through the subviews in alert looking for our button
    for (UIView *view in alert.subviews) 
    {
        // If it's a button
        if([view isKindOfClass:[UIButton class]]) 
            // And if it's the button we're looking for
            if ([((UIButton *)view).titleLabel.text isEqualToString:@"OK"])
            {
                pOKButton = (UIButton *)view;
                break;
            }
    }
    
    // So long as the alert is active
    while ([alert isVisible]) 
    {
        // NSDate init returns 'now' 
        d = [[NSDate alloc] init];
        
        // runUntil will run once and stop, since 'now' is 'then
        [rl runUntilDate:d];
        
        // Since we've disallowed delegate methods, we handle our button status here
        if ([pTextField.text length] == 0)
            pOKButton.enabled = NO;
        else 
            pOKButton.enabled = YES;
    }
    
    // Once we break out of our loop, we return whatever they entered
    return pTextField.text;
}

Tuesday, June 5, 2012

VIDEO: Lua Battle Engine Test

There's a lot to catch up on, I know, but I find that if I dwell on what I haven't said, I won't say anything.

Lately, I've been re-energized with regards to game dev and have vaulted head-first into writing a scripting engine to facilitate this desire.  

In college I began messing with Lua before my team deemed it unnecessary for our game.  I understood it in concept, and liked the idea of it, however I found it really hard to approach due to the lack of syntax highlighting, debugging and error-handling.  Since I was not the gameplay lead, I had little say in how the logic was handled, and as a level scripting engine, it was highly unnecessary.  We really only stored the locations of objects for each level.  I never had a reason to stick with it after Particle Panic! removed it from the design, as my own projects moved away from known programming languages into the world of ActionScript, Java and Objective-C.

Times have changed, dear readers, and now I've not only picked it up again, but I've successfully scripted an entire rudimentary battle scenario!  The only thing the C++ console app does at present is initialize the Lua libs and dofile('./startup.lua').  I'll devote a couple of additional posts about Lua in the near future, but without further ado, the video:


Friday, August 26, 2011

How I learned to stop worrying and love the iMac

Hey there readers! I recently realised that I have a lot of empty time here on my blog. My learning experience has been varied and I've had a lot of trouble figuring out just what was worth sharing, and how to share it. I've been doing a lot of reading lately about social media, social marketing and smartphones, and while my brain is quite full, I feel like I'm not sure yet how to channel it.

The one thing I do know is that in the last week, I have suddenly grown an appreciation for my iMac.

As I mentioned a few months back, we managed to get our department head to authorise a new iMac for us to push out our iPhone app with. While I did toy with the idea of using a virtual machine to do so, in the end I decided that if I were to ever pursue this seriously, not knowing Apple's products intimately would be my downfall. After a little bit of back-and-forth about which model and what features, we decided on something that everyone could be happy with. It took quite a bit of time to get it here, set up and on the network, so I spent my free time boning up on Objective-C.


I was not entirely new to Mac OS before this point, but it was definitely not something I was comfortable with.  I dated someone who swore by Macs and had messed around on a couple of Powerbooks in our time together.  It was alien, and like most people, I didn't like being taken out of my comfort zone.

That feeling spread as I tried to get used to XCode and Objective-C and after a week, I was more than happy to ditch the iMac for a while to work on some promotional material for upcoming events and new features on our Android app.  I didn't even turn the iMac back on until this past Monday.

During that interim, we had to re-write a significant portion of our Android app due to the problems with our website, which it was running on top of.  In the end, it was a good thing we were forced to change, as it lead to a lot more exciting possibilities and a solid API to work off of for any of our mobile applications.  We may be doing a Blackberry app in the near future, by the by, so the easier to get all the information we need, the better.

Over the weekend, we had a huge problem with one of the drains outside of our store, to put it lightly.  Coming in on Monday, you could smell the problem right away.  Our store had flooded and the water had been sitting there all weekend, soaking into anything and everything it could.  My office was the second worst damaged and the smell was enough to make you faint.  We discussed what I needed to continue working and the decision was unanimous: the iPhone app.

While picking and choosing what we would take to my new temporary office, I opted to only bring the iMac, as it was a lot easier to set up, required less desk space and was necessary for what I needed to do. This meant, however, that I would be dropped face-first into OSX and have nowhere to run.

I have to tell you, it was the best thing that I ever did.

I previously had been following parts of Ray Wenderlich's tutorials trying to set up the app with little understanding and mediocre success.  That isn't to say Ray isn't good at what he does; I actually highly recommend him to anyone looking to get into iPhone game programming.  His website is raywenderlich.com, his twitter is @rwenderlich and his book(s?) can be found on Amazon.  For those who are making their own assets, his wife's blog is a good starting point.  Her links are vickiwenderlich.com and @vwenderlich, respectively

The trouble wasn't Ray, it was me.  I was highly resistant to everything about the process and dismissed things as 'dumb' when they didn't seem intuitive.  I have since learned the error of my ways, and he has a very good basis for how to set things up within your class structures.  The information is there that I needed, I just couldn't see the trees for the forest.

After the initial learning curve of the new OS, I actually started realising that the way it was all set up was startlingly good.  The only thing I haven't gotten used to is how easy it is to lose windows behind other windows.  I'm a little bit of a desktop junkie and keep exactly 1 million things open at a time, so it's not too hard, haha!

The only thing I've found myself scrambling for are the keyboard shortcuts I've become so accustomed to.  CMD+A, CMD+C, CMD+X and CMD+X are all fairly easy to figure out but print screen was completely absent from the keyboard.  F5 doesn't refresh my page, XCode doesn't follow the usual function key debugging I'm used to and forget about ALT+130 for my accented e.

Print screening on the Mac is actually somewhat convoluted, but also rather intuitive.  My favourite method is CMD+CTRL+SHIFT+4, which brings up a selection crosshair.  Using that, I can clip exactly what I want out without having to use image editing software.  It copies straight to the clipboard, ready to go.  There are other key combos that do an automatic save as well, but I'm trying not to junk up my desktop too much.

Accents for typing are found using OPTION and various letter keys.  To get my accented e, OPT+E gives me the accent and whatever letter I hit following is the letter it will put it on, in this case, e.  It also works for uppercase letters, which is a helluva lot easier than remembering separate codes for everything.  Typing in other languages on the Mac is a lot easier than on Windows.  Oops.

There are still a few snafu's that I'm stuck on, like how the file structure is set up, how to figure out where things were saved, how to access the SD card I put in and how to create a new, blank file in GIMP.  I honestly can't wait until I get CS5 approved to use on this machine, but I'll save that rant for another day, haha!  Finding free software has been a little bit of a task and the singular time I searched for it, the moment I hit 'enter', the earth started shaking! (We're okay, the office is okay, but man that was startling!)

Overall, at the end of the week, I'm rather pleasantly using my iMac.  The mouse doesn't give me as many fits, and the softer key sounds and scrolling noises all somehow add to the aesthetic.  It feels a lot more... polished, I suppose.  I feel as if somehow I'm a traitor for saying so, ha!  But it's true.  If nothing else, the iMac package is a well designed package and everything feels very good.

No one has to know I've been entertaining the idea of buying a Mac for my home use.

Wednesday, February 23, 2011

NACS College Store of 2015 Video

Sorry that I seemed to have abandoned you, dear readers! Pushing toward our final deadline had me completely tied up, and since then, though things have slowed down a great deal, I've been quite busy nonetheless! We'll start of this long recap with a post on our submission video! Here it is, with the process details behind the jump!