Harmony icon indicating copy to clipboard operation
Harmony copied to clipboard

[BUG] Current Project Release Process Uses Broken Builds

Open MisutaaAsriel opened this issue 4 months ago • 13 comments

Description

When attempting to use Harmony with Unity, if the Burst Compiler is used by the project, it will fail to operate.

[!WARNING] This was previously thought to be due to invalid metadata in release builds.

[!TIP] This no longer seems to be the case.

Reproduction

  1. Create a VRChat World project
  2. Close Unity
  3. Swap 0Harmony.dll under Packages/com.vrchat.base/Runtime/VRCSDK/Plugins/Harmony/0Harmony.dll within the project directory with the fat dll from Harmony 4.2.1, variant net472.
  4. Open Unity

Expectation

  • Nothing happens

Result

  • The VRC SDK breaks
  • The following is output to the console:
Failed to find entry-points:
System.Exception: Error while loading assembly references for UdonSharp.Editor ---> System.Exception: Error while hashing assembly /Packages/com.vrchat.base/Runtime/VRCSDK/Plugins/Harmony/0Harmony.dll ---> System.AggregateException: One or more errors occurred. (Error while hashing type reference '1000136' in assembly '0Harmony.dll') ---> System.Exception: Error while hashing type reference '1000136' in assembly '0Harmony.dll' ---> System.BadImageFormatException: Read out of bounds.
  at System.Reflection.Throw.OutOfBounds () [0x00005] in <dd9f65e0a5bd49ea8090db671948b5fc>:0 
  at System.Reflection.Internal.MemoryBlock.PeekHeapReference (System.Int32 offset, System.Boolean smallRefSize) [0x0000b] in <dd9f65e0a5bd49ea8090db671948b5fc>:0 
  at System.Reflection.Metadata.Ecma335.AssemblyRefTableReader.GetName (System.Int32 rowId) [0x0000b] in <dd9f65e0a5bd49ea8090db671948b5fc>:0 
  at System.Reflection.Metadata.AssemblyReference.get_Name () [0x00020] in <dd9f65e0a5bd49ea8090db671948b5fc>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.Util.SrmExtensions.GetAssemblyNameReference (System.Reflection.Metadata.AssemblyReference& assemblyReference, System.Reflection.Metadata.MetadataReader metadataReader) [0x00000] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.Util.CachingMetadataReader.GetAssemblyNameReferenceImpl (System.Reflection.Metadata.AssemblyReferenceHandle handle) [0x0000d] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].GetOrAdd (TKey key, System.Func`2[T,TResult] valueFactory) [0x00034] in <b904252b6b4e4277834bcca7e51f318d>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.Util.CachingMetadataReader.GetAssemblyNameReference (System.Reflection.Metadata.AssemblyReferenceHandle handle) [0x00000] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.Util.SrmExtensions.WriteAssemblyNameTo (System.Reflection.Metadata.TypeReference& typeReference, Burst.Compiler.IL.Helpers.Hash128Builder builder, Burst.Compiler.IL.Hashing.CacheBuilder.Util.CachingMetadataReader reader, Burst.Compiler.TargetFramework targetFramework) [0x00037] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.HashTypeReferenceImpl (System.Reflection.Metadata.TypeReferenceHandle typeReferenceHandle) [0x00089] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.HashTypeReference (System.Reflection.Metadata.TypeReferenceHandle typeReferenceHandle) [0x00000] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
   --- End of inner exception stack trace ---
  at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.HashTypeReference (System.Reflection.Metadata.TypeReferenceHandle typeReferenceHandle) [0x00031] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher+<>c__DisplayClass14_0.<HashImpl>b__6 (System.Reflection.Metadata.TypeReferenceHandle typeReferenceHandle, System.Threading.Tasks.ParallelLoopState loopState, System.Int64 i) [0x00000] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.ForEach[T] (System.Collections.Generic.IEnumerable`1[T] elements, System.Action`3[T1,T2,T3] callback) [0x00018] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher+<>c__DisplayClass14_0.<HashImpl>b__1 () [0x00000] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at System.Threading.Tasks.Task.InnerInvoke () [0x0000f] in <b904252b6b4e4277834bcca7e51f318d>:0 
  at System.Threading.Tasks.Task.Execute () [0x00000] in <b904252b6b4e4277834bcca7e51f318d>:0 
   --- End of inner exception stack trace ---
  at System.Threading.Tasks.Task.WaitAll (System.Threading.Tasks.Task[] tasks, System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x001c8] in <b904252b6b4e4277834bcca7e51f318d>:0 
  at System.Threading.Tasks.Task.WaitAll (System.Threading.Tasks.Task[] tasks, System.Int32 millisecondsTimeout) [0x00000] in <b904252b6b4e4277834bcca7e51f318d>:0 
  at System.Threading.Tasks.Task.WaitAll (System.Threading.Tasks.Task[] tasks) [0x00000] in <b904252b6b4e4277834bcca7e51f318d>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.HashImpl () [0x00243] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.HashAssembly (System.String filePath, System.Threading.Tasks.TaskFactory taskFactory, Burst.Compiler.TargetFramework targetFramework) [0x00009] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
   --- End of inner exception stack trace ---
  at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.HashAssembly (System.String filePath, System.Threading.Tasks.TaskFactory taskFactory, Burst.Compiler.TargetFramework targetFramework) [0x0002e] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Hashing.CacheRuntime.HashCacheLoader.CreateHashingResult (Mono.Cecil.AssemblyNameReference assemblyNameReference, Burst.Compiler.IL.AssemblyLoader assemblyLoader, Burst.Compiler.IL.Helpers.DebugLogWriter debugLogWriter) [0x001b9] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Hashing.CacheRuntime.HashCacheAssemblyStore.GetAssemblyState (System.String assemblyName, Burst.Compiler.IL.AssemblyLoader assemblyLoader) [0x000a0] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Server.EntryPointMethodFinder.LoadAllAssemblyReferences (Mono.Cecil.AssemblyDefinition asmDef, System.Collections.Generic.Dictionary`2[TKey,TValue] visited, System.Collections.Generic.Dictionary`2[TKey,TValue] jobProducers, Burst.Compiler.IL.Hashing.CacheRuntime.HashCacheAssemblyStore assemblyStore, Burst.Compiler.IL.AssemblyLoader assemblyLoader) [0x00025] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Server.EntryPointMethodFinder.LoadAllAssemblyReferences (Mono.Cecil.AssemblyDefinition asmDef, System.Collections.Generic.Dictionary`2[TKey,TValue] visited, System.Collections.Generic.Dictionary`2[TKey,TValue] jobProducers, Burst.Compiler.IL.Hashing.CacheRuntime.HashCacheAssemblyStore assemblyStore, Burst.Compiler.IL.AssemblyLoader assemblyLoader) [0x001de] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Server.EntryPointMethodFinder.FindEntryPoints (System.String[] rootAssemblyNames, Burst.Compiler.IL.Hashing.CacheRuntime.HashCacheAssemblyStore assemblyStore, Burst.Compiler.IL.AssemblyLoader assemblyLoader, Burst.Compiler.IL.NativeCompilerOptions options, Burst.Compiler.IL.Server.ProfileDelegate profileCallback, System.Boolean includeRootAssemblyReferences, System.Boolean splitTargets) [0x00071] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
   --- End of inner exception stack trace ---
  at Burst.Compiler.IL.Server.EntryPointMethodFinder.FindEntryPoints (System.String[] rootAssemblyNames, Burst.Compiler.IL.Hashing.CacheRuntime.HashCacheAssemblyStore assemblyStore, Burst.Compiler.IL.AssemblyLoader assemblyLoader, Burst.Compiler.IL.NativeCompilerOptions options, Burst.Compiler.IL.Server.ProfileDelegate profileCallback, System.Boolean includeRootAssemblyReferences, System.Boolean splitTargets) [0x00094] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Server.CompilerServer+<>c__DisplayClass18_1.<FindMethods>b__0 (Burst.Compiler.IL.Server.Caching.CacheManager cacheManager) [0x0005e] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Server.CompilerServer+<>c__DisplayClass26_0`1[TResult].<RunTask>b__0 () [0x00145] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Server.CompilerServer.RunTask[TResult] (Burst.Compiler.IL.Server.TargetKey target, System.String taskName, System.String[] assemblyFolders, System.Threading.CancellationToken cancellationToken, System.Func`2[T,TResult] function) [0x00131] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Server.CompilerServer.FindMethods (Burst.Compiler.IL.Server.CompilerServerOptions options, Burst.Compiler.IL.Aot.AotCompilerOptions aotOptions, Burst.Compiler.IL.Server.TargetKey target, Burst.Compiler.IL.Server.Caching.CacheManager cacheManager, Burst.Compiler.IL.CompilerStatistics stats, System.Threading.CancellationToken cancellationToken) [0x00299] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Server.CompilerServer+<>c__DisplayClass26_0`1[TResult].<RunTask>b__0 () [0x00145] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Server.CompilerServer.RunTask[TResult] (Burst.Compiler.IL.Server.TargetKey target, System.String taskName, System.String[] assemblyFolders, System.Threading.CancellationToken cancellationToken, System.Func`2[T,TResult] function) [0x00131] in <f26dfc19a37a442ea317a7ab78395fa6>:0 
  at Burst.Compiler.IL.Server.CompilerServer.Compile (Burst.Compiler.IL.Server.CompilerServerOptions options, Burst.Compiler.IL.Server.CompilationMessageStreamer streamer, System.Threading.CancellationToken cancellationToken) [0x001af] in <f26dfc19a37a442ea317a7ab78395fa6>:0

Environment

  • Host: MacBook Air M2, 24GB RAM
  • OS: macOS Sequoia 15.6
  • Target Application: Unity Editor 2022.3.22f1
  • Project Type: VRChat SDK (World)
  • Harmony Version: 4.2.1
  • Net Framework Version: 4.7.2
    • Also tested with 4.8 & 4.5.2 with similar results

Additional Notes

  • The VRCSDK relies on Harmony for the Client Sim/UDON, as it is runtime patching the editor itself, not the game or its scripts. The version included is an old local build from its original maintainer that fixed some localization issues at the time, targeting Net Framework 4.5.
    • The SDK also relies on Burst compilation and as such it cannot be removed.
  • The metadata issues are reported with PEVerify.exe 0Harmony.dll /MD. When ran against the copy provided by the SDK, it reports that all classes and methods are verified, ~~confirming this issue is unique to provided release builds. The following is the output of the same command when ran against the release builds of Harmony:~~
Microsoft (R) .NET Framework PE Verifier.  Version  4.0.30319.0
Copyright (c) Microsoft Corporation.  All rights reserved.

[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x00000138, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x00000140, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x00000143, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x00000146, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x0000014b, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x0000014e, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x00000153, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x0000015a, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x0000015b, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x0000015c, has coded rid out of range.
10 Error(s) Verifying D:\Shared\0Harmony.dll
  • The Unity Forum post which mentions this issue notes that it does not appear in local builds from the main branch, suggesting there may be an issue with the build pipeline?

MisutaaAsriel avatar Sep 07 '25 21:09 MisutaaAsriel

Further Testing

  • Building from a Mac for ReleaseFat using reference assemblies results in an identical output from peverify on a PC.
  • Building from a Mac for DebugFat using reference assemblies results in new output from peverify but a working DLL that can coexist with Unity Burst.
  • Building for Release at the solution level results in a functioning build.

DebugFat DLL peverify Output

Microsoft (R) .NET Framework PE Verifier.  Version  4.0.30319.0
Copyright (c) Microsoft Corporation.  All rights reserved.

[MD]: Warning: TypeDef (token=0x020000c4) has same name as TypeRef. [token:0x01000055]
[MD]: Error: Value class has neither fields nor size parameter. [token:0x02000587]
[MD]: Error: Value class has neither fields nor size parameter. [token:0x02000590]
[MD]: Error: Value class has neither fields nor size parameter. [token:0x0200059D]
[MD]: Error: Value class has neither fields nor size parameter. [token:0x0200059E]
[MD]: Error: Value class has neither fields nor size parameter. [token:0x0200059F]
[MD]: Error: Value class has neither fields nor size parameter. [token:0x020005BA]
[MD]: Error: Value class has neither fields nor size parameter. [token:0x020005C3]
[MD]: Error: Value class has neither fields nor size parameter. [token:0x020005D6]
[MD]: Error: Value class has neither fields nor size parameter. [token:0x020005D7]
[MD]: Error: Value class has neither fields nor size parameter. [token:0x020005D8]
10 Error(s) Verifying D:\Shared\0Harmony.dll
(1 Warnings)

Update

I can confirm that after running dotnet restore in the project root, on a fresh copy of Harmony's source, followed by dotnet build -c:Release -f:net452 will create a working release build. It seems dotnet restore is important to download the reference assemblies, else the build may fail. The Lib.Harmony.Ref library will naturally fail to build anyways, as this is expected due to the .NET 4.5.2 framework target.

MisutaaAsriel avatar Sep 08 '25 00:09 MisutaaAsriel

To be clear, this seems to be an issue with the build pipeline that this project uses to create the releases here, and the library level build pipeline.

The project itself will build fine when built at the solution level. This would suggest some sort of reference is being lost when built at the library level (e.g. just building the DLL).

MisutaaAsriel avatar Oct 06 '25 15:10 MisutaaAsriel

[!WARNING] Whilst this report makes direct mention of Unity, please note the following:

This is for manipulating the Unity Editor itself, not Unity games. HarmonyX, a fork of Harmony targeting Unity games, does not apply in this situation. There are fundamental API changes between the two which makes HarmonyX incompatible with more complex Unity Editor packages built against the Harmony library. Harmony is required in these cases.

This issue may impact other applications as well; to note, this issue in particular impacts Unity's burst compiler. This would suggest that any non-standard compiler could be susceptible to the faults found in the published libraries.

MisutaaAsriel avatar Oct 06 '25 15:10 MisutaaAsriel

I don't know enough about the things you refer to for me to fix this. Not sure I can help you.

pardeike avatar Oct 06 '25 17:10 pardeike

I don't know enough about the things you refer to for me to fix this. Not sure I can help you.

To be honest, I don't quite understand it myself. This seems to be a build process issue though.

[!TIP]

The gist of it is this, though:

  • When you clone and build this project from the root of the project ("solution level"), everything is fine.
  • When you clone the project and build just the library, from within its folder, as "ReleaseFat", it results in libraries which breaks certain compilers, such as Unity Burst.
    • Building for DebugFat does not exhibit this issue when built from the same directory, strangely.
  • The precompiled builds you provide in Releases include libraries which break such compilers in identical fashion.
    • E.G. net452/0Harmony.dll inside Harmony-Fat.2.4.1.0.zip

[!WARNING]

I think the metadata thing is actually a red herring.

I say this because, despite local builds lacking any errors when running them through peverify /MD, GitHub generated builds I have packaged for use with the VRCSDK in Unity have the same results from peverify as "broken" builds, despite functioning perfectly fine. This would suggest something else is going on with the libraries.

The reasons others seemed to conclude it was metadata related was because local builds at the solution level didn't have these issues. These metadata errors being reported anyways when built via GitHub on working builds would suggest this is unrelated to the actual issue at hand.

I, and some others, seemed to blindly accept the metadata conclusion, as we have no real understanding otherwise what makes one build different from the other, despite being built from the same code.

[!TIP] You can obtain a copy of the "functioning" library from here: dev.pardeike.harmony-2.4.1.0.zip

  • It is located under Plugins/Harmony/0Harmony.dll in the extracted folder.

The action used to generate this code is here: build.yml.

  • As only the net452 target was required, -c:release -f:net452 was used for the build.
  • As the Ref library throws a build error which interrupts the GitHub workflow when targeting net452, care was taken to remove it from the solution before building.

[!NOTE] PEVerify is a tool by Microsoft to validate the type safety of a binary or compiled library, both in its assembly and its accompanying metadata.

MisutaaAsriel avatar Oct 06 '25 18:10 MisutaaAsriel

I need more details on what you are actually doing. Like, what commands are you using exactly when you try to build Harmony. I also don’t understand the motivation behind building Harmony yourself and why you need to build it in the specific way you do.

pardeike avatar Oct 07 '25 05:10 pardeike

I need more details on what you are actually doing. Like, what commands are you using exactly when you try to build Harmony. I also don’t understand the motivation behind building Harmony yourself and why you need to build it in the specific way you do.

[!TIP] The Simplified Version:

  • Unity Editor is .NET based
  • Using Harmony on the Editor requires a .NET 4.5 target
  • An SDK built on Unity I use relies on Harmony
    • As do user packages built for said SDK
  • It is possible to "drop in" a copy of the updated library .dll
    • As long as the library itself is valid, the SDK appears to support it.
  • Unity's (MSIL) "Burst" compiler breaks when using your published builds.
    • Errors mention out of bounds reads by 0Harmony.dll & metadata errors
  • There are no errors when the library is built from the project solution
    • Building just the "fat" library, as opposed to the "full" project, requires a DebugFat build.
      • ReleaseFat builds will be "broken" when built the same way.
  • I'm only building it at all because the published copies are in some obscure way broken.

To be clear, your published builds have issues.

These issues can merely be mirrored by library-level builds.

[!WARNING] This issue in question impacts all platforms for the Unity Editor (Windows, Mac; Intel, ARM), despite the necessity of using a newer copy of Harmony primarily impacting Mac.

Ok, so here's the rundown

Also known as the "long version"

I, and many others, create content for a platform called VRChat.

In their SDK, they include a copy of Harmony. This is used to override elements of the Unity Editor for their custom scripting environment. Their scripts behave as C# when editing but as custom scripts in play mode and on compile, using Harmony to swap between the two. This facilitates features like Editor Scripting.

Harmony is also used by the community to extend functionality of both the Unity Editor & the VRChat SDK. For example, one package adds "user switching" to the SDK's control panel by injecting itself via Harmony. Another is a port of a Unity Package which overrides its menu declarations to allow easy reorganization of Unity Editor menus. Etc.

Critical functionality for parts of the SDK, and many packages designed for the SDK, rely on Harmony to patch the Unity Editor. It is not used in-game.

However, the version in use is quite old. It was a local build as part of the scripting SDK back whenever it was a community project. Amongst other things, it lacks support for ARM64, which means content creators on Mac experience a subpar experience. In the wake of upcoming Apple platform support, the ability to create content on Mac has become more relevant.

Now, it is possible to "drop in" a replacement copy of Harmony. Specifically, a "fat" build targeting net452. However, the Unity Burst Compiler, the MSIL compiler by Unity used by the VRChat SDK to expedite compilation, finds fault with the published copies of the Harmony library. One will note the errors above in the original post.

The errors mention entry points and metadata issues. What is exactly wrong is unclear, as mentioned previously my builds also echo metadata issues, albeit slightly different, leading me to believe that the errors reported by the compiler are not true to the actual problem, just a symptom. Yet I digress.

When Harmony is built from the solution, the Burst Compiler has no issues with Harmony library. Only your uploads, and local builds when the "fat" library is built independently for release, are incompatible, despite purportedly being identical libraries otherwise.

The cause for -c:release -f:net452 and removing the "Ref" library from the solution before building merely stems from the simple facts that:

  1. The SDK only needs the net452 copy of the library. Wasting resources, especially limited ones as are Actions, to compile unneeded versions would be pointless.
  2. The reference library doesn't support targeting net452 — This causes aa build error which, in the case of GitHub Actions, aborts the entire run.

MisutaaAsriel avatar Oct 07 '25 06:10 MisutaaAsriel

Currently, the method of successfully building Harmony in a way that is compatible with Burst is as follows:

# Ran from the cloned project root directory

dotnet restore
# Ensures .NET Reference libraries are installed

dotnet sln remove Lib.Harmony.Ref/Lib.Harmony.Ref.csproj
# Removes reference library, as we're only targeting .NET 4.5.2; Prevents build errors
# This is unnecessary if you intend to build all framework variants

dotnet build -c:release -f:net452
# Builds entire project, sans-reference library, with a release build and a target framework of .NET 4.5.2

Incompatible builds, which mirror your uploads, were built via:

# Ran from the cloned project root directory

dotnet restore
# Ensures .NET Reference libraries are installed

dotnet build Lib.Harmony/Lib.Harmony.csproj -c:ReleaseFat -f:net452
# Builds *just* the fat library, with a release build and a target framework of .NET 4.5.2

MisutaaAsriel avatar Oct 07 '25 06:10 MisutaaAsriel

The merge process in Lib.Harmony seems to have problems with the Burst compiler. Since I cannot simply switch this the only option left is to use Lib.Harmony.Thin - its sole purpose is for exactly this kind of problem. So for now this will be a WONTFIX

pardeike avatar Oct 07 '25 08:10 pardeike

The merge process in Lib.Harmony seems to have problems with the Burst compiler.

What's the difference between building the csproj and the sln though? I'm not using the thin libraries.

Also, out of curiosity, how are the github releases built, command wise?

I'm wondering if there's something missing from the project file that is given at the solution level…

MisutaaAsriel avatar Oct 07 '25 12:10 MisutaaAsriel

What's the difference between building the csproj and the sln though? I'm not using the thin libraries.

Basically none. The solution only holds all projects together. Not sure how much you can see if you’re not the owner but check out the PR that copilot started. It confirms the corruption but I am not sure if it makes a difference between caproj and sln builds.

Also, out of curiosity, how are the github releases built, command wise?

I just build them with the pack command or the script on my own PC. Can’t remember which one I used in the 2.4.1 release.

I'm wondering if there's something missing from the project file that is given at the solution level…

Look at the solution file. It does not contain any shenanigans.

pardeike avatar Oct 07 '25 14:10 pardeike

Btw, I ran this:

# Ran from the cloned project root directory
dotnet restore
# Ensures .NET Reference libraries are installed
dotnet sln remove Lib.Harmony.Ref/Lib.Harmony.Ref.csproj
# Removes reference library, as we're only targeting .NET 4.5.2; Prevents build errors
# This is unnecessary if you intend to build all framework variants
dotnet build -c:release -f:net452
# Builds entire project, sans-reference library, with a release build and a target framework of .NET 4.5.2

and verified it with PEVerify and got this result:

>"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools\x64\PEVerify.exe" Lib.Harmony\bin\Release\net452\0Harmony.dll /md /il

Microsoft (R) .NET Framework PE Verifier.  Version  4.0.30319.0
Copyright (c) Microsoft Corporation.  All rights reserved.
[MD]: .NET Framework Internal error: 0x80131205
[MD]: .NET Framework Internal error: 0x80131205
[MD]: .NET Framework Internal error: 0x80131205
[MD]: .NET Framework Internal error: 0x80131205
[MD]: .NET Framework Internal error: 0x80131205
[MD]: .NET Framework Internal error: 0x80131205
<snipped lots of IL errors>

So your statement is not correct - or - PEVerify is not the correct way to verify fat 0Harmony.dll I stand by my statement: this is not a problem I am inclined to fix because its pretty obscure and the recommendation is to use Lib.Harmony.Thin and to manage the dependencies yourself.

pardeike avatar Oct 07 '25 15:10 pardeike

What's the difference between building the csproj and the sln though? I'm not using the thin libraries.

Basically none. The solution only holds all projects together. [ … ] not sure if it makes a difference between csproj and sln builds.

Problem is there is a difference. The .csproj output breaks the Burst compiler, the .sln does not.

So your statement is not correct - or - PEVerify is not the correct way to verify fat 0Harmony.dll

If you read my previous replies I stated that the metadata was a red herring. My original statement was based on the errors output by the compiler and other, more knowledgeable people's input. However, I had since corrected myself at this point (hence the title change).

the recommendation is to use Lib.Harmony.Thin and to manage the dependencies yourself.

Using the thin library is not an option since the dependencies are difficult to import into Unity properly and may conflict with other libraries in my experience. The "fat" library is what the original SDK used so to "drop in" a replacement it ideally need match.


I readily admit this is a bit of a strange case. It's not using a standard MSIL compiler, it's being used against commercial software which I do not control, and the form of library being included is likewise outside my control. — I can supersede it, with a newer copy of the library, but I cannot replace it with a different format (thin/fat/ref), to my knowledge. At least, not easily.

I have a working build pipeline nonetheless, so I'm not immediately pressed about this, and if VRChat so chooses to update the version included in their SDK, they could opt to build it themselves similar to how I have when packaging it.

I just wanted to bring it to your attention that something isn't building quite right with your releases that may cause errors in select use cases.

MisutaaAsriel avatar Oct 07 '25 20:10 MisutaaAsriel