Visual Studio 2012 solution file grammar

Here is the start for a grammar for sln files in Visual Studio 2012. Since the solution file format hasn’t changed much since Visual Studio 2005, a little parameterization probably handles all projects, and I’ve attempted to do that here. Also, I’ve made non-terminals as short as possible without killing readability, in the interests of making something that’s legible in just a few columns. And I really need to respect the whitespace indentation rules – the parser in Visual Studio doesn’t force them on input, but does follow indentation rules on output, so I may as well bake them into the grammar somehow.

Also note that MSBuild has an internal parser for sln files that you can access with some work – see Getting Visual Studio version of a Solution file. I have no idea if there is a formal grammar with a parser, or if Microsoft only has ad-hoc parsers. I’m guessing the latter…

sln = ver-header entries
entries = (project | global)+

ver-header = visual-studio ", " format-version "\n" comment-version "\n"
visual-studio = "Microsoft Visual Studio Solution File"
format-version = "Format Version numeric-version
numeric-version = nv_2002 | nv_2003 | nv_2005 | nv_2008 | nv_2010 | nv_2012
nv_2002 = "7.00"
nv_2003 = "8.00"
nv_2005 = "9.00"
nv_2008 = "10.00"
nv_2010 = "11.00"
nv_2012 = "12.00"
comment-version = "# Visual Studio " year-version
year_version = "2005" | "2008" | "2010" | "2012"

project = project-id "\n" project-parms* "EndProject" "\n"
project-id = "Project(" '"{' pt-guid '}"' )" = " proj_parms
proj_parms = proj-name ", " proj-path ", " proj_guid
pt-guid = vcppguid | vbguid | vcsharpguid | webguid | siguid
vcppguid = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
vbguid = "F184B08F-C81C-45F6-A57F-5ABD9991F28F"
vcsharpguid = "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"
webguid = "E24C65DC-7377-472b-9ABA-BC803B73C61A"
siguid = "2150E333-8FDC-42A3-9474-1A3956D46DE8"
proj_name = '"' STRING '"'
proj_path = '"' STRING '"'
proj_guid = HEX{8} "-" HEX{4} "-" HEX{4} "-" HEX{4} "-" HEX{12}

global = "Global" "\n" global-section* "EndGlobal" "\n"
global_section = gs_start "\n" gs_body "EndGlobalSection" "\n"
gs_start = "GlobalSection" "(" gs_kind ")" " = " gs_when
gs_kind =   "SolutionConfigurationPlatforms"
          | "ProjectConfigurationPlatform"
          | "SolutionProperties"
          | "ExtensibilityGlobals"
          | "ExtensibilityAddIns"
gs_kind_05 =   "SolutionConfiguration"
             | "ProjectConfiguration"
             | "ProjectDependencies"
gs_when = "preSolution" | "postSolution"
gs_body = gs_configs | gs_plats | gs_props
gs_configs = (gs_config "\n")*
gs_config = sol_cfg_plat " = " sol_cfg_plat
sol_cfg_plat = sol_cfg "|" sol_plat
sol_cfg = "Debug" | "Release" | STRING
sol_plat = "Win32" | "x64" | STRING
gs_plats = (gs_plat "\n")*
gs_plat = "{" proj_guid "}" "." sol_cfg_plat "." gs_action " = " sol_cfg_plat
gs_action = "ActiveCfg | "Build.0"
gs_props = "HideSolutionNode = " ("TRUE" | "FALSE") "\n"

This is horribly incomplete and horribly informal. I need to work more in individual elements and write the grammar fragments for them. The above would parse a subset of solution files, but it would generate many illegal solution files. Also, there are some elements that are deprecated and probably converted to newer elements. I noted a few of those in the gs_kind_05 field for elements that stopped existing at some point after VS 2005.

This is what an trivial wizard-generated solution file looks like in Visual Studio 2012, that has one project. I have split lines in some cases using a C-preprocessor ‘\’ syntax, in order to not have line wrapping, and I made short GUIDs for the same reason. Visual Studio probably needs the exact Microsoft GUID format – a 128-bit GUID split into 5 chunks of 32-16-16-16-48 bits, respectively. For completeness’ sake, I turned 8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942 into 8BC9-8D11-00A0C91B, and 67DC3F40-5C82-445C-8EE9-0B78724D839D into 67DC-8EE9-0B78724D.

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{8BC9-8D11-00A0C91B}") = "vc12-test-1-empty", \
        "vc12-test-1-empty\vc12-test-1-empty.vcxproj", \
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|Win32 = Debug|Win32
        Release|Win32 = Release|Win32
    GlobalSection(ProjectConfigurationPlatforms) = postSolution
        {67DC-8EE9-0B78724D}.Debug|Win32.ActiveCfg = Debug|Win32
        {67DC-8EE9-0B78724D}.Debug|Win32.Build.0 = Debug|Win32
        {67DC-8EE9-0B78724D}.Release|Win32.ActiveCfg = Release|Win32
        {67DC-8EE9-0B78724D}.Release|Win32.Build.0 = Release|Win32
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE

Some notes

For SolutionConfigurationPlatforms, I can’t figure out what’s going on here. I’m guessing that one side is a label that’s used in places, and the other side is the actual name of a config. I’m guessing that there’s some unification going on here for projects that have different subsets of configurations? I tried editing one side or the other, but Visual Studio must be “repairing damage”, because it puts things back the way it wants it.

For Project, I can’t figure out what the proj-name item is actually for. I don’t know what uses it, because it doesn’t control what’s displayed in Visual Studio (the name from the vcxproj file itself is used).

The values for GlobalSection are actually in the registry, in a key named SolutionPersistence for the relevant version of Visual Studio. Each entry just has a GUID, which in turn probably points to a DLL that handles that value? There are 20 of these in my installs of VS 2010 and VS 2012, and even the deprecated VS 2005 variants are listed, so maybe they aren’t deprecated?

Visual Studio 2002, which is “Format Version 7.00″, and Visual Studio 2003, which is “Format Version 8.00″, did not have the second comment line with the Visual Studio year entry.

Project dependencies are in a ProjectSection inside a Project entry, like so:

Project("{8BC9-8D11-00A0C91B}") = "Tool", "Tool.vcproj", "{0C1B-BCF4-01F038A7}"
    ProjectSection(ProjectDependencies) = postProject
        {6678-A354-3A61F442} = {6678-A354-3A61F442}

The dependencies are always “project depends on itself”, instead of “B depends on A”. It’s possible that there’s some other dependency allowed?


Hack the Project and Solution Files

Premake generates sln files, but in an ad-hoc fashion. It doesn’t read them.

Solution (.sln) File from MSDN – old, it’s for VS 2005, but still mostly relevant.

One thought on “Visual Studio 2012 solution file grammar”

  1. It seems that the Project section Guid:

    … is actually not the Guid for that project but a Guid for the solution. This would make sense given that in the GlobalSection(ProjectConfigurationPlatforms) has each project Guid as listed in the Project section just beyond the relative path to the .csproj.

    Would this be a correct assumption?


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>