5 // Todd Berman <tberman@sevenl.net>
6 // Jackson Harper <jackson@ximian.com>
8 // Copyright 2003, 2004 Todd Berman
9 // Copyright 2004 Novell, Inc (http://www.novell.com)
15 using System
.Diagnostics
;
17 using System
.Collections
;
18 using System
.Globalization
;
19 using System
.Runtime
.InteropServices
;
20 using System
.Security
.Cryptography
;
23 using Mono
.Security
.Cryptography
;
25 using IKVM
.Reflection
;
27 namespace Mono
.Tools
{
31 private enum Command
{
42 private enum VerificationResult
50 private static bool silent
;
51 static bool in_bootstrap
;
52 private static Universe _universe
;
54 public static int Main (string [] args
)
59 Command command
= Command
.Unknown
;
60 string command_str
= null;
63 string name
, package
, gacdir
, root
;
64 name
= package
= root
= gacdir
= null;
65 bool check_refs
= false;
67 // Check for silent arg first so we can suppress
68 // warnings during command line parsing
69 if (Array
.IndexOf (args
, "/silent") > -1 || Array
.IndexOf (args
, "-silent") > -1)
72 for (int i
=0; i
<args
.Length
; i
++) {
73 if (IsSwitch (args
[i
])) {
75 // for cmd line compatibility with other gacutils
76 // we always force it though
77 if (args
[i
] == "-f" || args
[i
] == "/f")
80 // Ignore this option for now, although we might implement it someday
81 if (args
[i
] == "/r") {
82 WriteLine ("WARNING: gacutil does not support traced references." +
83 "This option is being ignored.");
88 // This is already handled we just dont want to choke on it
89 if (args
[i
] == "-silent" || args
[i
] == "/silent")
92 if (args
[i
] == "-check_refs" || args
[i
] == "/check_refs") {
97 if (args
[i
] == "-bootstrap" || args
[i
] == "/bootstrap") {
102 if (command
== Command
.Unknown
) {
103 command
= GetCommand (args
[i
]);
104 if (command
!= Command
.Unknown
) {
105 command_str
= args
[i
];
110 if (i
+ 1 >= args
.Length
) {
111 Console
.WriteLine ("Option " + args
[i
] + " takes 1 argument");
118 package
= args
[++i
];
130 // we currently don't display a
131 // logo banner, so ignore it
132 // for command-line compatibility
143 if (command
== Command
.Unknown
&& IsSwitch (args
[0])) {
144 Console
.WriteLine ("Unknown command: " + args
[0]);
146 } else if (command
== Command
.Unknown
) {
148 } else if (command
== Command
.Help
) {
153 if (gacdir
== null) {
154 gacdir
= GetGacDir ();
155 libdir
= GetLibDir ();
157 gacdir
= EnsureLib (gacdir
);
158 libdir
= Path
.Combine (gacdir
, "mono");
159 gacdir
= Path
.Combine (libdir
, "gac");
162 string link_gacdir
= gacdir
;
163 string link_libdir
= libdir
;
165 libdir
= Path
.Combine (root
, "mono");
166 gacdir
= Path
.Combine (libdir
, "gac");
172 case Command
.Install
:
174 WriteLine ("Option " + command_str
+ " takes 1 argument");
177 if (!Install (check_refs
, name
, package
, gacdir
, link_gacdir
, libdir
, link_libdir
))
180 case Command
.InstallFromList
:
182 WriteLine ("Option " + command_str
+ " takes 1 argument");
185 if (!InstallFromList (check_refs
, name
, package
, gacdir
, link_gacdir
, libdir
, link_libdir
))
188 case Command
.Uninstall
:
190 WriteLine ("Option " + command_str
+ " takes 1 argument");
193 int uninstallCount
= 0;
194 int uninstallFailures
= 0;
195 Uninstall (name
, package
, gacdir
, libdir
, false,
196 ref uninstallCount
, ref uninstallFailures
);
197 WriteLine ("Assemblies uninstalled = {0}", uninstallCount
);
198 WriteLine ("Failures = {0}", uninstallFailures
);
199 if (uninstallFailures
> 0)
202 case Command
.UninstallFromList
:
204 WriteLine ("Option " + command_str
+ " takes 1 argument");
207 if (!UninstallFromList (name
, package
, gacdir
, libdir
))
210 case Command
.UninstallSpecific
:
212 WriteLine ("Option " + command_str
+ " takes 1 argument");
215 if (!UninstallSpecific (name
, package
, gacdir
, libdir
))
226 static void Copy (string source
, string target
, bool v
)
229 File
.Delete (target
);
231 File
.Copy (source
, target
, v
);
234 private static bool Install (bool check_refs
, string name
, string package
,
235 string gacdir
, string link_gacdir
, string libdir
, string link_libdir
)
237 string failure_msg
= "Failure adding assembly {0} to the cache: ";
240 if (!File
.Exists (name
)) {
241 WriteLine (string.Format (failure_msg
, name
) + "The system cannot find the file specified.");
245 Assembly assembly
= null;
246 AssemblyName an
= null;
249 assembly
= ReflectionOnlyLoadFrom (name
);
251 WriteLine (string.Format (failure_msg
, name
) + "The file specified is not a valid assembly.");
255 an
= assembly
.GetName ();
257 switch (VerifyStrongName (an
, name
)) {
258 case VerificationResult
.StrongNamed
:
259 case VerificationResult
.Skipped
:
261 case VerificationResult
.WeakNamed
:
262 WriteLine (string.Format (failure_msg
, name
) + "Attempt to install an assembly without a strong name"
263 + (in_bootstrap
? "(continuing anyway)" : string.Empty
));
267 case VerificationResult
.DelaySigned
:
268 WriteLine (string.Format (failure_msg
, name
) + "Strong name cannot be verified for delay-signed assembly"
269 + (in_bootstrap
? "(continuing anyway)" : string.Empty
));
275 resources
= new ArrayList ();
276 foreach (string res_name
in assembly
.GetManifestResourceNames ()) {
277 ManifestResourceInfo res_info
= assembly
.GetManifestResourceInfo (res_name
);
279 if ((res_info
.ResourceLocation
& ResourceLocation
.Embedded
) == 0) {
280 if (!File
.Exists (res_info
.FileName
)) {
281 WriteLine (string.Format (failure_msg
, name
) + "The system cannot find resource " + res_info
.FileName
);
285 resources
.Add (res_info
);
289 if (check_refs
&& !CheckReferencedAssemblies (an
)) {
290 WriteLine (string.Format (failure_msg
, name
) +
291 "Attempt to install an assembly that " +
292 "references non strong named assemblies " +
293 "with -check_refs enabled.");
297 string [] siblings
= { ".config", ".mdb" }
;
298 string version_token
= an
.Version
+ "_" +
299 an
.CultureInfo
.Name
.ToLower (CultureInfo
.InvariantCulture
) + "_" +
300 GetStringToken (an
.GetPublicKeyToken ());
301 string full_path
= Path
.Combine (Path
.Combine (gacdir
, an
.Name
), version_token
);
302 string asmb_file
= Path
.GetFileName (name
);
303 string asmb_path
= Path
.Combine (full_path
, asmb_file
);
304 string asmb_name
= assembly
.GetName ().Name
;
306 if (Path
.GetFileNameWithoutExtension (asmb_file
) != asmb_name
) {
307 WriteLine (string.Format (failure_msg
, name
) +
308 string.Format ("the filename \"{0}\" doesn't match the assembly name \"{1}\"",
309 asmb_file
, asmb_name
));
314 if (Directory
.Exists (full_path
)) {
315 // Wipe out the directory. This way we ensure old assemblies
316 // config files, and AOTd files are removed.
317 Directory
.Delete (full_path
, true);
319 Directory
.CreateDirectory (full_path
);
321 WriteLine (string.Format (failure_msg
, name
) +
322 "gac directories could not be created, " +
323 "possibly permission issues.");
327 Copy (name
, asmb_path
, true);
329 var name_pdb
= Path
.ChangeExtension (name
, ".pdb");
330 if (File
.Exists (name_pdb
)) {
331 Copy (name_pdb
, Path
.ChangeExtension (asmb_path
, ".pdb"), true);
334 foreach (string ext
in siblings
) {
335 string sibling
= String
.Concat (name
, ext
);
336 if (File
.Exists (sibling
))
337 Copy (sibling
, String
.Concat (asmb_path
, ext
), true);
340 foreach (ManifestResourceInfo resource_info
in resources
) {
342 Copy (resource_info
.FileName
, Path
.Combine (full_path
, Path
.GetFileName (resource_info
.FileName
)), true);
344 WriteLine ("ERROR: Could not install resource file " + resource_info
.FileName
);
345 Environment
.Exit (1);
349 if (package
!= null) {
350 string ref_dir
= Path
.Combine (libdir
, package
);
351 string ref_path
= Path
.Combine (ref_dir
, asmb_file
);
353 if (File
.Exists (ref_path
))
354 File
.Delete (ref_path
);
356 Directory
.CreateDirectory (ref_dir
);
358 WriteLine ("ERROR: Could not create package dir file.");
359 Environment
.Exit (1);
361 if (Path
.DirectorySeparatorChar
== '/') {
362 string pkg_path_abs
= Path
.Combine (gacdir
, Path
.Combine (an
.Name
, Path
.Combine (version_token
, asmb_file
)));
363 string pkg_path
= AbsoluteToRelativePath (ref_dir
, pkg_path_abs
);
364 symlink (pkg_path
, ref_path
);
366 var pdb_pkg_path
= Path
.ChangeExtension (pkg_path
, ".pdb");
367 var pdb_ref_path
= Path
.ChangeExtension (ref_path
, ".pdb");
369 if (File
.Exists (pdb_pkg_path
)) {
370 symlink (pdb_pkg_path
, pdb_ref_path
);
373 File
.Delete (pdb_ref_path
);
375 // Ignore error, just delete files that should not be there.
379 foreach (string ext
in siblings
) {
380 string sibling
= String
.Concat (pkg_path
, ext
);
381 string sref
= String
.Concat (ref_path
, ext
);
383 if (File
.Exists (sibling
))
384 symlink (sibling
, sref
);
389 // Ignore error, just delete files that should not be there.
393 WriteLine ("Package exported to: {0} -> {1}", ref_path
, pkg_path
);
395 // string link_path = Path.Combine (Path.Combine (link_gacdir, an.Name), version_token);
397 // We can't use 'link_path' here, since it need not be a valid path at the time 'gacutil'
398 // is run, esp. when invoked in a DESTDIR install.
399 Copy (name
, ref_path
, true);
400 WriteLine ("Package exported to: " + ref_path
);
404 WriteLine ("Installed {0} into the gac ({1})", name
,
410 //from MonoDevelop.Core.FileService
411 unsafe static string AbsoluteToRelativePath (string baseDirectoryPath
, string absPath
)
413 if (!Path
.IsPathRooted (absPath
) || string.IsNullOrEmpty (baseDirectoryPath
))
416 absPath
= Path
.GetFullPath (absPath
);
417 baseDirectoryPath
= Path
.GetFullPath (baseDirectoryPath
).TrimEnd (Path
.DirectorySeparatorChar
);
419 fixed (char* bPtr
= baseDirectoryPath
, aPtr
= absPath
) {
420 var bEnd
= bPtr
+ baseDirectoryPath
.Length
;
421 var aEnd
= aPtr
+ absPath
.Length
;
422 char* lastStartA
= aEnd
;
423 char* lastStartB
= bEnd
;
426 // search common base path
432 if (IsSeparator (*a
)) {
440 if (a
>= aEnd
|| IsSeparator (*a
)) {
451 if (lastStartA
>= aEnd
)
454 // handle case a: some/path b: some/path/deeper...
456 if (IsSeparator (*b
)) {
462 // look how many levels to go up into the base path
464 while (lastStartB
< bEnd
) {
465 if (IsSeparator (*lastStartB
))
469 var size
= goUpCount
* 2 + goUpCount
+ aEnd
- lastStartA
;
470 var result
= new char [size
];
471 fixed (char* rPtr
= result
) {
474 for (int i
= 0; i
< goUpCount
; i
++) {
477 *(r
++) = Path
.DirectorySeparatorChar
;
479 // copy the remaining absulute path
480 while (lastStartA
< aEnd
)
481 *(r
++) = *(lastStartA
++);
483 return new string (result
);
487 static bool IsSeparator (char ch
)
489 return ch
== Path
.DirectorySeparatorChar
|| ch
== Path
.AltDirectorySeparatorChar
|| ch
== Path
.VolumeSeparatorChar
;
492 private static void Uninstall (string name
, string package
, string gacdir
, string libdir
, bool listMode
, ref int uninstalled
, ref int failures
)
494 string [] assembly_pieces
= name
.Split (new char[] { ',' }
);
495 Hashtable asm_info
= new Hashtable ();
497 foreach (string item
in assembly_pieces
) {
498 if (item
== String
.Empty
) continue;
499 string[] pieces
= item
.Trim ().Split (new char[] { '=' }
, 2);
500 if(pieces
.Length
== 1)
501 asm_info
["assembly"] = pieces
[0];
503 asm_info
[pieces
[0].Trim ().ToLower (CultureInfo
.InvariantCulture
)] = pieces
[1];
506 string assembly_name
= (string) asm_info
["assembly"];
507 string asmdir
= Path
.Combine (gacdir
, assembly_name
);
508 if (!Directory
.Exists (asmdir
)) {
511 WriteLine ("Assembly: " + name
);
513 WriteLine ("No assemblies found that match: " + name
);
517 string searchString
= GetSearchString (asm_info
);
518 string [] directories
= Directory
.GetDirectories (asmdir
, searchString
);
520 if (directories
.Length
== 0) {
523 WriteLine ("Assembly: " + name
);
524 WriteLine ("No assemblies found that match: " + name
);
529 for (int i
= 0; i
< directories
.Length
; i
++) {
530 if (listMode
&& i
> 0)
533 string dir
= directories
[i
];
534 string extension
= null;
536 if (File
.Exists (Path
.Combine (dir
, assembly_name
+ ".dll"))) {
538 } else if (File
.Exists (Path
.Combine (dir
, assembly_name
+ ".exe"))) {
542 WriteLine("Cannot find the assembly: " + assembly_name
);
546 string assembly_filename
= assembly_name
+ extension
;
548 AssemblyName an
= AssemblyName
.GetAssemblyName (
549 Path
.Combine (dir
, assembly_filename
));
550 WriteLine ("Assembly: " + an
.FullName
);
552 Directory
.Delete (dir
, true);
553 if (package
!= null) {
554 string link_dir
= Path
.Combine (libdir
, package
);
555 string link
= Path
.Combine (link_dir
, assembly_filename
);
560 // The file might not exist, happens with
561 // the debugger on make uninstall
564 if (Directory
.GetFiles (link_dir
).Length
== 0) {
565 WriteLine ("Cleaning package directory, it is empty.");
567 Directory
.Delete (link_dir
);
569 // Workaround: GetFiles does not list Symlinks
575 WriteLine ("Uninstalled: " + an
.FullName
);
578 if (Directory
.GetDirectories (asmdir
).Length
== 0) {
579 WriteLine ("Cleaning assembly dir, it is empty");
581 Directory
.Delete (asmdir
);
583 // Workaround: GetFiles does not list Symlinks
588 private static bool UninstallSpecific (string name
, string package
,
589 string gacdir
, string libdir
)
591 string failure_msg
= "Failure to remove assembly from the cache: ";
593 if (!File
.Exists (name
)) {
594 WriteLine (failure_msg
+ "The system cannot find the file specified.");
598 AssemblyName an
= null;
601 an
= AssemblyName
.GetAssemblyName (name
);
603 WriteLine (failure_msg
+ "The file specified is not a valid assembly.");
607 int uninstallCount
= 0;
608 int uninstallFailures
= 0;
609 Uninstall (an
.FullName
.Replace (" ", String
.Empty
),
610 package
, gacdir
, libdir
, true, ref uninstallCount
,
611 ref uninstallFailures
);
612 WriteLine ("Assemblies uninstalled = {0}", uninstallCount
);
613 WriteLine ("Failures = {0}", uninstallFailures
);
614 return (uninstallFailures
== 0);
617 private static void List (string name
, string gacdir
)
619 WriteLine ("The following assemblies are installed into the GAC:");
622 FilteredList (name
, gacdir
);
627 DirectoryInfo gacinfo
= new DirectoryInfo (gacdir
);
628 foreach (DirectoryInfo parent
in gacinfo
.GetDirectories ()) {
629 foreach (DirectoryInfo dir
in parent
.GetDirectories ()) {
630 string asmb
= Path
.Combine (Path
.Combine (parent
.FullName
, dir
.Name
), parent
.Name
) + ".dll";
631 if (File
.Exists (asmb
)) {
632 WriteLine (AsmbNameFromVersionString (parent
.Name
, dir
.Name
));
637 WriteLine ("Number of items = " + count
);
640 private static void FilteredList (string name
, string gacdir
)
642 string [] assembly_pieces
= name
.Split (new char[] { ',' }
);
643 Hashtable asm_info
= new Hashtable ();
645 foreach (string item
in assembly_pieces
) {
646 string[] pieces
= item
.Trim ().Split (new char[] { '=' }
, 2);
647 if(pieces
.Length
== 1)
648 asm_info
["assembly"] = pieces
[0];
650 asm_info
[pieces
[0].Trim ().ToLower (CultureInfo
.InvariantCulture
)] = pieces
[1];
653 string asmdir
= Path
.Combine (gacdir
, (string) asm_info
["assembly"]);
654 if (!Directory
.Exists (asmdir
)) {
655 WriteLine ("Number of items = 0");
658 string search
= GetSearchString (asm_info
);
659 string [] dir_list
= Directory
.GetDirectories (asmdir
, search
);
662 foreach (string dir
in dir_list
) {
663 string asmb
= Path
.Combine (dir
, (string) asm_info
["assembly"]) + ".dll";
664 if (File
.Exists (asmb
)) {
665 WriteLine (AsmbNameFromVersionString ((string) asm_info
["assembly"],
666 new DirectoryInfo (dir
).Name
));
670 WriteLine ("Number of items = " + count
);
673 private static bool InstallFromList (bool check_refs
, string list_file
, string package
,
674 string gacdir
, string link_gacdir
, string libdir
, string link_libdir
)
676 StreamReader s
= null;
677 int processed
, failed
;
678 string listdir
= Path
.GetDirectoryName (
679 Path
.GetFullPath (list_file
));
681 processed
= failed
= 0;
684 s
= new StreamReader (list_file
);
687 while ((line
= s
.ReadLine ()) != null) {
688 string file
= line
.Trim ();
689 if (file
.Length
== 0)
692 string assemblyPath
= Path
.Combine (listdir
,
695 if (!Install (check_refs
, assemblyPath
, package
, gacdir
,
696 link_gacdir
, libdir
, link_libdir
))
701 WriteLine ("Assemblies processed = {0}", processed
);
702 WriteLine ("Assemblies installed = {0}", processed
- failed
);
703 WriteLine ("Failures = {0}", failed
);
705 return (failed
== 0);
706 } catch (IOException
) {
707 WriteLine ("Failed to open assemblies list file " + list_file
+ ".");
715 private static bool UninstallFromList (string list_file
, string package
,
716 string gacdir
, string libdir
)
718 StreamReader s
= null;
719 int failed
, uninstalled
;
721 failed
= uninstalled
= 0;
724 s
= new StreamReader (list_file
);
727 while ((line
= s
.ReadLine ()) != null) {
728 string name
= line
.Trim ();
729 if (name
.Length
== 0)
731 Uninstall (line
, package
, gacdir
, libdir
,
732 true, ref uninstalled
, ref failed
);
735 WriteLine ("Assemblies processed = {0}", uninstalled
+failed
);
736 WriteLine ("Assemblies uninstalled = {0}", uninstalled
);
737 WriteLine ("Failures = {0}", failed
);
739 return (failed
== 0);
740 } catch (IOException
) {
741 WriteLine ("Failed to open assemblies list file " + list_file
+ ".");
749 private static Universe
GetUniverse () {
750 if (_universe
== null) {
751 _universe
= new Universe (UniverseOptions
.MetadataOnly
);
756 private static Assembly
ReflectionOnlyLoadFrom (string fileName
)
758 return GetUniverse ().LoadFile (fileName
);
760 private static AssemblyName
GetCorlibName ()
762 return GetUniverse ().Mscorlib
.GetName ();
765 private static bool CheckReferencedAssemblies (AssemblyName an
)
768 Assembly a
= ReflectionOnlyLoadFrom (an
.CodeBase
);
769 AssemblyName corlib
= GetCorlibName ();
771 foreach (AssemblyName ref_an
in a
.GetReferencedAssemblies ()) {
772 if (ref_an
.Name
== corlib
.Name
) // Just do a string compare so we can install on diff versions
774 byte [] pt
= ref_an
.GetPublicKeyToken ();
775 if (pt
== null || pt
.Length
== 0) {
776 WriteLine ("Assembly " + ref_an
.Name
+ " is not strong named.");
780 } catch (Exception e
) {
781 WriteLine (e
.ToString ()); // This should be removed pre beta3
788 private static string GetSearchString (Hashtable asm_info
)
790 if (asm_info
.Keys
.Count
== 1)
792 string version
, culture
, token
;
794 version
= asm_info
["version"] as string;
795 version
= (version
== null ? "*" : version
+ "*");
796 culture
= asm_info
["culture"] as string;
797 culture
= (culture
== null ? "*" : (culture
== "neutral") ? String
.Empty
: culture
.ToLower (CultureInfo
.InvariantCulture
));
798 token
= asm_info
["publickeytoken"] as string;
799 token
= (token
== null ? "*" : token
.ToLower (CultureInfo
.InvariantCulture
));
801 return String
.Format ("{0}_{1}_{2}", version
, culture
, token
);
804 private static string AsmbNameFromVersionString (string name
, string str
)
806 string [] pieces
= str
.Split ('_');
807 return String
.Format ("{0}, Version={1}, Culture={2}, PublicKeyToken={3}",
808 name
, pieces
[0], (pieces
[1] == String
.Empty
? "neutral" : pieces
[1]),
812 static bool LoadConfig (bool quiet
)
814 System
.Reflection
.MethodInfo config
= typeof (System
.Environment
).GetMethod ("GetMachineConfigPath",
815 System
.Reflection
.BindingFlags
.Static
| System
.Reflection
.BindingFlags
.NonPublic
);
817 if (config
!= null) {
818 string path
= (string) config
.Invoke (null, null);
820 bool exist
= File
.Exists (path
);
821 if (!quiet
&& !exist
)
822 Console
.WriteLine ("Couldn't find machine.config");
824 StrongNameManager
.LoadConfig (path
);
827 Console
.WriteLine ("Couldn't resolve machine.config location (corlib issue)");
833 // modified copy from sn
834 private static VerificationResult
VerifyStrongName (AssemblyName an
, string assemblyFile
)
836 byte [] publicKey
= StrongNameManager
.GetMappedPublicKey (an
.GetPublicKeyToken ());
837 if ((publicKey
== null) || (publicKey
.Length
< 12)) {
839 publicKey
= an
.GetPublicKey ();
840 if ((publicKey
== null) || (publicKey
.Length
< 12))
841 return VerificationResult
.WeakNamed
;
844 // Note: MustVerify is based on the original token (by design). Public key
845 // remapping won't affect if the assembly is verified or not.
846 if (StrongNameManager
.MustVerify (new System
.Reflection
.AssemblyName (an
.FullName
))) {
847 RSA rsa
= CryptoConvert
.FromCapiPublicKeyBlob (publicKey
, 12);
848 StrongName sn
= new StrongName (rsa
);
849 if (sn
.Verify (assemblyFile
)) {
850 return VerificationResult
.StrongNamed
;
852 return VerificationResult
.DelaySigned
;
855 return VerificationResult
.Skipped
;
859 private static bool IsSwitch (string arg
)
861 return (arg
[0] == '-' || (arg
[0] == '/' && !arg
.EndsWith (".dll") && !arg
.EndsWith (".exe") && arg
.IndexOf ('/', 1) < 0 ) );
864 private static Command
GetCommand (string arg
)
866 Command c
= Command
.Unknown
;
876 case "--install-from-list":
877 c
= Command
.InstallFromList
;
883 c
= Command
.Uninstall
;
887 case "--uninstall-from-list":
888 c
= Command
.UninstallFromList
;
892 case "--uninstall-specific":
893 c
= Command
.UninstallSpecific
;
909 [DllImport ("libc", SetLastError
=true)]
910 public static extern int symlink (string oldpath
, string newpath
);
912 private static string GetGacDir () {
913 System
.Reflection
.PropertyInfo gac
= typeof (System
.Environment
).GetProperty ("GacPath",
914 System
.Reflection
.BindingFlags
.Static
|System
.Reflection
.BindingFlags
.NonPublic
);
916 WriteLine ("ERROR: Mono runtime not detected, please use " +
917 "the mono runtime for gacutil.exe");
918 Environment
.Exit (1);
920 System
.Reflection
.MethodInfo get_gac
= gac
.GetGetMethod (true);
921 return (string) get_gac
.Invoke (null, null);
924 private static string GetLibDir () {
925 System
.Reflection
.MethodInfo libdir
= typeof (System
.Environment
).GetMethod ("internalGetGacPath",
926 System
.Reflection
.BindingFlags
.Static
|System
.Reflection
.BindingFlags
.NonPublic
);
927 if (libdir
== null) {
928 WriteLine ("ERROR: Mono runtime not detected, please use " +
929 "the mono runtime for gacutil.exe");
930 Environment
.Exit (1);
932 return Path
.Combine ((string)libdir
.Invoke (null, null), "mono");
935 private static string GetStringToken (byte[] tok
)
937 StringBuilder sb
= new StringBuilder ();
938 for (int i
= 0; i
< tok
.Length
; i
++)
939 sb
.Append (tok
[i
].ToString ("x2"));
940 return sb
.ToString ();
943 private static string EnsureLib (string dir
)
945 DirectoryInfo d
= new DirectoryInfo (dir
);
948 return Path
.Combine (dir
, "lib");
951 private static void WriteLine ()
955 Console
.WriteLine ();
958 private static void WriteLine (string line
)
962 Console
.WriteLine (line
);
965 private static void WriteLine (string line
, params object [] p
)
969 Console
.WriteLine (line
, p
);
972 private static void Usage ()
975 Environment
.Exit (1);
978 private static void ShowHelp (bool detailed
)
980 WriteLine ("Usage: gacutil.exe <commands> [ <options> ]");
981 WriteLine ("Commands:");
983 WriteLine ("-i <assembly_path> [-check_refs] [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
984 WriteLine ("\tInstalls an assembly into the global assembly cache.");
986 WriteLine ("\t<assembly_path> is the name of the file that contains the " +
987 "\tassembly manifest\n" +
988 "\tExample: -i myDll.dll");
992 WriteLine ("-il <assembly_list_file> [-check_refs] [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
993 WriteLine ("\tInstalls one or more assemblies into the global assembly cache.");
995 WriteLine ("\t<assembly_list_file> is the path to a test file containing a list of\n" +
996 "\tassembly file paths on separate lines.\n" +
997 "\tExample -il assembly_list.txt\n" +
998 "\t\tassembly_list.txt contents:\n" +
999 "\t\tassembly1.dll\n" +
1000 "\t\tassembly2.dll");
1004 WriteLine ("-u <assembly_display_name> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
1005 WriteLine ("\tUninstalls an assembly from the global assembly cache.");
1007 WriteLine ("\t<assembly_display_name> is the name of the assembly (partial or\n" +
1008 "\tfully qualified) to remove from the global assembly cache. If a \n" +
1009 "\tpartial name is specified all matching assemblies will be uninstalled.\n" +
1010 "\tExample: -u myDll,Version=1.2.1.0");
1014 WriteLine ("-ul <assembly_list_file> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
1015 WriteLine ("\tUninstalls one or more assemblies from the global assembly cache.");
1017 WriteLine ("\t<assembly_list_file> is the path to a test file containing a list of\n" +
1018 "\tassembly names on separate lines.\n" +
1019 "\tExample -ul assembly_list.txt\n" +
1020 "\t\tassembly_list.txt contents:\n" +
1021 "\t\tassembly1,Version=1.0.0.0,Culture=en,PublicKeyToken=0123456789abcdef\n" +
1022 "\t\tassembly2,Version=2.0.0.0,Culture=en,PublicKeyToken=0123456789abcdef");
1026 WriteLine ("-us <assembly_path> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
1027 WriteLine ("\tUninstalls an assembly using the specifed assemblies full name.");
1029 WriteLine ("\t<assembly path> is the path to an assembly. The full assembly name\n" +
1030 "\tis retrieved from the specified assembly if there is an assembly in\n" +
1031 "\tthe GAC with a matching name, it is removed.\n" +
1032 "\tExample: -us myDll.dll");
1036 WriteLine ("-l [assembly_name] [-root ROOTDIR] [-gacdir GACDIR]");
1037 WriteLine ("\tLists the contents of the global assembly cache.");
1039 WriteLine ("\tWhen the <assembly_name> parameter is specified only matching\n" +
1040 "\tassemblies are listed.");
1045 WriteLine ("\tDisplays a detailed help screen");
1051 WriteLine ("Options:");
1052 WriteLine ("-package <NAME>");
1053 WriteLine ("\tUsed to create a directory in prefix/lib/mono with the name NAME, and a\n" +
1054 "\tsymlink is created from NAME/assembly_name to the assembly on the GAC.\n" +
1055 "\tThis is used so developers can reference a set of libraries at once.");
1058 WriteLine ("-gacdir <GACDIR>");
1059 WriteLine ("\tUsed to specify the GACs base directory. Once an assembly has been installed\n" +
1060 "\tto a non standard gacdir the MONO_GAC_PREFIX environment variable must be used\n" +
1061 "\tto access the assembly.");
1064 WriteLine ("-root <ROOTDIR>");
1065 WriteLine ("\tUsed by developers integrating this with automake tools or packaging tools\n" +
1066 "\tthat require a prefix directory to be specified. The root represents the\n" +
1067 "\t\"libdir\" component of a prefix (typically prefix/lib).");
1070 WriteLine ("-check_refs");
1071 WriteLine ("\tUsed to ensure that the assembly being installed into the GAC does not\n" +
1072 "\treference any non strong named assemblies. Assemblies being installed to\n" +
1073 "\tthe GAC should not reference non strong named assemblies, however the is\n" +
1074 "\tan optional check.");
1077 WriteLine ("Ignored Options:");
1079 WriteLine ("\tThe Mono gacutil ignores the -f option to maintain commandline compatibility with");
1080 WriteLine ("\tother gacutils. gacutil will always force the installation of a new assembly.");
1083 WriteLine ("-r <reference_scheme> <reference_id> <description>");
1084 WriteLine ("\tThe Mono gacutil has not implemented traced references and will emit a warning");
1085 WriteLine ("\twhen this option is used.");