Xcode 10, sourcery & swiftlint build phases order - xcode

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.

Related

Run custom tool before each build even if it is up-to-date

I want to embed the output of git describe --dirty --always --tags into my program to easily differentiate different versions of the same executable. To do so I generate a source file containing the output of said command.
Since the command produces a string that ends with dirty if there are any modified files in my worktree that are not yet committed I cannot really define a trigger when to re-generate my source file (e.g. as show in this answer).
To solve this problem I wrote a batch script which compares the content of the existing source file and the output of the git command and re-generates the source file only if necessary.
My problem now is that I need to run this batch script before each build, even if msbuild considers the project up-to-date. I tried to use a Pre-Build Event but it is not triggered if the project is up-to-date. I also tried a Custom Build Step and configured a non-existing file as output (this is also an accepted answer here). This causes my batch script to always execute but it also causes code generation being executed for the project even if my generated source file did not change.
4>------ Build started: Project: TestProject, Configuration: Release Win32 ------
4> Current git Version is 9.6-13-g2c753a1727-dirty
4> Include with version number is up-to-date
4> Generating code
4> 0 of 9106 functions ( 0.0%) were compiled, the rest were copied from previous compilation.
4> 0 functions were new in current compilation
4> 0 functions had inline decision re-evaluated but remain unchanged
4> Finished generating code
4> TestProject.vcxproj -> C:\bin\TestProject.exe
4> TestProject.vcxproj -> C:\bin\TestProject.pdb (Full PDB)
I tried it with Execute Before set to ClCompile. Might this be the cause? I also tried some others but with the same effect.
How can I always run my batch script but make the project only produce a new executable if my generated source file was updated?
How can I always run my batch script but make the project only produce
a new executable if my generated source file was updated?
Try adding <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck> into PropertyGroup:
<PropertyGroup Label="Globals">
...
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
</PropertyGroup>
Then VS will always run the project, and if the output xx.exe is up-to-date with no changes to xx.cpp files, the ClCmpile target won't actually create new xx.exe.
Update:
I create a new simple C++ project, set it release mode, and add the DisableFastUpToDateCheck property. Now the vs will always build the project.
I both use the pre-build event and custom target which execute before ClCompile to execute the command git describe --dirty --always --tags.
Now my msbuild output log verbosity is minimal.
1.Build the project:
2.Change nothing to source file,build the project again:
3.Do the same action like #2. And same result.
4.Add a comment the xx.cpp(Not affect the code), build the project:
5.Msbuild project build output verbosity is a good tool when you try to get details about what happen in the build process. For me, I always set it to Detailed. For this issue, if we set it to Normal we can find:
In my opinion:
When I change something in code, the message is 1 of 10 functions (10.0%) were compiled, the rest were copied from previous compilation. And after comparing #1 and #4, we can conclude when it shows 0 of xxx functions were compiled, it actually not spend time generating code, so it won't affect time of your build process.
For the reason why it creates new executable, please see this document. In vs, most of the targets have their inputs and outputs. Like ClCompile target, xx.h files and xx.cpp files are its inputs. Whether this target will execute doesn't depend on if the output files are earlier than inputs.
For example: When I add a comment in xx.cpp, code actually not change. But since now the xx.cpp is newer than output xx.exe from earlier build. Then this time the build engine will execute ClCompile and Link target to create new xx.exe. And code generation is part of Link target, since no changes to code itself, it will show 0 of xxx functions were compiled to indicate it won't really generate though this time new xx.exe will be created.
So in normal situation the DisableFastUpToDateCheck do work for this situation like #2 and #3. According to the pic you shared above, you must do something which not change the code content(0 functions were compiled) in source files but update the modified date of input files.

Xcode 10 fails to copy file generated by target dependency

I have one target A that just runs a script and generates a bunch of files (localization files via twine). Other targets that copy these localization files have a target dependency on A so that they don't run before the files are generated.
Somehow, this doesn't work. Even though the files are all generated successfully, and I see that the copy files phases are running later, the files aren't found.
Also this only fails when I do a clean build. On the second build, the generated files already exist and the copies complete successfully.
For example, my script runs this:
bundle exec twine generate-all-localization-files Strings/ExtensionStrings.txt MyExtension/Resources --format apple --create-folders --tags ios
find /Users/me/proj/myapp -name Localizable.strings
I see it output /Users/me/proj/myapp/MyExtension/Resources/zh-Hans.lproj/Localizable.strings early on in the build process, then later on I see this:
builtin-copyStrings --validate --outputencoding binary --outdir /Users/me/Library/Developer/Xcode/DerivedData/myapp-adfoisdfnasdao/Build/Products/Debug-iphonesimulator/MyExtension.appex/zh-Hans.lproj -- /Users/me/proj/myapp/MyExtension/Resources/zh-Hans.lproj/Localizable.strings
error: Build input file cannot be found: '/Users/me/proj/myapp/MyExtension/Resources/zh-Hans.lproj/Localizable.strings'
And again, if I build a second time it works. What the heck is going on? I'm guessing this has something to do with Xcode 10's parallel builds but I thought that putting the generation/copy in separate targets with a dependency between them would solve that problem.

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)

