I'd like to put some categories I wrote for different projects into a central folder and put the header files together with some common macros into a mystuff.h which I'd like to add to the Prefix.pch like so:
Prefix.pch:
#import "myStuff.h"
myStuff.h
#import "/Users/foo/Documents/Xcode-Projects/my_stuff/NSNumber+someCategory.h"
#if DEBUG
// some macros
#endif
The goal is to add only the one line where I import myStuff.h to the Prefix.pch file of a new project and be done. The approach above so far compiles fine, but the runtime throws exceptions for all the category methods I use in the project, because the .m files of the categories don't get compiled.
So far I found two solutions:
a) I can add the .m files manually to "Build Phases => Compile Sources"
b) for every .h file that I import in myStuff.h I add the associated .m file, like so:
myStuff.h
#import "/Users/foo/Documents/Xcode-Projects/my_stuff/NSNumber+someCategory.h"
#import "/Users/foo/Documents/Xcode-Projects/my_stuff/NSNumber+someCategory.m"
(or merge the .h's into the .m's)
While approach a) seems to be clean, it does require additional work, whereas approach b) requires less work but I'm not sure whether that is best practice. Any ideas on how to solve this cleanly, or is approach b) acceptable?
One option might be to put your categories together into a library, and then refer to that library in your current project. See Ray Wenderlich's example at:
http://www.raywenderlich.com/41377/creating-a-static-library-in-ios-tutorial
It sounds like what you really want is a library or framework. Here are the docs for creating a framework in Xcode. Or if you want to build a library for iOS this discussion may be useful.
Related
Whenever I create a new project I add my own class files -often the same ones. It has become tedious to manually create these over and over. I want an automatic way to do this. I discovered custom Project Templates and I'm not sure if they are well documented by Apple.
I can create a cocos2D project with my custom classes and it works wonders. The problem is when I create a basic empty application with my custom classes.
Basically okay I'll give a little context. See my TemplateInfo.plist: This works. Note the "Ancestors" part. Here's how I interpret it: this inherits from cocos2d templates and does things like:
add necessary frameworks
adds cocos2D things like the splash image
other project-specific things
Now I don't know where these ancestor templates are or what format they are in, so I can't yet break down the individual things and say "OK I want the frameworks they include but not the launch image," but that's essentially what I want to do. I want to start with the most basic template and build from there manually.
I discovered that I can add specific frameworks in the "Targets" area. But before tackling that, I have a question: What Ancestors do I use, so that it does not use the Cocos2D base templates? I want the most basic thing.
1) Try removing all Ancestors and create a new Project and Xcode won't let you name the project and it crashes.
2) Try including only the Ancestors for the Default Empty Application: com.apple.dt.unit.cocoaTouchApplication
And it adds the correct frameworks:
Foundation
CoreGraphics
UIKit
XCTest
which is cool. However I noticed it overrides my Prefix.pch with a [Project-Name]-Prefix.pch and my project does not compile because I include a Debug Logger statement in my custom Prefix.ch like this:
#ifdef DEBUG
#define DLog(...) NSLog(__VA_ARGS__)
I figure this is the "com.apple.dt.unit.cocoaTouchApplication" ancestor doing its thing, and I want custom behavior that's different.
Is there a list of Ancestors somewhere that I can look at? Or is there a way I can look at the specific settings defined in "com.apple.dt.unit.cocoaTouchApplication" (if that even makes sense)?
Has anyone else run into this? What techniques do you use? Does anyone wish for an easier way to do this? Or is it better to create files manually every time?
I'm spinning wheels and any insight would be helpful. Thanks.
I figured it out. Searching through Xcode's default templates, I found one that uses basic ancestors. I used the following two:
And in Targets you can easily add the frameworks you want to include:
There are many little quirks like how to include an Info.plist file and Prefix.pch file and how to get it to rename properly (and replace the default one placed by the template). I am creating a video tutorial to show all these things in detail.
Creating your own custom templates is quite satisfying. Saves a lot of time and hassle when beginning new projects.
I have the following project setup:
1) A main iOS project ('super project')... nothing special here, the project was built on top of one of the default iOS templates from Xcode.
2) A second project ('subproject'), which was created on top of the Static Library template. I added this project to the super project, and created references to it from the superproject in the 'Target Dependencies' and 'Link Binary with Libraries' build phases.
Inside the subproject, I have a C function declaration which looks like this:
ABAddressBookRef myABAddressBookCreateWithOptions(CFDictionaryRef options, CFErrorRef * error);
It's meant as a replacement/proxy of the similarily named function from the AddressBook framework and uses a type (ABAddressBookRef) from that framework. The declaration is stored in a header file, and the implementation exists in the corresponding .m file. To make this type available, I added the framework header to the .pch file of my subproject:
#ifdef __OBJC__
#import <AddressBook/AddressBook.h>
#import <Foundation/Foundation.h>
#endif
The following problem occurs:
If I build the superproject (release or debug config), the build fails with this error message:
.../ManagedCFunctions.h:24:1: Unknown type name 'ABAddressBookRef'
Things I've done to fix the issue, or at least get an idea of what's going on:
Building the subproject separately works (but a subsequent superproject build fails regardless)
Uncommenting the declaration gets rid of the error, but naturally raises an "Implicit Declaration of Function" warning at the calling location
Adding the import to the superproject's .pch file does not help
Adding the import to the header file of the function directly works, but is not an option in my scenario (parts of the code are autogenerated, and it would be hard to find out which file needs which frameworks)
I suspect that maybe the header file is not processed in Objective-C, but rather C mode, so the imports are ignored due to the #ifdef __OBJC__ macro around the import, but removing it hasn't helped either. I also tried to add #import <Foundation/Foundation.h> to the function's header file to 'suggest' Objective-C mode, and it actually enabled correct syntax highlighting in the file, but hasn't helped for building.
Any suggestions as to why the symbol is found in the .m, but not in the .h file? Or any workaround that does not require adding the import to a specific header file, but globally?
Today I found a isuue after I in project -> Info -> Configurations add a configuration file, then I run my project, it goes wrong in my pch file.
It shows that xxx.h not found, I search a lot of solutions, but I can not get the right answer. So I remember that step.
I deleted the configuration file, and my project become normal.
I hope this will be helpful for this kind issue.
How to build a .bundle from source code?
This might sound like a simple problem but it has been hurdling me for a week...
Here is my problem:
I have a bunch of .c and .h files that are organized in a folder and its sub folders. The source code was written and compiled with gcc make and tested by many other make tools. The source code has some utilities and command line tools and it has more code that serve as library for those utilities and tools. It is the files that serve as libraries that I want to reuse. (By library I don't mean static library or something, I just mean that some .c and .h files in certain subfolders provide functions that can be called by some other .c files. I want to be able to call those functions, too)
Yet my problem is more complex than that: I need to build those .c and .h into a bundle to reuse it. I am not writing my application in C; I am developing in Unity and Unity can only take in .bundle files on Mac OS.
Here is my goal:
Organize the source code folder in a proper way so that I can build them into a bundle in Xcode 4.
Here is where I got stuck:
When building the project I got the following error:
Duplicate symbol _main in
/Users/zeningqu/Library/Developer/Xcode/DerivedData/ccn-cfygrtkrshubpofnfxalwimtyniq/Build/Intermediates/ccn.build/Debug/ccn.build/Objects-normal/i386/ccndsmoketest.o
and
/Users/zeningqu/Library/Developer/Xcode/DerivedData/ccn-cfygrtkrshubpofnfxalwimtyniq/Build/Intermediates/ccn.build/Debug/ccn.build/Objects-normal/i386/ccnd_main.o
for architecture i386
I can relate to this error because I can find lots of main entries in the source code. Most of them are test utilities.
Here is what I tried:
I tried removing all those utility .c files but with no luck. The error is still there. I delete and delete until some files cannot find the definition of the function they are calling. So I had to stop there.
Though I wasn't able to build a bundle I was able to build a C/C++ static library (with an .a extension). After I got the .a file I tried to put it into another Xcode project and tried to build it into a bundle. I could build a bundle in that way, but then I had problem accessing the content of the bundle. How do I call functions defined in a .a static library if that library is hidden in a bundle? I read about Apple's documentation which says:
Note: Some Xcode targets (such as shell tools and static libraries) do
not result in the creation of a bundle or package. This is normal and
there is no need to create bundles specifically for these target
types. The resulting binaries generated for those targets are intended
to be used as is.
(quoted from: https://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFBundles/AboutBundles/AboutBundles.html#//apple_ref/doc/uid/10000123i-CH100-SW1)
Here is what I thought about:
I thought about replacing all main with something like main_sth. But the source code was not written by me so I didn't want to modify it. (It just doesn't feel like a proper way of doing things to me...)
I learnt that Xcode has gcc compiler built in. So I guess if gcc can make it, so can Xcode? It's just a wild guess - I am not familiar with Xcode and gcc.
Here is a summary of my questions:
Is there a way to properly organize a pile of code previously compiled and made by gcc make so that they can be built into an Xcode bundle?
Is it meaningful to put a .a library in an Xcode project and build it into a bundle? If it is meaningful, how do I call functions defined in .a after it is built into a bundle?
Is it proper to just replace all main() entries with something else?
Alright I think I have figured out at least one solution to the problem.
The duplicate main error was caused by a bunch of main entries in my source code. When the code was compiled by gcc make, I guess the author defined a sort of compilation order so that duplicate mains won't be an issue. (If you know how to do this, please let me know. I barely know make tools.) But when I just add the entire source code folder into my Xcode project, of course Xcode would complain during linking...
As I was unwilling to modify the source code (because the source code library is not developed by me), I decided to use another strategy to walk around this problem.
If your duplicate main error was reported from your own code, you can stop reading here. But if you are like me, with a bunch of gcc compiled source code and badly need a bundle yet don't know what to do, I may be able to help.
Okay here is what I did:
I set up an empty workspace.
I built a C/C++ static library project.
Import my entire source code folder into the static library project.
Set some header search path for the static library project.
Build the static library project. (Now I have a .a library which I could link against)
I set up another project, with a bundle target.
At the bundle project -> Build Phases -> Link Binary with Libraries, add the .a library that I just built.
At the bundle project -> edit scheme -> Build, add the static library project to the scheme and move it up the list so that it is built prior to my bundle project.
Then add .h files of my library project to my bundle project as references.
After that, add a .c file in my bundle project that basically functions as a wrapper. I picked a function that I want to call in Unity, wrote a wrapper function in the new .c file, and was able to build the bundle.
After several trial and error, I was able to import the bundle into Unity and was able to call the test function from Unity.
I was really excited about this! Though it's not completed yet I think this gives me hope and I am confident I can use the source code now! And the best thing about this solution is that I don't have to modify the library code developed by others. Whenever they update their code, I just update my .a library and that's it!
Though I have listed 11 steps I still feel that there are lots of details that I missed. So here are my references:
I followed this tutorial to build my source code into a static library: http://www.ccnx.org/?post_type=incsub_wiki&p=1315
I followed this blog to link static library against my bundle code and twist build phases and search headers: http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/
I followed this doc to import my bundle to Unity3D Pro as a plugin: http://unity3d.com/support/documentation/Manual/Plugins.html
I strongly recommend the second reference because that's what solved my problem!
Though the problem is almost solved there are still a few things that I haven't figured out:
I don't know if a wrapper function is at all necessary. I will try this out tomorrow and come back to update.
-- I am coming back to update: the wrapper function is NOT necessary. Just make sure you have all the headers in your bundle project and you will be able to use all the data structures and call functions defined in your headers.
I haven't used NSBundle class though I read a few docs about it. Previously I was thinking about using that class to access my .a library encapsulated in my bundle, but as I found the solution I wrote above, I didn't try the class out.
Lastly, if you have better solution, please don't hesitate to let me know!
I tried to follow the steps in the accepted answer, but had no luck. In the end, I realised step 10 needed to be modified slightly:
Create a dummy.c under (.bundle) project and the dummy.c can just be totally empty.
Remove the setting for the library you want to link inside Link Binary With Libraries
Instead use -Wl,-force_load,$(CONFIGURATION_BUILD_DIR)/libYourLib.a or -all_load to Other Linker Flags
PS: And also can use sub-project instead of workspace. and use Target Dependencies instead of Edit Scheme to achieve the same effect.
When trying to make a Cocoa framework I ran into the old problem of the headers not copying, which I fixed by changing the visibility(?) of the headers to public. now I Would Like to organise the framework more logically. when the headers are copied there are are placed all in the same directory with no subfolders. I would like it to organise the framework by placing the headers in sub folders so that I can #import them like:
#import <Myframework/Math/MathFunction.h> // import some math related functions
however I notice that the system frameworks contain subframeworks. If I must I am willing to do that and also is there a fast way to convert all the
#import "someFile.h"
to
#import <Myframework/somefile.h>
in the release so the in other project I can #import them without confufing the compiler?
when I create an xCode project with the 'Command Line Tool' c++ stdc++ template, i am able to include and compile opencv headers and run some code.
But i want to use OpenCV in a 'Cocoa Application' context. When created with that template, i got compile errors when I include the OpenCV headers in main.mm. (I already changed main.m to main.mm, the '//NSApplicationMain(argc, (const char **) argv);' is commented out)
One of those errors is: "Statement-expressions are allowed only inside functions"
I suppose its some kind of compiler version error, but when i compare the project build settings i cant find differences.
Do you have any ideas/expertise?
I ran into the same problem, I spent 2 days doing serious system tracing and as expected, the solution was so simple that an 8-year-old could have found it more quickly than I did.
Ready for this?
In the .mm file where you want to use OpenCV, you need to do your #include "opencv2/opencv.hpp" BEFORE any other includes. That's it! Just move it up a line and watch your problem magically disappear faster than that rug that really tied the room together.
This is for OpenCV 2.2 by the way, hence the new include file. Also if your XCode project uses a prefix header file (look in "Other Sources" for a "YourProjectName_Prefix.pch" file), then you'll need to put your #include "opencv2/opencv.hpp" there instead of in any other file.
Ian Charnas's Answer is correct, but there is one modification I would make.
This article has a more specific solution, and an explanation of why you need to do this.
http://aptogo.co.uk/2011/09/opencv-framework-for-ios/
// Add this new section BEFORE the #import statements for UIKit and Foundation
#ifdef __cplusplus
#import <opencv2/opencv.hpp>
#endif
Even if you rename your "main.m" to "main.mm" and moving the "#include opencv2/opencv.hpp" to the top (in the main file), the preprocessor will insert cocoa.h first because of the precompiled header files nemed something like "_Prefix.pch". To avoid such problems
- delete the #import statement or
- insert an #import statement above the cocoa.h import statement
Try adding: -lstdc++ to the "Other linker flags" in the build settings for your Cocoa app.
A cocoa application made by the Xcode templates won't link include the c++ library in it's settings by default.
add this to your .pch file
#ifdef __cplusplus
#import <opencv2/opencv.hpp>
#endif
dont forget to convert all of your .m files into .mm files
You'll probably find it easier to use OpenCV's C API rather than the C++ API. You can call C APIs directly from Objective C of course, so this makes life a lot easier. You just lose some of C++'s syntactic sugar, like default parameter values.