{"id":365,"date":"2009-02-26T19:54:43","date_gmt":"2009-02-26T18:54:43","guid":{"rendered":"http:\/\/t-machine.org\/?p=365"},"modified":"2009-02-26T19:54:43","modified_gmt":"2009-02-26T18:54:43","slug":"using-shared-libraries-for-iphone-with-multiple-projects","status":"publish","type":"post","link":"http:\/\/new.t-machine.org\/index.php\/2009\/02\/26\/using-shared-libraries-for-iphone-with-multiple-projects\/","title":{"rendered":"Using shared libraries for iPhone with multiple projects"},"content":{"rendered":"<p>You would think this is easy, seeing as how it&#8217;s an essential, simple, part of any programming project. HA! You obviously haven&#8217;t used Apple&#8217;s shockingly bad IDE (Xcode) much, have you? <\/p>\n<p>You can read the extremely widely-linked blog post &#8211; <a href=\"http:\/\/www.stormyprods.com\/blogger\/2008\/11\/using-static-libraries-with-iphone-sdk.html\">http:\/\/www.stormyprods.com\/blogger\/2008\/11\/using-static-libraries-with-iphone-sdk.html<\/a> &#8211; which is incomplete, and doesn&#8217;t work properly if you want to do auto-updates when source changes (which, in most cases, you do). Unfortunately, it doesn&#8217;t give any pointers to making linked projects work. I don&#8217;t blame the author for stopping at that point, their solution &#8220;works&#8221;, but I wanted to get the full benefits of auto recompilation.<\/p>\n<p>You can google to try and find some documentation from Apple. I can&#8217;t find any, although I can find lots of other people on forums asking for documentation on how to do it themselves.<\/p>\n<p>Eventually I worked it out, after hours of trial and error, and reading as much of the Xcode docs as I could find that seemed to relate to what was going on.<\/p>\n<ol>\n<li>Make a new project to hold your shared library\n<li>Put all the .m and .h files for your library in that project (drag\/drop them to the groups and files list)\n<ul>\n<li>XCode &#8220;feature&#8221;: it will by default fail to copy the files, even though that means everything will break later on, when you delete the originals. You need to tick the &#8220;copy files if necessary&#8221; checkbox)\n<\/ul>\n<li>Create a &#8220;Static Library&#8221; build target\n<li>Drag the .m files *only* to the static library build target&#8217;s &#8220;sources&#8221; twisty\n<li>DO NOT DELETE THE FILES FROM THE MAIN PROJECT (because you&#8217;ve just created references, not copies, although it doesn&#8217;t tell you that &#8230; so Xcode will silently delete them everywhere, and OS X still doesn&#8217;t support undelete; Sulka tells me that Undelete will be coming to OS X in the next version. Oh, how I laughed)\n<li>DO delete the files from the main Build Target\n<ul>\n<li>(again, they&#8217;re not actually files there, just references, so &#8220;deleting&#8221; them merely gets rid of the reference, not the file)\n<li>is this another bug in XCode? It seems strange that you use the &#8220;delete&#8221; funciton to do something that isn&#8217;t really a delete\n<\/ul>\n<li>Click the NEW build target (the static library) and right click and select &#8220;build&#8221;.\n<ul>\n<li>XCode &#8220;feature&#8221;: if you highlight the thing you want to build, and hit Cmd-B to build, it WILL NOT BUILD the selected target, it will instead build the main target and ignore the target you actually wanted built\n<li>The *only* way to make cmd-b build the thing you want is to change some of the options on the Target dropdown at top left of the window &#8211; but you&#8217;ll have to change it back and forth each time you want to build somethign different with cmd-b &#8230; there seems to be no context-sensitive Build command in Xcode (bug?)\n<\/ul>\n<li>If you want to test that your static lib built correctly (hint: you probably do)\n<ol>\n<li>Add the static library to the main target\n<ul>\n<li>XCode bug: you can add the static library to the &#8220;direct dependencies&#8221; section. This has no effect; don&#8217;t do it. The static library MUST be added to the &#8220;linked libraries&#8221; section, i.e. the bottom panel of the General tab of the Inspector for the Build Target\n<\/ul>\n<li>Write some code that uses your static lib &#8211; I suggest putting it in the app delegate class that Xcode auto-generated when you created the new project &#8211; and try building the main target (you CAN use cmd-b for this &#8230; unless you switched targets above, in which case you&#8217;ll need to switch them back first). If you have added the static lib in &#8220;the wrong place&#8221; or created it &#8220;in the wrong way&#8221; then this will fail with missing class errors etc\n<\/ul>\n<\/ol>\n<p>All that has achieved is to compile your source code. No, seriously &#8211; it is THAT HARD. Now you have to actually try using it from another project.<\/p>\n<p>This is where the StormyProds link takes the easy way out (which only partially works): it simply copies the .a file (generated by the compiler) to somewhere on your hard disk, and has you hard-link to that file from other XCode projects. This will work; but it will also get out of date rapidly, and cause all sorts of bugs if you forget to update it. It will never auto-compile when there are changes.<\/p>\n<p>What Apple wants you to do (and for once I agree with them :) &#8211; this makes sense for most developers who aren&#8217;t using an external build system) is to link the projects directly, so that changes in one cause the other to automatically recompile *if necessary*.<\/p>\n<p>NB: for all my disappointments with Xcode, this is one feature I think has been extremely well done &#8211; it handles &#8220;links&#8221; between discrete Xcode projects extremely well, and (although the menus and docs for it are a bit hard to find) it mostly Just Works.<\/p>\n<ol>\n<li>Link the two projects\n<ol>\n<li>Following Apple&#8217;s instructions here: <a href=\"http:\/\/developer.apple.com\/DOCUMENTATION\/DeveloperTools\/Conceptual\/XcodeProjectManagement\/040-Files_in_Projects\/chapter_5_section_7.html#\/\/apple_ref\/doc\/uid\/TP40002666-CJBJHJCJ\">http:\/\/developer.apple.com\/DOCUMENTATION\/DeveloperTools\/Conceptual\/XcodeProjectManagement\/040-Files_in_Projects\/chapter_5_section_7.html#\/\/apple_ref\/doc\/uid\/TP40002666-CJBJHJCJ<\/a> &#8211; i.e.:\n<li>Open the project that will import the static library\n<li>Go to the &#8220;Project&#8221; menu and select &#8220;Add to Project&#8221;\n<li>Find the .xcodeproj file on your harddisk that representst the other project, and select it\n<li>Check it worked:\n<ul>\n<li>At the top of Groups and Files panel, you should see a blue twisty for your project, and just inside it a blue twisty for your imported \/ linked project\n<li>Inside the second twisty MIGHT be a .app file (representing the main target of the imported project, which you won&#8217;t need &#8211; you MIGHT have created a project wihtout a main executable, or deleted the spec for it, but by default you&#8217;ll have this)\n<li>Inside the second twisty should be a .a file (representing the static library from the imported project, which you DO NEED)\n<\/ul>\n<\/ol>\n<li>Make the secondary project import the compiled static library from the first project\n<ol>\n<li>Drag the .a file from inside the second twisty, and drop it inside the &#8220;Link Binary with Libraries&#8221; section of the main Build Target of the main project\n<ul>\n<li>DO NOT drop it anywhere else in the Built Targets section &#8211; it will work, but will have no effect (you do that in the next step)\n<li>If you do it correctly, you should see the static library appear with the same icon as each of your included Frameworks (all iPhone projects have at least 2 Frameworks normally: UIKit.framework, Foundation.framework), and appear right next to them in the same twisty underneath Build Targets\n<li>ALSO open the inspector for your build target and add a second dependency in the main dependencies section to the static lib &#8211; NOT the app &#8211; from the imported project.\n<li>(if you don&#8217;t do this, you&#8217;ll see weird things like the build compiling for iPhone, but not for the Simulator, for no apparent reason)\n<\/ol>\n<\/ol>\n<p>Finally &#8230; drag and drop the header files from the original project&#8217;s location in Finder into the new project&#8217;s source folders. Do NOT check the &#8220;copy files if necessary&#8221;. Xcode will do a reference \/ softlink, so that changes to the header files in the original project are picked up. NB: you will need to do a drag\/drop each time you add a new header file to the original project.<\/p>\n<p>(You *might* be able to get away with putting all the header files in a sub-fodler of their own in the original project, and drag\/dropping that FOLDER into the new project, but &#8230; I tried that, and it seemed to sometimes fail to notice the new header files, so I&#8217;m not sure I&#8217;d risk it).<\/p>\n<p>Some fun errors:<\/p>\n<h4>Line Location Tool:0: &#8220;_OBJC_CLASS_$_ScoreUploader&#8221;, referenced from:<\/h4>\n<p>Various causes of this useless error message:<\/p>\n<ol>\n<li>you added a class to the source project &#8230; but forgot to drag\/drop that .m file into the &#8220;Compile Sources&#8221; part of the Target for the Static Library in the source project (or you did so, but you didn&#8217;t link your xcodeproj&#8217;s directly &#8230; but forgot to recompile the source project (linking the projects, as described above, triggers auto-rebuilds and you dont see this problem so often))\n<li>you had all the source in one project originally &#8230; but haven&#8217;t deleted FROM YOUR HARD DISK the source files for the source inside the original, main project\n<\/ol>\n<p>(this is IMHO another bug in Xcode: it silently leaves the files in place, by default, and yet silently (secretly) uses them when compiling &#8211; but ONLY when dealing with imported libraries, NOT when dealing with local compilation. Huh?)<\/p>\n<h4>Line Location Tool:0: literal-pointer@__OBJC@__cls_refs@NSMutableList in libhiscorelib.a(XMLSuperParser.o)<\/h4>\n<p>You haven&#8217;t added the static lib as a non-lib dependency<\/p>\n<h4>Some things to be aware of<\/h4>\n<p>The header files that you drag\/dropped from one project to the other have NOT been copied to the new project and are therefore NOT real files &#8211; they are references.<\/p>\n<p>If you delete the original files (in the statically compiled lib project) then the references in all other projects will vanish; be careful!<\/p>\n<p>If you updarte the original files (in the statically compiled lib project) then the referneces in all ohter projects will automatically update (with no UI indication of this).<\/p>\n<p>Unlike most normal IDE&#8217;s, there is no obvious UI indication that the files are not inside the current project (you can check by doing cmd-i on any of the files and looking at the value of the &#8220;Full Path&#8221; field, but otherwise you won&#8217;t see a difference).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You would think this is easy, seeing as how it&#8217;s an essential, simple, part of any programming project. HA! You obviously haven&#8217;t used Apple&#8217;s shockingly bad IDE (Xcode) much, have you? You can read the extremely widely-linked blog post &#8211; http:\/\/www.stormyprods.com\/blogger\/2008\/11\/using-static-libraries-with-iphone-sdk.html &#8211; which is incomplete, and doesn&#8217;t work properly if you want to do auto-updates [&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,20],"tags":[],"_links":{"self":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/365"}],"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=365"}],"version-history":[{"count":0,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/365\/revisions"}],"wp:attachment":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/media?parent=365"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/categories?post=365"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/tags?post=365"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}