Generate an .xcscheme file from the command line

I am working on my company's continuous integration server, and the build process is failing because the server does not have access to schemes in an xcode project.
Basically, they are using Cmake to generate xcode projects on the fly to be used for a single build, and then discarded until the next check in.
My research indicates that this problem will be fixed if there is an .xcscheme file with the .xcodeproj file, but for various reasons that can't be generated and checked in ahead of time.
Is there a way to generate this file using xcodebuild or some other command line tool so that we can work it into existing build shell scripts?
The xcodebuild documentation, google, and S.O. are surprisingly lacking on this topic.
I generate the XCode project using the -G Xcode too; I'm using the scan-build plugin ( http://blog.manbolo.com/2014/04/15/automated-static-code-analysis-with-xcode-5.1-and-jenkins ) in jenkins.
It requires the workspace files.
My script to launch & watch xcode looks like that:
($WORKSPACE is set by jenkins)
#!/bin/bash
/Applications/Xcode.app/Contents/MacOS/Xcode "${WORKSPACE}/Build/arangodb.xcodeproj" &
XCODE_PID=$!
# now we wait for xcode to build the workspace:
WAIT_FOR_XCODE=0
while test ${WAIT_FOR_XCODE} -lt 6; do
WAIT_FOR_XCODE=`find "${WORKSPACE}/Build/arangodb.xcodeproj" |wc -l`
sleep 2
COUNT=`ps -p ${XCODE_PID} |wc -l`
if test ${COUNT} -lt 2; then
echo "XCode went away unexpectedly!"
exit -1
fi
done
#ok, we believe its done. kill it, and wait until its realy dead.
kill ${XCODE_PID}
COUNT=2;
while test ${COUNT} -gt 1; do
sleep 1
COUNT=`ps -p ${XCODE_PID} |wc -l`
done
Unfortunately, as of Xcode 5.1.1 there does not exist a mechanism for auto-generating .xcodeproj or .xcworkspace build schemes from the command line as the Xcode UI does. The good news though is that an Xcode project's pbxproj markup is an order of magnitude more complex than the XML markup that describes a build scheme. If you've managed to get CMake to spin up a well-formed Xcode project on-commit, then using a very similar procedure you can build out the 100 or so lines of XML that describe the build-run-test-profile-archive actions of that Xcode project.
If you've not taken a peek at the underlying XML structure of a scheme, create a sample iOS project from the new project wizards and then go poking through the contents of the .xcodeproj or .xcworkspace file for .xcscheme files. The structure is fairly self-documenting and you might even be able to get away without actually specifying the XML markup for those actions you know that will not be run on CI.
Failing that, a less robust approach would be to looking into opening up the Xcode project/workspace file upon the completion of your CMake build process. After a handful of seconds, Xcode's indexer will have had time to identify the projects and auto-generate the schemes for the projects within the master project file itself. Obviously, as you are relying on a UI-layer operation in this approach, you are subject to Xcode's whims, and the indexer may take more than a few seconds to build its index (ex. larger projects will take longer to auto-generate schemes!) ...and there is no trigger advising command-line processes that the indexing and generation has succeeded or failed. You'd wind up having to poll for the existence of a file with an appropriate timeout which can get a bit dicey in an automated build and test environment.
I was actually able to do this by using cmake to generate the project, then using the xcode gui to make the scheme files I need. I used the terminal to extract the xcscheme files from the project and put them in another directory being tracked by source control. As part of the generation process, I just added a bit of shell script to copy the copies I made earlier into the newly generated project, then continue the build process as normal.
The latest version of cmake has added this functionality:
https://blog.kitware.com/cmake-3-9-0-rc3-is-now-ready-for-testing/
The "Xcode" generator learned to create Xcode schema files. This
is an experimental feature and can be activated by setting the
"CMAKE_XCODE_GENERATE_SCHEME" variable to a "TRUE" value.
For CMake based project use XCODE_GENERATE_SCHEME setting for your target.
Setting:
set_target_properties(<your_target> PROPERTIES
XCODE_GENERATE_SCHEME YES
)
will produce following file
your_project.xcodeproj/xcshareddata/xcschemes/your_target.xcscheme

Xcode: Running a script before every build that modifies source code directly

