views:

37

answers:

1

What are common practices for designing a build system/project structure that allows targeting multiple .NET versions with different feature sets?

Specifically:

  • Should you branch in source control?
  • Should you use conditional compilation?
  • Should you derive interfaces, thereby versioning them?
  • Should you create seperate "versionX" projects and link common project files?
+2  A: 

I've tried a few different ways of doing this.

I ruled out branching because it's a bit difficult to keep all the branches in sync using SVN/TFS. Distributed SCC does have more advanced support for branching/merging, so I'm planning to reconsider this approach if I ever convert.

I use conditional compilation along with version-specific projects using linked source files. The most aggressive library I've done along these lines is Nito.Linq, which hasn't been released yet. You can check out the source, though, to see how I've set up the projects. It currently targets 3.5, 4.0, SL3, and SL4, and has "with Rx" and "without Rx" variants for each of these. I had CF 3.5 working as well, but VS2010 doesn't support it.

There are a few drawbacks to this approach:

  • In my solution, I defined a "Sources" project that acts as a container for the files. Unfortunately, it's built when loaded and I can't add source files when it's unloaded; so it ends up getting in the way.
  • Linking the source files in projects targeting different frameworks causes another problem: it's not possible to open the same source file in different projects. VS will inform you of the fact and then show the already-open source file from another project. This affects IntelliSense, especially with the conditional compilation. Not a show-stopper, but many times you'll open a file and then have to close it and re-open it (and then go back to the position where you were).
  • Unit tests on VS2010 have to target the 4.0 framework. So any testing on other framework versions has to be done in a non-VS2010 way. I haven't found a good solution for this yet; it doesn't affect Nito.Linq because unit testing the 4.0 variants tests all the code.

I did ask the Rx team how they handled this situation (they support 3.5, 4.0, SL3, and SL4 with the same codebase). Apparently, they use a custom in-house tool to create metadata-only versions of the runtime assemblies and then combine these into a superset-profile containing the merged metadata-only assemblies. The project is built against this superset-profile and a post-compilation "retargeting" is done to change the project's profile to one of the normal profiles.

I briefly played around with building an open-source equivalent of the Rx team's tool, but ran into too many "underdocumented" snags. It should be possible in theory, but I figured it would take way too much time for anyone without the correct contacts inside Microsoft.

Stephen Cleary