I have a project in Xcode (swift) and I want to build it in two ways. a build with a framework (embedded in project) and another build without that framework.
Is there any way to do this with minimum changes for each update?
I means something like if #available statement which determine whether a particular framework is embedded in project or not.
something like:
if ... {
import framework
}
Finally, I found my solution.
In this case we should do four main tasks:
creating a scheme for separate builds
defining an Active Compilation Condition
excluding the frameworks we want to remove from build.
putting depended codes in #if scope.
First of all, we need to create two build configurations by duplicating and renaming debug and release build configurations (In this case, I named those as Debug_no_charkhune and Release_no_charkhune). For first step, with choosing main scheme and clicking on duplicate scheme in edit scheme page our new scheme is ready. just remember to change its name and build configurations in all tabs with new build configurations. For second step, we should go to Build settings tab in project setting page and set Active Compilation Condition values for wanted schemes. (In this case I defined CHARKHUNE as a condition).
Now we need to exclude unwanted frameworks in new scheme. for this, we should add framework name as a string in Excluded source file names section in project's builds settings like image:
Now we're ready for it. we should put codes that are related to excluded framework in an if statement like this:
#if CHARKHUNE
import charkhunePayment
#endif
At last. thanks #Cristik and #dfd for their advices.
Hope you enjoy ;)
Related
From the beginning of my project, I use a custom framework, let's call it "custom.framework". But there was a bug in this framework and now I want to use another version of the "custom.framework".
At first, I simply removed the "custom.framework" file from my project and added the new one. But nothing changed, the bug was still there.
After multiple tries and hours, I understood that Xcode add the old version in memory and used this one instead of the new version. I know it because in the new version I added a method and when I cmd+click the class I've add the method into, it's not there and the file's path is unavailable.
Searching through the web, I tried to change some version parameters to my framework projects: Compatibility version, Curent Library version, Framework version. But this didn't change anything to Xcode which keeps using the old version.
I also tried to make the framework's project as a sub-project and add resulting framework as a dependency to my target. It worked well, but as the framework's project is on a separated remote git repository, I don't think this is an acceptable solution.
So my last try was to build a "custom2.framework", to force Xcode to use the real file and not some cached version. But again, it doesn't work and when building I get errors telling me that all my classes in custom2.framework are duplicated symbols of its cached version of "custom.framework".
So my question is simple: how can I finally tell Xcode to deleted its cached old version and let me use the file I gave him? I already tried to delete my project's derivedData but it seems cached frameworks aren't there.... I'm so desperate :(
Edit: Here are 2 screenshots to illustrate the issue
First screenshot is the path as shown by Xcode when I opened the file from the .framework object in the project navigator.
Second screenshot is the path as shown by Xcode when I opened the file from a cmd+click to a "DCEquipmentManager" in code.
As you can see, the framework linked with the code is not the framework in the project.
it seems problem with binding in new framework, your project still linked with old framework files.
try to remove all files and folder related to your "custom.framework and also remove path for that framework from project setting--> build setting --> search Path
Then after Drag and Drop Your "custom.framework" files in project.
it works for me.hope it resolve your problem.
Please try to clear derrived data:
Window -> Organizer
at the right side you will see projects list. Find your project and tap on it. I the top part of window you will see button delete in front of Derrived data, tap on it.
I guess it will solve your problem.
It might sound silly, but sometimes restarting XCode or the whole machine fix things.
Did you remove the old framework from Build Phases --> Link Binary With Libraries?
Use Clean Build Folder: option-shift-command-K, or select it from the Product menu when holding down the alt/option key.
First lets say something upfront. The build stage is a(are) command line tool(s) that is managed by Xcode according to your Build Settings.
So when Xcode doesn't find your Framework - the Build System will usually also not find it. This forces you to act but may end up in confused Xcode to catch an older reference.
Yes it may happen that the Header Xcode is pointing to is correct but the build system still uses an old copy somewhere. An outdated copy can dangle around literally anywhere depending on the steps you took before.
It (Xcode) assumes where it is located but the Build System still uses another version or the Search Paths just pointing in the wrong Locations even if they are visible to you and even your Framework icons are visible in the lists. So when you erase the last build you actually only force Xcode to rebuild from the known arguments, the settings stay the same, the lists stay the same. Even restarting Xcode does not change anything, the problem persists.
Ergo: Compiler Instructions, Xcode settings and Build System settings don't match what the code tells with #import <NAME/Name.h>
So you will check at least those 6 stages again:
Is your Framework Header File published in your Framework project?
are Build Settings really pointing to the right Framework Search Paths or System Framework Search Paths?
Is your Framework in linking list?
Is your Framework in Embed Framework list?
Does your framework appear in the Framework Group Folder in Workspace/Project Browser? (usually the very last Group Folder in the Browser below all your other files)
Is my Folder Structure correct?
At least 1 to 4 must be right otherwise it will fail.
Here a random list of common causes
Framework is located outside your Source Paths structure
Structure got changed after you added it to the project
You use Workspace's where Framework development and Final Application can appear side by side but you assume Xcode uses this to change its Search Paths
The contained build settings are misleading from former drag and drop operations, ending up tricking Xcode in the "wrong" corner. In this case recreating a project is just one of the possible ways to fix it but not the solution.
Also dragging a Framework into your Project > General or separated in Build Phases > Link Binary list or Embed Framework lists does not make Xcode aware of the wrong Build Settings.
The Linking works, embedding works, but compiling does not. The Header information is still missing.
The solution must be to correct your Build Settings.
As mentioned above Build System and Xcode are two different things. In particular only setting the right Framework Search Paths will solve those issues, even if you managed to kick your derived data manually.
Erasing Derived data?
Derived data is the place where precompiler collects data to compile. So it can be seen as expression of what all the settings are told to do. Erasing it does of course not change the settings but may fix inconsistencies related to former Build Settings. It would erase the derived data and rebuild from the Build System Settings you gave.
Correcting Linking?
Also Linking is not the same as making Xcode aware of the desired Headers. Linking is for your final Product to know where Symbols are to call on them at runtime, it does not change Framework Search Paths and System Framework Search Paths, they stay the same as given.
But it is not wrong to start fixing first with
Product > Clean Build Folder, it forces your build to parse all and compile all again on the next Build.
When the troubles come up because of folder structure in parallel or Frameworks are simply placed outside the Source Directory then you must point to them directly or relative.
Most likely you should place one extra entry in your Framework Search Paths like $(SRCROOT)/../Yourframeworksource/build/Debug. expression to point to relative higher folder structure.
Needless to say that a Release Build likely needs another entry ending in "/Release".Hint: Well you can have different Search Paths for different Compile Schemes..
This works particular good after you cleaned Linking List, Embed Frameworks List and then also check the very last Group Folder "Frameworks" for double entries to drag and drop a fresh Framework reference in there.
How to know if leading /../ will fix it?
Click on the dropped Framework Icon inside the workspace Framework Group Folder (lower most) while your Project is the active selected to work on, now watch for the relative Path information on the very upper right side of Xcode, if there is some /../ you know you need it as well.
Sorting of Framework Search Paths
play a role of course, just the same as #import/#include rule sorting matters.
Remember the first found, first wins rule because often we use #import that works different then #include but ignores second attempts to declare. This leads to once wrongfully declared headers to hide corrected declarations later on in parsing that share the same filename or define rules
#ifndef xyz
#define xyz
// all your code here.
// a second read attempt would be ignored
// a second read is hidden also when you use #include then.
#endif
So you can sort those entries either by code and/or in the build settings if needed because of course it matters what is declared before other declarations depend on it.
I have an Xcode Project with three targets:
A Mac app to be distributed on the Mac App Store
The same Mac app, but to be distributed as a demo version on my
website
A login helper app that is a target dependency for the first two
targets
The login helper app is copied on build to the target of the current scheme (let's say the first target), which has a build path of
$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
When I change the scheme to the second target (the demo), I'd like for the build products path of the third target to be the same, except with _Demo attached to it. Basically, the third target's build path should always be the same as the current scheme's target (either target one or two).
Currently, I do it manually before building, but that's tedious.
Is there no way to make the Per-configuration Build Products Path (and the Per-configuration Intermediate Build Files Path, etc) dependent on the current target?
So when I select the first target, no _Demo gets attached to the path, when I select the second target, _Demo does get attached to the path.
Any pointers would be highly appreciated.
Thank you very much,
Matt
As I understand it, you want the login helper’s building to be aware of which “parent target” it’s being built in. Not sure if that’s possible.
What I’d do in this case, is add a separate “Copy” build step into targets 1 and 2. It sounds like copy is currently a part of building target 3, but it works better if it’s part of building targets 1 and 2.
I have a very similar situation with a command-line helper in one of my tools. Here’s the relevant part of my build settings.
I am looking for a way to add libraries to an Xcode project, using the command line.
I have been successful in adding files to groups with the XCS tool, but it does not support libraries.
I would, for example, like to be able to add CoreVideo.framework to a specific project with a command on the Terminal.
This project can handle frameworks:
https://github.com/kronenthaler/mod-pbxproj
Just add it as a normal file, it will figure out the correct type and how to set everything up (i.e., add it to the link library phase – before using it, you still need to import the header(s), of course).
// libFilePath: Path to the framework
frameworkGroup = project.get_or_create_group('Frameworks')
project.add_file(libFilePath,
parent=frameworkGroup,
tree='SDKROOT',
weak=True)
You can decide whether you want to weak-link frameworks (see code example) or not (just leave out the last parameter, it defaults to False). You can find the code to open/save Xcode projects in the repository.
Another way to do it is adding linker flags directly, e.g., -framework CoreVideo.framework. If the framework paths are set up correctly, you don't have to provide absolute paths. The disadvantage of this approach is that the linked frameworks aren't obvious if you open the Xcode project, as they are not part of the link library section, nor does the framework show up in any Xcode group in the Project Navigator.
You can try generating your .xcodeproj using tools like XcodeGen. It allows you to include different types of dependencies.
Yeah the title says it :-) What do they mean in plain English language? I really don't understand the explanation on Apple's website and I need to rename my target and I'm afraid that nothing works after that..
I've added in Workspace and Project too!
Workspace - Contains one or more projects. These projects usually relate to one another
Project - Contains code and resources, etc. (You'll be used to these!)
Target - Each project has one or more targets.
Each target defines a list of build settings for that project
Each target also defines a list of classes, resources, custom scripts etc to include/ use when building.
Targets are usually used for different distributions of the same project.
For example, my project has two targets, a "normal" build and an "office" build that has extra testing features and may contain several background music tracks and a button to change the track (as it currently does).
You'll be used to adding classes and resources to your default target as you add them.
You can pick and choose which classes / resources are added to which target.
In my example, I have a "DebugHandler" class that is added to my office build
If you add tests, this also adds a new target.
Scheme - A scheme defines what happens when you press "Build", "Test", "Profile", etc.
Usually, each target has at least one scheme
You can autocreate schemes for your targets by going to Scheme > Manage Schemes and pressing "Autocreate Schemes Now"
A target is an end product created by running "build" in Xcode. It might be an app, or a framework, or static library, or a unit test bundle. Whatever it is, it generally corresponds to a single item in the "built products" folder.
A scheme represents a collection of targets that you work with together. It defines which targets are used when you choose various actions in Xcode (Run, Test, Profile, etc.) Often, you will have just one scheme, which uses the main app target for the Run, Archive, and Profile actions, and a unit test target for the Test action. If you were building two related apps, you might have two schemes that used the same unit test bundle but different app targets.
The main benefit of schemes (introduced in Xcode 4) is that they allow you to switch between running your app and your unit tests without needing to toggle the selected target.
I am a visual person, hence to explain the concept I will be using a diagram.
When you have multiple targets they can be one-to-one matched with Xcode's Run,Test,Profile actions, this concept defines a scheme
A target is a version of your Project,i.e targets differ slightly in classes & resources to use during built time. A project can have multiple built time setting for separate distribution requirements.
Xcode structure
Workspace
-> Project
-> Target
-> Dependency
-> Scheme
-> Action
-> Build Configuration
-> Build Configuration File(.xcconfig)
Workspace (.xcworkspace) - is a container of multiple projects. It was created as a next step of cross-project references[About]
Workspace contains all schemes from included projects
Workspace handles all implicit dependencies[About]
Observations:
It is safe to work with different projects inside the same workspace and do not catch
//if you try to open two projects on two Xcode instances
Couldn't load Project.xcodeproj because it is already opened from another project or workspace
Cocoapods[About] working with workspace where creates Pods project
Project (.xcodeproj) - It is a container for targets and scheme. It defines code files, resources...
Also Projects manages Build Configuration(changed by scheme) and Build Configuration File[About]
You can convert existing Project into Workspace
File -> Save As Workspace...
[Workspace vs Project]
Target - PBXNativeTarget section. Defines a specific set of build settings that generate:
Application target
Library and framework targets
Test
Aggregate[About]. E.g. it is used to create a Universal framework or Umbrella framework
Scheme
Contains action(run, test, profile, analyze, archive) + configuration(additional arguments, [Build Configuration], diagnostic)
Scheme can be shared which helps you in CI, Carthage[Example]... and located:
<project_path>/<project_name>.xcodeproj/xcshareddata/xcschemes
Dependency - Targets can have dependencies. Dependency is a source link against. These dependencies can be linked statically or dynamically[About] There are two types of them:
Explicit Dependency[About] - Source code of the dependency that is located in the same project or nested project
Implicit Dependency[About] - Source/closed code of the dependency that is located in the project that is a part of the same workspace.
[Vocabulary]
tldr; Targets contain instructions to build a module/framework/library or an App/end Product e.g. instructions to build a watchOS app and an iOS App. Schemes know how to respond to certain actions e.g. a build action or test action or archive action.
Make sure you See WWDC16 video — Introduction to Xcode [45:13]. If you wanted to gain deeper knowledge then watch the entirety of the video. The video is simple to follow yet very foundational. My answer is mostly off of that.
Scheme
A scheme is how you specify what you want to run and it also contains
information about how you want to run it.
For example, I could have a project with an iOS app and a Watch app,
and in that case, I would have one scheme to run my iOS app and one
scheme to run my Watch app
Run will run my app in the debugger.
Test will run my tests.
Profile will run my app in instruments so I can measure its
performance.
Analyze will run Xcode's static analyzer and help catch problems I
might otherwise have missed.
And finally, the Archive action will build my app for release and put
it in the archive that I can then use to distribute to my testers or
to the App Store or to save for future crash log de-symbolication, or
symbolication.
Project
A project is a document that you use to organize your code an
resources in Xcode.
You have references to source code files and resource files on disc,
targets which actually build those files into products like your app,
Build settings which configure how your targets build their products,
and schemes which configure how you perform actions, such as Run, with
your targets.
Now, to access your project settings, you select your project in the
navigator, you select the popover at the top of the editor, and select
your project there.
Target
You have references to source code files and resource files on disc,
targets which actually build those files into products like your app,
Build settings which configure how your targets build their products,
and schemes which configure how you perform actions, such as Run [test, build], with
your targets.
A target contains the instructions to build one thing like an app or a
framework.
The thing that your target produces is called its product. The set of
steps that your target takes to build its product are called build
phases.
And lastly, a target has Build settings to configure how it builds its
product.
Now, one thing to note is that both projects and targets have Build
settings, and targets inherit the value set at the project level but
can override them with a target-specific value.
A target's build phases do things like cause dependencies to build
first, compile the source files in that target, and link the target
against libraries and frameworks.
To summarize:
Targets
Helps put a set of files together to build/run a product/module/package
Usually it ends up just being a product you ship to app store.
But often it can be a module that you just run unit-tests against it.
Like a single app can have an iOS target along with a watchOS target. Or just a single iOS Target. Or a single iOS target along with a test target, etc.
If you go to your target's Build Phase >> Compile Sources you'll see every file that's being built for that target. Example:
To explicitly quote Apple docs:
A target specifies a product to build and contains the instructions for building the product from a set of files in a project or workspace. A target defines a single product; it organizes the inputs into the build system—the source files and instructions for processing those source files—required to build that product. Projects can contain one or more targets, each of which produces one product.
The instructions for building a product take the form of build settings and build phases, which you can examine and edit in the Xcode project editor. A target inherits the project build settings, but you can override any of the project settings by specifying different settings at the target level. There can be only one active target at a time; the Xcode scheme specifies the active target.
A target and the product it creates can be related to another target. If a target requires the output of another target in order to build, the first target is said to depend upon the second. If both targets are in the same workspace, Xcode can discover the dependency, in which case it builds the products in the required order. Such a relationship is referred to as an implicit dependency. You can also specify explicit target dependencies in your build settings, and you can specify that two targets that Xcode might expect to have an implicit dependency are actually not dependent. For example, you might build both a library and an application that links against that library in the same workspace. Xcode can discover this relationship and automatically build the library first. However, if you actually want to link against a version of the library other than the one built in the workspace, you can create an explicit dependency in your build settings, which overrides this implicit dependency.
Schemes
A given target can be put through different actions.
build
run
test
profile
archive
You can have a scheme that has all the diagnostics enabled (which makes debugging slow) vs. a scheme that doesn't have any. Or a scheme that runs certain performance related tests vs. a scheme that runs both unit-tests and performance tests. You can edit a scheme so that it performs such actions as:
Building multiple targets
Executing scripts before or after any action
Sending emails before or after any action
Running with memory management diagnostics
Producing either a debug or release build for any action.
For more on that see Customizing the build schemes for a project
To put it all together:
Once you hit run, Xcode will look at the selected scheme. It will find its associated target(s). Use the Build Phases of that target and its Build Settings (any Project Settings that isn't overridden by the target settings will get included) to build a product into the selected destination (the destination can be an iPhone simulator or a physical iPhone or watchOS, etc).
AGAIN WATCH THE WWDC VIDEO!
My take:
Target -- a lower abstraction -- various kinds of builds. Each target has its own Build Settings (so if you split into several targets, take care of that huge sheet individually for each target). Targets have a convenient way of including/excluding files, so you can configure the build effectively on a per-file basis.
Scheme -- a higher abstraction -- guides a target through various ways of deployment (Run, Test, Archive). Has modest ways of configuring the build through Environment Parameters, but employs the Build Settings from the target. Creating / editing / deleting schemes is cheaper and easier than targets.
You can have several schemes guiding one target in several different ways.
Is there any way to create a project/application which will have multiple targets.Its same as how we create multiple targets for an iPhone application in XCode.Basically I have an app which has to be made for different targets, with almost all the similar functionalities but with little change.
You can use Configuration Manager to add additional configurations to the list of Debug and Release. Then for each configuration go to Project/Properties/Build/Conditional compilation symbols and add a symbol used with your configuration or target, eg. make it SILVERLIGHT;WINDOWS_PHONE;CUSTOMVERSION1
Then in your code you can say
#if CUSTOMVERSION1
Debug.WriteLine("This is a CUSTOMVERSION1");
#else
Debug.WriteLine("This is not CUSTOMVERSION1");
#endif
Otherwise - if you want to make bigger changes - you would create another project and link files from one project to another project - project/Add/Existing Item//Add As Link(an option in the "Add" button menu). You can then add more files or add different versions of these files as needed. You could use Project Linker to do it faster.