Subject: [bug#74609] [PATCH 21/21] gnu: Add mono-6.12.0.

From: Efraim Flashner <[email-masked]>
Date: Mon, 16 Dec 2024 19:26:44 +0200

From: unmush <[email-masked]>

This includes a patch to add support for a <runpath> element to
mono's *.dll.config and *.exe.config files.  See mono-6.12.0-add-runpath.patch
for details.

* gnu/packages/dotnet.scm
  (mono-6.12.0-external-repo-specs, mono-6.12.0): New variable.
* gnu/packages/patches/mono-6.12.0-{add-runpath,fix-AssemblyResolver,fix-ConditionParser}.patch: New patches.
* gnu/local.mk (dist_patch_DATA): Register new patches.

Change-Id: I9d5bd5d366c368eb235483411818c90374bfc4d4
---
 gnu/local.mk                                  |   3 +
 gnu/packages/dotnet.scm                       | 194 ++++++++++++++
 .../patches/mono-6.12.0-add-runpath.patch     | 185 ++++++++++++++
 .../mono-6.12.0-fix-AssemblyResolver.patch    | 236 ++++++++++++++++++
 .../mono-6.12.0-fix-ConditionParser.patch     |  46 ++++
 5 files changed, 664 insertions(+)
 create mode 100644 gnu/packages/patches/mono-6.12.0-add-runpath.patch
 create mode 100644 gnu/packages/patches/mono-6.12.0-fix-AssemblyResolver.patch
 create mode 100644 gnu/packages/patches/mono-6.12.0-fix-ConditionParser.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 35a2d7e55a7..8722c2a33d9 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1830,6 +1830,9 @@ dist_patch_DATA =						\
   %D%/packages/patches/mono-5.4.0-patches.patch		\
   %D%/packages/patches/mono-5.8.0-patches.patch		\
   %D%/packages/patches/mono-5.10.0-later-mcs-changes.patch	\
+  %D%/packages/patches/mono-6.12.0-add-runpath.patch		\
+  %D%/packages/patches/mono-6.12.0-fix-AssemblyResolver.patch	\
+  %D%/packages/patches/mono-6.12.0-fix-ConditionParser.patch	\
   %D%/packages/patches/mono-mcs-patches-from-5.10.0.patch	\
   %D%/packages/patches/mosaicatcher-unbundle-htslib.patch	\
   %D%/packages/patches/mrrescue-support-love-11.patch		\
diff --git a/gnu/packages/dotnet.scm b/gnu/packages/dotnet.scm
index 03e18e29c6d..22dcf88adb4 100644
--- a/gnu/packages/dotnet.scm
+++ b/gnu/packages/dotnet.scm
@@ -1634,3 +1634,197 @@ (define-public libgdiplus
 most of the heavy lifting.")
     (home-page "https://github.com/mono/libgdiplus")
     (license license:expat)))
