So here’s one that shouldn’t be nearly as complicated as it is.
Keeping any opinions to myself of whether it is good or bad, we use Xamarin for iOS/Android development. One of the problems that I recently ran into is that Xamarin’s iOS command line build is EXTREMELY SKETCHY. It will fail for reasons that you will absolutely never see in Xamarin Studio.
Here’s one of my favorites
1 |
/Library/Frameworks/Mono.framework/External/xbuild/Xamarin/iOS/Xamarin.iOS.Common.targets : error: Error executing task IBTool: 'Element' is an invalid XmlNodeType. |
Seriously, what the heck good is that?
We also get an error that will say one of our xib files has “error” but it won’t tell us what the error is, and when we look at the xib, there’s nothing wrong with it. Build the project again without any changes, and suddenly its working for another hour.
We use FAKE for our iOS build script. I’m not really sure why, but that decision was made before I joined the project. So after learning F# (I recommend Pluralsight’s F# jumpstart course), I decided to undertake a project of updating our scripts.
We were on FAKE 3.34.7, and as of today the latest version is FAKE 4.20.0. So clearly there’s some updating to do.
FAKE syntax/scripting is not exactly what I had in mind for this post so I’ll get right to it. In FAKE 4.4.0, they changed iOSBuild from using mdtool to using xbuild. I’m hoping that updating will reduce the amount of false errors we get on our build server.
Unfortunately when running our script, none of our before and after build steps were running. Some of our steps look like this
1 2 3 4 5 6 7 8 |
<CustomCommands> <CustomCommands> <Command type="BeforeBuild" command="echo "##teamcity[blockOpened name='Building MyProject']"" /> <Command type="AfterBuild" command="echo "##teamcity[blockClosed name='Building MyProject']"" /> <Command type="BeforeClean" command="echo "##teamcity[blockOpened name='Cleaning MyProject']"" /> <Command type="AfterClean" command="echo "##teamcity[blockClosed name='Cleaning MyProject']"" /> </CustomCommands> </CustomCommands> |
Basically all these are doing is printing a command so that TeamCity will format our build log better. They’re really useful to have. But unfortunately they stopped running. This probably seems like it shouldn’t matter too much, but we have some other before build steps that actually generate code. So we needed to get this working again.
From this bug report we can find that basically the syntax above is only supported in Xamarin Studio or when building using mdtool. The expected thing to do is use MSBuild Targets. But when I followed the documentation, the BeforeBuild targets were never executing.
From looking at a ton of logs, I eventually came to the conclusion that the Targets defined by Xamarin seem to overwrite the normal Targets. So instead we needed to do something different.
Creating a Property Group with a BuildDependsOn block, you can insert your own Targets to run before and after all of the Xamarin stuff. It ends up looking like this
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<PropertyGroup> <BuildDependsOn> CustomBeforeAny; $(BuildDependsOn); CustomAfterAll </BuildDependsOn> </PropertyGroup> <Target Name="CustomBeforeAny"> <Exec Command="echo "##teamcity[blockOpened name='Building $(MSBuildProjectName)']"" /> </Target> <Target Name="CustomAfterAll"> <Exec Command="echo "##teamcity[blockClosed name='Building $(MSBuildProjectName)']"" /> </Target> |
This was especially cool because I found the $(MSBuildProjectName) which made it so I could just copy and paste these lines into all of my csproj files without having to tailor the code to any particular csproj file. There are loads of other variables, just follow the links on this Stack Overflow answer.