From 967ceba5b7fc56f7642947b2c48199a4d9db0d4a Mon Sep 17 00:00:00 2001
From: stijn <stijn@ignitron.net>
Date: Thu, 12 Nov 2015 09:42:12 +0100
Subject: [PATCH] msvc: Use different output directories depending on build
 type

This allows multiple versions (e.g. Debug/Release, x86/x64) of micropython.exe
to co-exist instead and also solves potential problems where msbuild does not
completely rebuild the output and/or pdb files when switching between builds,
which in turn can cause linker errors in dependent projects.

By default exe/map/... files go in windows/build/$(Configuration)$(Platform)

After each build micropython.exe is still copied from the above directory to
the windows directory though, as that is consistent with the other ports and
the test runner by default uses that location as well.

Also rename env.props -> path.props which is a clearer name,
and add ample documentation in the affected build files.

(also see discussion in #1538)
---
 windows/msvc/common.props   | 27 ++++++++++++++++++----
 windows/msvc/env.props      |  9 --------
 windows/msvc/genhdr.targets |  2 +-
 windows/msvc/paths.props    | 45 +++++++++++++++++++++++++++++++++++++
 windows/msvc/sources.props  |  2 +-
 5 files changed, 70 insertions(+), 15 deletions(-)
 delete mode 100644 windows/msvc/env.props
 create mode 100644 windows/msvc/paths.props

diff --git a/windows/msvc/common.props b/windows/msvc/common.props
index 73103f627..cfb6adbc1 100644
--- a/windows/msvc/common.props
+++ b/windows/msvc/common.props
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ImportGroup Label="PropertySheets">
-    <Import Project="env.props" />
+    <Import Project="paths.props" Condition="'$(PyPathsIncluded)' != 'True'"/>
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup>
     <OutDir>$(PyOutDir)</OutDir>
-    <IntDir>$(PyBuildDir)$(Configuration)$(Platform)\</IntDir>
-    <PyIncDirs>$(PyBaseDir);$(PyBaseDir)windows;$(PyBaseDir)windows\msvc;$(PyBuildDir)</PyIncDirs>
+    <IntDir>$(PyIntDir)</IntDir>
+    <PyFileCopyCookie>$(PyBuildDir)copycookie$(Configuration)$(Platform)</PyFileCopyCookie>
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
@@ -22,5 +22,24 @@
       <GenerateMapFile>true</GenerateMapFile>
     </Link>
   </ItemDefinitionGroup>
-  <ItemGroup />
+  <ItemGroup>
+    <PyOutputFiles Include="$(TargetPath)">
+      <Destination>$(PyWinDir)%(FileName)%(Extension)</Destination>
+    </PyOutputFiles>
+    <PyCookieFiles Include="$(PyBuildDir)copycookie*" Exclude="$(PyFileCopyCookie)"/>
+  </ItemGroup>
+
+  <!-- Copy PyOutputFiles to their target destination.
+       To force this when switching between platforms/configurations which are already up-to-date (and as such,
+       for which a build wouldn't even start because all outputs are effectively newer than the inputs)
+       an empty file $(PyFileCopyCookie) is created serving as a record to indicate what was last copied,
+       and any previous records are deleted. So when switching between builds which are otherwise up-to-date
+       the tracker will notice a missing file and a build is started anyway (and it will just copy our files). -->
+  <Target Name="CopyFilesToWinDir" AfterTargets="Build"
+          Inputs="$(TargetPath)" Outputs="$(PyFileCopyCookie);@(PyOutputFiles->'%(Destination)')">
+    <Delete Files="@(PyCookieFiles)"/>
+    <Touch Files="$(PyFileCopyCookie)" AlwaysCreate="true"/>
+    <Copy SourceFiles="%(PyOutputFiles.Identity)" DestinationFiles="%(PyOutputFiles.Destination)"/>
+    <WriteLinesToFile File="$(TLogLocation)$(ProjectName).write.u.tlog" Lines="$(PyFileCopyCookie);@(PyOutputFiles->'%(Destination)')" Overwrite="True"/>
+  </Target>
 </Project>
diff --git a/windows/msvc/env.props b/windows/msvc/env.props
deleted file mode 100644
index 824b529e6..000000000
--- a/windows/msvc/env.props
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <PyBaseDir>$([System.IO.Path]::GetFullPath(`$(MSBuildThisFileDirectory)..\..`))\</PyBaseDir>
-    <PyBuildDir Condition="'$(PyBuildDir)'==''">$(MSBuildThisFileDirectory)build\</PyBuildDir>
-    <PyOutDir Condition="'$(PyOutDir)'==''">$(PyBaseDir)windows\</PyOutDir>
-    <PyEnvIncluded>True</PyEnvIncluded>
-  </PropertyGroup>
-</Project>
diff --git a/windows/msvc/genhdr.targets b/windows/msvc/genhdr.targets
index 93bb74ee9..3d9a148be 100644
--- a/windows/msvc/genhdr.targets
+++ b/windows/msvc/genhdr.targets
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="GenerateHeaders">
 
-  <Import Project="env.props" Condition="$(PyEnvIncluded)!=True"/>
+  <Import Project="paths.props" Condition="'$(PyPathsIncluded)' != 'True'"/>
 
   <!--Generate qstrdefs.h and mpversion.h similar to what is done in py/py.mk-->
   <Target Name="GenerateHeaders" DependsOnTargets="MakeQstrData;MakeVersionHdr">
diff --git a/windows/msvc/paths.props b/windows/msvc/paths.props
new file mode 100644
index 000000000..716698243
--- /dev/null
+++ b/windows/msvc/paths.props
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <PyPathsIncluded>True</PyPathsIncluded>
+
+    <!-- The properties below specify the output directory structure.
+         This defaults to, for example for Configuration = Debug and Platform = x64:
+
+         micropython [PyBaseDir]
+          |- ...
+          |- windows [PyWinDir]
+              |- ...
+              |- micropython.exe
+              |- build [PyBuildDir]
+                  |- Debugx64 [PyOutDir]
+                  |   |- ...
+                  |   |- micropython.exe
+                  |   |- micropython.map
+                  |   |- obj [PyIntDir]
+                  |- genhdr
+
+         Note that the micropython executable will be copied from PyOutDir
+         to PyWinDir after each build. -->
+
+    <!-- Start from project root -->
+    <PyBaseDir>$([System.IO.Path]::GetFullPath(`$(MSBuildThisFileDirectory)..\..`))\</PyBaseDir>
+    <PyWinDir>$(PyBaseDir)windows\</PyWinDir>
+    <PyBuildDir Condition="'$(PyBuildDir)' == ''">$(PyWinDir)build\</PyBuildDir>
+
+    <!-- All include directories needed for uPy -->
+    <PyIncDirs>$(PyBaseDir);$(PyWinDir);$(PyBuildDir);$(PyWinDir)msvc</PyIncDirs>
+
+    <!-- Within PyBuildDir different subdirectories are used based on configuration and platform.
+         By default these are chosen based on the Configuration and Platform properties, but
+         this file might be imported by other projects (to figure out where the artifacts go
+         or what the include files are) and those projects might already contain conflicting
+         Configuration/Platform properties, so allow to override these -->
+    <PyPlatform Condition="'$(PyPlatform)' == ''">$(Platform)</PyPlatform>
+    <PyConfiguration Condition="'$(PyConfiguration)' == ''">$(Configuration)</PyConfiguration>
+
+    <!-- The final destination directories -->
+    <PyOutDir>$(PyBuildDir)$(PyConfiguration)$(PyPlatform)\</PyOutDir>
+    <PyIntDir>$(PyOutDir)obj\</PyIntDir>
+  </PropertyGroup>
+</Project>
diff --git a/windows/msvc/sources.props b/windows/msvc/sources.props
index eea28fc46..b84002500 100644
--- a/windows/msvc/sources.props
+++ b/windows/msvc/sources.props
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="env.props" Condition="$(PyEnvIncluded)!=True"/>
+  <Import Project="paths.props" Condition="'$(PyPathsIncluded)' != 'True'"/>
   <ItemGroup>
     <ClCompile Include="$(PyBaseDir)py\*.c" />
     <ClCompile Include="$(PyBaseDir)windows\*.c" />
-- 
GitLab