0

I am currently fighting MSBuild, which won't build a solution file in library found on Github. The problem seems to be that for some inexplicable reason Microsoft decided that the target SDK needs to be set in an XML file and the version specified of course doesn't match what's installed in the VM.

So I want an easy way to update it. I had decided to use xsltproc to do this. I have created the following XSLT file:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="WindowsTargetPlatformVersion"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="WindowsTargetPlatformVersion/text()[.='X']">
        <xsl:value-of select="$WindowsTargetPlatformVersion"/>
    </xsl:template>
</xsl:stylesheet>

But for some reason this doesn't work for the solution file. An example of the solution file I am trying to modify is this:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{1A234565-926D-49B2-83E4-D56E0C38C9F2}</ProjectGuid>
    <RootNamespace>libconfig</RootNamespace>
    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <PlatformToolset>v141</PlatformToolset>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <PlatformToolset>v141</PlatformToolset>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup>
    <_ProjectFileVersion>15.0.26919.1</_ProjectFileVersion>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <OutDir>$(SolutionDir)$(Configuration)\</OutDir>
    <IntDir>$(ProjectName).$(Configuration)\</IntDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <OutDir>$(SolutionDir)$(Configuration)\</OutDir>
    <IntDir>$(ProjectName).$(Configuration)\</IntDir>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <PreprocessorDefinitions>LIBCONFIG_EXPORTS;YY_NO_UNISTD_H;YY_USE_CONST;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <CompileAs>CompileAsC</CompileAs>
    </ClCompile>
    <Link>
      <AdditionalDependencies>Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
      <OutputFile>$(OutDir)$(ProjectName)_d.dll</OutputFile>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <GenerateMapFile>true</GenerateMapFile>
      <MapExports>true</MapExports>
      <RandomizedBaseAddress>false</RandomizedBaseAddress>
      <DataExecutionPrevention />
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <PreprocessorDefinitions>LIBCONFIG_EXPORTS;YY_NO_UNISTD_H;YY_USE_CONST;_CRT_SECURE_NO_DEPRECATE;_STDLIB_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
      <CompileAs>CompileAsC</CompileAs>
    </ClCompile>
    <Link>
      <AdditionalDependencies>Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
      <RandomizedBaseAddress>false</RandomizedBaseAddress>
      <DataExecutionPrevention />
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClCompile Include="grammar.c" />
    <ClCompile Include="libconfig.c" />
    <ClCompile Include="scanctx.c" />
    <ClCompile Include="scanner.c" />
    <ClCompile Include="strbuf.c" />
    <ClCompile Include="strvec.c" />
    <ClCompile Include="util.c" />
    <ClCompile Include="wincompat.c" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="..\ac_config.h" />
    <ClInclude Include="grammar.h" />
    <ClInclude Include="libconfig.h" />
    <ClInclude Include="parsectx.h" />
    <ClInclude Include="private.h" />
    <ClInclude Include="scanctx.h" />
    <ClInclude Include="scanner.h" />
    <ClInclude Include="strbuf.h" />
    <ClInclude Include="strvec.h" />
    <ClInclude Include="util.h" />
    <ClInclude Include="win32\stdint.h" />
    <ClInclude Include="wincompat.h" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

I cannot figure out why xsltproc refuses to replace the text. I run it like this, from bash:

xsltproc --stringparam WindowsTargetPlatformVersion $SDKVERSION retarget.xslt $SOLUTIONFILE

If I create a simple xml-file with the tag it works as expected. The solution file doesn't work.

Martijn Otto
  • 878
  • 4
  • 21
  • 1
    The solution file XML has a default namespace (`xmlns="http://schemas.microsoft.com/developer/msbuild/2003"`), but you have not accounted for that in your XSLT (so your template is trying to match "WindowsTargetPlatformVersion" in no namespace). See https://stackoverflow.com/questions/1344158/xslt-with-xml-source-that-has-a-default-namespace-set-to-xmlns for how to handle default namespaces. – Tim C Jul 20 '18 at 08:42
  • That indeed solves the issue. If you post the comment as an answer I could accept it. – Martijn Otto Jul 20 '18 at 08:50

1 Answers1

1

Visual Studio solution files have a default namespace (The xlmns here...)

 <Project DefaultTargets="Build" ToolsVersion="15.0" 
          xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

But you have not accounted for this in your XSLT. Where your template matches "WindowsTargetPlatformVersion", it is trying to match the element in no namespace

You just need to declare the namespace in your XSLT, bound to a prefix, and use that in your template match.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ms="http://schemas.microsoft.com/developer/msbuild/2003">
    <xsl:param name="WindowsTargetPlatformVersion"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ms:WindowsTargetPlatformVersion/text()[.='X']">
        <xsl:value-of select="$WindowsTargetPlatformVersion"/>
    </xsl:template>
</xsl:stylesheet>

If you could use XSLT 2.0 (which I am guessing not, if you are in Microsoft's world) you could use xpath-default-namespace, so you would not need to bind to a prefix

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xpath-default-namespace="http://schemas.microsoft.com/developer/msbuild/2003">
    <xsl:param name="WindowsTargetPlatformVersion"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="WindowsTargetPlatformVersion/text()[.='X']">
        <xsl:value-of select="$WindowsTargetPlatformVersion"/>
    </xsl:template>
</xsl:stylesheet>
Tim C
  • 70,053
  • 14
  • 74
  • 93