You have been rejected. Last Friday you thought you had hit bottom when you got rejected by the barista of the day in account of you flirting with the barista of a different day that showed up out of turn to, surprise, have a coffee. What can you say, you got confused.

But things just went down hill from there. On Sunday your main competitor, Mystery Bunny Games, publicly criticized you on their blog! They pointed out that all that Telnet business you were babbling about made your applications waste memory, increased the size of your binary, and misspent time initializing frameworks that were never used in the final release of your app. They called it a disservice to the users, that have to suffer slow, bloated apps cause some lazy developer decided to add thousands of lines of code just for his own convenience. Ouch.

If that was not enough, this morning you got rejected again… by Apple! They discovered they could use your binary to upload Lua scripts and run all kinds of hacks on the device. Somehow they didn’t thought that was cool.

But you have learned the lesson: never follow any advice you get on the intertubes. Now, let me explain you how you can fix two of those three problems.

Debug/Release

Whenever you build your applications you always start with an Xcode project template that has the basis all setup for you. Between other things it comes with one Target representing the product you are building, and two Configurations with the settings appropriate for both a Debug build, and a Release one.

The Target contains between other things what files, libraries, and frameworks are linked and compiled. And that is your problem. Your Telnet debug server class, AsyncSocket and the CFNetwork framework it requires, plus all those files of the Lua runtime, should really not be in your Release build; they are Debug tools. How can you have the two different builds include different files? You only see two ways of doing this, and you don’t like either.

  1. To create different Targets for Debug and Build, and forget about the Configurations all together. But then for files that should be shared you will have to keep the targets in sync yourself, adding files to one then to the other.
  2. The old #ifdef/#endif trick: edit all those files so they end up empty if you are building a Release. But modifying 3rd party code? You will need to do it every time they update it! And what about that framework you are linking to? Even linking empty files takes time, especially since your development powerhouse is the cheapest Mac Mini you could find on eBay.

Chunking with static libs

The first thing you really need to do is separate all this code into chunks. On one side all the code that is required for both Debug and Release. On the other, all the code for your debug server. So you start by putting it all into its own project, and building one of those static libraries you have heard about. It is so easy these days… Apple even provides you with a project template out of the box to do this.

What? Don’t want to do it yourself? Gosh, you are so damn lazy. OK, I will give you the code! Just grab it, build it and you will end up with a libLuaDebugServer.a that contains all the stuff from the last time. Well… almost all.

Remember that CFNetwork framework we needed? Static libraries don’t… well, they don’t include frameworks so… I guess we still need to link to that in the main proj… Why are you looking at me like that? Man, I am getting there! Don’t worry! When have I failed you? Yeah, don’t answer that.

Otherworldly flags

So now that you have that library, you can delete all that code from the main project and add the library instead. If you want to get serious you could even do some of that cross-project referencing and target dependencies crap. But you know what? You will still have the same problem! Adding your static lib to the project will add it to the Target, and that will link and compile it in both Configurations!

So is time to rethink this. Linking is the problem, and you need to do it differently depending on your Configuration. Hey, what’s this?

flags.png

Other Linker Flags? I know you never look at any of these arcane build settings unless it is to check the -O Turbo button. But you can pass to this one here parameters for things you want linked only in the configuration selected! How? Easy.

-framework NameOfFramework
-l NameOfLibrary

So in our case, this should be…

-framework CFNetwork
-l LuaDebugServer

By the way, notice is not CFNetwork.framework or libLuaDebugServer.a; it figures out the filenames on its own. Now that you have that you don’t need to add the files to the Target, so they will not be linked and compiled with the Release build. Except that if you try to build the project right now, you are just going to receive a bunch of gibberish errors.

Paths

Although Xcode has no problem finding that CFNetwork framework, it has no clue where the hell your static library is. Not only that, but it doesn’t know where the headers of your static library are either, so when you call any of the methods of your LuaServer class, is more bitter than your quadruple shot of the mornings.

