-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hot Reload doesn't work on ARM devices #17
Comments
That's new! :D First, you can check whether the HotReloadDemo from this repo works for you. If it does, you can create a debug build of HotAvalonia via That said, could you provide a bit more details about your situation? Did it work previously, and did it stop functioning after upgrading to version 2.0.0? Which version of Avalonia are you using? Are there any HotAvalonia-related logs in the debug output at all? |
Just tried the demo and get an exception when I start the project:
One thing which may be at play here is the fact that I'm running Windows on ARM64 (Windows 11 24H2). Maybe it's related to that. To answer your other questions: I did not use the previous version of HotAvalonia with that project. I tried it a while back on a different project. Running my application (not the demo app) with HotAvalonia 2, I don't see anything in the console and debug output related to HotAvalonia. |
Yup, it is. Anything non-x86_64 (except for x86 Windows) is not really supported. I need a reliable method for performing method injections to enable HotAvalonia to operate at its fullest potential. Previously, I relied on a homebrewed cross-platform injection method for that, but it had quite a few pretty annoying limitations: firstly, it only supported unoptimized assemblies; secondly, since .NET 7, it required a debugger to be attached to the application. To address these issues, I decided to switch to MonoMod for a bit more competent injection capabilities. And just in time! As .NET 9 rendered my homebrewed injection method completely obsolete (which is quite sad, because I've been using it since the .NET Framework era). However, MonoMod only supports x86_64 Linux, macOS, and Windows, along with x86 Windows. While this covers most users, it doesn't accommodate your scenario. Unfortunately, I have no control over this.
It should have at least blown up just like the demo app did. Did you forget to define the |
That's too bad 😞 I went over to MonoMod and see if there's already an issue for that but could only find a Linux and macOS issue with ARM CPUs. The one issue with Windows on ARM is closed. I would like to open an issue over there in hope the issue can be addressed but I'm clearly not a good fit as I have no idea what's actually needed or what the real problem/root cause is. Would you be able to submit an issue for that? |
MonoMod needs the ability to create ARM-specific stubs. There are requests for this functionality from users of ARM-based Macs and Linux machines, and many people are even willing to subsidize its development. However, progress has stalled because the main maintainer does not appear particularly interested in dedicating their time to it. So, unless someone steps up, implements and tests the necessary logic, and submits a PR, I don't think this is moving forward anytime soon. That said, I can reintroduce injection-less hot reload for now. It's possible to hot reload controls (and controls only) without requiring any injections. I had actually already supported this scenario but got carried away with the new and improved functionality, which inadvertently broke that part of the codebase (whoops). Unfortunately, while controls will become hot-reloadable again, assets (such as images and icons) and resources (like styles and resource dictionaries) will not. Still, it's better than having nothing at all, I suppose. |
I'll update the issue title to reflect that we're primarily focusing on ARM support here, if that's alright with you. In the meantime, let me know if you've been able to get any sign of life from HotAvalonia for your existing projects (once again, I suspect that you forgot to specify the |
Btw, I checked the const |
The
That's really strange. I either need an MRE, or it would be helpful if you could debug the app yourself. With the current information, I don't see how this could even ever happen. |
No, wait - it's practically impossible! At the very least, you should see the following message:
Add this code somewhere in your project: #if ENABLE_XAML_HOT_RELOAD && !DISABLE_XAML_HOT_RELOAD
Debug.WriteLine("Hot reload should be enabled!");
#else
Debug.WriteLine("Hot reload is disabled.");
#endif Then, let me know what the output is. |
Hi again! One mystery solved: hot reload wasn't active because the I put the I also tested the development branch and I'm afraid it's still not working for me :( When the app starts up, I get the following:
I then tested a couple of axaml files to see if something is reloaded and saw the following errors:
Then there's another question I hope you could answer: Thanks again for your help and patience! I really appreciate it. |
Happens to the best of us! :) At least it's sorted out now - that's great news. Regarding the exceptions you're encountering, see #11. The That said, I just pushed 4edc9b8, which should mostly solve the problem even without injections. You can give it a try and see if it finally works in your scenario! :D |
I pulled the latest development branch and created new nugets. Unfortunately it still won't work. I guess you don't have an ARM machine to test this, right? I will see if I can get an x64 machine to check if it's working there as expected. |
Yup, I don't. However, I did test the demo with injections disabled, and it seems to work fine - at least as much as it can in that state. As I mentioned earlier, styles, resource dictionaries, images, icons, and similar assets do require injections to support hot reloading.
What's the current problem? Are you still encountering those same exceptions as before? If so, I have a sneaky suspicion it might be a caching issue. |
I can rule out a nuget caching issue. I actually created nuget packages from source (2.0.1-beta1 and 2.0.1-beta2) and uploaded it to my private nuget feed. I'm 100% sure the right nuget is used here. What I see in the Debug Output is:
When I change something in a axaml file I see this But whatever I change (a font size, a margin, whatever), it doesn't really hot reload I don't see any exceptions or any other output. Also, a lot of my pages (the sample above with the ShellContent.axaml is not affected) are instantiated and loaded by code. I'm not sure if this affects hot reload but if I edit something in such a page, I don't even get the [HotReload]Reloading ... output. Any ideas what eIse I can do? |
That's the important part: if there are no exceptions, it works (or rather doesn't) the same way it would on an x64 machine. However, it's unclear to me why you aren't seeing any changes. It shouldn't matter how you instantiate the control, it should still be re-populated successfully.
I would greatly appreciate an MRE I could dig through, as it's very hard to determine what went wrong based solely on this brief description. At the moment, HotAvalonia doesn't blow itself up on ARM devices and seems to work as expected, so I'm going to push a new release. However, there are additional issues related to your use case that break hot reload, and these require further investigation. |
So, I pulled the 2.0.1 from the main brunch and used the HotAvaloniaDemo app to test it out and it seems to work great. So, I think the platform specific issue for ARM64 has been resolved. My project still doesn't work. When I start the app and modify any of the XAML files, nothing happens (either visibly in the app or in the debug output). So I guess it has something to do the way the project is set up (multiple projects where the App.axaml is not located in the startup project). I tried to tweak the HotAvaloniaDemo app to reflect a similar project structure like mine but it still works after those changes. Something weird must be going on in my setup and was wondering if you have any other suggestions on how to go to the bottom of this. Thanks! |
Yes, the parts of HotAvalonia that don't rely on method injections are functioning correctly now. This means the issue you're facing now is platform-independent :D
While I initially wanted to say that your project organization doesn't really matter, it got me thinking: how - and more importantly, when - do you enable hot reload? For HotAvalonia to hot reload existing control instances, it needs to be aware of their existence. However, it only starts tracking the creation of new controls after hot reload is enabled. This means that if your controls are populated before that, they won't be reloaded. If you call |
I did some more testing and the results are... weird. Here's the current state:
Then I have controls I mentioned before which are instantiated manually. I think the culprit here is that I control the lifetime of these controls. Once I instantiated the control, I put it on the But: when I change the XAML of such a page, I don't even get the So, we are making progress but I'm not sure what exactly the issue is with my pages in the TransitioningContentControl. Is there some verbose logging or so where I can see if the file change is registered? Any idea why these files are not monitored? |
This isn't part of HotAvalonia. All HotAvalonia logs are prefixed with
Nothing described here should cause an issue. HotAvalonia doesn't particularly care about the lifetime of your controls (though this can occasionally lead to some funny side effects, such as reloading controls that are about to be garbage collected, but oh well). Additionally, I see nothing inherently unusual about As I mentioned earlier, my current suspicion is that you're calling
Correct. This means that the file changes aren't being monitored at all for some reason. That's interesting.
Welp, not really, it's already as verbose as it gets :D
Not at this point. Are these pages listed in the output of |
Hi again! I'm sorry I missed to answer the question before. I can confirm that the EnableHotReload call is done at the very beginning, before any XAML content is loaded. I made some progress during debugging and found out that all controls/pages which are internal (sealed) are the ones which do not work. I've created a repro project which shows the effect. I already tried to provide the correct binding flags for the reflection calls and also set the |
I just figured out that controls marked as internals are not listed in the TryLoad method which is looked at in order to locate controls. Not sure if HotAvalonia can look at something else in order to get internal controls as well or what the impact might be if I change all my internal controls to public. |
It was worth a shot! If you're initializing your cached components statically somewhere, they might have been effectively created before the
Great job! That's unfortunate, really - it was incredibly convenient to grab all (or so I thought) the controls from that method. Sadly, it seems I'll need to resort to assembly scanning to reliably locate all available user controls. The main issue, however, isn't just finding an alternative way to detect the controls. The real problem is that By the way, I really appreciate your dedication and ongoing debugging efforts to improve HotAvalonia. Big preesh! :D |
For now I changed all my controls from So, changing a templated control markup is not picked up by HotReload on ARM64 and I guess it would be picked up on x64 (which I can't really test). Is this true? If so, I'm wondering what exactly needs to be done on the MonoCicil side and maybe on your side to make the full feature set of HotReload work for ARM64. If you can help me to submit a proper issue on their side I would really appreciate it. I'm willing to put up a donation to get this work properly on ARM64. I've seen you haven't setup sponsorship for your account. Would be great if you can set it up. The least I can do is buy you a coffee, or 17... |
So, about that... I just released
Thanks a ton! It's always amazingly heartwarming to know that my work has made a difference for someone ❤️
A general rule of thumb is that controls with the
Essentially, MonoMod requires an
Maybe I'll throw something together a bit later!
That's very kind of you! I've been thinking about it lately, especially as several of my projects have somewhat gained traction among fellow developers. So, if someone wants to sponsor my evenings working on these projects, why not? :D |
No worries, I reverted that commit and it wasn't that much of a hassle. I tested with
Woah! That's way out of my league 😅 So as a first step I would open an issue on their repo to see if they can provide ARM64 support as well. Would it be sufficient to just ask for the ARM64 implementation of the IArchitecture interface or is there something else required I should mention? |
Sorry for spamming on this thread again (a chat or maybe enabling discussions would be better?) I've found this: Discussed here: Looks like ARM64 is actually quite in demand and there is some movement at least. |
Always glad to help! :)
It looks scarier than it actually is. It's not that hard - just a lot of meticulous work scavenging through poorly written (if any) documentation for various platforms xD
They know what needs to be done, so even a simple "Windows ARM support when?" would be sufficient. It's really just about showing that there's demand for it now.
No problem at all! It's all relevant to the issue at hand. And even if it weren't, I'm not one of those on-topic-only, keep-it-short purists :)
It is but, as far as I know, the lead (and essentially the only active) developer of MonoMod is not interested in dealing with it - even if someone were to fund the work. Moreover, there simply aren't enough developers out there who simultaneously (1) have an ARM-like MacBook (since Apple deviates from the spec, because of course they do, requiring separate testing for MacBooks and similar devices), (2) own a more conventional ARM-based laptop, (3) are interested in MonoMod, (4) know C#, and (5) possess the skills required to bring ARM support to MonoMod. Currently, the only relevant work is a single, stale commit that brought ARM support to the "somewhat works on my machine, sometimes" stage. Perhaps if we leave Apple out of the picture, it might be easier to focus on supporting more conventional devices first? Anyways, I've been thinking about this for the past few days. I still need a way to provide hot reload functionality without relying on injections because there's still an entire market for Avalonia apps developed for mobile devices. And let me tell you, MonoMod support for those isn't likely to materialize anytime this century. Back in the day, I proposed AvaloniaUI/Avalonia#13085, which, admittedly, is a crutchy solution. However, it kinda makes sense and it would have enabled HotAvalonia to work without requiring injections already. Unfortunately, the proposal was met with responses like, "Well, this is a crutch; we'd prefer a perfect solution instead [which, of course, would take too much time and resources to actually develop, so no one is going to bother]." As a result, we now have neither the simple crutch solution nor any progress on "the perfect one," which hasn't even been discussed over a year later. Finally, I decided: Fine, I'll do it myself. Yesterday, I implemented a weaver that does exactly what I proposed to the Avalonia team. Now, I can run the HotReloadDemo completely injection-free. The only downside is that, since weaving is done on a per-project basis, users will need to define the |
So you're trying to make it work without MonoMod? That would be fantastic, especially since MonoMod seems like it's "dead" already.
I can live with putting the deps in a shared props file. The Fody dependency would only be relevant in debug builds when HotAvalonia is enabled, right? Release builds won't be affected by this, correct? If so, I can't think of any reason/downside to not use it. I also guess there's no caveats when using ARM64 for that, so I think it's good news 😅 If you want me to test something, feel free to ping me. I'm happy to look at it. |
Welp, "dead" might be a bit too harsh of a word here, honestly. I'd say it's more accurate to describe it as being in maintenance mode. And I don't think MonoMod will ever truly die, though, because the entire modding scene for Unity games (and more) depends solely on it. That said, it would be great to move away from relying on it, especially since I want HotAvalonia to be supported in environments where MonoMod likely will never work.
Of course! One of the core principles I've developed HotAvalonia around is that no hot reload-related logic slips into the production build of your app. If I weren't concerned about this, I could have packed HotAvalonia as a single package and skipped all this conditional setup :) Anyways, v2.1.0 is up and running, and you can now make use of Current SetupCurrently, for a single project, your <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DefineConstants>$(DefineConstants);ENABLE_XAML_HOT_RELOAD</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Condition="$(DefineConstants.Contains(ENABLE_XAML_HOT_RELOAD))" Include="Avalonia.Markup.Xaml.Loader" Version="$(AvaloniaVersion)" />
<PackageReference Condition="$(DefineConstants.Contains(ENABLE_XAML_HOT_RELOAD))" Include="HotAvalonia" Version="2.1.0" />
<PackageReference Include="HotAvalonia.Extensions" Version="2.1.0" PrivateAssets="All" />
</ItemGroup> With <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DefineConstants>$(DefineConstants);ENABLE_XAML_HOT_RELOAD</DefineConstants>
+ <WeaverConfiguration><Weavers><HotAvalonia/></Weavers></WeaverConfiguration>
+ <FodyDependsOnTargets>CompileAvaloniaXaml</FodyDependsOnTargets>
</PropertyGroup>
<ItemGroup>
<PackageReference Condition="$(DefineConstants.Contains(ENABLE_XAML_HOT_RELOAD))" Include="Avalonia.Markup.Xaml.Loader" Version="$(AvaloniaVersion)" />
<PackageReference Condition="$(DefineConstants.Contains(ENABLE_XAML_HOT_RELOAD))" Include="HotAvalonia" Version="2.1.0" />
+ <PackageReference Condition="$(DefineConstants.Contains(ENABLE_XAML_HOT_RELOAD))" Include="HotAvalonia.Fody" Version="2.1.0" PrivateAssets="All" />
<PackageReference Include="HotAvalonia.Extensions" Version="2.1.0" PrivateAssets="All" />
</ItemGroup> Essentially, you need to:
And that's all there is to it! Multi-Project SetupSince assembly weaving is done on a per-project basis, you'll need to set up
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DefineConstants>$(DefineConstants);ENABLE_XAML_HOT_RELOAD</DefineConstants>
<WeaverConfiguration><Weavers><HotAvalonia/></Weavers></WeaverConfiguration>
<FodyDependsOnTargets>CompileAvaloniaXaml</FodyDependsOnTargets>
</PropertyGroup>
<ItemGroup>
<PackageReference Condition="$(DefineConstants.Contains(ENABLE_XAML_HOT_RELOAD))" Include="HotAvalonia.Fody" Version="2.1.0" PrivateAssets="All" />
</ItemGroup> Your entrypoint project's <ItemGroup>
<PackageReference Condition="$(DefineConstants.Contains(ENABLE_XAML_HOT_RELOAD))" Include="Avalonia.Markup.Xaml.Loader" Version="$(AvaloniaVersion)" />
<PackageReference Condition="$(DefineConstants.Contains(ENABLE_XAML_HOT_RELOAD))" Include="HotAvalonia" Version="2.1.0" />
<PackageReference Include="HotAvalonia.Extensions" Version="2.1.0" PrivateAssets="All" />
</ItemGroup> With that, your experience should be pretty much the same as if you were on AMD64. Hope this helps! :) |
Wow! I just tried 2.1.0 and also added Fody. So far, I tested the following and this seems to work quite well:
What kind of worked but needed a "manual reload":
What didn't work:
If I change this style to:
I get the following crash:
Overall, this is a huge improvement and works much better for me on my ARM64 machine! If you want me to open separate issues and dig deeper regarding the two issues I encountered so far, let me know. Again, thanks for all the great work. This is a game changer for Avalonia! |
Really appreciate the kind words as always! :D
The problems you're encountering now are not architecture-specific anymore. So feel free to open new issues so I can address them for you and other users. MREs (and maybe even PRs for the demo app, which I use for manual testing) are more than welcome! ;) |
Understood! I see what I can come up with and file another issue or PR for the demo with the issue. Thanks again and a happy new year! |
Thanks a bunch and a happy New Year to you too! :) |
Hi!
I was just trying out the version 2 with .net 9 in my project. For me it seems it doesn't work on my projects. Is there anything I can do to investigate/trouble shoot the issue. I don't see any errors or output - it just doesn't do anything.
The text was updated successfully, but these errors were encountered: