Wrap a C++ library in Swift code, compile as a Cocoa Touch framework - swift

I have a C++ library that is full of warts and weird features, and I want to make it much easier to use (and reuse) in a Swift project. So I intend to wrap this C++ library in some Swift code, then make it available as a Cocoa Touch framework.
I've added both my (fat) .a file and the required .h files to my project, then added the .a to the "Link Binary with Libraries" section of Build Phases, and added the main .h file to the Project section of the Headers build phase. But the build fails with:
Library not found for -lMyLib
I'm obviously missing something here - I'm guessing maybe I need to adjust the Framework Search Path and/or Header Search Path? Or am I missing something more fundamental? My desired end result is a .framework another developer can pull into their Swift project without having to do any other build setting tweaks.

You're probably looking for "Library Search Paths" (LIBRARY_SEARCH_PATHS). You may need to add to "Header Search Paths (HEADER_SEARCH_PATHS) as well, depending on your setup. In this case, you shouldn't have to add anything to the Framework search paths, since you are not dealing with a Framework.
(As an aside, you are likely going to find that you have to wrap your C++ library in Objective-C++ code to expose the functionality to Swift.)

Related

How to selectively import a module in Swift depending on target?

Our Xcode project contains a sub-project that builds first party frameworks which we use as our standard libraries. One is built for each platform (iPhone, iPad, watchOS,...) but there is significant overlap between them (extensions for example).
In our Objective-C code in the main project, I simply have a different prefix header for each target based on its platform, and I import the relevant framework header. This means in my entire project I can use all the symbols that are in our "standard library".
I want this to happen in our Swift code as well (for both Swift and Objective-C symbols). From what I'm aware, Swift doesn't have the concept of prefix headers, so I'm needing to import the framework/module manually in each file.
What's more annoying, my imports won't just need to be
import MyFrameworkForiPhone
But because of the platform specific frameworks, with the help of Swift compiler flags, they'll need to become
#if RD_IPHONE
import MyFrameworkForiPhone
#elseif RD_IPAD
import MyFrameworkForiPad
#endif
Does anyone have any suggestions about how to cleanly work around this problem, or am I stuck with this for the time being?
While it may not be advisable to have separate modules for different platforms, sometimes we find ourselves in this situation and have to deal with it. Fortunately, there is one way to shorten that boilerplate...
Solution
You could create a third module, perhaps called MyFramework that selectively includes the appropriate framework for the current platform. Such a module would only need one source file that looks just like your example above:
#if RD_IPHONE
import MyFrameworkForiPhone
#elseif RD_IPAD
import MyFrameworkForiPad
#endif
Then, every other source file would simply import MyFramework. This works because a module will re-expose anything public from other modules it imports.
Analysis
This approach also provides a sensible location for anything that the two platform-specific modules have in common. Shared code can move into this platform-agnostic module, helping you move closer to the ideal scenario.
Notes
If you're using Swift Package Manager, see the documentation on modules. It's as simple as making a new directory.
In Xcode, creating a module means creating a framework. See Ray Wenderlich's guide for an example. It references iOS, but the same process applies to other platforms.
I would strongly advise against creating frameworks designed only for iPhone or iPad. If there is any UI code It would likely make it impossible for an app to be resizable on iPad and there isn't any code that will compile for one and not the other.
Besides that, you're not compiling separate binaries for iPad and iPhone if it's the same app. Imports are done at compile time, so you cannot dynamically include different frameworks based on the device on which it's being installed.
If you have completely separate apps that only support iPhone or iPad (which should be avoided), you could add compiler flags to each of them to do different things with the same files.
[edit: oops, I answered the wrong question. This answer is for Frameworks that target multiple platforms]
The support for cross-platform frameworks is still pretty bad. In Xcode, I work as follows:
create a single source tree for my library
create subfolders for platform-specific stuff
if a class is implemented differently for different platforms, it appears in each platform subfolder (where it is supported at all)
Now create a "Target" in XCode of type "... Static Library" for each platform you want to support (I have WatchOS, iOS, and MacOS in mine). Name them differently, obviously. However, change the "Build Settings | Basic | Product Name" on every one of these static libraries to be the same, like "MyLibrary" for example.
for each source file in your library, tick the "Target Membership" in the file properties to select which the platform libraries that should include this file. Obviously, everything in the platform-specific folders should only be included in those platform targets.
for other platform-specific targets, add Library linking and Target Dependency for the platform-specific target, like "MyLibrary_MacOS" or whatever you called your library targets above.
Now you can have "import MyLibrary" in your source files and it will automagically find the one that is actually available on the platform that you are compiling. This way, you can have platform abstractions or platform-specific stuff in your library and it doesn't appear everywhere in the code, just like "Foundation."
I also add headers in there for MacOS to provide dummy implementations of WatchOS APIs that I need for testing, for example. That way, I can unit test code on MacOS.
No, this is not optimal, because a formal "Framework" compile would be better, but it is the only way I have found to do it locally with full debuggability.
If anyone else has actually used something that works better, please let me know. Please don't recommend something you haven't actually used :)

Library Project Reference in Xcode

I know something like this is already asked many times on SO, but I've tried everything (been at this for three hours now) and I still didn't find a solution. I'm quite new to xCode and I'm starting to work on a project that was originally created by somebody else.
So, I have a library project in my xcode (XS2Library) and now I would like to reference to that library in my other project (WaarBenJij). Building the Library succeeds and I reference to it by adding the LibXS2Library.a to the Project target's "Link Binary With Libraries".
Xcode doesn't give me any errors, so it looks like the library project is referenced appropriately. However, when I try to build my project I get the error that a class that resides in my library project cannot be found ("'XS2URLLoader.h' file not found").
Can anybody steer me in the right direction, maybe?
There's a sensible difference between the .a file, which is needed for linkage and contains the library source, and the .h file, which is needed to compile (and preprocess) and which contains the functions and classes declarations.
Here you included the .a file, which is required for a later step, but to use the library you also need to import the required .h files into your project.
The easier way is to simply put them in your project.
Or you can add the whole library as a subproject and as a dependency.

How come Xcode doesn't automatically link with QuartzCore when the project uses it?

I am somewhat curious for iOS apps development with Xcode, even though we specifically state:
#import <QuartzCore/QuartzCore.h>
in our ViewController.h, when the project is linked, the QuartzCore library is not automatically linked. Why is that?
Because importing a header is in no way connected to linking against a library.
You will need to add QuartzCore Framework to the list libraries that your target links against.
Why does Xcode not do that automatically?
Well, the headers you are importing are actually part of that framework. So Xcode would have to scan through all of its frameworks, check their headers and possibly automatically link the connected libraries. That is certainly doable for OS-related frameworks but close to impossible for custom frameworks as long as Xcode does not know their location.
Sometimes, Apps do actually not want to link against a library just because they use e.g. an enum defined in a header.
Xcode doesn't automatically add any libraries other than the base 3. It doesn't take much to just link. Perhaps a future version will detect, but for now you have to go to Build Phases and Link them.
The point is that Xcode has no way to know that your project should link with Quartz Core Framework.
#import <QuartzCore/QuartzCore.h> is not enough to say that you need Quartz Core Framework. You can write your own library which included a header file named QuartzCore.h and put it under a folder named QuartzCore. If it is in your include files searching path, it is OK to use, unless you also add the official Quartz Core Framework into your project (which leads to conflicts).
There are other examples. When you import a namespace in Visual Studio for a .NET project, it doesn't automatically add any assembly into "Reference" of your project. It's because you can add a third-party assembly as reference which has the same namespace. You also can add a different version of official .NET Framework assembly.

Compiling static library inside a static library -- issue

I created a static library which internally contains another static library (X) inside "Link Binary With Libraries" folder. But when I export my library to a sample project and try to compile it fails to locate the X library path. I am adding "." in the "Library search path" build parameter while building my static library.
What is that I am missing here?
If I understood your issue correctly, then it is less a linker-search-path problem but more a conceptual problem.
I see two options for solving the issue:
The common and straight-forward solution;
add both static library projects into the project of your app
expand the included projects
expand the Targets of your app-project
expand the "Link Binary With Libraries"-Entry
drag the product files of your library projects (actual libraries) down into that "Link Binary With Libraries"-Entry
include the header-path to both of your library-projects within your USER_HEADER_SEARCH_PATHS build settings
The next approach is rather unconventional and in most cases just not worth the extra mile. Here comes some explanation before going into the details.
The concept of a static library basically is a bunch of object-files stuffed into one single file (archive). Linking a static library against another static library is rather uncommon - well, to spell it out correctly, impossible.
...but then again, nothing is impossible when it comes to coding ;)...
The wrapper-library solution;
use ar to extract all object files from all the libraries you want to combine
use ar to combine all those object files into one big, new library
ALong with setting up Header Search Path , Try setting up the Other Linkers Flag too..
Go to “Other Linker Flags” under the “Linker” section, and add “-ObjC” and “-all_load” to the list of flags
Hope that works for you,

Thrift framework for iPhone

I'm currently stuck trying to get my objective c generated files to compile in my iPhone project. Basically it keeps telling me there is no such directory for the following four imports:
Thrift/TProtocol.h
Thrift/TApplicationException.h
Thrift/TProtocolUtil.h
Thrift/TProcessor.h
I'm following all the instructions on the Thrift wiki and have downloaded and compiled the Thrift framework in XCode but there is no information specific to iPhone development. I'm almost certain it's a problem specific to an iPhone project because if I create a new command line project in XCode, I can import those files just fine.
After retaining the services of some kind of sorcerer I have figured out how to get Thrift to work with the iPhone/iPad (or at least get it to compile okay).
First, you want to grab the objective-c files with this command instead of from the wiki:
svn co http://svn.apache.org/repos/asf/incubator/thrift/trunk/lib/cocoa/src/ thrift-cocoa
Then, make a new Xcode project by going to New Project, selecting Framework & Library and Cocoa Framework. Click create and save it somewhere nice. Right click on Targets and select Add -> New Target. Choose Cocoa Touch and then Static Library. Give it a nice name. Go to the target's Build tab in info and change the Base SDK to iPhone Device (I'm using 3.2 but you can use whatever) and change Architectures to either Standard (armv6 armv7) or Optimized (armv7). Under the General tab add the Foundation and Cocoa frameworks.
Drag all of the files and folders you got from the svn repository into the Classes folder in the project. Check the copy items box and check the boxes next to both targets. Remove TSocketServer.h and .m from the Static Library's Copy Headers and Compile Sources folders respectively. You can now build the Static Library (and Framework optionally).
Open the project you want to use Thrift in and go to your target's General tab in info. Add the Static Library you just created to the Linked Libraries list. It should be named libYOUR_TARGET_NAME.a. Under the build tab go to Header Search Paths and add the path to the Thrift project you just created and check the recursive box.
Finally you just need to change the import statements in the Thrift generated code by simply removing the brackets and replacing them with quotes. You can now build you iPhone project again.
Try adding those .h files to your Xcode project.