{"id":683,"date":"2009-10-14T01:01:20","date_gmt":"2009-10-14T00:01:20","guid":{"rendered":"http:\/\/t-machine.org\/?p=683"},"modified":"2011-02-03T15:10:47","modified_gmt":"2011-02-03T14:10:47","slug":"how-to-make-an-iphone-static-library-part-2","status":"publish","type":"post","link":"http:\/\/new.t-machine.org\/index.php\/2009\/10\/14\/how-to-make-an-iphone-static-library-part-2\/","title":{"rendered":"How to make an iPhone static library &#8211; part 2"},"content":{"rendered":"<blockquote><p>UPDATE: Apple changed everything (again) without telling developers (again) and broke everything (again).<\/p>\n<p>Current versions of Xcode (the minimum that Apple allows you to use) will *not* work with the architecture-link part of this blog post.<\/p>\n<p>Instead, see this StackOverflow question I asked (and answered) with an updated technique: <a href=\"http:\/\/stackoverflow.com\/questions\/3520977\/build-fat-static-library-device-simulator-using-xcode-and-sdk-4\n\">http:\/\/stackoverflow.com\/questions\/3520977\/build-fat-static-library-device-simulator-using-xcode-and-sdk-4<\/a>\n<\/p><\/blockquote>\n<h4>Intro<\/h4>\n<p>This is NOT a perfect way of doing static libs on iPhone; however, it does work &#8211; I&#8217;ve used it in iPhone apps that are on the App Store right now &#8211; and I&#8217;ve been sitting on this post for over a month, improving it, tweaking it. It&#8217;s not perfect, but I think it&#8217;s better to put it out onto Google than to keep it quiet any longer.<\/p>\n<p>NB: I&#8217;m not a Mac developer; the iPhone is relatively new to me. I apologize in advance for any stupid mistakes I make here where I should have known better!<\/p>\n<p>PS: If you don&#8217;t read this blog normally, you might be dismayed at the amount of whinging about Apple&#8217;s less-than-perfect code and documentation in this post. Sorry. Let me just say that I am *trying* to be even-handed &#8211; and that that requires not only praising Apple, but also calling out their bad acts where relevant. I and many of my friends and ex-colleagues have suffered hours and days of wasted time &#8211; ON THIS TOPIC ALONE &#8211; because of tiny things that Apple staff &#8220;forgot to mention&#8221; or &#8220;didn&#8217;t bother testing&#8221;. It&#8217;s understandable, but it&#8217;s also painful.<br \/>\n<!--more--><\/p>\n<h4>A recap of what we need<\/h4>\n<p>You might want to read <a href=\"http:\/\/t-machine.org\/index.php\/2009\/10\/13\/how-to-make-an-iphone-static-library-part-1\/\">How to make an iPhone static library &#8211; part 1<\/a> if you haven&#8217;t already &#8211; it goes into much more detail on what we need, and why.<\/p>\n<p>Recapping the key points:<\/p>\n<ul>\n<li>One (or more&#8230;) &#8220;libSOMETHING.a&#8221; files that we can include in other projects\n<li>Must work both in Simulator and on Device\n<li>Must be distributable with NO SOURCE CODE (even if we ourselves have the source code &#8211; this makes version control much simpler!)\n<li>Must be implemented ENTIRELY inside Xcode &#8211; no external tools or dependencies\n<li>Must work on iPhone OS 2.x and iPhone OS 3.x\n<\/ul>\n<h4>The Trick<\/h4>\n<p>On OS 2.x, I didn&#8217;t need to do this, but with 3.x, Apple hard-coded some new bugs into Xcode, making Xcode even harder to use.<\/p>\n<p>Here&#8217;s the bug:<\/p>\n<blockquote><p>\nIn the Build Settings for a Target, Xcode for iPhone OS 3.x and above will IGNORE the architecture instructions you give it\n<\/p><\/blockquote>\n<p>This means that &#8220;Compile these architectures&#8221; (a list of names) and &#8220;Only build the selected architecture&#8221; (a checkbox) are both ignored. You MUST treat these settings as &#8220;FYI only&#8221;, and be careful not to set them manually &#8211; your settings will be silently overridden. I&#8217;ve tested this by editing the Xcode .xcodeproj files (XML format) manually, and finding that they are ignored no matter what.<\/p>\n<p>Instead, you MUST make all your architecture-configuration inside the &#8220;Base SDK&#8221; setting, and then NEVER EVER use anything EXCEPT the &#8220;Base SDK&#8221; setting in the main Build drop-down (the one you can see at all times when in the main Xcode view, up at the top left, just underneath the red, yellow, and green buttons (close window\/minimize window\/maximize window).<\/p>\n<p>Unfortunately, this makes that drop-down ENTIRELY USELESS. Crap.<\/p>\n<p>(UPDATE: <a href=\"http:\/\/stackoverflow.com\/questions\/1162336\/building-iphone-sdk-2-x-targets-with-base-sdk-3-0-when-linking-static-libraries\">See this link for another entire class of problems caused by the SAME major bug in Xcode for iPhone 3.0<\/a>)<\/p>\n<p>But &#8230; there&#8217;s a workaround!<\/p>\n<p>You can create MULTIPLE values for Base SDK, and use the master drop-down to choose between them.<\/p>\n<p>How?<\/p>\n<p>By (manually) creating new Target&#8217;s.<\/p>\n<p>Ultimately, we create a unique Target for every set of Build Settings we need. In the simple version, all we have to do is create one Target for the Device, and a separate Target for the Simulator. However, ultimately, you want (MUST!) create a separate Target for each combination of:<\/p>\n<ol>\n<li>Device \/ Simulator\n<li>Debug \/ Release\n<li>Main app \/ Lite app\n<\/ol>\n<p>&#8230;because if you don&#8217;t, then it&#8217;s highly likely you&#8217;ll accidentally change that drop-down one day, your project will screw up completely, and you&#8217;ll have no idea what&#8217;s going on. I have helped lots of people who broke their projects by using the master drop-down in OS 3.x. So many that I&#8217;m sure Apple *never* bothered to test this drop-down with basic Unit Tests, sadly, or they would have noticed quickly that they&#8217;d broken the settings that populate it.<\/p>\n<h4>Creating your Targets<\/h4>\n<p>First, understand that there are two &#8220;sets&#8221; of targets in Xcode (and there is NO way of telling the difference between them &#8211; this is a classic Xcode design bug).<\/p>\n<p>There&#8217;s the Targets you can see &#8211; in the Targets twisty &#8211; and then there&#8217;s the &#8220;root&#8221; or &#8220;default&#8221; Target, which you access by scrolling to the top of the &#8220;Groups &#038; Files&#8221; pane, and clicking on the first line (should be the same name as your Xcode Project). ALL values in the default target are copied into the real Targets, and then any &#8220;local overrides&#8221; in the real Targets are applied.<\/p>\n<p>Usually, you only have 3-10 settings in the real Targets &#8211; all the rest is inherited from the default target.<\/p>\n<p>Create new Targets by right-clicking on the Targets twisty and selecting &#8220;Add&#8230; -> New Target&#8230;&#8221; and selecting &#8220;Static Library&#8221; from the GUI. Make sure to give the new static lib a unique name!<\/p>\n<p>MAKE SURE you do not re-use the same product name \/ target name \/ executable name that the original project&#8217;s target had (again, just trust me: this exposes so many horrible bugs in Xcode that you simply DO NOT want to go there&#8230;). Standard practice is to make TWO new Targets, include &#8220;Device&#8221; in the name of one of them, and &#8220;Simulator&#8221; in the name of the other one, and delete the original one (but only after you&#8217;ve tested the new projects are fully working!)<\/p>\n<p>NB: Xcode has hard-coded a &#8220;magic&#8221; relationship between the Target name and the Project name and the Application Binary name. Just don&#8217;t go there. I&#8217;ve tried; it&#8217;s a horrible hacky mess, and if you screw it up you have to manually edit Xcode&#8217;s behind-the-scenes text files to fix it &#8211; Xcode is hard-coded to prevent you from editing it yourself, so just avoid it all and keep all your Target names &#8220;unique&#8221;.<\/p>\n<h4>One Target for device, one Target for simulator<\/h4>\n<p>On iPhone OS 2.x, you could create a single file, e.g. &#8220;libMY-LIBRARY.a&#8221; (NB: other standards, not important here, dictate that the filename must begin &#8220;lib&#8221; and must end &#8220;.a&#8221;), which contained both the Device binary and the Simulator binary; this is no longer possible on OS 3.x.<\/p>\n<p>Instead, you MUST create two separate binaries. If you look at the mainstream 3rd-party libraries (e.g. AdMob), you&#8217;ll see that they give you TWO .a files, one &#8220;something-something-device.a&#8221; and the other &#8220;something-something-simulator.a&#8221;. This is because they&#8217;re using separate Xcode Target&#8217;s for Simulator and Device.<\/p>\n<p>In each of those Target&#8217;s, simply:<\/p>\n<ol>\n<li>Click on the Target name in the Groups &#038; Files pane\n<li>Press command-I\n<li>Go to the &#8220;Build&#8221; tab\n<li>Change the Base SDK (It&#8217;s right at the top of the list) to whatever is appropriate &#8211; Simulator 2.2.1, or Device 3.0, or whatever\n<\/ol>\n<p>Now you have some &#8220;unconfigured&#8221; new Targets, but you need to add all your source files to them, or they will do nothing.<\/p>\n<p>This is a bit trickier, because you have to: Close your eyes, cross your fingers (because there&#8217;s no way you can know if this will work or not &#8211; this being Apple (useless at UI design), and this being Xcode (highly random on what it does for drag\/drop)). However, *trust me*: it just so happens that Xcode will 100% of the time in this situation do what you actually wanted: duplicate all the links to the files and move the duplicates to the place you wanted them.<\/p>\n<p>So&#8230;<\/p>\n<ol>\n<li>Select everything in the original Target&#8217;s sub-groups, one sub-group at a time, and drag them to the equivalent sub-group of each of the new targets.\n<\/ol>\n<h4>Making life simpler: screw Apple&#8217;s (broken) Configurations<\/h4>\n<p>Configurations are a pain in the ass &#8211; now that OS 3.x has broken the Base SDK and Architecture settings, they don&#8217;t really work; it&#8217;s far, FAR easier just to delete them.<\/p>\n<p>So &#8230;:<\/p>\n<ol>\n<li>select the root Target (first item in the Groups &#038; Files pane)\n<li>hit command-I\n<li>Go to the &#8220;Configurations&#8221; tab\n<li>select each of them and press &#8220;Delete&#8221; button at bottom left of the screen, until there&#8217;s only one left\n<\/ol>\n<p>Of course, now you&#8217;ve lost the ability to dynamically change between &#8220;normal&#8221; and &#8220;highly optimized&#8221; compiles.<\/p>\n<p>Or .. have you?<\/p>\n<p>No, of course you haven&#8217;t &#8211; you just need to create some more Targets!<\/p>\n<p>Assuming you deleted the &#8220;Release&#8221; Configurations, create 2 new Targets: &#8220;Release Simulator&#8221; and &#8220;Release Device&#8221;. Set them as per the original targets (you can in fact create them FROM the original Targets &#8211; although Apple has removed the keyboard shortcut, you can select each existing Target, and from the Edit menu select &#8220;Duplicate&#8221;; this is a good idea, as it spares you from manually setting the Base SDK and possibly getting it wrong).<\/p>\n<p>Unfortunately, you will need to manually re-create the &#8220;Release&#8221; custom settings.<\/p>\n<p>Create a new, virgin, Xcode project, set it to Release mode, and then open the Build Settings. From the second drop-down at top-left, titled &#8220;Show:&#8221;, select &#8220;Settings Defined at This Level&#8221;, to see ONLY the things that are &#8220;unique&#8221; to Release builds &#8211; and copy the changed settings across to your manually-created &#8220;Release&#8221; Targets.<\/p>\n<h4>How do I use this to Build?<\/h4>\n<p>The drop down at top-left of Xcode&#8217;s main window should now:<\/p>\n<ol>\n<li>NOT have multiple things in the &#8220;Active Configurations&#8221; section &#8211; instead it should have only one, either &#8220;Debug&#8221; (or &#8220;Release&#8221; &#8211; which ever one you didn&#8217;t delete). NB: this DOES NOT MEAN ANYTHING\n<li>SHOULD have multiple things in the &#8220;Active Target&#8221; section &#8211; one for each different thing you think you want to build\n<li>WILL have lots of things in the &#8220;Active SDK&#8221; section\n<\/ol>\n<p>This is VERY IMPORTANT:<\/p>\n<blockquote><p>\nALWAYS leave the &#8220;Active SDK&#8221; set to &#8220;Base SDK&#8221;; this is to workaround the bug(s) in the version of Xcode that came with iPhone OS 3.x; you may be tempted to change it BUT DO NOT! Instead, only ever change the Active Target\n<\/p><\/blockquote>\n<p>This way, all you have to do is glance at the Active Target, and you will always &#8211; ALWAYS &#8211; know exactly what Xcode is going to build right now.<\/p>\n<p>Eventually, Apple will (hopefully) fix the new bugs they introduced for OS 3.x, and we can go back to using the drop-down to select Configurations, SDK&#8217;s, etc &#8211; but, actually, now that I&#8217;m used to using Targets, I see it&#8217;s much, much easier &#8211; and a lot less error-prone. Basically, Apple&#8217;s GUI is too poorly designed, and it&#8217;s just easier to have ONE thing to click on, rather than lots of them. So, I think I&#8217;ll stick to it from now on.<\/p>\n<h4>How do I use this in a separate project?<\/h4>\n<p>Still a lot of work to do, I&#8217;m afraid&#8230;<\/p>\n<p>But first of all, you need to right-click EACH of the items in the Products twisty (there will be exactly one for each Target you have), and select &#8220;Reveal in Finder&#8221;.<\/p>\n<p>Then, you need to drag\/drop the revealed files &#8211; one by one &#8211; into the APP project.<\/p>\n<p>NB: a lot of people have their Xcode setup such that these binaries will be located in DIFFERENT directories &#8211; that&#8217;s why you should use &#8220;Reveal in Finder&#8221; to make sure that you are *guaranteed* to be drag\/dropping the correct file. I&#8217;ve confidently dragged the wrong file before (an old build from a previous setup), and wasted hours trying to figure out why none of my source changes seemed to show up in the app. Oh, how I laughed when I worked out the cause (actually, I nearly cried).<\/p>\n<h4>Libraries: the problem(s)<\/h4>\n<p>First, you need to copy all the Header files. Frameworks do this for you &#8211; but, remember: Apple has banned us from using Frameworks on iPhone :(.<\/p>\n<p>Second, you need to implement some minor manual fixes to make Objective C work correctly. Objective C is very, very hacky, and with external libraries you need to set an extra linker flag to make it link the libs correctly.<\/p>\n<h4>Copying the header files<\/h4>\n<p>More bugs. Xcode&#8217;s &#8220;Add Files&#8221; dialog box has multiple bugs that have been around for multiple versions of Xcode. I&#8217;ve found only one way of reliably adding header files for external libs &#8211; and it&#8217;s not perfect :(.<\/p>\n<ol>\n<li>create a folder on your hard disk, inside the LIBRARY proejct, called &#8220;[library] headers&#8221; where [library] is the name of your library\n<li>inside Xcode, manually delete all headers from your LIBRARY project &#8211; but do NOT click &#8220;also move to trash&#8221;\n<li>manually move all header files (using Finder) into the &#8220;library headers&#8221; sub-folder\n<li>inside Xcode, select &#8220;add existing files&#8221; and re-add all the headers\n<li>&#8230;now go to your APP project&#8230;\n<li>drag\/drop the &#8220;library headers&#8221; folder from Finder into your APP project inside Xcode\n<li>you MUST select &#8220;Recursively create groups for any added folders&#8221; &#8211; there are bugs in the other option that cause it to break your Xcode project\n<li>you SHOULD NOT select &#8220;Copy items into destination group&#8217;s folder&#8221;; any changes to your header files inside LIBRARY project will automatically be picked up by APP project; however, if you delete the source for LIBRARY project (e.g. if you do a CVS checkin and then delete the working directory), then the APP project will refuse to build any more&#8230; it&#8217;s up to you.\n<\/ol>\n<p>What&#8217;s wrong with this?<\/p>\n<p>Only one thing: when you create new Header files in LIBRARY, they do not automatically appear inside APP. You have to manually drag\/drop them from finder into Xcode when it has APP project open.<\/p>\n<p>However, at least Xcode does automatically create a Group named &#8220;[library] headers&#8221; and place all the files inside that group, which is nice&#8230;<\/p>\n<h4>Fixing the Objective C linker<\/h4>\n<p>If you don&#8217;t do this, then several things go wrong:<\/p>\n<ol>\n<li>Interface Builder appears to work, but any time your NIB files reference a LIBRARY class, they will cause your APP to crash with &#8220;impossible&#8221; line numbers and &#8220;impossible&#8221; error messages&#8221;\n<li>Funky code in your library that uses custom Categories on Apple classes will fail to run at all\n<\/ol>\n<p>Apple (and sites you&#8217;ll find on Google) warn you about the second item above, but I only discovered the first item by accident.<\/p>\n<p>UPDATE: To fix the first item:<\/p>\n<p>UPDATE: &#8230;well, the approach for the second used to work for me, but now it dosn&#8217;t any more. Maybe a bug in the latest SDK update from apple, may be something else enitrely. <\/p>\n<p>To fix the second item:<\/p>\n<ol>\n<li>open up your APP project\n<li>go to the root Target\n<li>in the Build Settings page type: &#8220;Other Linker Flags&#8221; into the search box. You should get one result\n<li>double-click on the RHS, and click the &#8220;+&#8221; button on the dialog that pops up\n<li>type &#8220;-ObjC&#8221; into the second dialog, and OK out of there\n<\/ol>\n<p>UPDATE: <a href=\"http:\/\/developer.apple.com\/mac\/library\/qa\/qa2006\/qa1490.html\">here&#8217;s a link to Apple&#8217;s official explanation of the need for the -ObjC flag<\/a><\/p>\n<p>I have heard rumours that you might also need &#8220;-all_load&#8221; for some libraries &#8211; but I&#8217;ve not investigated that myself, and I&#8217;ve not (yet) encountered situations where it&#8217;s needed, sorry!<\/p>\n<p>UPDATE: With iPhone OS 3.0 and above, you often DO need the -all_load flag &#8211; it&#8217;s due to bugs in Apple&#8217;s shipped SDK for 3.0. Oops.<\/p>\n<h4>UPDATE: Other problems with Interface Builder<\/h4>\n<p>If you do NOT manually copy all your header files across to the application project, IB will stop working.<\/p>\n<p><a href=\"http:\/\/stackoverflow.com\/questions\/1058766\/interface-builder-cant-see-classes-in-a-static-library\">Here&#8217;s an explanation of how to trivially fix this in just a few clicks<\/a><\/p>\n<p>That&#8217;s a great feature of IB. That&#8217;s terrible GUI design from Apple, though: the only way you&#8217;d ever find out about it is if someone else told you first. I&#8217;ve not yet heard of this technique anywhere except on that one linked page above. YMMV&#8230;<\/p>\n<h4>Conclusion<\/h4>\n<p>Hopefully I haven&#8217;t missed anything out. If I have, I&#8217;ll re-write the post as necessary when people point out what&#8217;s missing.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>UPDATE: Apple changed everything (again) without telling developers (again) and broke everything (again). Current versions of Xcode (the minimum that Apple allows you to use) will *not* work with the architecture-link part of this blog post. Instead, see this StackOverflow question I asked (and answered) with an updated technique: http:\/\/stackoverflow.com\/questions\/3520977\/build-fat-static-library-device-simulator-using-xcode-and-sdk-4 Intro This is NOT a [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[51],"tags":[],"_links":{"self":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/683"}],"collection":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/comments?post=683"}],"version-history":[{"count":0,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/683\/revisions"}],"wp:attachment":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/media?parent=683"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/categories?post=683"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/tags?post=683"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}