# Tuesday, December 06, 2005

I posted almost a month ago about all the searches that I've been noticing on my blog about gacutil.exe. I believe I've determined the question that at least some of the folks are wanting to ask. Folks don't know where to get it.

gacutil.exe and other tools such as ildasm.exe are part of the .NET Framework SDK. The .Net Framework admin tool, which used to be part of the redist, is now part of the SDK.

There may be some confusion around gacutil in particular. It has never shipped with the redist, but apparently a servicing package of the redist in the Everett (v1.1) timeframe used it as part of its servicing logic (oops) and didn't properly clean up after itself (double oops). As a result, there may be developers out there that have gotten used to gacutil being in the framework directory. If that's the case, we're sorry for giving the wrong impression. gacutil is intended to be a developer-only tool, used as part of development.

Instead of using gacutil at deployment time (as our not-so-smart servicing package did), you should use MSI or code against the fusion APIs yourself (with the former being the preferred method). For more info, you might take a look through Junfeng's blog.

Happy GACing.

Tuesday, December 06, 2005 6:43:16 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 
# Wednesday, August 24, 2005

I mentioned earlier that a customer question started off this thread. This is the post that most closely aligns with their question. You can likely see why I've waited until now to answer it, since the earlier posts have all provided information on how the GACs work, either separately or in tandem.

This post isn't exclusive to the GAC, but we'll keep it in the same theme since we're on a roll here and since it does apply w/o too much of a stretch.