I am sure that you saw this coming, but you will have to mess with build settings again. The two we need are Header Search Paths and Library Search Paths. Let’s imagine that you have your static library project in the same folder than your main project. Then the paths should be like this:

Header Search Path:
"$(SRCROOT)/../LuaDebugServer/"
Library Search Path:
"$(SRCROOT)/../LuaDebugServer/build/
$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/"

The important parts of those paths are the quotes (useful in case you have your projects in folders with names containing spaces), the $(SRCROOT) (that points to the folder containing the main project), and the $(EFFECTIVE_PLATFORM_NAME) (that makes sure to grab the correct version of your library whether you are building for the simulator or for the device).

Check?

There you have it. The same project than before, featuring Pancho the Begging Cat, built so it only uses the Telnet Debug Server and all the Lua code in Debug configuration, but not in Release. You don’t believe me? Is easy to check!

Debug, 938 KBDebug


Release, 541 KBEt Release

Also, did you noticed how after building for the simulator, the firewall in your Mac didn’t bug you about accepting connections when running the Release build? I say you are ready for a nasty response to the Mystery Bunny Games people. If you only knew who they were…

LuaSockets Source Code! Again!

This time not one, but two Xcode projects! One containing all the Telnet server and Lua code that builds a static library, and one with the example project.

The static library only contains headers for the LuaSocketServer class. If you want to make any of the other AsyncSocket or Lua methods available to the main project, you will need to add those headers to the Target’s Copy Headers build phase.

If you check the main project you will see the debug server code and the CFNetwork framework are gone; the Target Settings of the Debug configuration contain the necessary linking flags.

Have fun!

Download LuaSockets Lib project

9 Responses

  1. Pingback: App Tweaking at Under The Bridge

  2. Great post, with a bunch of useful information. Just one thought though. Often there is a good argument for leaving things like Lua scripting and diagnostic code in the optimised Release build.

    One option here is to have a third Build configuration (called Shipping, or Distribution, say), which is purely for submitting to the App store. This configuration can be a duplicate of the Release mode build, but with the scripting etc pulled out. This way, you can still get value from an optimised build with diagnostics / tweaking while testing.

    George Sealy; July 29, 2010, 12:15 AM

  3. great stuff!

    Bob; July 29, 2010, 1:39 AM

  4. Great article, Miguel. Thank you.

    Followup question for you: Do you know if there’s a way to link a static library for one platform (simulator) and not for others (device)? I know I can create a “blank” library and use the naming trick, but maybe there’s something cleaner.

    Noel; July 29, 2010, 6:29 AM

  5. @Noel Indeed there is. Select the build setting in either the Target or the Project, then in the sprocket menu at the bottom of the window choose “Add Build Setting Condition”. This will let you specify different settings by SDK and architecture.

    Miguel A. Friginal; July 29, 2010, 6:57 AM

  6. Great post!, haven’t tried this telnet thing yet, I’m still in the process of exposing our game engine to Lua. :-)

    Will try it out ASAP though, looks great, and now the main issue is solved.

    Nicolas; September 15, 2010, 11:17 AM

  7. This is awesome Miguel, I’ve started using it in my game already. I’ve added it as a git submodule and if you don’t have any objections can I make it public on github? I’d like to keep working on it and I think it could help others too!

    Dave Newman; December 7, 2010, 6:02 PM

  8. Do as you wish :) It will be much appreciated if you name the source (maybe a link to this or the previous post?), but is not required.

    Miguel A. Friginal; December 7, 2010, 11:24 PM

  9. Great! I’ll definitely link it back to your articles here. I’m planning on using Lua for more stuff in my game (entity states, AI etc) and this article has been a great help. I’m also open sourcing anything that’s not specific to my game.

    Dave Newman; December 8, 2010, 1:07 AM

Leave a Reply

Your email address will not be published. Required fields are marked *

five + fourteen =

This site uses Akismet to reduce spam. Learn how your comment data is processed.