Bug 19231 - PropertyChanged.Fody fails from Android project, works from PCL
Summary: PropertyChanged.Fody fails from Android project, works from PCL
Alias: None
Product: Android
Classification: Xamarin
Component: General ()
Version: 4.12.3
Hardware: PC Mac OS
: --- normal
Target Milestone: ---
Assignee: Jonathan Pryor
Depends on:
Reported: 2014-04-22 16:21 UTC by Tom Gilder
Modified: 2014-04-23 13:38 UTC (History)
1 user (show)

Is this bug a regression?: ---
Last known good build:

Test case (837.56 KB, application/zip)
2014-04-22 16:21 UTC, Tom Gilder
Build log from build that fails unit test (176.40 KB, text/plain)
2014-04-23 08:41 UTC, Tom Gilder
Application output from build that fails unit test (28.70 KB, text/plain)
2014-04-23 08:42 UTC, Tom Gilder

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Tom Gilder 2014-04-22 16:21:02 UTC
I'm using PropertyChanged.Fody to inject calls to INotifyPropertyChanged's PropertyChanged event in a class within a PCL. Everything was working fine until I tried to use the PCL from an Android app.

See attached project for a test case. In Android.Test the unit test always fails, in ScriptTimer.TestsPCL the unit test always passes. Occasionally the unit test in the PCL project silently fails to run from Xamarin Studio, I have no idea why.
Comment 1 Tom Gilder 2014-04-22 16:21:27 UTC
Created attachment 6634 [details]
Test case
Comment 2 Tom Gilder 2014-04-22 16:22:50 UTC
(OS X 10.9.2, Xamarin Studio 4.2.4, Xamarin.Android 4.12.3, Mono 3.2.6)
Comment 3 Tom Gilder 2014-04-23 07:35:14 UTC
Ack. This seems to be a real heisenbug. I could replicate it every single time yesterday, but I can't at all today, with exactly the same project. I'll post some logs if I can make it do it again!
Comment 4 Tom Gilder 2014-04-23 08:41:38 UTC
Created attachment 6638 [details]
Build log from build that fails unit test
Comment 5 Tom Gilder 2014-04-23 08:42:06 UTC
Created attachment 6639 [details]
Application output from build that fails unit test
Comment 6 Jonathan Pryor 2014-04-23 11:41:46 UTC
I have a repro! (Wow!)

1. Load the project into Xamarin Studio
2. Edit ScriptTimer.Core/Script.cs. Doesn't matter what the edit is, we just want to rebuild it.
3. Set a breakpoint on Android.Test/TestsSample.cs:25 (Assert.IsTrue())
4. Debug the project.
5. Tap Run Tests within the app.

Result: hasSet is False, not True.

So, why?

Because Fody isn't being invoked as part of the build. Enable Diagnostic build output:


Then view Errors pad > Build Output, and you'll find that the Fody.WeavingTask task is _not_ invoked, nor is the NonWinFodyTarget target invoked.

Meanwhile, if you do the same from the command line, the target + task IS invoked:

     $ xbuild /t:Install /v:diag > b.txt

`xbuild` produces (in the volumes output):

>        Target PostBuildEvent skipped due to false condition: '$(PostBuildEvent)' != '' and
>                                 ('$(RunPostBuildEvent)' != 'OnOutputUpdated' or
>                                   '$(_AssemblyModifiedTimeBeforeCompile)' != '$(_AssemblyModifiedTimeAfterCompile)')
>                 Target NonWinFodyTarget:
>                 Task "Fody.WeavingTask"
>                 ...
>                 Done building target "NonWinFodyTarget" in project "/Users/jon/Downloads/bxc-19231/FodyTest/ScriptTimer.Core/ScriptTimer.Core.csproj".
>         Done building project "/Users/jon/Downloads/bxc-19231/FodyTest/ScriptTimer.Core/ScriptTimer.Core.csproj".
> Done executing task "MSBuild"

vs. the ~equivalent Xamarin Studio output:

> 	Target PostBuildEvent skipped due to false condition: '$(PostBuildEvent)' != '' and
> 		('$(RunPostBuildEvent)' != 'OnOutputUpdated' or
> 		  '$(_AssemblyModifiedTimeBeforeCompile)' != '$(_AssemblyModifiedTimeAfterCompile)')
> 	Done building project "/Users/jon/Downloads/bxc-19231/FodyTest/ScriptTimer.Core/ScriptTimer.Core.csproj".
> Done executing task "MSBuild"

Since Fody isn't invoked, nothing works as expected.

The question then becomes, _why_ isn't Xamarin Studio invoking the NonWinFodyTarget target?
Comment 7 Jonathan Pryor 2014-04-23 11:44:02 UTC
Possible extenuating circumstances: it could be that calling <MSBuild/> is screwing things up (as it has for various other bugs I can't easily find right now), which will be fixed (by removing the <MSBuild/> invocation) in the 4.14 release.

Or that's entirely unrelated; I'm not sure.
Comment 8 Jonathan Pryor 2014-04-23 12:58:25 UTC
Investigating further...

The problem appears to be in Xamarin Studio's Run > Start Debugging behavior.

This fails:

F1: Make change to Script.cs
F2: Click Run > Start Debugging (or the "Debug" toolbar button)

This works:

W1: Make change to Script.cs
W2: Click Build > Clean All
W3: Click Build > Build All
W4: Click Run > Start Debugging (or the "Debug" toolbar button)

The former doesn't invoke the Fody.WeavingTask task, while the latter does.

However, that's not quite all. Skipping W2 results in Fody.WeavingTask being executed, but the resulting app doesn't work, as the generated ScriptTimer.Core/bin/Debug/ScriptTimer.Core.dll doesn't have a "fixed" Script.set_Text() method, apparently because the ScriptTimer.Core/obj/Debug/ScriptTimer.Core.dll is later used (post Fody-fixup), which doesn't contain the Fody changes, and the "bad" obj copy is used.
Comment 9 Jonathan Pryor 2014-04-23 13:09:00 UTC
Further interesting...

This might not be a Xamarin bug.

Please see packages/Fody.1.23.2/build/Fody.targets, and note that it has Windows and non-Windows code paths. There are two differences of consequence between the Windows and the non-Windows targets:

1. Windows uses an AssemblyPath of @(IntermediateAssembly), while non-Windows uses an AssemblyPath of $(TargetPath)

2. Windows has AfterTargets="AfterCompile", while non-Windows has AfterTargets="AfterBuild".

I'm not sure if (2) is important, but (1) certainly is. If I change Fody.targets so that non-Windows uses @(IntermediateAssembly) (just like Windows does), then it rebuilds reliably, i.e. the "fails" path in Comment #8 no longer fails, it works.
Comment 10 Jonathan Pryor 2014-04-23 13:11:39 UTC
Closing as UPSTREAM as per Comment #9.
Comment 11 Tom Gilder 2014-04-23 13:38:12 UTC
That is tremendously amazing debugging, thank you :-)

I'll try to fix it in Fody.