+
+(define mono-6.12.0-external-repo-specs
+  '(("api-doc-tools"               "5da8127af9e68c9d58a90aa9de21f57491d81261"
+     "0rq8dxmy5av36nd298k60d8s386zhqlw63yn2ywc0416xsflscg4"
+     #:recursive? #t)
+    ("api-snapshot"                "808e8a9e4be8d38e097d2b0919cac37bc195844a"
+     "1i5migdw649bmxqii99q2hd6vka11wlcphfrm98kb7pprz4k401a")
+    ("aspnetwebstack"              "e77b12e6cc5ed260a98447f609e887337e44e299"
+     "0rks344qr4fmp3fs1264d2qkmm348m8d1kjd7z4l94iiirwn1fq1")
+    ;; (("https://github.com/Unity-Technologies/bdwgc" "bdwgc")
+    ;;  "a27eddb837d613cb4cf436405c23ce39ed16a86d"
+    ;;  "")
+    (("reference-assemblies" "binary-reference-assemblies")
+     "e68046d5106aa0349c23f95821456955fc15b96b"
+     "1mqpz274qdhl84y6x8bazrfmajcf6qagiks2g0gyg4qyqwgrp490")
+    ("bockbuild"                   "3bd44f6784b85b1ece8b00b13d12cf416f5a87e7"
+     "0z3d8qylfwnlklpcvsmsgy5n248gcff5vmzqjzalfj7d1h7vcjxs")
+    ("boringssl"                   "296137cf989688b03ed89f72cd7bfd86d470441e"
+     "11ghdayfcvysnh1617bj478hxrg7b43jpk7vgafm6jb7ykpxl8fa")
+    ("cecil"                       "8021f3fbe75715a1762e725594d8c00cce3679d8"
+     "0j19lwbs30y2xz8myk0fbxs4hbal1p8vqjmnkvn301v0xxacynxm")
+    (("cecil" "cecil-legacy")      "33d50b874fd527118bc361d83de3d494e8bb55e1"
+     "1p4hl1796ib26ykyf5snl6cj0lx0v7mjh0xqhjw6qdh753nsjyhb")
+    ("corefx"                      "c4eeab9fc2faa0195a812e552cd73ee298d39386"
+     "03530pf6dddqlihvb83m9z34bark8mzrffnrclq726gndfg4vqs8")
+    ("corert"                      "11136ad55767485063226be08cfbd32ed574ca43"
+     "1g0q83fff13237nwsfcmk7fmzwx0kv93zsqqybcigwip5x6ani8f")
+    ("helix-binaries"              "64b3a67631ac8a08ff82d61087cfbfc664eb4af8"
+     "1f6kkpbzj3bx9p1hb36kzjq0ppckk4rpmjnr82hyq7y18fwikfd7")
+    ("ikdasm"                      "f0fd66ea063929ef5d51aafdb10832164835bb0f"
+     "0313pvmmjh01h9b306jd6cd6fcbnbxaglaj81m0l0acf4yn7zb10")
+    (("ikvm-fork" "ikvm")          "08266ac8c0b620cc929ffaeb1f23ac37629ce825"
+     "1g0v1v8nvxkwq7w9qyqhf9kgmxq3qm6rsw4al8x0w3dmbgxjhqjv")
+    ("illinker-test-assets"       "ec9eb51af2eb07dbe50a2724db826bf3bfb930a6"
+     "1b4vq4jbgnl4lzffg02n5w1sppg2k6bfks0150pj403sbnml85gl")
+    ("linker"                      "ed4a9413489aa29a70e41f94c3dac5621099f734"
+     "16rdpch9anarnhczi441a9zna4rz93jwpb31x0dzrb4j03cxajg2")
+    ;; (("https://github.com/dotnet/llvm-project" "llvm-project")
+    ;;  "7dfdea1267f0a40955e02567dcbcd1bcb987e825"
+    ;;  "")
+    ("Newtonsoft.Json"             "471c3e0803a9f40a0acc8aeceb31de6ff93a52c4"
+     "0dgngd5hqk6yhlg40kabn6qdnknm32zcx9q6bm2w31csnsk5978s")
+    (("NuGet.BuildTasks" "nuget-buildtasks")
+     "99558479578b1d6af0f443bb411bc3520fcbae5c"
+     "1434m6z9sb7bvki9ba6iinqpmh4a4iyld76jz10qz07sycklflq3")
+    (("NUnitLite" "nunit-lite")    "a977ca57572c545e108b56ef32aa3f7ff8287611"
+     "02zwdfpw8pazllwbp4hkzqwfql98g4854diykqdb9wa0vrb8w4sj")
+    ;; ("roslyn-binaries"             "1c6482470cd219dcc7503259a20f26a1723f20ec"
+    ;;  "")
+    ("rx"                          "b29a4b0fda609e0af33ff54ed13652b6ccf0e05e"
+     "1n1jwhmsbkcv2d806immcpzkb72rz04xy98myw355a8w5ah25yiv")
+    ;; ("xunit-binaries"              "8f6e62e1c016dfb15420852e220e07091923734a"
+    ;;  "")
+    ))
+
+(define-public mono-6.12.0
+  (package
+    (inherit mono-5.10.0)
+    (version "6.12.0.206")
+    (name "mono")
+    (source (origin
+              (method git-fetch)
+              (uri
+               (git-reference
+                (url "https://gitlab.winehq.org/mono/mono.git")
+                (commit (string-append "mono-" "6.12.0.206"))))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1cw9v53bgbc6v7xmp5ij76y6inb6sz1g1zx2jk825rxshq96alvk"))
+              (modules '((guix build utils)
+                         (ice-9 string-fun)))
+              (snippet #~(begin
+                           #$(add-external-repos
+                              mono-6.12.0-external-repo-specs)
+                           #$@prepare-mono-source-0))
+              (patches
+               (search-patches
+                "mono-6.12.0-fix-ConditionParser.patch"
+                "mono-6.12.0-add-runpath.patch"
+                "mono-6.12.0-fix-AssemblyResolver.patch"))))
+    (native-inputs (modify-inputs (package-native-inputs mono-5.10.0)
+                     (replace "mono" mono-5.10.0)
+                     (append (default-python))))
+    (inputs (modify-inputs (package-inputs mono-5.10.0)
+              (append libgdiplus)))
+    (arguments
+     (substitute-keyword-arguments (package-arguments mono-5.10.0)
+       ((#:make-flags make-flags #~'())
+        #~(append #$make-flags
+                  (list
+                   (string-append "PLATFORM_DISABLED_TESTS="
+                                  ;; segfaults (!), reason unknown
+                                  "safehandle.2.exe"
+                                  ;; unclear why these fail
+                                  "bug-10834.exe"
+                                  "bug-60848.exe"
+                                  ;; these are tests of microsoft
+                                  ;; telemetry.  They fail because
+                                  ;; microsoft telemetry is only
+                                  ;; enabled on OSX.  No idea why
+                                  ;; these tests are run by default.
+                                  "merp-crash-test.exe"
+                                  "merp-json-valid.exe"))))
+       ((#:phases phases #~%standard-phases)
+        #~(modify-phases #$phases
+            (delete 'patch-sub-autogen.sh-shebang)
+            ;; Our 5.10.0 compiler has been rather souped up.
+            (add-after 'unpack 'disable-profile-version-check
+              (lambda _
+                (substitute* "mcs/build/common/basic-profile-check.cs"
+                  (("min_mono_version = .*")
+                   "min_mono_version = new Version (0, 0);\n"))))
+            (add-after 'unpack 'disable-c#-8.0-tests
+              ;; These aren't compilable by mcs
+              (lambda _
+                (substitute* "mono/mini/Makefile.am.in"
+                  (("-langversion:8\\.0")
+                   ""))
+                (substitute* "mono/tests/Makefile.am"
+                  (("	(dim-generic|dim-issue-18917|interface-2|delegate18|generic-unmanaged-constraint|async-generic-enum)\\.cs.*")
+                   ""))))
+            (add-after 'unpack 'disable-verification-error
+              (lambda _
+                ;; For some reason verification fails complaining about a bunch
+                ;; of missing icalls.
+                (substitute* "runtime/Makefile.am"
+                  (("	    fi; done; done;")
+                   "	    fi; done; done; ok=:;"))))
+            ;; This requires binary blobs to be used, it doesn't provide a
+            ;; clear way to regenerate them and no corresponding source is
+            ;; linked, plus from what little I know of it it sounds like it's
+            ;; not something we need at all?
+            (add-after 'unpack 'disable-helix-client
+              (lambda _
+                (substitute* "mcs/tools/Makefile"
+                  (("mono-helix-client")
+                   ""))))
+            (replace 'build-reference-assemblies
+              (lambda* (#:key make-flags #:allow-other-keys)
+                (let ((top (getcwd)))
+                  (with-directory-excursion
+                      "external/binary-reference-assemblies"
+                    (substitute* (find-files "." "^Makefile$")
+                      (("CSC_COMMON_ARGS := " all)
+                       (string-append all "-delaysign+ "))
+                      (("IBM\\.Data\\.DB2_REFS := " all)
+                       (string-append all "System.Xml "))
+                      (("Mono\\.Data\\.Sqlite_REFS := " all)
+                       (string-append all "System.Xml "))
+                      (("System\\.Data\\.DataSetExtensions_REFS := " all)
+                       (string-append all "System.Xml "))
+                      (("System\\.Data\\.OracleClient_REFS := " all)
+                       (string-append all "System.Xml "))
+                      (("System\\.IdentityModel_REFS := " all)
+                       (string-append all "System.Configuration "))
+                      (("System\\.Design_REFS := " all)
+                       (string-append all "Accessibility "))
+                      (("System\\.Web\\.Extensions\\.Design_REFS := " all)
+                       (string-append all "System.Windows.Forms System.Web "))
+                      (("System\\.ServiceModel\\.Routing_REFS := " all)
+                       (string-append all "System.Xml "))
+                      (("System\\.Web\\.Abstractions_REFS := " all)
+                       (string-append all "System "))
+                      (("System\\.Reactive\\.Windows\\.Forms_REFS := " all)
+                       (string-append all "System "))
+                      (("System\\.Windows\\.Forms\\.DataVisualization_REFS := " all)
+                       (string-append all "Accessibility "))
+                      (("Facades/System\\.ServiceModel\\.Primitives_REFS := " all)
+                       (string-append all "System.Xml "))
+                      (("Facades/System\\.Dynamic\\.Runtime_REFS := " all)
+                       (string-append all "System "))
+                      (("Facades/System\\.Xml\\.XDocument_REFS := " all)
+                       (string-append all "System.Xml "))
+                      (("Facades/System\\.Runtime\\.Serialization.Xml_REFS := " all)
+                       (string-append all "System.Xml "))
+                      (("Facades/System\\.Data\\.Common_REFS := " all)
+                       (string-append all "System System.Xml ")))
+                    (substitute* "build/monodroid/Makefile"
+                      (("ECMA_KEY := \\.\\./\\.\\./\\.\\./\\.\\./\\.\\./mono/")
+                       ;; it should only be 4 directories up, and it's in
+                       ;; mcs/, not mono/mcs/
+                       "ECMA_KEY := ../../../../"))
+                    (apply invoke "make" "CSC=mcs" make-flags)))))
+            (replace 'check
+              (lambda* (#:key tests? (make-flags '()) #:allow-other-keys)
+                (when tests?
+                  ;; There are more tests than these, but they depend on
+                  ;; external/xunit-binaries, so we limit ourselves to the
+                  ;; tests that debian runs.
+                  (with-directory-excursion "mono/mini"
+                    (apply invoke "make" "check" make-flags))
+                  (with-directory-excursion "mono/tests"
+                    (apply invoke "make" "check" make-flags)))))))))))
diff --git a/gnu/packages/patches/mono-6.12.0-add-runpath.patch b/gnu/packages/patches/mono-6.12.0-add-runpath.patch
new file mode 100644
index 00000000000..3062bd6a0de
--- /dev/null
+++ b/gnu/packages/patches/mono-6.12.0-add-runpath.patch
@@ -0,0 +1,185 @@
+mono: metadata: add <runpath> element to .config files.
+
+This new element is of the form:
+
+<runpath path="/path1/to/libs:/path2/to/libs:..."/>
+
+(the : will actually be whatever G_SEARCHPATH_SEPARATOR_S is, so likely ; on
+windows and : elsewhere).
+
+* mono/metadata/metadata-internals.h (struct _MonoImage): new 'runpath' field.
+* mono/metadata/mono-config.c (runpath_init, runpath_start, runpath_handler):
+  new functions and parser using them to populate runpath field from <runpath>
+  element.
+  (mono_config_init): register runpath_handler.
+* mono/metadata/assembly.c (mono_assembly_load_full_gac_base_default): new
+  'requesting' parameter, use it to search the requesting assembly's runpath
+  first.
+  (mono_assembly_request_byname_nosearch): use it.
+
+
+diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c
+index f9feaacf2c1..8c71ad0eb95 100644
+--- a/mono/metadata/assembly.c
++++ b/mono/metadata/assembly.c
+@@ -376,7 +376,7 @@ mono_assembly_invoke_search_hook_internal (MonoAssemblyLoadContext *alc, MonoAss
+ static MonoAssembly*
+ mono_assembly_request_byname_nosearch (MonoAssemblyName *aname, const MonoAssemblyByNameRequest *req, MonoImageOpenStatus *status);
+ static MonoAssembly*
+-mono_assembly_load_full_gac_base_default (MonoAssemblyName *aname, const char *basedir, MonoAssemblyLoadContext *alc, MonoAssemblyContextKind asmctx, MonoImageOpenStatus *status);
++mono_assembly_load_full_gac_base_default (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoAssemblyLoadContext *alc, MonoAssemblyContextKind asmctx, MonoImageOpenStatus *status);
+ static MonoAssembly*
+ chain_redirections_loadfrom (MonoAssemblyLoadContext *alc, MonoImage *image, MonoImageOpenStatus *out_status);
+ static MonoAssembly*
+@@ -4655,7 +4655,7 @@ mono_assembly_request_byname_nosearch (MonoAssemblyName *aname,
+ 	}
+ 
+ #ifndef ENABLE_NETCORE
+-	result = mono_assembly_load_full_gac_base_default (aname, req->basedir, req->request.alc, req->request.asmctx, status);
++	result = mono_assembly_load_full_gac_base_default (aname, req->requesting_assembly, req->basedir, req->request.alc, req->request.asmctx, status);
+ #endif
+ 	return result;
+ }
+@@ -4667,6 +4667,7 @@ mono_assembly_request_byname_nosearch (MonoAssemblyName *aname,
+  */
+ MonoAssembly*
+ mono_assembly_load_full_gac_base_default (MonoAssemblyName *aname,
++                                          MonoAssembly *requesting,
+ 					  const char *basedir,
+ 					  MonoAssemblyLoadContext *alc,
+ 					  MonoAssemblyContextKind asmctx,
+@@ -4718,6 +4719,23 @@ mono_assembly_load_full_gac_base_default (MonoAssemblyName *aname,
+ 			filename = g_strconcat (aname->name, ext, (const char*)NULL);
+ 		}
+ 
++                if (requesting
++                    && requesting->image
++                    && requesting->image->runpath) {
++                    char **runpath = requesting->image->runpath;
++                    int j;
++                    for (j = 0; runpath[j]; j++) {
++                        fullpath = g_build_filename (runpath[j], filename, NULL);
++                        result = mono_assembly_request_open (fullpath, &req, status);
++                        g_free (fullpath);
++                        if (result) {
++                            result->in_gac = FALSE;
++                            g_free (filename);
++                            return result;
++                        }
++                    }
++                }
++
+ #ifndef DISABLE_GAC
+ 		const gboolean refonly = asmctx == MONO_ASMCTX_REFONLY;
+ 
+diff --git a/mono/metadata/image.c b/mono/metadata/image.c
+index e0b86dd3d09..12a8094e4e0 100644
+--- a/mono/metadata/image.c
++++ b/mono/metadata/image.c
+@@ -2363,6 +2363,9 @@ mono_image_close_except_pools (MonoImage *image)
+ 
+ 	mono_metadata_clean_for_image (image);
+ 
++        if (image->runpath)
++            g_strfreev (image->runpath);
++
+ 	/*
+ 	 * The caches inside a MonoImage might refer to metadata which is stored in referenced 
+ 	 * assemblies, so we can't release these references in mono_assembly_close () since the
+diff --git a/mono/metadata/metadata-internals.h b/mono/metadata/metadata-internals.h
+index 9388d69b0fd..93f4b880c61 100644
+--- a/mono/metadata/metadata-internals.h
++++ b/mono/metadata/metadata-internals.h
+@@ -423,6 +423,12 @@ struct _MonoImage {
+ 	/**/
+ 	MonoTableInfo        tables [MONO_TABLE_NUM];
+ 
++    /*
++      Search path to be tried first when looking for assemblies referenced by
++      this image, or NULL. Is a NULL-terminated vector.
++     */
++        char               **runpath;
++
+ 	/*
+ 	 * references is initialized only by using the mono_assembly_open
+ 	 * function, and not by using the lowlevel mono_image_open.
+diff --git a/mono/metadata/mono-config.c b/mono/metadata/mono-config.c
+index d973de53c8c..8888c7b4fac 100644
+--- a/mono/metadata/mono-config.c
++++ b/mono/metadata/mono-config.c
+@@ -21,6 +21,7 @@
+ #include "mono/metadata/metadata-internals.h"
+ #include "mono/metadata/object-internals.h"
+ #include "mono/utils/mono-logger-internals.h"
++#include "mono/utils/mono-path.h"
+ 
+ #if defined(TARGET_PS3)
+ #define CONFIG_OS "CellOS"
+@@ -464,6 +465,59 @@ aot_cache_handler = {
+ 	NULL, /* finish */
+ };
+ 
++static void*
++runpath_init (MonoImage *assembly)
++{
++    return assembly;
++}
++
++static void
++runpath_start (gpointer user_data,
++               const gchar         *element_name,
++               const gchar        **attribute_names,
++               const gchar        **attribute_values)
++{
++    MonoImage *assembly = (MonoImage *) user_data;
++    int i;
++
++    if (strcmp (element_name, "runpath") != 0)
++        return;
++
++    for (i = 0; attribute_names[i]; i++)
++        {
++            if(!strcmp (attribute_names [i], "path"))
++                {
++                    char **splitted, **dest;
++
++                    splitted = g_strsplit (attribute_values[i],
++                                           G_SEARCHPATH_SEPARATOR_S,
++                                           1000);
++                    if (assembly->runpath)
++                        g_strfreev (assembly->runpath);
++                    assembly->runpath = dest = splitted;
++                    while (*splitted) {
++                        char *tmp = *splitted;
++                        if (*tmp)
++                            *dest++ = mono_path_canonicalize (tmp);
++                        g_free (tmp);
++                        splitted++;
++                    }
++                    *dest = *splitted;
++                    break;
++                }
++        }
++}
++
++static const MonoParseHandler
++runpath_handler = {
++    "runpath",
++    runpath_init,
++    runpath_start,
++    NULL, /* text */
++    NULL, /* end */
++    NULL, /* finish */
++};
++
+ static int inited = 0;
+ 
+ static void
+@@ -476,6 +530,7 @@ mono_config_init (void)
+ #endif
+ 	g_hash_table_insert (config_handlers, (gpointer) legacyUEP_handler.element_name, (gpointer) &legacyUEP_handler);
+ 	g_hash_table_insert (config_handlers, (gpointer) aot_cache_handler.element_name, (gpointer) &aot_cache_handler);
++        g_hash_table_insert (config_handlers, (gpointer) runpath_handler.element_name, (gpointer) &runpath_handler);
+ }
+ 
+ /**
diff --git a/gnu/packages/patches/mono-6.12.0-fix-AssemblyResolver.patch b/gnu/packages/patches/mono-6.12.0-fix-AssemblyResolver.patch
new file mode 100644
index 00000000000..05db7b9cdd3
--- /dev/null
+++ b/gnu/packages/patches/mono-6.12.0-fix-AssemblyResolver.patch
@@ -0,0 +1,236 @@
+diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/AssemblyResolver.cs b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/AssemblyResolver.cs
+index 5e0ec480956..9daf9d6920b 100644
+--- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/AssemblyResolver.cs
++++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/AssemblyResolver.cs
+@@ -67,54 +67,56 @@ public void ResetSearchLogger ()
+ 				search_log.Clear ();
+ 		}
+ 
+-		string GetGacPath ()
++		string[] GetGacPaths ()
+ 		{
+ 			// NOTE: code from mcs/tools/gacutil/driver.cs
+-			PropertyInfo gac = typeof (System.Environment).GetProperty ("GacPath", BindingFlags.Static | BindingFlags.NonPublic);
++			PropertyInfo gacs = typeof (System.Environment).GetProperty ("GacPaths", BindingFlags.Static | BindingFlags.NonPublic);
+ 
+-			if (gac == null)
++			if (gacs == null)
+ 				return null;
+ 
+-			MethodInfo get_gac = gac.GetGetMethod (true);
+-			return (string) get_gac.Invoke (null, null);
++			MethodInfo get_gacs = gacs.GetGetMethod (true);
++			return (string[]) get_gacs.Invoke (null, null);
+ 		}
+ 
+ 		void GatherGacAssemblies ()
+ 		{
+-			string gac_path = GetGacPath ();
+-			if (gac_path == null)
+-				throw new InvalidOperationException ("XBuild must be run on Mono runtime");
+-			if (!Directory.Exists (gac_path))
+-				return; // in case mono isn't "installed".
+-
+-			Version version;
+-			DirectoryInfo version_info, assembly_info;
+-
+-			foreach (string assembly_name in Directory.GetDirectories (gac_path)) {
+-				assembly_info = new DirectoryInfo (assembly_name);
+-				foreach (string version_token in Directory.GetDirectories (assembly_name)) {
+-					foreach (string file in Directory.GetFiles (version_token, "*.dll")) {
+-						version_info = new DirectoryInfo (version_token);
+-						version = new Version (version_info.Name.Split (
+-							new char [] {'_'}, StringSplitOptions.RemoveEmptyEntries) [0]);
+-
+-						Dictionary<Version, string> assembliesByVersion = new Dictionary <Version, string> ();
+-						if (!gac.TryGetValue (assembly_info.Name, out assembliesByVersion)) {
+-							assembliesByVersion = new Dictionary <Version, string> ();
+-							gac.Add (assembly_info.Name, assembliesByVersion);
+-						}
+-
+-						string found_file;
+-						if (assembliesByVersion.TryGetValue (version, out found_file) &&
+-							File.GetLastWriteTime (file) <= File.GetLastWriteTime (found_file))
+-								// Duplicate found, take the newer file
+-								continue;
+-
+-						assembliesByVersion [version] = file;
+-					}
+-				}
+-			}
+-		}
++            string[] gac_paths = GetGacPaths ();
++            if (gac_paths == null)
++                throw new InvalidOperationException ("XBuild must be run on Mono runtime");
++            if (gac_paths.Length == 0 || !Directory.Exists (gac_paths[0]))
++                return; // in case mono isn't "installed".
++
++            Version version;
++            DirectoryInfo version_info, assembly_info;
++
++            foreach (string gac_path in gac_paths) {
++                foreach (string assembly_name in Directory.GetDirectories (gac_path)) {
++                    assembly_info = new DirectoryInfo (assembly_name);
++                    foreach (string version_token in Directory.GetDirectories (assembly_name)) {
++                        foreach (string file in Directory.GetFiles (version_token, "*.dll")) {
++                            version_info = new DirectoryInfo (version_token);
++                            version = new Version (version_info.Name.Split (
++                                                       new char [] {'_'}, StringSplitOptions.RemoveEmptyEntries) [0]);
++
++                            Dictionary<Version, string> assembliesByVersion = new Dictionary <Version, string> ();
++                            if (!gac.TryGetValue (assembly_info.Name, out assembliesByVersion)) {
++                                assembliesByVersion = new Dictionary <Version, string> ();
++                                gac.Add (assembly_info.Name, assembliesByVersion);
++                            }
++
++                            string found_file;
++                            if (assembliesByVersion.TryGetValue (version, out found_file) &&
++                                File.GetLastWriteTime (file) <= File.GetLastWriteTime (found_file))
++                                // Duplicate found, take the newer file
++                                continue;
++
++                            assembliesByVersion [version] = file;
++                        }
++                    }
++                }
++            }
++        }
+ 
+ 		public ResolvedReference FindInTargetFramework (ITaskItem reference, string framework_dir, bool specific_version)
+ 		{
+diff --git a/mcs/class/corlib/System/Environment.cs b/mcs/class/corlib/System/Environment.cs
+index fd936ab21a4..b5a5c77c1a3 100644
+--- a/mcs/class/corlib/System/Environment.cs
++++ b/mcs/class/corlib/System/Environment.cs
+@@ -984,9 +984,18 @@ private static string GacPath {
+ 				return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
+ 			}
+ 		}
++
++        private static string[] GacPaths {
++            get {
++                return internalGetGacPaths ();
++            }
++        }
+ #pragma warning restore 169
+ 		[MethodImplAttribute (MethodImplOptions.InternalCall)]
+ 		internal extern static string internalGetGacPath ();
++
++        [MethodImplAttribute (MethodImplOptions.InternalCall)]
++		internal extern static string [] internalGetGacPaths ();
+ #endif
+ 		[MethodImplAttribute (MethodImplOptions.InternalCall)]
+ 		internal extern static string [] GetLogicalDrivesInternal ();
+diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c
+index 8c71ad0eb95..759d5aefbcf 100644
+--- a/mono/metadata/assembly.c
++++ b/mono/metadata/assembly.c
+@@ -854,6 +854,11 @@ mono_assembly_getrootdir (void)
+ 	return default_path [0];
+ }
+ 
++char **mono_assembly_get_extra_gac_paths()
++{
++    return extra_gac_paths;
++}
++
+ /**
+  * mono_native_getrootdir:
+  * 
+diff --git a/mono/metadata/assembly.h b/mono/metadata/assembly.h
+index e9c02ee26f5..e5f060e8238 100644
+--- a/mono/metadata/assembly.h
++++ b/mono/metadata/assembly.h
+@@ -50,6 +50,7 @@ MONO_API MONO_RT_EXTERNAL_ONLY MonoImage*    mono_assembly_load_module (MonoAsse
+ MONO_API void          mono_assembly_close      (MonoAssembly *assembly);
+ MONO_API void          mono_assembly_setrootdir (const char *root_dir);
+ MONO_API MONO_CONST_RETURN char *mono_assembly_getrootdir (void);
++MONO_API char **mono_assembly_get_extra_gac_paths (void);
+ MONO_API char         *mono_native_getrootdir (void);
+ MONO_API void	       mono_assembly_foreach    (MonoFunc func, void* user_data);
+ MONO_API void          mono_assembly_set_main   (MonoAssembly *assembly);
+diff --git a/mono/metadata/icall-decl.h b/mono/metadata/icall-decl.h
+index a77fcf38598..3f0f1758ec2 100644
+--- a/mono/metadata/icall-decl.h
++++ b/mono/metadata/icall-decl.h
+@@ -152,6 +152,7 @@ ICALL_EXPORT gint32 ves_icall_System_Environment_get_TickCount (void);
+ #if ENABLE_NETCORE
+ ICALL_EXPORT gint64 ves_icall_System_Environment_get_TickCount64 (void);
+ #endif
++ICALL_EXPORT MonoArray *ves_icall_System_Environment_GetGacPaths (void);
+ ICALL_EXPORT gint64 ves_icall_System_DateTime_GetSystemTimeAsFileTime (void);
+ ICALL_EXPORT gint64 ves_icall_System_Diagnostics_Process_GetProcessData (int, gint32, MonoProcessError*);
+ ICALL_EXPORT gint64 ves_icall_System_Diagnostics_Stopwatch_GetTimestamp (void);
+diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h
+index 0a44729674b..59c803ba488 100644
+--- a/mono/metadata/icall-def.h
++++ b/mono/metadata/icall-def.h
+@@ -327,6 +327,7 @@ HANDLES(ENV_16b, "get_bundled_machine_config", ves_icall_System_Environment_get_
+ HANDLES(ENV_16m, "internalBroadcastSettingChange", ves_icall_System_Environment_BroadcastSettingChange, void, 0, ())
+ HANDLES(ENV_17, "internalGetEnvironmentVariable_native", ves_icall_System_Environment_GetEnvironmentVariable_native, MonoString, 1, (const_char_ptr))
+ HANDLES(ENV_18, "internalGetGacPath", ves_icall_System_Environment_GetGacPath, MonoString, 0, ())
++NOHANDLES(ICALL(ENV_18_1, "internalGetGacPaths", ves_icall_System_Environment_GetGacPaths))
+ HANDLES(ENV_19, "internalGetHome", ves_icall_System_Environment_InternalGetHome, MonoString, 0, ())
+ NOHANDLES(ICALL(ENV_20, "set_ExitCode", mono_environment_exitcode_set))
+ ICALL_TYPE(GC, "System.GC", GC_10)
+diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c
+index 6d16b9c3540..1e592c30e27 100644
+--- a/mono/metadata/icall.c
++++ b/mono/metadata/icall.c
+@@ -7781,6 +7781,56 @@ ves_icall_System_Environment_GetGacPath (MonoError *error)
+ }
+ #endif
+ 
++ICALL_EXPORT MonoArray *
++ves_icall_System_Environment_GetGacPaths ()
++{
++    char **extra_gac_paths = mono_assembly_get_extra_gac_paths();
++    const char *rootdir = mono_assembly_getrootdir ();
++    char **e;
++    int n;
++    MonoDomain *domain;
++    MonoArray *out;
++    MonoString *str;
++    gchar *tmp;
++    MonoError error;
++    n = 0;
++    if (rootdir) n++;
++    if (extra_gac_paths) {
++        for (e = extra_gac_paths; *e != 0; e++);
++        n += (e - extra_gac_paths);
++    }
++
++    domain = mono_domain_get ();
++    out = mono_array_new_checked (domain, mono_defaults.string_class, n, &error);
++
++    if (mono_error_set_pending_exception (&error))
++        return NULL;
++
++    n = 0;
++    if (rootdir) {
++        tmp = g_build_path (G_DIR_SEPARATOR_S, rootdir, "mono", "gac", NULL);
++        str = mono_string_new_checked (domain, tmp, &error);
++        g_free (tmp);
++        if (mono_error_set_pending_exception (&error))
++            return NULL;
++        mono_array_setref_internal (out, n, str);
++        n++;
++    }
++    if (extra_gac_paths) {
++        for (e = extra_gac_paths; *e != 0; e++) {
++            tmp = g_build_path (G_DIR_SEPARATOR_S, *e, "lib", "mono", "gac", NULL);
++            str = mono_string_new_checked (domain, tmp, &error);
++            g_free (tmp);
++            if (mono_error_set_pending_exception (&error))
++                return NULL;
++            mono_array_setref_internal (out, n, str);
++            n++;
++        }
++    }
++
++    return out;
++}
++
+ #ifndef HOST_WIN32
+ static inline MonoStringHandle
+ mono_icall_get_windows_folder_path (int folder, MonoError *error)
diff --git a/gnu/packages/patches/mono-6.12.0-fix-ConditionParser.patch b/gnu/packages/patches/mono-6.12.0-fix-ConditionParser.patch
new file mode 100644
index 00000000000..4ecde07d426
--- /dev/null
+++ b/gnu/packages/patches/mono-6.12.0-fix-ConditionParser.patch
@@ -0,0 +1,46 @@
+diff --git a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ConditionParser.cs b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ConditionParser.cs
+index b5e2e809ae4..757492d15e4 100644
+--- a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ConditionParser.cs
++++ b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ConditionParser.cs
+@@ -205,19 +205,30 @@ ConditionExpression ParseFunctionExpression (string function_name)
+ 		{
+ 			List <ConditionFactorExpression> list = new List <ConditionFactorExpression> ();
+ 			ConditionFactorExpression e;
+-			
++
++            /* starts looking at the open paren, move past it */
++            tokenizer.GetNextToken ();
++            if (tokenizer.Token.Type == TokenType.RightParen) {
++                /* leave us looking past the end of the argument list */
++                tokenizer.GetNextToken ();
++                return list;
++            }
+ 			while (true) {
+-				tokenizer.GetNextToken ();
+-				if (tokenizer.Token.Type == TokenType.RightParen) {
+-					tokenizer.GetNextToken ();
+-					break;
+-				}
+-				if (tokenizer.Token.Type == TokenType.Comma)
++                e = (ConditionFactorExpression) ParseFactorExpression ();
++                list.Add (e);
++                /* ParseFactorExpression leaves us looking at what follows the
++                 * expression */
++                if (tokenizer.Token.Type == TokenType.RightParen) {
++                    /* leave us looking past the end of the argument list */
++                    tokenizer.GetNextToken ();
++                    break;
++                }
++                if (tokenizer.Token.Type == TokenType.Comma) {
++                    tokenizer.GetNextToken ();
+ 					continue;
+-					
+-				tokenizer.Putback (tokenizer.Token);
+-				e = (ConditionFactorExpression) ParseFactorExpression ();
+-				list.Add (e);
++                }
++
++                throw new ExpressionParseException (String.Format ("Unexpected token {0} in argument list while parsing condition \"{1}\"", tokenizer.Token, conditionStr));
+ 			}
+ 			
+ 			return list;
-- 
Efraim Flashner   <[email-masked]>   אפרים פלשנר
GPG key = A28B F40C 3E55 1372 662D  14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted