I'm trying to implement a unit test for my project.
When I use :
#testable import Project
it says:
"File 'ProjectTests.swift' is part of module 'Project'; ignoring
import". So I can't use project classes
I read similar questions and use all answers, but it gives no results.
Seems like I have some trouble:
Xcode - File is part of module, ignoring import
tried:
Check product module name in Project -> Build Settings -> Packaging
-> Product Module Name. (it is same for sure)
Enable testability in Build Options
Make Legacy Build system
Target Membership is on Tests target(not project, and this is right)
Full clean Derive Data and project
copy content of project, delete all content, copy back.
Related
I’m trying to change the product module name of a dynamic framework.
The main reason I’m doing this is that my framework is customised for each client, so I have different targets with different names and output files that I want to keep different as they are, but I would like the framework to be imported for all the targets with the product name.
The framework is in objective C and consumed by a swift application.
In the Xcode build settings the DefinesModule is set to YES.
Let’s say the product name is CustomerSDK and I want it to be imported as ProductSDK.
For example: The framework file will be CustomerSDK.framework and the import statement import ProductSDK.
If I use the $(PRODUCT_NAME:c99extidentifier) as the module name (the default option in Xcode) by calling import CustomerSDK it works, but when I try to change the Product Module Name field in build settings to another one the code completion of Xcode in the host application project doesn’t find the module name and even if I write it I get the “No such module ProductSDK” error. Looking inside the resulting product framework I can see that no modulemap file is generated.
I tried also to create a custom module.modulemap file, in this case the code completion of Xcode in the host application project proposes the new name, but when I try to compile I still get the “No such module ProductSDK” error.
framework module ProductSDK {
umbrella header "CustomerSDK.h"
export *
module * { export * }
}
Background: I'm converting a large old mixed language codebase to a framework. I'm having problems, so I thought I'd start with a minimal test project to see how things work. I ran into more problems. This is Swift 5.0 with Xcode 10.2.1.
I created a new iOS framework project called TestFramework. TestFramework has the following source files:
OCTest.[hm], with a single private class
OCPublic.[hm], with a single public class. It calls OCTest.
STest.swift, with a single public class. It calls both OCPublic and OCTest.
I also have the following two umbrella headers, in the same folder as the source files:
TestFramework.h, which is the one Xcode created automatically. I only added #import "OCPublic.h".
TestFramework_Private.h. It has two lines:
#include "TestFramework.h"
#include "OCTest.h"
They all reside in the TestFramework folder, along with Info.plist and everything else Xcode creates automatically.
I managed to make this compile, build a framework package with carthage build --archive and use the resulting framework successfully in a test app with the following module maps and build settings:
TestFramework/module.modulemap exists and is empty.
TestFramework/module.private.modulemap exists with these lines:
module TestFramework_Private {
umbrella header "TestFramework_Private.h"
export *
}
Both MODULEMAP_FILE and MODULEMAP_PRIVATE_FILE in build settings are unset.
SWIFT_INCLUDE_PATHS is $(PROJECT_DIR)/TestFramework.
DEFINES_MODULE is true.
If I add any content (framework module TestFramework { … }) to module.modulemap or try to make MODULEMAP_FILE or MODULEMAP_PRIVATE_FILE point to their files (with the values TestFramework/module.modulemap and TestFramework/module.private.modulemap) I get various build errors (can't find TestFramework_Private, redefinition of module TestFramework, etc.)
If I remove the empty main module map, I get No such module 'TestFramework_Private' where STest.swift tries to import it.
If I try to move the private things into a separate folder and change SWIFT_INCLUDE_PATHS and MODULEMAP_PRIVATE_FILE I get more build errors.
Are there some values for the MODULEMAP* settings that should work, with or without content inside the main module map? What should I do if I wanted to move things into different folders?
It seems at least some of my problems were caused by this:
When building a framework that has module maps in both the source and the install directories that define the same module, the compiler will show a redefinition message. (28638816)
Workaround: Rename the module map file in the source directory to a non-default name (the default name is module.modulemap or module.map), and set the Module Map File build setting to the renamed module map.
Renaming my module map file to anything other than module.modulemap — the name used in, for example, all over Clang documentation — made it possible to point MODULEMAP_FILE at it, and allowed me to move the headers to a different location etc.
I'm trying to write an open source app to show how you can write client + server code in Swift.
The source code is located here: https://github.com/haaakon/QuizWorld (QW for short)
The app is using a framework, located here: https://github.com/haaakon/QuizWorld-API (QWAPI) to access the API. I've imported the QWAAPI as a project into the QW app, it runs fine in simulator, but when running the tests, it doesn't compile because of this Error:
Undefined symbols for architecture x86_64:
"QuizWorld.QuestionViewModel.__allocating_init () -> QuizWorld.QuestionViewModel", referenced from
This is from only one line of code in the test:
let a = QuestionViewModel()
This means that the test target does not correctly get the imported module in. The imports are:
#testable import QuizWorld
#testable import QuizWorldAPI
import Prelude
import ReactiveSwift
import ReactiveExtensions
import Result
I've tried adding alot of different imports, even for the Frameworks used in the API Framework, but nothing seems to fix this. The QW-Tests target also has the correct target dependency setup. Anyone have a clue where i can go next with this? All the code is open source in the repos linked to.
In your test target, you have nothing set in Test Host and Bundle loader build settings. During linking phase it basically fails (doesn't know where from) to load the symbols. Target dependencies only says what should be built before, and "Link binary with libraries" has no effect for dynamic frameworks.
Set following build settings in your test target:
Test Host: $(BUILT_PRODUCTS_DIR)/QuizWorld.app/QuizWorld
Bundle Loader: $(TEST_HOST)
The docs for the latter:
Specifies the executable that will be loading the bundle output file being linked. Undefined symbols from the bundle are checked against the specified executable like it was one of the dynamic libraries the bundle was linked with.
I tried this on your project and it works.
UPD: In your second commit "setup for first test" you have removed these lines, so you might just reverse deletion of those individual lines.
UPD2: Regarding your general project setup. Try running your app on a real device, with this setup it won't find 3rd party frameworks included from QWAPI project, as they are not copied automatically. You will need to setup "Copy frameworks" build phase, to make sure that dynamic frameworks are copied in to the app bundle.
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)
I wrote a class in Swift. I want to use this code in two separate iOS app projects that I wrote. Both the shared code and the apps are written in Swift. What is the best way of doing that?
I tried to create both a framework and a library in Swift and then add it as a sub-project to my app. In both cases I could not make the app see the module. I tried to add the shared module to "Target Dependencies" and "Link Binary With Libraries" of the main app's target. No luck - the app still can not see the classes of the shared module.
Using Xcode6 Beta6 at the moment.
Solution
As Konstantin Koval and Heliem pointed out, all I needed is to use public in my class and method declarations, in the shared module. Now all works, both if I use workspace and if I add the module as a subproject.
Update
I just found an excellent easy solution for reusing code between projects in Swift. It is called Carthage (https://github.com/Carthage/Carthage). This is not a plug as I am not affiliated with it in any way, I just really like it. It works in iOS 8+.
Create a new project (iOS Cocoa Touch Framework) for your reusable code
Move your classes to that Framework project
Mark your methods and classes, that should be visible to others as public
Create Workspace.
You can create a workspace on step 1. When you create new Framework project, Xcode will ask you if you want to create new workspace and add that project to workspace. This is the best approach
Add both your project and Framework to the workspace
Select you project target -> General tab. Add Framework and Libraries (add your library here)
When you want to use code from your Library in swift file, import it using import 'LibTargetName'
You can take a more programatic approach by using SWM (Swift Modules): https://github.com/jankuca/swm
It is very similar to npm (node.js package manager) or bower (client-side module manager); you declare your dependencies in a swiftmodule.json file like below. It does not have a central module registry like the two mentioned JS solutions, it only accepts git URLs.
{
"name": "ProjectName",
"dependencies": {
"Dependency": "git://github.com/…/….git"
}
}
…run swm install and have the Dependency module (compiled into a *.swiftmodule binary) ready for import in the .modules/ directory.
import Dependency
And if you prefer to skip Xcode for app development, you can also build your whole app using swm build (more info in the project's readme).
The project is still in early stages but it makes itself useful a lot for me at least. It provides the most clean (and clear) way of creating importable modules.
Here is a video which is very straightforward: http://eonil-observatory.tumblr.com/post/117205738262/a-proper-way-to-add-a-subproject-to-another-xcode
The video is for OS X instead of iOS. But you will get it and figure out the process for iOS.
Let's assume that AppA needs to reused code from SharedProject.
The following process works for me in Xcode 7 Beta:
Create SharedProject. Project type must be Framework instead of Application. You write common code in this project and mark the code as public.
Open AppA in Xcode, open the folder which contains SharedProject in Finder. Drag the .xcodeproj file of SharedProject from Finder and drop it into the root folder of AppA in Xcode Project Navigator.
AppA --> Build Phases --> Link Binary with Libraries. Add SharedProject.
import SharedProject and reuse code from SharedProject!
Edit:
Nowadays I suggest you use Carthage. It's better than the home made solution above.