Why does xcodebuild give different build results than XCode UI - xcode

I have a series of projects within a workspace, and trying to use the following type of command to build them via the command line:
"Xcodebuild -project XXX"
or
"Xcodebuild -workspace XXX -scheme YYY"
Some of my projects build fine but others give strange errors, like "'XXX' for instance message does not declare a method with selector" or "ld: library not found for -lMyLibrary"
However all these projects build fine from within the XCode UI without issues.
Based on this is seems that the command line and UI builds are using a different toolset, but that seems like a very bad idea so I'm hoping I'm wrong about this. Or possibly there are just a few different build flags being set on the command line build.
I can try to troubleshoot the issues one by one but I'm hoping I can write a script which does the exact same type of build as the UI.
Any ideas?

Without including -configuration, xcodebuild is going to use the default configuration for each project. Generally that's Release. In Xcode, the Configuration you select will be applied to every project regardless of default.
Given your errors, your most likely problem is that you've used the build pane (why I hate the build pane for large projects), and you've made the classic mistake of applying some settings for Debug rather than all configurations.

Related

Xcode 10, sourcery & swiftlint build phases order

After updating to Xcode 10 there are some issues with initial project configurations. The steps look like this:
Generating some files using Sourcery
Linting with SwiftLint
Build
And configuration works like this:
And this was working fine in Xcode 9, but apparently, it's not working under Xcode 10 build system. The issue is if I download repository (.generated files are not a part of the repository). And hit build it will show me results like:
...
Using configuration file at '.sourcery.yml'
Scanning sources...
Found 239 types.
Loading templates...
Loaded 9 templates.
Generating code...
Finished.
Processing time 0.491948962211609 seconds
...
So sourcery works ok, then linting:
Linting 'FromResponse.generated.swift' (1/186)
Works fine as well as a process, but in the end, build will fail with:
error: Build input files cannot be found:
'/path/Generated/FromResponse.generated.swift',
...
So it's strange since a files are physically there and according to build settings file should be compiled later than generating them. How should I approach sourcery in build process then?
We are able to "fix" this in a similar way as this Github issue:
https://github.com/mac-cain13/R.swift/issues/438#issuecomment-416982928
We have to add each of the generated files by Sourcery to the output folder and it will get picked up by the Xcode correctly.
This relates to changes in the New Xcode Build System that has been enabled by default in Xcode 10. If a build phase creates files which are needed as an input to a later build phase then it needs to specify them explicitly in the Output Files or Output File List.
In your example the Sourcery build phase is generating Swift source file(s) which are needed as input to the Compile Sources phase.
However, the issue at this point is that after you specify the output files for Sourcery, the build phase doesn't re-run every time as it sees the output file is already there. So far I haven't worked out a useable solution to this part, beyond running tools like Sourcery and SwiftGen manually or keeping the generated files in Git so that they are always present.
I was having a similar problem with a buildphase calling mogenerator to build my data model classes. The approach given by #Yuchen should work.
#Andrew: To force always (re-)running this build phase, I add the line
touch .alwaysRun
as the last line in the shell command to run and mark the build phase "Input Files" to have $(SRCROOT)/.alwaysRun. That seems to do the trick.

xcodebuild test-without-building. How to override test run parameters from command line

I'm making macOS unit testing bundle (integration test for server software):
xcodebuild -project MyApp.xcodeproj -scheme MyApp.macOS build-for-testing
As result, xcodebuild generates xctest bundle MyAppTests.xctest and xctestrun file MyApp.xctestrun.
Now I can deploy xctest bundle on CI server and execute integration tests (by default targeted to release candidate version of server software).
xcodebuild test-without-building -xctestrun MyApp.xctestrun
Now I want to target another server instance (i.e. from development branch).
For doing this I can provide another xctestrun file MyApp-development.xctestrun with additional settings under TestingEnvironmentVariables key.
<key>TestingEnvironmentVariables</key>
<dict>
<key>com.myapp.ServerKind</key>
<string>development</string>
...
</dict>
Launch on CI server:
xcodebuild test-without-building -xctestrun MyApp-development.xctestrun
But maintaining several xctestrun files is not a good idea. I want to have default xctestrun file and override it's settings from command line.
Is it possible to pass additional settings (or override existing settings) in xctestrun file from command line?
Thank you!
Not sure if it solves your purpose, but if we wanted to override something like a User-Defined values in the Build settings of the target, i didn't find a straight forward to alter it while running test using xctestRun. So I tried directly altering the info.plist thats available inside the xctest bundle created with "build-for-testing" option before test execution and things seems to work well.
For eg. I wanted to run the test across different partitions, so i did
defaults write <plist_file_location> PARTITION B1
and this seems to do the trick
Note : Make sure <plist_file_location> is an absolute path. Providing relative path would end up creating an entry in ~/Library/Preferences/Info.plist

MBProgressHud Swift Compile Error when Archiving

