38

For Noda Time version 1.1, the main goal is to build a Portable Class Library flavour, primarily to support Windows Phone and Windows Store apps. This means losing some functionality, so we build a desktop configuration and a PCL configuration (for each of debug, release, and "signed release").

To avoid having to work with umpteen project files, all of the 6 configurations exist in the same project file. The project file is customized to generate a property called "Portability", which is set to either "PCL" or "Desktop", like this:

<!-- Set the custom Portability property based on configuration -->
<PropertyGroup>
  <Portability Condition="'$(Configuration)' == 'Debug Portable'">PCL</Portability>
  <Portability Condition="'$(Configuration)' == 'Release Portable'">PCL</Portability>
  <Portability Condition="'$(Configuration)' == 'Signed Release Portable'">PCL</Portability>
  <!-- Default to desktop if not explicitly set above -->
  <Portability Condition="'$(Portability)' == ''">Desktop</Portability>
</PropertyGroup>

We then have separate property groups for portable vs desktop, based on the above property. This is what defines the project type as "class library" or "portable class library" (along with the OutputType of Library, which is shared):

<!-- Desktop-specific properties -->
<PropertyGroup Condition="'$(Portability)' == 'Desktop'">
  <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
  <TargetFrameworkProfile>Client</TargetFrameworkProfile>
</PropertyGroup>

<!-- PCL-specific properties -->
<PropertyGroup Condition="'$(Portability)' == 'PCL'">
  <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
  <ProjectGuid>{c78f6992-28d7-45c9-a4c1-6eaa649f3247}</ProjectGuid>
  <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
  <TargetFrameworkProfile>Profile2</TargetFrameworkProfile>
  <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>

This generally works very well - I have the different solution configurations, so I can build and test everything at a moment's notice, and I only need to add each new .cs file to a single project file. So under Visual Studio 2012 Professional (which is what I use) I'm perfectly happy.

The problem comes when I try to load the solution in Visual Studio Express (either VS2010 or VS2012). While the solution is loading, it fails with an error to say that some projects can't be loaded, and the two projects which build PCL versions then have build output like this:

C:\Path\To\NodaTime.csproj : error  :
     The project file 'C:\Path\To\NodaTime.csproj' cannot be opened.

There is a missing project subtype.
     Subtype: '{786C830F-07A1-408B-BD7F-6EE04809D6DB}'
     is unsupported by this installation.

(Reformatted for clarity.) The two projects refuse to load, so you can't even browse the source code.

I had really hoped that even if Express users couldn't build the PCL versions, they'd still be able to load up the solution, browse the source, and build non-PCL versions. MSBuild works from the command line, but that's not as friendly.

I've tried removing the solution configurations which refer to the PCL project configurations, and that doesn't help. Weirdly enough, even commenting out the XML element, like this:

<!-- 
    <ProjectTypeGuids>(Guids as before)</ProjectTypeGuids>
 -->

doesn't help - although deleting the line does. It's as if Visual Studio isn't actually loading it as a real XML file. (I haven't tried loading the version with the commented out element into VS Pro.)

I could go down the route of generating separate PCL project files if I need to, but I'd really like to avoid it if possible - it would make normal development more painful. Likewise I could generate Express-only PCL and solution files, but again I'd rather not - it just feels wrong.

While ideally I'd like to support VS Express both 2010 and 2012, if there's a solution which only works for 2012, that would be a good start.

