Safely Inspect and Manage Mono's Global Assembly Cache with gacutil
By the end of this guide you will be able to list Mono's Global Assembly Cache (GAC), identify an assembly by its full display name, and understand the difference between installing, removing one exact assembly, and removing every matching version. The examples target the Ubuntu package mono-gac, version 6.8.0.105+dfsg-3.6ubuntu2, installed on the machine used for this guide.
The route
Jump straight to the step you need, or tick off Done means at the end.
- Checkpoint: confirm the tool and inspect before changing anything
- Step 1: narrow the listing to one assembly
- Step 2: verify the assembly before installation
- Step 3: install with the narrowest useful options
- Checkpoint: separate runtime lookup from compiler lookup
- Step 4: choose a removal mode deliberately
- Step 5: verify the final state
Allow about 10 minutes if you are only inspecting the cache. Installation and removal need more care because they change shared runtime state. You need Mono and an assembly file containing an assembly manifest. Use an unprivileged shell for listing. Use sudo only when the chosen GAC location is not writable by your user.
Checkpoint: confirm the tool and inspect before changing anything
- Check that the package and executable are present.
dpkg-query -W -f='${Package} ${Version}
' mono-gac
gacutil -l
The package query reports the installed version. The list command prints a heading followed by assembly display names, for example:
The following assemblies are installed into the GAC:
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
The local manual describes the GAC as relative to Mono's installation prefix, normally mono_prefix/lib/mono. On this installation, the unfiltered listing is readable without elevated privileges. Do not infer that every machine uses the same prefix, and do not edit GAC directories by hand: the cache has versioned layout and metadata that gacutil is responsible for maintaining.
Step 1: narrow the listing to one assembly
Pass an assembly name to -l when the full listing is distracting. Matching is useful for checking whether an assembly is already present, but it does not install or remove anything.
gacutil -l System
On this machine the result ends with:
The following assemblies are installed into the GAC:
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Number of items = 1
If the result says there are no matching items, check the spelling and the selected prefix before changing anything. For a non-standard installation, the manual says to use MONO_GAC_PREFIX to access assemblies under another Mono prefix. The -root option selects the lib directory for an installation prefix that differs from the system GAC.
Step 2: verify the assembly before installation
Installation takes a path to a file containing the assembly manifest. It is intended for versioned assemblies in the GAC, not arbitrary native libraries or an assembly copied from an unknown source. Before installing, check the file you intend to use and record its checksum in your deployment notes.
ASSEMBLY=/path/to/MyLibrary.dll
test -r "$ASSEMBLY" && sha256sum "$ASSEMBLY"
file "$ASSEMBLY"
Replace the placeholder with a real path. The test command produces no output on success; sha256sum gives you a value to compare with the build or release record. Stop if the file is missing, unreadable, or not the artefact you expected. A GAC entry makes a library available to applications at runtime, so provenance matters.
Step 3: install with the narrowest useful options
Use -i for installation. Add -check_refs when you want gacutil to reject references to non-strong-named assemblies. The manual recommends that GAC assemblies should not have those references, although the check is optional.
gacutil -i "$ASSEMBLY" -check_refs
Installation may require elevation if the GAC is under a system-owned prefix:
sudo gacutil -i /path/to/MyLibrary.dll -check_refs
Do not add -package just because the installation succeeds. That option also creates a directory under the prefix's lib/mono tree and a symlink to the GAC assembly, so it changes compiler-facing lookup paths as well as the cache. Use it only when your build or packaging layout explicitly needs that name:
gacutil -i /path/to/MyLibrary.dll -package MyLibrary
After installation, verify by listing the assembly name rather than trusting a successful exit alone:
gacutil -l MyLibrary
Checkpoint: separate runtime lookup from compiler lookup
A common trap is assuming that a GAC entry automatically makes an assembly available to the compiler. The local manual explicitly separates those jobs: the GAC serves runtime availability, while compiler access conventionally uses another directory. The -package option can create the named directory and symlink used for that purpose. If a compiler still cannot resolve a reference, inspect the compiler reference path and package layout instead of repeatedly reinstalling the same assembly.
Step 4: choose a removal mode deliberately
Removal is destructive. First list the candidate and copy its display name somewhere safe. The -u command accepts an assembly display name, either partial or fully qualified:
gacutil -l MyLibrary
gacutil -u MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0123456789abcdef
The manual says spaces in the display name do not need quoting. A fully qualified name is the safer choice. A partial name is greedy: gacutil -u MyLibrary removes all matching versions. Treat that form as a deliberate bulk deletion and check the listing first. If -package was used during installation, include the package name when removing it according to the same layout, for example:
gacutil -u MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0123456789abcdef -package MyLibrary
To remove the assembly identified by a file path, use -us instead. It reads the full name from the file and removes the matching GAC entry:
gacutil -us /path/to/MyLibrary.dll
For a prepared list of display names, -ul removes one or more entries, one name per line:
gacutil -ul /path/to/assembly-list.txt
Because these commands change shared state, keep the list file under version control or make a backup copy before running it. If you removed the wrong entry, recovery requires reinstalling the original assembly file with -i; there is no undo command that reconstructs a deleted binary.
Step 5: verify the final state
Run the same focused listing after an install or removal:
gacutil -l MyLibrary
For an installation, the expected result contains the intended display name. For a removal, it should report no matching item. If several versions remain after an exact removal, that is expected when the command named only one version. If the result is unexpectedly empty, check MONO_GAC_PREFIX, the -root value, and whether you ran the command with the same privilege and environment as the original operation.
Done means
gacutil -lshows the cache you intended to inspect.- The assembly file and checksum were checked before installation.
-check_refswas used when strong-name reference checking mattered.- A full display name was used for targeted removal, not a partial name by accident.
- The focused listing was run again after every state-changing command.
- You know whether the problem is runtime GAC lookup or compiler search-path configuration.