I already finished my project, it works and runs perfectly on the simulator or in my own device. When I select to Archive the project to upload de build to Itunes Connect, I get all these compile errors
"Use of undeclared type MBProgressHUD"
"Use of unresolved identifier MPProgressHUD"
And so on..
NOTE: I'm using CocoaPods for this library
What solved it for me was adding import MBProgressHUD in the classes where I use this library, not only in the Bridge-Header.h
Navigate to your project build settings and find the “Swift Compiler – Code Generation” section (You may find it faster to type in “Swift Compiler” into the search box to narrow down the results)
Next to “Objective-C Bridging Header” you will need to add the name/path of your header file. If your file resides in your project’s root folder simply put the name of the header file there. Examples: “ProjectName/ProjectName-Bridging-Header.h” or simply “ProjectName-Bridging-Header.h”.
Refer this link http://www.learnswiftonline.com/getting-started/adding-swift-bridging-header/
Welcome to Cocoapods Hell (a.k.a. : where the magic ends), where one must dive into his project build settings and make sense of what went wrong...
It's very hard to answer to you, as any number of reasons might be causing that.
Do you use the same target for Build / Run & Archive ? It might be because your libPods.a isn't copied into your Archive target
Have you installed Pods using pod install , have you tried playing that command again. (yes, faced with magic going wrong, one can sometimes rely on magic to save him again)
'Build' and 'Archive' product often differ in the build configuration they use (Build most of the time uses 'debug' configuration, while Archive uses 'release' configuration... ). Check your Pods configuration files (debug/release) and make sure they both include your MBProgressHud. Also, in your Project 'Info', check which pods Xcode configuration files are selected for 'debug' and 'release'
Good luck !
(PS : as MBProgressHud is a single file, and one you can often change, another solution is to get rid of Cocoapods and just copy/paste it)

Variable for path to XCode's SharedPrecompiledHeaders folder

During our iOS client build we run a clean to prevent/reduce failures. But last week all our build servers failed with this error
fatal error: malformed or corrupted AST file: 'could not find file 'worspace/file_name.h' referenced by AST file'
It seemed that file_name.h was no longer required and a developer removed the svn external which brought it in. But the AST files still held a reference to it - despite the clean.
After investigating I found it was the files in the following folder
var/folders/f3/bznwl6md2bx82f1fv_kkdzl00000gn/C/com.apple.DeveloperTools/5.0.2-5A3005/Xcode/SharedPrecompiledHeaders
Deleting SharedPrecompiledHeaders fixed the issue. At the time I manually did this.
But I'd like a way to automate it. Is there an environmental variable/alternative that can be used to find this directory? I noticed it varies between machines.
The environment variable you are looking for is SHARED_PRECOMPS_DIR
The final solution was to place the shared precomps dir within the checkout. This allowed the build servers to completely clean the workspace between builds.
Achieved this by passing in the SHARED_PRECOMPS_DIR to xcodebuild.
e.g.
xcodebuild -project ProjectName -target "Target" -configuration Configuration -sdk SDKName SHARED_PRECOMPS_DIR=/absolute/path/to/checkout
By passing this value in at the command line the SHARED_PRECOMPS_DIR was set for all projects. i.e. Including Dependent Projects.
Lane's answer is correct. If you need to retrieve this value from the command line parse the output of
xcodebuild -project myProj.xcodeproj -target "myTarg" -showBuildSettings
For further details see How do I print a list of "Build Settings" in Xcode project?

Making a CI server build all XCode targets as .ipa's

I'm looking into TeamCity and Jenkins, for a CI server.
My goal is this: every time someone commits a change to our repo, the CI server builds all targets in the project as .ipa's - ready for downloading/installing on a device.
I got Teamcity and Jenkins up and running, using a Mac mini as a build slave. That part of it is working fine.
Using Jenkins XCode plugin, I succeeded in building all targets as .ipa's.
I havent had such luck with Teamcity. The XCode plugin doesnt allow building all targets. Rather, you have to specify which targets you want to build, in each build configuration.
I approached the makers of Teamcity, and they gave me some convoluted method involving meta runners and a lot of duplication, in order to accomplish my goal.
Instead of relying on plugins, I'd rather build the .ipa's using shell scripting. However, as I'm not a script ninja, I can't figure out how to go about this.
I can figure out how to build one target via scripting, but it illudes me how make it build them all. Everytime I create a new target in the project, I don't want to have to add it at the CI server. The server should be able to automatically build all targets in the project.
...Maybe someone has a better solution? Any help is much appreciated.
What you should do (codes are bash script snippets, ready to run on OS X, you don't need to install anything except Xcode's CLI/Command Line Tools):
if you want to do this for every Xcode project file you have in your repository you should first search for these (if you have a specific Xcode project you can skip this)
for path in $(find . -type d -name '*.xcodeproj' -or -name '*.xcworkspace')
do
after this you can query all the shared (!) schemes through Xcode's command line tool
if [[ "$project" == *".xcodeproj" ]]; then
xcodebuild_output=($(xcodebuild -list -project "$project"))
else
xcodebuild_output=($(xcodebuild -list -workspace "$project"))
fi
now you have all the schemes so you can simply xcodebuild them one-by-one
Here's a bash script we developed to search for every Xcode project and every scheme configuration in a repository: https://github.com/concretebuilder/steps-cocapods-and-repository-validator/blob/master/find_schemes.sh
Note: you need to mark you schemes as shared to get xcodebuild (the command line interface of Xcode) list them.

Resources