So I'm working on an iOS project in Swift, and I wanted to create a Static library with some useful stuff in it.
My problem is when I try to build my lib in Xcode (version 6.3) I have a "Build Failed" followed by : /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: unknown option character 'X' in: -Xlinker
I've never saw this and it's not my first static lib. So I was thinking I may be linked to the fact that I'm using exclusively Swift class.
What do you guys think ?
Thank you in advance.
As mentioned, Apple does allow Swift in static libraries as of Xcode 9 Beta 4.
We attempted to do this on an existing project with an Objective-C-based target and "child" static library projects and kept running into a linking error
ld: library not found for -lswiftSwiftOnoneSupport for architecture x86_64
also
ld: library not found for -lswiftDispatch for architecture x86_64
This is because the main target (app) is trying to build solely against Objective-C and isn't told by the static library that it needs to include Swift libraries. This was because there weren't any Swift files in the Compile Sources section of our Build Phases for the app target.
So basically all you have to do is add at least one .swift file to that compile list and it will include the Swift libraries for you. It doesn't even need to have any code or values in it, it can be an empty file.
Then you can start adding Swift files to your "child" static library project. I would let it generate the bridging header for you at first then you can move it around and change what gets imported (make sure the project points to the right file in the build settings if you move it).
You should still keep in mind that using Swift and Objective-C within the same static library may have issues of its own. I suggest reading the Apple developer doc "Swift and Objective-C in the Same Project" on how to address importing Objective-C into Swift (using a bridging header) and how to use the Swift files in your Objective-C code (importing the generated -Swift.h for your library).
Swift doesn't support static library
Although the correct way should be create a framework, there is a workaround here.
As of Xcode 9 beta 4, Xcode natively supports static libraries with Swift sources.
Swift consumer -> Swift static library
Xcode version 10.2.1
Create Swift static library
Create a library project or create a library target
File -> New -> Project... -> Cocoa Touch Static Library
//or
Project editor -> Add a Target -> Cocoa Touch Static Library
Add files .swift
Select `.swift` file -> Select File Inspectors Tab -> Target Membership -> Select the target
//or
Project editor -> select a target -> Build Phases -> Compile Sources -> add files
Build library - ⌘ Command + B or Product -> Build
Note 1: Be sure that you build library for the same process architecture as the client code.
Note 2: expose your API that should be visible for consumer using public or open access modifiers[About]
Find generated output[Build location]
Products group -> lib<product_name>.a -> Show in Finder
The directory includes
lib<product_name>.a – a built static library
<product_name>.swiftmodule. swiftmodule describe an interface of a library and a compiler version. This folder includes:
.swiftdoc - docs
.swiftmodule - public interface/definitions
Swift consumer with Swift static library
Drag and drop the binary into the Xcode project[About]
Link Binary[Undefined symbols] [Link vs Embed]
Project editor -> select a target -> General -> Linked Frameworks and Libraries -> add -> Add Others... -> point to `lib<target_name>.a` file
//or
Project editor -> select a target -> Build Phases -> Link Binary With Libraries -> add -> Add Others... -> point to `lib<target_name>.a` file
Add Library Search paths(LIBRARY_SEARCH_PATHS)[Library not found for] [Recursive path]
Project editor -> select a target -> Build Settings -> Search Paths -> Library Search paths -> add path to the parent of `lib<target_name>.a` file
Add Import Paths[No such module] [Recursive path]
Project editor -> select a target -> Build Settings -> Swift Compiler - Search Paths -> Import Paths -> add path to a folder with `.swiftmodule`
Import module to the Swift client code [module_name]
import module_name
[More examples]
Related
I am trying to use an Objective-C framework with the Swift programming language for iOS 8 development. This is a specific case of an import but the general problem is:
How do you import an Objective-C framework into swift and get the import recognized?
I am trying to integrate the Parse framework into a swift application using the iOS 8 and Xcode 6 betas.
Here is the technique for Parse framework integration in Objective-C:
https://www.parse.com/apps/quickstart#social/mobile/ios/native/existing
I have downloaded the Parse framework as a compressed archive, extracted it, and imported it into Xcode 6 without any problems. Within my application it appears as a properly formatted framework under the name Parse.framework.
My current thought process is to modify the AppDelegate.swift file in the root directory of my project. Here is the current file without modifications (automatically generated by Xcode upon swift project creation):
https://gist.github.com/fconcklin/e8ef7d8b056105a04161
I have tried to import parse by adding the line import Parse below the line import UIKit. However, Xcode issues a warning that there is no such module found and the build fails.
I also tried creating a file ${PROJ_NAME_HERE}-Bridging-Header.h that contains the Objective-C import of Parse using import <Parse/Parse.h>. This line doesn't throw an error but appears to ultimately make no difference.
After further research I found the solution and realized that I was just confused.
The correct approach is as follows:
Import your Objective C framework by dragging and dropping the framework into an Xcode 6 Swift project.
Create a new Objective C file in your project (File->New->File [Objective C for iOS]).
Accept the prompt (agree) to create a bridging header file between Objective C and Swift.
Delete your newly created Objective C file but retain the bridging header file ${YOURPROJ}-Bridging-Header.h.
In the Bridging header file, import your framework using the standard Objective C import syntax (e.g. #import <Parse/Parse.h>).
This relinquishes the need to perform an import Parse statement in your AppDelegate.swift file. You can now write code that utilizes whatever framework as long as it is imported using the bridging header. It is available throughout your project's Swift files.
Now, if you would like to test Parse integration in your project, you can type Parse. and use code completion to browse the framework and see that the code completion is indicative of a successful import.
However, there is another caveat here that needs to be addressed when using a Bridging Header file. All dependencies of the framework need to be specified in the Bridging Header file as well. In the case of integrating Parse framework into a Swift application your Bridging Header file will look like this:
#import <Foundation/Foundation.h>
// Parse Dependencies
#import <AudioToolbox/AudioToolbox.h>
#import <CFNetwork/CFNetwork.h>
#import <CoreGraphics/CoreGraphics.h>
#import <CoreLocation/CoreLocation.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <QuartzCore/QuartzCore.h>
#import <Security/Security.h>
#import <StoreKit/StoreKit.h>
#import <SystemConfiguration/SystemConfiguration.h>
// Import parse framework
#import <Parse/Parse.h>
Hope this helps.
A "Fool Proof" way of adding a bridging header is as follows:
If you have a Swift project, add a new Objective-C File to your project and Xcode will prompt if you want to configure your project with a bridging header. Press yes.
If you have a Objective-C project, add a new Swift File to it and you will get the same prompt. Press yes.
After you get the bridging header, you can delete the file you just added if you want to.
To add Parse framework to the Swift project:
Add this libaries to the Swift Project.
Paste this frameworks from ParseSDK to your project:
Add a ProjectName-Bridging-Header.h (https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/MixandMatch.html) (https://stackoverflow.com/a/24272431/1847511) file with such content.
Add path to tie bridging header:
Add the TestCode:
Run the app.
The answer for my problem was different. I had the Framework Search Paths in my project's Build Settings set to recursive when they should have been non-recursive.
In my case, my target has its Framework Search Paths set to $(inherited), which means to inherit the setting from my project.
My project's Framework Search Paths only had one path, $PROJECT_DIR/../External/** (with the two asteriks meaning "search this folder recursively". My Parse.framework file was located in the base level of the External folder.
Changing the path from recursive to non-recursive fixed things for me. Very strange...
Using Objective-C Classes in Swift
If you are going to import code within an App Target (Mixing Swift and Objective-C in one project) you should use bridging header file to expose Objective-C code to Swift code. [Mixing Swift and Objective-C code in a project]
In this post I will describe how to import Objective-C framework to Swift code
Swift consumer -> Objective-C dynamic framework
Xcode version 10.2.1
Create Objective-C framework
Create a framework project or create a framework target
File -> New -> Project... -> Cocoa Touch Framework
//or
Project editor -> Add a Target -> Cocoa Touch Framework
Two files will be generated:
Info.plist - Build Settings -> Info.plist File
<product_name>.h - Build Phases -> Headers. It is umbrella header file which will be open for consumer[About]
Add all .h files to this umbrella file(<product_name>.h)
#import "header_1.h"
#import "header_2.h"
Add Implementation files .m
Select `.m` file -> Select File Inspectors Tab -> Target Membership -> Select the target
//or
Project editor -> select a target -> Build Phases -> Compile Sources -> add files
Add Headers files .h that were listed in <product_name>.h in public zone (header_1.h, header_2.h)[can not do it] [public target membership]
Select `.h` file -> Select File Inspectors Tab -> Target Membership -> Select the target and make it **public**
//or
Project editor -> select a target -> Build Phases -> Headers -> add files to the **public** zone
Build the framework - ⌘ Command + B or Product -> Build
Note: Be sure that you build the framework for the same process architecture as the client code.
Find generated output[Build location]
Products group -> <product_name>.framework -> Show in Finder
The framework includes
Info.plist
Modules folder with:
module.modulemap[About] [Custom modulemap] This file was autogenerated because Build Settings -> Defines Module -> YES
Headers folder with:
files from Headers section. There are public interfaces/definitions
Swift consumer with Objective-C framework
Drag and drop the binary into the Xcode project[About]
Embed binaries[Library not loaded] [Link vs Embed]
Project editor -> select a target -> General -> Embedded Binaries -> path to `<product_name>.framework` file
I will automatically add the framework to:
Project editor -> select a target -> General -> Linked Frameworks and Libraries
Project editor -> select a target -> Build Phases -> Embed Frameworks
Project editor -> select a target -> Build Phases -> Link Binary With Libraries
Add Framework Search paths(FRAMEWORK_SEARCH_PATHS)[Module not found] [Recursive path]
Project editor -> select a target -> Build Settings -> Search Paths -> Framework Search paths -> add path to the parent of `<product_name>.framework` file
Import module to the Swift client code[module_name]
import module_name
More examples here
New Parse framework version need some update.
Such as You should insert libsqlite3.0.dylib in Library Binary With Libraries and update header file with #import and #import
I have a project with multiple targets that one of them uses a special framework. The framework has been written with Objective-C and my project is written with Swift.
So I need to have a Bridging-header file where defines the framework. Now I use the communal Bridging-header file but I don't want to use that framework on the other targets.
I tried to use the Bridging-header file separately for each target but I faced compile error which was couldn't find the framework in those of class files that import it!
- TL;DR
My question is: How can I add an Objective-C framework in the Swift project with multiple targets with considering that it should use in one target as well as the bridging-header file?
After a couple of days, I could manage to solve it.
1) Add a custom flag (MY OPTIONS) as well as #ifdef and #endif on the BridgingHeader.h file. like the following picture:
2) Select Target(specific) -> Build Settings -> Preprocessor Macros then add
MY_OPTIONS=1
3) Select Target(specific) -> Build Settings -> Swift Compiler - Custom Flags -> Other Swift Flags then add
-DMY_OPTIONS
4) On your class add this line to prevent get a compile error when compiling other targets
#if MY_OPTIONS
let specificVC = SpecificViewController()
self.present(specificVC, animated: true, completion: nil)
#endif
I have made an Xcode Swift project ("Project1"). In a new project ("Project2"), I have trouble adding project 1.
I have tried adding project 1 to project 2's build phases (target dependancies, compiled sources, link binary with libraries); didn't work. When adding to the compiled sources, it wouldn't work no matter which option I chose (folder references, groups, copy if needed).
I get no compiler errors at:
import Project1
But when I try to use a class from project 1, I get the error "Use of undeclared type".
I have also tried to following links with no success:
External library usage in xcode
Xcode : Adding a project as a build dependency
Xcode how to add an external project
Both projects are in Swift (iOS).
I'd be very thankful if someone helped me with this issue.
Update: Project 1 is not a framework - it's an iOS app. I need to use some of its classes in project 2. The problem is that project 1 uses the Objective C library Common Crypto via a bridging header. When I manually add project 1 classes into project 2, I get an error ("unresolved identifier") in the project 1 Swift code that uses Common Crypto.
So in a nutshell: I have an iOS app (project 1), which is in Swift but uses Common Crypto via bridging header. When I add a number of classes from project 1 into project 2, it cannot resolve the references (in project 1) to Common Crypto variables.
Assuming Project1is a Framework and Project2 is an application using the framework:
Create a virgin Workspace (Xcode File -> new -> Workspace) named TestWorkspace
From the Finder, drag the Project1.xcodeprojfile to the TestWorkspace
From the Finder, drag the Project2.xcodeprojfile to the TestWorkspace, above Project1
Edit your TestWorkspace schemas Build setup:
Add Project1 and Project2
make sure Project1 is above Project2
Untick "Paralellize Build" to assure Project1 is build first
Build
Select Project2s target -> General
Drag artefact project1.framework(in Productsgroup) to "Linked Framworks and Libraries"
Note: To be visible for the client, all classes and methods in your project1.framework have to be public or open. Finde detailed information in Apples documentation.
Edit: As you have CommonCrypto as a dependency you will have to add the module to your Project2 project instead to solve your issues ( this is the easiest without resorting to an umbrella framework ). Add a run script build phase and include http://pastebin.com/1vmiqffu
-- Credits: Script 'stolen' from: https://github.com/henrinormak/Heimdall
Ok so I'm going to assume here that Project1 actually has a framework as a target. What are the access permissions set on the types you are trying to use?
Here are a couple of catchya's with Swift and frameworks as I encountered them:
You do not have a bridging header, instead your framework includes headers of non-Swift dependencies inside the header file of your framework ( ModuleName.h ). This also means these will be available to whatever project you import them to. As far as I know you need to use a module.modulemap in order to make use of private headers and includes.
All Swift Classes / Structs / Definitions in general are internal by default. It is a very good design choice and it forces you to think about the access rights on every component you write. Keeping things private by default makes it easier to only open stuff that really needs to be open ( public, open ), allowing for easier code maintenance since you know that private things are only accessed within the same context. ( Otherwise: error )
For some more assistance this link might be of help to you on how to do some fundamentals:
your first ios framewok (swift)
My goal in this was to create an iOS framework that incorporates both Swift and Objective-C that I could use in my development projects. The nature of this framework is that the framework itself is undergoing development. So, it was important that each time I build a project using this framework (I'll call projects using the framework "using" projects for lack of a better term), I wanted to make sure the framework itself was re-built. I wanted this to be a framework because I have a few using apps across which I want to use the same framework code. I have struggled with this for a good hunk of today, and wasted a lot of time on something that should have been, in my thoughts at least, easier. So, I'll share my process.
The first thing to observe (which was certainly not my first observation!) is that you cannot do this using a static library under iOS. Xcode will not let you use Swift in a static framework Try it. Xcode will deny your wishes!
Here's the process I ended up with. The two main issues I had to deal with were: (i) making Xcode link to the framework in the using project without errors, and (ii) getting access to the headers of the framework in the using project. In Apple's enlightened view these two issues are separate. Note the sarcasm. ;).
1) Create a Cocoa Touch Framework using Xcode. I believe this works with Xcode6 and Xcode7. Use:
File > New > Project > iOS > Framework & Library > Cocoa Touch
Framework
I happen to be using Xcode7. (Do not make a Cocoa Touch Static Library-- like I said above, Xcode will not let you incorporate Swift into static libraries).
2) With your Swift classes, make sure the members and functions are public. I've not experimented with this, but it seems that the public attribute is necessary for the members and functions to be visible to users of the framework.
3) Add what ever Swift classes (and Objective-C) you want to your framework.
4) Close that framework project. (The same project can't be open twice in Xcode, and you need to incorporate the framework into your using project next).
5) Open your using project in Xcode. For me this was an existing universal app project. You may be creating a new using project. In any event, drag the .xcodeproj file of your framework project, in the Finder, into your using project.
6) Inside of your using project, open your framework project. And drag the framework file into Embed Frameworks in Build Phases (the Embed Frameworks section wasn't present in Build Phases when I first started my experiments and I don't know yet what magic caused it to appear!).
These steps so far should enable you to build and link without actually yet integrating the usage of your library code.
(I was using https://github.com/RadiusNetworks/swift-framework-example for some of my testing).
7) Now for the coup de grace: Under Build Settings, search for Framework Search Paths. And add in:
${TARGET_BUILD_DIR}/YourFrameworkName.framework
(It seems you do not have to have this marked as recursive).
8) In your Swift code files using the framework, you need to add an import at the top of each file:
import YourFrameworkName
You should now be able build and link using your new library!
9) One more gotcha: Make sure your Deployment Target for your framework matches your destination project. E.g., if your using project builds for iOS7, make sure your framework builds for iOS7 or earlier.
10) Second gotcha (10/23/15): I just learned that it is necessary for my framework to have "App-Swift.h" (the name I use for this) as the Objective-C Generated Interface Header name in Build Settings. When I took this (Objective-C Generated Interface Header) out (trying to fix another issue), I get serveral interesting issues coming up in App-Swift.h. These issues look something like:
"Cannot find interface declaration for NSObject"?
11) Third gotcha (10/29/15): When I tried to upload my first app to iTunes Connect that makes use of this Framework, I got an uploading error. The error read:
ERROR ITMS-90206: "Invalid Bundle. The bundle at
'Your.app/Frameworks/YourFramework.framework' contains disallowed file
'Frameworks'."
Various SO and other posts have run into this kind of error, and the trick for me was, for the Framework target, in Build Settings, to set "Embedded Content Contains Swift Code" to NO. (My app Build Settings had this flag set to NO already).
An example project with most of these steps completed is on https://github.com/crspybits/CocoaTouchFramework.git
Swift consumer -> Swift dynamic framework
Xcode version 10.2.1
Create Swift framework
Create a framework project or create a framework target
File -> New -> Project... -> Cocoa Touch Framework
//or
Project editor -> Add a Target -> Cocoa Touch Framework
Two files will be generated:
Info.plist - Build Settings -> Info.plist File
<product_name>.h - Build Phases -> Headers. It is umbrella header file [About]
Add files .swift
Select `.swift` file -> Select File Inspectors Tab -> Target Membership -> Select the target
//or
Project editor -> select a target -> Build Phases -> Compile Sources -> add files
Build library - ⌘ Command + B or Product -> Build
Note: Be sure that you build the framework for the same process architecture as the client code.
Find generated output[Build location]
Products group -> <product_name>.framework -> Show in Finder
The framework includes
Info.plist
Modules[About] folder with:
module.modulemap
<product_name>.swiftmodule
.swiftdoc
.swiftmodule
Headers folder with:
files from Headers section. There are public interfaces/definitions
<product_name>-Swift.h - Xcode-generated header file[About]
Swift consumer with Swift framework
Drag and drop[About] the binary into the Xcode project
Embed dynamic binary(or not embed || link a static binary)[Link vs Embed] [Library not loaded]
//Xcode 11
Project editor -> select a target -> General -> Frameworks, Libraries, and Embedded Content -> path to `<product_name>.framework` -> Embed
//pre Xcode 11
Project editor -> select a target -> General -> Embedded Binaries -> path to `<product_name>.framework`
Add Framework Search paths(FRAMEWORK_SEARCH_PATHS)[Module not found] [Recursive path]
Project editor -> select a target -> Build Settings -> Search Paths -> Framework Search paths -> add path to the parent of `<product_name>.framework` file
Import module to the Swift client code[module_name]
import module_name
More examples here
since latest XCODE 6 update my XCTest framework dissappeared from Developer/Library/Frameworks dir.
Is there any way to get this framework back? I can only see the SentestingKit there, which I don't want to use since I moved to XCTests/Kiwi tests
The project's FRAMEWORK SEARCH PATHS are set as they should ->
EDIT:
I've also added $(PLATFORM_DIR)/Developer/Library/Frameworks to my test target's framework search paths
In your Test Target, make sure Build Settings -> Linking -> Other Linker Flags is set to "-framework XCTest"
Also make sure these are set (In Test Target):
Build Settings -> Linking -> Packaging -> Private Headers Folder Path = $(CONTENTS_FOLDER_PATH)/PrivateHeaders
Build Settings -> Linking -> Packaging -> Public Headers Folder Path = $(CONTENTS_FOLDER_PATH)/Headers
Build Settings -> Linking -> Packaging -> Wrapper Extension = xctest