If something is not used in C++, it's not compiled at all. Is the same true for iPhone?
If I compile a program and there are unused classes or other stuff, will it be compiled or ignored?
It depends on your build settings.
Under your target build settings, then under "Linking" there is an option for "Dead Code Stripping". It defaults to yes for projects created with Xcode.
Here's a link to the build settings documentation from Apple (with an excerpt):
https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html
DEAD_CODE_STRIPPING (Dead Code Stripping)
Description: Boolean value.
Specifies whether dead code is stripped from the binary.
Prerequisite: $GCC_DEBUGGING_SYMBOLS = full
Values:
YES: Dead code is stripped from
the binary when the prerequisite is met.
NO: Dead code is not stripped
from the binary.
Default value: NO Companions: “GCC_DEBUGGING_SYMBOLS
(Level of Debug Symbols).” Prerequisite for:
PRESERVE_DEAD_CODE_INITS_AND_TERMS
Note, the docs say the value defaults to NO, but Xcode project settings default the value to YES.
I believe that any resource that is added to a target will get compiled and/or copied to your application bundle at build time. To edit which files are built/copied, you can modify the settings in Xcode 4, by clicking on project, then your target. Under Build Phases, you can change the files as needed.
Here's a screenshot:
There is also a setting for Dead Code Stripping under Build Settings. Here's what that looks like:
It defaults to yes, but if you want to disable it for some reason, that's how you'd do so.
Related
I have one functionality and it is depending on one static library. Actually, Apple is not allowing this static library because of few reasons. So, for now we have decided to add one Preprocessor macro and based on that functionality should be switch on/off.
I have switched my code to behave based on that Preprocessor macro. But I didn't find any to link or unlink the library based on preprocessor macro. I can not allow to link the library all times, as I have already told apple is not allowing it.
One solution that I already know : I can create the multiple target. But problem is that my app has already lots of targets. So, again to manage this I have to create one more target for each target those are already created.
Any help will be appreciated.
Edit:
I have created configuration like Francesco suggested. But One quick question I have let's say If I will remove the path of library from "Library Search Path" then that library will not be linked to app? Because that library is still in target of App.
Instead of targets you can create multiple configurations. And you can change the linker flags there.
I did this think for Sparkle framework (which is not allowed on App Store)
EDIT:
To create/manage the configurations click on the project in the sidebar. Then in the main window select again the project, not the targets, and select the "Info" tab.
Together with Deployment Target selection and Languages you will find a Configuration section.
You can add or remove configurations from there.
Then to launch it you have to go to Product -> Scheme -> Edit Scheme -> Build Configurations.
You can duplicate an existing scheme and choose the correct configuration from there.
You can remove the static library from the list of linked items by setting a (somewhat undocumented) Xcode build setting:
EXCLUDED_SOURCE_FILE_NAMES = libUnwanted.a
You can do this in an .xcconfig file or in the normal target build settings UI (by adding a custom build setting). If you for example set this in the "Release" configuration Xcode will include the library in the "Debug" build but omit if for the release build.
EXCLUDED_SOURCE_FILE_NAMES works with all kinds of files that can be added to a target: source files, resources, libraries, ...
Here's how to do this step by step:
Open the target build settings by clicking on the blue project icon in the Project Navigator and select the Build Settings tab.
Click the plus icon to add a "User-Defined Setting"
Name the setting "EXCLUDED_SOURCE_FILE_NAMES"
Expand the Configurations for the setting and set the "Release" value to the name of your unwanted library.
Credit of this answer goes to Nikolai Ruhe & Francesco
I have combined the answer of both and I got the solution.
Here are the steps that I followed.
Created new configuration. ( To know how to create configuration see
the answer of Francesco)
Added flag EXCLUDED_SOURCE_FILE_NAMES in user-defined setting of Build settings. (For steps see the answer of Nikolai Ruhe). And in this flag I have added the name of my static library under the my custom configuration.
Here is a good tutorial that will definitely help you : Remove tesflight from Distriubtion
I have a bit of a problem with setting different configuration for my project. I have two versions of the same static library. One has logging enabled, the other doesn't.
I am using two different xcconfig files for Debug vs. Release. In these files I specify the library and header search paths for the two variants of the static lib. So far so good.
However, in my build settings I can't see a way to conditionally link the actual library. I.e use the debug variant for Debug and the release for Release.
Any ideas?
You need to link the library using the "Other Linker Flags" build setting, rather than the standard "Link Binary With Libraries" UI. The build setting can be changed depending on the configuration:
Click the triangle and you can give different values for Debug/Release. You will need to use the -l flag. For example, for a filename of libMyLib.a use the flag -lMyLib. You may need to edit the "Library Search Paths" to search the appropriate location.
If the filenames for the debug and release version are the same and you don't want to change them, put them into their own lib/Debug and lib/Release directories respectively. Then edit the "Library Search Paths" build setting adding either "$SRCROOT/lib/Debug" or "$SRCROOT/lib/Release" for the appropriate configuration.
My iPhone application connects to three different servers, say: production, staging and testing. There is a bunch of configuration values that the application uses depending on to which server it connects to, e.g. Facebook App ID, TestFlight team key, etc.
I'd like to have all the settings in GIT and only select which configuration the application supposed to use when compiling or releasing. For example, when testing is selected, Product -> Run in Xcode runs the debug version of the app connecting to testing, and Product -> Archive creates the IPA file with the release version that also connects to testing.
I don't want to create more build configurations than debug and release (because that would mean 6 different combinations of build configurations/run-time configurations). The ideal solution, as I see it, would be that I have three schemes: production, testing and staging, and each scheme selects one of three Info.plist files to use with the application. That would allow me to not only define different run-time settings, but also different application versions or bundle identifiers depending on the back-end server. But it doesn't look like I can configure the Archive action in any other way apart from selecting a different build configuration. Any ideas if that could be achieved in any way?
Edit: To make it a bit more clear, production/staging/testing is the back-end server, not the version of the iOS application. The iOS app comes in two versions: debug/release. In other words I may want to run a debug version of the application connecting to the production server for example to debug a crash caused by JSON returned from that server. I could have named the servers as A, B and C for the sake of clarity.
A good way to do this would be with build configurations and C macros. This avoids having to create a separate target for every configuration which is not really the correct use of targets.
First you want to set up the configurations at the project level:
You can create different configurations for debugging, enterprise distribution, and any other type of special build you want.
Next you can define some macro flags for each configuration which will be passed to the compiler. You can then check for these flags at compile time. Find the "Preprocessor flags" build setting at the target level:
If you expand the triangle you can define different values for each of your configurations. You can define KEY=VALUE or just KEY macros here.
In your code, you can check for the existance of these macros, or their value (if there is one). For example:
#ifdef DISABLE_FEATURE_X
featureXButton.hidden = YES;
#endif
// ...
#if FOOBAR_VISIBLE == 0
foobarView.hidden = YES;
#elif FOOBAR_VISIBLE == 1
foorbarView.hidden = NO;
#else
#error Invalid value for FOOBAR_VISIBLE
#endif
You can pass in string values as well, which must be wrapped with single quotes in the build setting, e.g. DEFAULT_LOCALIZATION_NAME='#"en"'.
You can also configure which configuration is used during Debug and Archive time using the Schemes editor. If you choose "Run" or "Archive" in the Schemes editor you can select the appropriate configuration.
If you need to parameterize entries in the Info.plist file, you can define their value using a custom build setting. Add a custom build setting for your target:
And then give it an appropriate value for your different configurations:
Then in the Info.plist file you can reference this setting:
Note that the one limitation of this approach is that you cannot change the following items:
Settings.bundle
Additionally, in older versions of Xcode without asset catalog support, you cannot change the following items:
Icon.png
Default.png
These cannot be explicitly defined in the Info.plist file or anywhere else, which means you need different targets to change them.
I would suggest using different build targets for each environment. I successfully used this model before. In your project's settings you can duplicate the current target and change the build settings as needed. There's an Info.plist File property that will let you change the default plist for that target.
After that, you can create a scheme for each environment that will use the according target.
You can get a step further and use different bundle id for each target and different names. That will allow you to install both the staging and the production builds on the same device for example.
The only downside in this is that you have more work when you want to update provisioning profiles.
Here's a much easier solution if the concerned libs allow to set the keys in code, meaning that you can have production value in your plist file, but change them in your AppDelegate (or whichever file they are first used in).
Works with facebook, twitter and google sdk at the moment.
Ex:
#ifdef DEBUG
// Facebook
[FBSettings setDefaultAppID:#"SandboxID"];
// Fabric / TwitterKit - must be called above [Fabric with:#[TwitterKit]];
[[Twitter sharedInstance] startWithConsumerKey:#"SandboxKey" consumerSecret:#"SandboxIDSecret"];
#endif
Same in Swift, just use #if instead of #ifdef.
Note about Facebook This worked with version 3 of their SDK, I'm not sure it's possible with later versions.
It is probably very low tech but I just have a method called apiURL() that returns the URL of the API I want. I have localhost, stage, and production and I simply uncomment the one I want. It's worked well for me so far. I've only forgotten to switch it back a few times. Oops.
I really enjoy switching from gcc to LLVM compiler, but do I have to switch manually every time I start a new project, or is there any way to make LLVM the default compiler?
I'm talking about xcode 3.
Thanks.
To accomplish this you will have to modify the project template within the Developer directory.
Navigate to where your templates are (probably something like: /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Project Templates/
Once you're there, you can select the project template you wish to modify, and locate it's .xcodeproj file. You can "show package contents" and inside is a project.pbxproj. You can modify this file and edit in the build setting to change the default compiler.
You'll have to find each section that relates to the build settings for each configuration (Debug, Release etc.), search for /* Begin XCBuildConfiguration section */.
Then you'll have to add GCC_VERSION as a key and com.apple.compilers.llvm.clang.1_0 as the value (1_0 in this instance is actually LLVM 1.6 according to Xcode. I also assume that the key-name GCC_VERSION only has GCC in it for legacy reasons, this will probably be updated to COMPILER_VERSION or something in the future).
Save the template and create a new project (You may have to restart Xcode if it was open). The compiler should be set to LLVM now.
However, I don't recommend you do this as LLVM still isn't 100% fit for deploying applications to users.
I don't believe there's an (easy) way to do this. (i.e.: There's no preference pane option for such a thing.) That said, the advice within the existing Setting GCC 4.2 as the default compiler on Mac OS X Leopard question should work #Jasariens answer seems ideal, if the per-project setting is proving tiresome.
However, LLVM isn't quite ready for prime time, so I'd really recommend not using it for the final deployment of apps, etc. (If you're encountering any odd issues, switch back to using GCC and they'll quite possibly go away.)
Incidentally, whilst off-topic, there's some great tips within the Hidden Features of Xcode question as well, so that might be worthy of a browse. :-)
The very easiest way (and smartest, I think) to do it for all future projects is to do the following 5 steps :
go to /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/iPhone Base.xctemplate (you can simply Command + o (open) in Xcode then Command + Shift + G (go to folder), then paste this path)
open the file TemplateInfo.plist in Xcode
go to Project > SharedSettings > GCC_VERSION property and change its String value to com.apple.compilers.llvm.clang.1_0 : http://grab.by/a0dV
save the file
test by opening a new iPhone project.
You can do the same for other new project by going to, for example, /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/iPad Base.xctemplate for the iPad projects, etc.
That's it.
Have a nice day everybody.
I’ve written a simple script that creates a fresh Xcode project with sane defaults. Might be worth adapting, so that you don’t have to set up every new project by hand.
All answers tell how to change default compiler value for new projects.
This is how to change directly the "iOS default" values in XCode for any projects :
EDIT the file (with sudo)
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOSXXXX.sdk/SDKSettings.plist
Restart XCode and done!
I've been tasked to work on a project that has some confusing attributes.
The project is of the nature that it won't compile for the iPhone Simulator And the iPhone Device with the same compile settings. I think it has to do with needing to be specifically compiled for x86 or arm6/7 depending on the target platform.
So the project's build settings, when viewed in Xcode's Build Settings view doesn't enable me to set specific compiler flags per specific files. However, the previous developer that worked on this project has somehow declared the line:
CE7FEB5710F09234004DE356 /* MyFile.m in Sources */ = {isa = PBXBuildFile; fileRef = CE7FEB5510F09234004DE356 /* MyFile.m */; settings = {COMPILER_FLAGS = "-fasm-blocks -marm -mfpu=neon"; }; };
Is there any way to do this without editing the project file by hand? I know that editing the project file can result in breaking it completely, so I'd rather not do that, as I obviously don't know as much as the previous developer.
So to clarify, the question is:
The build fails when compiling for simulator unless I remove the -fasm-blocks flag. The build fails when compiling for device unless I add the -fasm-blocks flag. Is there a way to set this flag per file without editing the project file by hand?
This blog post by Joshua Nozzi explains how to do this in Xcode 4, where he says:
... select your project in the Project Navigator, select the relevant target (you may have only one), then select the Build Phases tab. Expand the Compile Sources phase and viola! A Compiler Flags column lets you set each file’s flags for that target.
You can define additional compiler flags for individual source files as follows:
first select the target you are going to build
right click on the source file
select "Get Info"
click on the "Build" tab
define your additional compiler flags
However it sounds like a better solution in your case is just to duplicate the target and have two targets - one for an actual device and one for the simulator. Inherit common build settings from the project level and just tweak the per-target build settings as necessary.
Call GetInfo for the specific file, you can set the Build settings there for this file. See also the XCode Project Management Guide about this.