Strong-naming assemblies using Mono.Cecil
As the Microsoft FxCop libraries are inherently 32-bit (including native code as they do), developing code using them on a 64-bit platform throws up places where the modes get mixed, and an assembly that is generally AnyCPU ends up needing to load an x86 library and barfs. No real problem here, use corflags assembly /32BIT+ /Force
, where you need the /Force for a strong-named assembly. And then if later you need that one strong-named... There is the standard technique of ILDasm/ILAsm to rebuild the assembly with strong-naming (as documented e.g. here), but you still end up with the corflags yellow warning in the MSBuild output about breaking the original strong-naming if you need that too.
But when the code I was working on also uses Mono.Cecil to do stuff, it was easier to silently do the whole lot in one script:
// script relative paths to the Mono.Cecil and Mono.Options assemblies | |
#I "..\_Tools\Mono.Cecil" | |
#I "..\_Tools\Mono.Options" | |
#r "Mono.Cecil" | |
#r "Mono.Cecil.Pdb.dll" // Have to put the .dll on if Mono.Cecil.Pdb is also present | |
#r "Mono.Options" | |
open System | |
open System.Collections.Generic | |
open System.IO | |
open System.Reflection | |
open Microsoft.FSharp.Text | |
open Mono.Cecil | |
open Mono.Cecil.Pdb | |
open Mono.Options | |
// Command line argument parsing preamble --------------------------------- | |
let (!+) (option: string * string * (string->unit)) (options:OptionSet) = | |
let prototype, help, action = option | |
options.Add(prototype, help, new System.Action<string>(action)) | |
let Usage (intro:string) (options:OptionSet) = | |
Console.Error.WriteLine(intro) | |
options.WriteOptionDescriptions(Console.Error); | |
Environment.Exit(1) | |
let assemblyName = ref "" | |
let keyName = ref "" | |
let cor32plus = ref false | |
let options = new OptionSet() | |
|> !+ ( | |
"k|key=", | |
"The strong naming key to apply", | |
(fun s -> keyName := s)) | |
|> !+ ( | |
"a|assembly=", | |
"The assembly to process", | |
(fun s -> assemblyName := s)) | |
|> !+ ( | |
"c|cor32", | |
"Do what CorFlags /32BIT+ /Force does.", | |
(fun x -> cor32plus := x <> null)) | |
let rest = try | |
options.Parse(fsi.CommandLineArgs) | |
with | |
| :? OptionException -> | |
Usage "Error - usage is:" options | |
new List<String>() | |
// The meat of the script starts here --------------------------------- | |
// load files | |
let stream = new FileStream(!keyName, FileMode.Open, FileAccess.Read) | |
let key = new StrongNameKeyPair(stream) | |
let definition = AssemblyDefinition.ReadAssembly(!assemblyName) | |
// Do what CorFlags /32BIT+ /Force does if required | |
if !cor32plus then definition.MainModule.Attributes <- ModuleAttributes.Required32Bit ||| definition.MainModule.Attributes | |
// The headline section : strong-naming --------------------------------- | |
// (Re-)apply the strong name | |
definition.Name.HasPublicKey <- true | |
definition.Name.PublicKey <- key.PublicKey | |
let pkey = new WriterParameters() | |
pkey.WriteSymbols <- true | |
pkey.SymbolWriterProvider <- new PdbWriterProvider() | |
pkey.StrongNameKeyPair <- key | |
// Overwrite the assembly | |
definition.Write(!assemblyName, pkey) |
Yes, you can do that in PowerShell too, just with more fussing about the path to the Cecil assemblies because of the schizophrenic current directory model it has. And because the rest of the code in this particular project is F#, keeping the build scripts in the same language is just natural.
No comments :
Post a Comment