What I did:
I have a script that
Read some configuration files to generate source code snippets
Find relevant Objective-C source files and
Replace some portions of the source code with the generated code in step 1.
and a Makefile that has a special timestamp file as a make target and the configuration files as target sources:
SRC = $(shell find ../config -iname "*.txt")
STAMP = $(PROJECT_TEMP_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME).stamp
$(STAMP): $(SRC)
python inject.py
touch $(STAMP)
I added this Makefile as a "Run Script Build Phase" on top of the stack of build phases for the project target.
What happened:
The script build phase was run before compiling the source.
However, since the script modifies source code during its execution, I needed to build twice to get the most recent version of the build product. Here is what I imagine to be happening:
1st run: Xcode collects dependency information ---> no changes
1st run: Xcode runs "Run Script Build Phase" ---> source is changed behind Xcode's back
1st run: Xcode finishes build, thinking nothing needs to be updated
2nd run: Xcode collects dependency information ---> source has changed, needs rebuild!
2nd run: Xcode runs Run Script Build Phase" ---> everything is up-to-date
2nd run: Xcode proceeds to compilation
After reading Xcode documentation on Build Phases, I tried adding a source file which is known to be updated every time the script is run as the output of "Run Script Build Phases", but nothing changed. Since the number of configuration files may vary in my project, I don't want to specify every input and output file.
Question:
How do I make Xcode aware of source file changes made during "Run Script Build Phase"?
Edit:
Added that I placed the script build phase before the other build phases
Every technique mentioned so far is an overkill. Reproducing steve kim's comment for visibility:
In the build phases tab, simply drag the "Run Script" step to a higher location (e.g. before "Compile Sources").
Tested on Xcode 6
This solution is probably outdated. See the higher voted answer instead; I no longer actively use Xcode and am not qualified to vet a solution.
Use "External Target":
Select "Project" > "New Target..." from the menu
Select "Mac OS X" > "Other" > "External Target" and add it to your project
Open its settings and fill in your script setup
Open the "General" tab of the main target's settings and add the new target as it's direct dependency
Now the new "External Target" runs before the main target even starts gathering dependency information, so that any changes made during the script execution should be included in the build.
There is another, slightly simpler option that doesn't require a separate target, but it's only viable if your script tends to modify the same source files every time.
First, here's a brief explanation for anyone who's confused about why Xcode sometimes requires you to build twice (or do a clean build) to see certain changes reflected in your target app. Xcode compiles a source file if the object file it produces is missing, or if the object file's last-modified date is earlier than the source file's last-modified date was at the beginning of the first build phase. If your project runs a script that modifies a source file in a pre-compilation build phase, Xcode won't notice that the source file's last-modified date has changed, so it won't bother to recompile it. It's only when you build the project a second time that Xcode will notice the date change and recompile the file.
Here's a simple solution if your script happens to modify the same source files every time. Just add a Run Script build phase at the end of your build process like this:
touch Classes/FirstModifiedFile.m Classes/SecondModifiedFile.m
exit $?
Running touch on these source files at the end of your build process guarantees that they will always have a later last-modified date than their object files, so Xcode will recompile them every time.
As of Xcode 4, it looks like if you add the generated files to the output section of the build phase, it will respect that setting, and not generate the ... has been modified since the precompiled header was built error messages.
This is a good option if your script is only generating a handful of files each time.
I as well struggled with this for a long time. The answer is to use ento's "External Target" solution. He is WHY this problem occurs and how we use it in practice...
Xcode 4 build steps do not execute until AFTER the plist has been compiled. This is silly, of course, because it means that any pre-build steps that modify the plist won't take effect. But if you think about it, they actually DO take effect...on the NEXT build. That's why some people have talked about "caching" of plist values or "I have to do 2 builds to make it work." What happens is the plist is built, then your script runs. Next time you build, the plist builds using your modified files, hence the second build.
ento's solution is the one way I've found to actually do a true pre-build step. Unfortunately I also found that it does not cause the plist to update without a clean build and I fixed that. Here is how we have data-driven user values in the plist:
Add an External Build System project that points to a python script and passes some arguments
Add user-defined build settings to the build. These are the arguments that you pass to python (more on why we do this later)
The python script reads some input JSON files and builds a plist preprocessor header file AND touches the main app plist
The main project has "preprocess plist files" turned on and points to this preprocessor file
Using touch on the main app plist file causes the main target to generate the plist every time. The reason we pass in build settings as parameters is so our command-line build can override settings:
Add a user-defined variable "foo" to the prebuild project.
In your prebuild you can use $(foo) to pass the value into the python script.
On the command-line you can add foo=test to pass in a new value.
The python script uses base settings files and allows for user-defined settings files to override the defaults. You make a change and immediately it ends up in the plist. We only use this for settings that MUST be in the plist. For anything else it's a waste of effort....generate a json file or something similar instead and load it at run-time :)
I hope this helps...it's been a couple rough days figuring this out.
The External Target solution from #ento no longer works as of Xcode 11.5. The solution is to add all files that will be changed under Output Files in the Run Script.
Another option is to create a subproject framework with your scripts and just add it as a dependency to all targets. The phase scripts of this subproject should now be executed before all targets.

Resources