Ship both Everett and Whidbey Versions
This is the approach that will make your customers most happy. Everett customers have a library that they can code against. At this point, there are way more Everett customers out there than Whidbey ones, so providing an Everett version likely makes business sense in the short-term. At the same time, you recognize that Whidbey customers have different requirements. Folks who have been playing (or more than playing with our Beta 2 "Go Live" license) with Whidbey for a number of months now (or longer) have gotten used to the Whidbey way of doing things. A bunch of them probably now say "of T" at the end of all their sentences, even at home. Kinda like how I always say "eh" ;) In the same way that you want to keep existing customers on Everett happy, you want to ride the Whidbey adoption curve, picking up sales (if that's the kind of business you are in) from folks coding exclusively in VS2005 with a Whidbey version of your product.

This post isn't intended to cover exactly how you produce these two separate version. I should consider a post on this topic at a later time. The two basic approaches are: (A) have two separate source trees, or (B) a single one with lots of conditional code. There are advantages and disadvantages to both and you need to decide which path you will go down.

Versioning The Everett and Whidbey Versions
Finally, we're at the core of the customer question. Now that you've decided to ship the two versions in tandem, what do you do about version numbers and that sort of thing. Hmmm.

Scenario 1 - The Whidbey version is the same code as the Everett version, just compiled with a Whidbey compiler
- For starters, this is not a super-high-value proposition for class libraries. You definitely are doing your due diligence to avoid breaking changes, but that's it. Also, you can run your Everett code through the Whidbey compilers to do compatibility testing as part of your general testing.
- This is a high-value-proposition for applications (you get an .exe from the compiler). By compiling an Everett app with a Whidbey compiler, you enable running natively on a 64-bit machine. Everett apps always run under WoW64 on 64-bit machines. This post isn't about applications though, but class libraries.
- Anyway, if you decide to go this route, I would keep the version numbers of the Everett and Whidbey components exactly the same, but give the binaries different names (i.e. FooWidgetE.dll, FooWidgetW.dll). Since they are compiled against different CLRs, the code will end up in different GACs, which will further separate them.

Scenario 2 - The Whidbey and Everett versions are mostly the same code, compiled out of the same codebase with pre-processor directives
- First, I would only do this if the differences between the Everett and Whidbey versions -- which will directly affect the number of pre-processor directives you have in your code -- is not dramatic
- I'm assuming that the Everett and Whidbey versions have the same general object models, with a few members and types being specific to Whidbey
- I would do the same thing as Scenario 1 above with differently named assemblies
- If they are on radically different ship cycles, I might start to lean towards scenario 3

Scenario 3 -- The Whidbey and Everett versions are different code
- This approach will be the best one if you intend to move your object model in a different direction in the Whidbey codebase
- I would name the assemblies differently, more differently than in scenario 1 above
- I would not make any effort to keep the version numbers in sync. They might stay in sync, however, if you always ship the two versions on the same schedule
- I would probably change the namespace names too, to make it clear that this is a new thing. This is debatable though since it makes migration harder. The thing that this does do though is make it clear when a customer moves to the Whidbey version that they have more than just a re-compile on their hands

Your code may not fall perfectly into the above buckets, but you'll at least get the idea of some possible directions to take. As always, you need to come up with a plan that makes sense for your product, not just blindly follow a plan outlines on some blog, particularly one that is called "hoser".

Wednesday, August 24, 2005 2:38:10 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
# Tuesday, August 23, 2005

In my two (one and two) earlier "Wonders of the Whidbey GAC" posts, I talked about processor architecture and interop with the Everett GAC. I left out one piece of interesting data because it wouldn't make as much sense until you had read the earlier posts. This data point is the binding order among the GACs. Naturally, you cannot look at them all at once, so we defined an order of probing the GACs that we always adhere to and tends to make sense.

Here is is:

  1. Bitness GAC
    • "gac_32" when running on a 32-bit machine or under WoW64 on a 64-bit machine
    • "gac_64" when running natively (not WoW64) on a 64-bit machine (this is the normal case for Whidbey apps on a 64-bit machine)
  2. Bitness agnostic GAC
    • "gac_msil" on all machines
    • assemblies in this GAC run equally well everywhere (X64, X86, IA64)
  3. Legacy v1.x GAC
    • "gac" on all machines
    • this is where v1.0 and everett assemblies go

You can read this same information on Junfeng's blog too, as he implemented all of this. I just slow him down ;)

Junfeng referes to MSIL assemblies as "portable". I use the term "agnostic". It is the same thing.

If you write managed code in your favourite language (i.e. c#, vb) and don't do anything special, your assemblies will fall into this category. You can do the same thing with MC++ code too, if you compile it as /clrpure; otherwise, mc++ code is by design "bit-specific". Oh, there's another term, but I'm sure you can figure that one out.

If you are unsure of which of the three GAC buckets above your assembly will fall into, and your assembly is strong-name signed, install it into the GAC with gacutil /i from the Whidbey SDK. Gacutil will install the assembly into the correct GAC and then you'll know for sure. You can also open up the assembly (not required to be strong-name signed) in ildasm. That will also tell you the same answer.

Tuesday, August 23, 2005 3:47:45 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, August 22, 2005

I received a question from a customer a few days ago about assembly versioning. I receive questions quite often, of which >90% surprisingly enough come via Brad. I can only imagine what his inbox looks like every morning! Anyway, the question touched on the focus for this post which is the relationship between the Everett and Whidbey GACs. Before I go any further, I’m happy to report that the relationship is sensible and easy to understand. Too often, things don’t make a lot of sense and that always bugs me.

 

The customer’s question was actually about assembly versioning in the case that you want to support Everett and Whidbey, which I hope to cover tomorrow, since that’s when I told them I’d give them an answer ;)

 

First things first, on the surface it seems like interop between the GACs is what is wanted. In actual fact, it is the behaviour of the CLR loader and gacutil.exe that is really the interesting part. The GACs themselves are passive and don’t do anything other than act as a quite compelling directory structure for holding code w/o any naming conflicts.

 

Migrating the Everett GAC to the Whidbey GAC

We don’t do anything like this. This would have been the wrong direction for multiple reasons. Just thought I’d take care of this one up-front.

 

Hard linking assemblies between the Everett and Whidbey GACs as a Perfomance Enhancement

I’m glad that we didn’t do anything like this either. Ouch. OK, now onto the real answers.

 

Whidbey CLR Loader GAC Probing

The Whidbey CLR loader – Fusion in this case – probes for assemblies in the Everett and Whidbey GACs when an assembly request comes through the system. I’ll skip the exact algorithm and any optimizations that we might do. The high-order bit here is that we do indeed look in both GACs, so there is no need to stop using the Everett GAC for Everett assemblies since we look there. In fact, as you’ll find out below, you cannot stop using the Everett GAC.

 

Gacutil.exe, the Fusion APIs and installation via MSI (installers)

There are several ways that you can get assemblies installed into the GAC, with the last one being the recommended option. The big thing I wanted to know when I asked the question is what the expected behaviour was when I added an assembly to the GAC via these different methods.

 

Question:

Do the Whidbey tools put Everett assemblies into the Everett GAC?

 

Given:

Everett and Whidbey .NET Frameworks are installed on the machine

 

Assemblies:

1) 1 assembly compiled against Everett csc.exe (csharp compiler)

2) 1 assembly compiled against Whidbey vbc.exe (vb compiler)

Note: the compilers (vb, csharp) don’t matter for the assemblies above. I’m just trying to mix it up a little. It is the .Net Framework versions that matter.

 

Tools:

A) Everett Gacutil

B) Everett Fusion APIs

C) Whidbey Gacutil