So, is there any way of persuading Visual Studio Express that it really can load a project despite a conditional property group (whose condition isn't met) referring to a project type it doesn't know about?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Wow, very interesting question. Extremely weird how VS is loading commented out XML – Earlz Jan 27 '13 at 20:39
  • @pst: Which part only applies to the Express versions? The failing to load does. I don't know about the "commenting out" part. I'll clarify both. – Jon Skeet Jan 27 '13 at 20:41
  • Except the part about VS trying to load the commented xml fragment, this looks indeed like the purpose of the Express edition: you can't work with unsupported project types, regardless of whether the current configuration makes them active or not. Not sure I understand why you find it strange. Compare it to bringing your workbook to an exam and swear that you won't use it. It's thus prevented in the first place. – Simone Jan 27 '13 at 21:39
  • @Simone: I'm not expecting them to be "worked with" at all. I'm happy for them to be treated as if they weren't there at all. I'd like them to be ignored if the user doesn't try to interact with them at all. I don't think your comparison with the exam is relevant in the slightest - or if you want to make it relevant, I'd think that's fine so long as the workbook has an alarm attached so that if you *tried* to use it, all hell would break loose. I have no problem with it failing if the user tries to build the PCL version. – Jon Skeet Jan 27 '13 at 21:42
  • What's weird is that I've just installed Visual Studio 2012 Express to my Windows 2008 Server box, and all 10 projects appeared to have opened just fine. All I did was double click the solution file and I appear to be able to browse all of the projects. – dash Jan 27 '13 at 22:06
  • This behavior is similar to what I experienced with VS 2012 Premium running on a Win7 machine when I tried to load a PCL that targets WinRT (a long with other platforms). Visual Studio failed to open the project with a similar message, but on Windows 8 machine the same project opened fined. I find this behavior erratic because even though I can't develop WinRT apps under Win7, this is a portable library, so it should be accessible on any of the platforms it's intended to support. Seems that portable profile in a project manifest may fool VS in thinking that it's something it does not support. – Vagif Abilov Jan 27 '13 at 23:21
  • @dash: That's really odd. I'm trying it on Windows 8, and it doesn't work... on the same box where it works with VS Pro. – Jon Skeet Jan 28 '13 at 00:00
  • @VagifAbilov: It's failing for me on a Windows 8 box with VS Pro installed as well. – Jon Skeet Jan 28 '13 at 00:01
  • @JonSkeet: May I suggest checking if it works with just VS Express installed on Win8. Also, the order that VS Pro and VS Express are installed may be relevant. I'm thinking about this problem from a 'there might be a bug in VS' point of view. – Jonathan Parker Jan 28 '13 at 00:57
  • 5
    is a property that indicates to VS what project system to load when opening a given project file. Clearly the thing that reads it isn't a real XML reader if its still seeing it the comment. There's a bit of chicken and egg problem; the project system reads the XML, but VS doesn't know which project system to load until it itself reads this property - its a real hack. – David Kean Jan 28 '13 at 01:25
  • 2
    I don't think there's a going to be a way to do what you want - you'll need to separate the portable projects into separate projects, or remove the element entirely - this will opt you of "portable" enhancements, such as a UI for changing the target framework, etc. As a completely side note, I'd really recommend that instead of treating portable as a separate build, instead you have a portable core, and then separate assemblies for desktop specific functionality. Have a look at what RX Extensions did for v2 for an example of what I mean. – David Kean Jan 28 '13 at 01:29
  • @DavidKean: I'll take a look - but unfortunately there are bits that are small changes within the same class, such as working round PCL not supplying `DateTimeFormatInfo.DateSeparator`. I quite like the idea of just removing the `` part entirely, if that's just around UI and not actual build... – Jon Skeet Jan 28 '13 at 06:46
  • @dash Which flavor of Express did you try? The 'for Windows Desktop' or the 'for Windows 8'? Maybe there are differences in allowed projects between the two? – jv42 Jan 28 '13 at 08:36
  • @jv42 Good question - it was the `for Windows Desktop` version. – dash Jan 28 '13 at 09:02

2 Answers2

10

David Kean's comment here gave me the answer I'm using for the moment:

or remove the <ProjectTypeGuid> element entirely - this will opt you of "portable" enhancements, such as a UI for changing the target framework, etc

I've tried that, and it works like a dream. On machines which have everything appropriately installed, you can then even build the PCL version under Express! I've verified that the resulting binary really is a PCL, and it seems fine.

I wouldn't be surprised to find that I ran into some problems later on, but for the moment this works fine for me. I can easily live without the enhancements in Visual Studio - it was already confused by my project having very different build configurations, so I don't think I was getting much benefit anyway.

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
3

As answered here:
Visual Studio 2012 Express with Portable Class Library?
and here:
Share functionality using Portable Class Libraries

Portable Class library projects are not supported in the express SKU...need a higher SKU for the full support. Of course the binary (e.g., using it as a reference) is, just not the project/source support.

I can imagine there is a simple reason for that - there are different types of VS2012 Express editions: for Windows Phone development, for Desktop apps, for Windows 8 apps... I bet the Windows Phone Express edition does not know about the Windows Phone project type and vice versa. This could be the simple reason why PCLs are not supported as well.

Although the idea of Portable Class Libraries is really nice, it's still quite limited in many ways, for instance you cannot use conditional compilation using #if xy as far as I know. If you really have to use Visual Studio Express for development, then it might be better to use projects for each platform with referenced source files and conditional compilation.

Martin Suchan
  • 10,600
  • 3
  • 36
  • 66
  • I'm not wanting PCLs to be *really* supported by Express - just the loading of a project which has *some* flavour which would build the PCL. It sounds like removing the `ProjectTypeGuids` element may solve this... I need to experiment further. – Jon Skeet Jan 28 '13 at 09:25
  • Maybe if there is a way how to detect the type of Visual Studio, like detecting VS Express for WP8, and changing the project type from PCL to WP8 using project file conditions? – Martin Suchan Jan 28 '13 at 10:05
  • I'm already using conditional sections in the project file: you can't even load it into a solution where *no* configuration uses the PCL. Just the presence of the element causes a problem :( – Jon Skeet Jan 28 '13 at 10:06