Repository: conan-io/conan

Issue:
MSBuild build helper always overrides runtime library field
Affects Conan 1.2.x on Windows/MSVC. (pretty sure previous versions behaved slightly differently)

- Recipe for a library that still uses .sln / .vcxproj files rather than CMake generated ones
- Recipe builds both Debug and Release in the same package (`build_type` is not a setting on windows)
- vcxproj files specify different `<RuntimeLibrary>` for Debug and Release configurations
- conan default profile specifies `MD` as the desired compiler runtime
- `build()` method uses the MSBuild build helper


When building the recipe with `conan create` and conan 1.2.0, I observed that `/MD` was being passed to both Release *and* Debug configurations, which is undesired (do not want a Debug library linked with `/MD`, as that will not link with my projects). 

In light of this, I proceded to remove the compiler runtime as a setting:
`self.settings.compiler.remove("runtime")` in the `configure()` method.

Which caused the libraries to be built with a completely different runtime altogether (`/MT`). 

I believe the issue is in the function `_get_props_file_contents()` in the MSBuild build helper. By the looks of it, if `compiler.runtime` is empty, the value in the custom .props file gets initialised to an empty string (and in that case, I think MSBuild decides ?).

I was able to work around this by calling `msbuild.get_command()` (which allows me to bypass the .props file) and then calling the command using `VisualStudioBuildEnvironment` . Kudos for the functionality :)  (The one thing that I couldn't really work out was why MSBuild was warning me that the compiler runtime flag was being overridden when technically it shouldn't have been at this point. However it was being built with the correct values). 







Discussion:

Resolving patch:
diff --git a/conans/client/build/msbuild.py b/conans/client/build/msbuild.py
--- a/conans/client/build/msbuild.py
+++ b/conans/client/build/msbuild.py
@@ -116,14 +116,21 @@ def _get_props_file_contents(self):
             flags = vs_build_type_flags(self._settings)
             flags.append(vs_std_cpp(self._settings))
 
+        flags_str = " ".join(list(filter(None, flags))) # Removes empty and None elements
+        additional_node = "<AdditionalOptions>" \
+                          "{} %(AdditionalOptions)" \
+                          "</AdditionalOptions>".format(flags_str) if flags_str else ""
+        runtime_node = "<RuntimeLibrary>" \
+                       "{}" \
+                       "</RuntimeLibrary>".format(runtime_library) if runtime_library else ""
         template = """<?xml version="1.0" encoding="utf-8"?>
-    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-      <ItemDefinitionGroup>
-        <ClCompile>
-          <RuntimeLibrary>{runtime}</RuntimeLibrary>
-          <AdditionalOptions>{compiler_flags} %(AdditionalOptions)</AdditionalOptions>
-        </ClCompile>
-      </ItemDefinitionGroup>
-    </Project>""".format(**{"runtime": runtime_library,
-                            "compiler_flags": " ".join([flag for flag in flags if flag])})
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemDefinitionGroup>
+    <ClCompile>
+      {runtime_node}
+      {additional_node}
+    </ClCompile>
+  </ItemDefinitionGroup>
+</Project>""".format(**{"runtime_node": runtime_node,
+                        "additional_node": additional_node})
         return template


Test patch:
diff --git a/conans/test/build_helpers/msbuild_test.py b/conans/test/build_helpers/msbuild_test.py
--- a/conans/test/build_helpers/msbuild_test.py
+++ b/conans/test/build_helpers/msbuild_test.py
@@ -16,7 +16,8 @@ class MSBuildTest(unittest.TestCase):
     def dont_mess_with_build_type_test(self):
         settings = MockSettings({"build_type": "Debug",
                                  "compiler": "Visual Studio",
-                                 "arch": "x86_64"})
+                                 "arch": "x86_64",
+                                 "compiler.runtime": "MDd"})
         conanfile = MockConanfile(settings)
         msbuild = MSBuild(conanfile)
         self.assertEquals(msbuild.build_env.flags, ["-Zi", "-Ob0", "-Od"])
@@ -30,6 +31,16 @@ def dont_mess_with_build_type_test(self):
 
         self.assertNotIn("-Ob0", template)
         self.assertNotIn("-Od", template)
+        self.assertIn("<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>", template)
+
+    def without_runtime_test(self):
+        settings = MockSettings({"build_type": "Debug",
+                                 "compiler": "Visual Studio",
+                                 "arch": "x86_64"})
+        conanfile = MockConanfile(settings)
+        msbuild = MSBuild(conanfile)
+        template = msbuild._get_props_file_contents()
+        self.assertNotIn("<RuntimeLibrary>", template)
 
     @attr('slow')
     def build_vs_project_test(self):