D) Whidbey Fusion APIs

E) MSI installation

 

Scenarios + expected outcome:

1. (1) + (A) -- Everett GAC

2. (1) + (B) -- Everett GAC

3. (1) + (C) -- Everett GAC

4. (1) + (D) -- Everett GAC

5. (1) + (E) -- Everett GAC

6. (2) + (A) -- failure

7. (2) + (B) -- failure

8. (2) + (C) -- Whidbey GAC

9. (2) + (D) -- Whidbey GAC

10. (2) + (E) -- Whidbey GAC

 

Scenarions 6 and 7 fail since Whidbey-compiled assemblies are not loadable via the Everett CLR. Also, since processor architecture is a major part of Whidbey, it would be difficult to store Whidbey assemblies in the Everett GAC in a reasonable manner.

 

Why does Whidbey put Everett assemblies into the Everett GAC?

We continue putting Everett assemblies into the Everett GAC for two reasons:

 

-          Everett apps still require those assemblies and will only be able to use them if they are in the Everett GAC since the Everett CLR loader knows nothing about the Whidbey GAC. It is much easier and smarter for the Whidbey loader to look in the Everett GAC.

-          Everett assemblies didn’t have the concept of processor architecture, which the Whidbey GAC is heavily based on, so it doesn’t make sense to store Everett assemblies in that new structure.

-          Everett is going to live for a long time. Let’s not mess with a good thing ;)

 

That was actually 3 reasons, if you count the last one.

 

Is there an Everett GAC if there is no Everett .NET Framework on the Machine, but only Whidbey?

Yes. The Everett GAC is created as needed when Everett is not on machine. This means that the Everett GAC structure is auto-created when the first Everett-era assembly is added to the Whidbey-only machine. If Everett was also on this machine, the Everett GAC would have been created at the point that the Everett .NET Framework was installed.

 

Monday, August 22, 2005 5:39:12 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
# Saturday, August 20, 2005

The GAC -- Global Assembly Cache -- is a popular topic among managed code developers. It serves two main purposes: (A) as a catalogue of the globally publicly available assemblies available on the system, indexed by strong name, and (B) the location of those same files. It is not my intent to describe the GAC, however; look here for more info. My intent is to describe some interesting changes that have been made to the GAC for Whidbey and to promote some good practices. This is part I and is dedicated to processor architecture; we'll see how far we get with the series ;)

Whidbey is the first CLR release in which we support 64-bit execution. The CLR team has been working on porting the CLR to 64-bit for several years now and is now releasing it to the world with Whidbey. Woohoo! Not surprisingly, 64-bit has required a lot of changes all over the CLR, as it imports a bunch of new concepts onto us. My favourite is the general concept of processor architecture, of which there are four that we now support: X86, X64, IA64 and MSIL. We always supported the first and the last, but there was never a strong reason to differentiate them considerably as we only ran on a 32-bit system.

With respect to the v1.x GAC (v1.0 and Everett share the same GAC), you can see pretty clearly that processor architecture was not a design point.

V1.x GAC location
C:\Windows\assembly\GAC

V1.x System.dll location
C:\WINDOWS\assembly\GAC\System\1.0.5000.0__b77a5c561934e089\System.dll

Where would you have tagged the processor architecture? Nowhere that I can see. As a result, we changed the GAC structure in Whidbey to accommodate processor architecture, which is now an incredible important aspect of the GAC.

V2.0 GAC locations on an x86 machine
C:\Windows\assembly\GAC_MSIL
C:\Windows\assembly\GAC_32

V2.0 System.dll and mscorlib.dll locations on an x86 machine
C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll
C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll

V2.0 GAC locations on an x64 or IA64 machine
C:\Windows\assembly\GAC_MSIL
C:\Windows\assembly\GAC_32
C:\Windows\assembly\GAC_64

V2.0 System.dll and mscorlib.dll locations on an x64 machine
C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll
C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
C:\WINDOWS\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll

You can now see that it is easy to tag assemblies with processor architecture. We’ve created three GACs to do just that! As you can see, the GAC_64 directory only shows up on 64-bit machines, which is hopefully quite intuitive.

I’ve run out of time to get any further in this post, but hopefully it gives you a good idea of how and why the GAC changed, at least with respect to processor architecture in Whidbey. I also hope I left you with the opinion that these changes were a good idea ;)

A question to ponder: If you call System.Reflection.Assembly.Load(“System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”) and there is both a copy in the bit-specific GAC and another in the bit-agnostic (MSIL) GAC, which do you get?

Saturday, August 20, 2005 6:02:47 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [5]  |