Repository: mesonbuild/meson

Issue:
Visual Studio 2019 backend doesn't pick up c++ standard version
Bug description:
I use ```project('Hyra','cpp', default_options : ['cpp_std=c++17'], version : '0.01')``` in my meson build file to specify that c++17 should be used. When configuring the project (and also regenerating it) however, VS doesn't seem to care about this setting, it doesn't get applied, as you can see here (the last entry):
![image](https://user-images.githubusercontent.com/11295581/70388549-d6b13700-19b3-11ea-8126-a430cbf19435.png)
I have to manually change the standard version in the UI in order to use c++ 2017 (e.g. std::variant).

System Parameters
* Native build
* Win 10
* Python version: 3.7.0
* Meson version: 0.52.0



Discussion:
The /std:c++17 arg is passed into vs2010backend.py:gen_vcxproj but I didn't trace it farther. Is there a anyone familiar with Meson's VS backend to know if setting cpp_std used to work for MSVC? It looks like it's intended to work but maybe there's a glitch somewhere in vs2010backend.py?
That might be the case.
I found out that when I manually set the language standard, the option appears in the corresponding vcxproj file: 
![image](https://user-images.githubusercontent.com/11295581/70430150-6e795880-1a7a-11ea-9a75-93f754650472.png)

A newly setup VS2019 project doesn't have that option.
Indeed vs2010backend.py doesn't specify "\<LanguageStandard>...\</LanguageStandard>" anywhere. I think that's the problem. 
So I created a method which defines "\<LanguageStandard>...\</LanguageStandard>" as if I had specified the option manually in the UI.
```python
    def set_cpp_std_version(self, clconf, target):
        std_standard = self.environment.coredata.compiler_options[target.for_machine]['cpp_std'].printable_value()
        std_standard_xml = ET.SubElement(clconf,"LanguageStandard")
        std_standard_xml.text = "std" + std_standard.replace("+","p")
        std_standard_xml.attrib["Condition"] = "'$(Configuration)|$(Platform)'=='" + self.buildtype + "|" + self.platform + "'" 
        # END
```
It should work as a temporary workaround I guess.



here's a minimal example meson.build

```meson
project('demo','cpp', default_options: ['cpp_std=c++17'])

executable('main', 'main.cpp')
```
Using Meson as-is (without your changes above) this produces build/main@exe.vcxproj that has a line like the following, using `--backend vs2019` or `--backend vs2017` since VS2017 was the [first version language /std was available](https://docs.microsoft.com/en-us/cpp/build/reference/std-specify-language-standard-version)
 
```
<AdditionalOptions>&quot;/EHsc&quot; &quot;/std:c++17&quot; &quot;/permissive-&quot; %(AdditionalOptions)</AdditionalOptions>
```

This is not recognized by VS as a language standard option.
So it's an VS issue?
No it's a Meson issue. It may be that when VS2017 was added, this cpp_std option was not handled. So I think the cpp_std support needs to be added for VS2017 and VS2019 in Meson. When adding this, please keep in mind `intel-cl` compiler with Visual Studio backend--consider asking me or dcbaker if needing help testing `intel-cl`.

W.r.t. deprecation, it appears VS2013 (EOL 4/2019) was already deprecated, and VS2015 EOL is 10/2019 so we may need to ensure the cpp_std option is *not* passed to VS2015.
Okay Im trying to figure out how to deal with the regen and install projects. If I update the standard version, it recognizes the option changed, but doesn't update.

This is related #4455, I agree with DaOnlyOwner on `LanguageStandard` tag.

I tried the 
> ```meson
> project('demo','cpp', default_options: ['cpp_std=c++17'])
> 
> executable('main', 'main.cpp')
> ```
> 

Then modified the config without build. Saving, exit and grep 17
xpath `/Project/ItemDefinitionGroup/ClCompile/LanguageStandard` was added

With the value: `<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='debugoptimized|x64'">stdcpp17</LanguageStandard>`

vs2017 populates `stdcpp14` `stdcpp17` or `stdcpplatest`

I don't know the variable to read to get `cpp_std` value from but I hard coded the value by adding a line at `/mesonbuild/backend/vs2010backend.py:822`

`ET.SubElement(clconf, 'LanguageStandard').text = 'stdcpp17'`

After generating a new build dir and opening the solution the value was set and stayed set on regen.

Karl

Resolving patch:
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -1119,6 +1119,7 @@ def gen_vcxproj(self, target, ofname, guid):
         else:
             ET.SubElement(clconf, 'FavorSizeOrSpeed').text = 'Speed'
         # Note: SuppressStartupBanner is /NOLOGO and is 'true' by default
+        self.generate_lang_standard_info(file_args, clconf)
         pch_sources = {}
         if self.environment.coredata.options.get(OptionKey('b_pch')):
             for lang in ['c', 'cpp']:
@@ -1507,3 +1508,6 @@ def generate_debug_information(self, link):
     def add_regen_dependency(self, root):
         regen_vcxproj = os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj')
         self.add_project_reference(root, regen_vcxproj, self.environment.coredata.regen_guid)
+
+    def generate_lang_standard_info(self, file_args, clconf):
+        pass
\ No newline at end of file
diff --git a/mesonbuild/backend/vs2017backend.py b/mesonbuild/backend/vs2017backend.py
--- a/mesonbuild/backend/vs2017backend.py
+++ b/mesonbuild/backend/vs2017backend.py
@@ -50,3 +50,13 @@ def __init__(self, build: T.Optional[Build], interpreter: T.Optional[Interpreter
     def generate_debug_information(self, link):
         # valid values for vs2017 is 'false', 'true', 'DebugFastLink', 'DebugFull'
         ET.SubElement(link, 'GenerateDebugInformation').text = 'DebugFull'
+
+    def generate_lang_standard_info(self, file_args, clconf):
+        if 'cpp' in file_args:
+            optargs = [x for x in file_args['cpp'] if x.startswith('/std:c++')]
+            if optargs:
+                ET.SubElement(clconf, 'LanguageStandard').text = optargs[0].replace("/std:c++", "stdcpp")
+        if 'c' in file_args:
+            optargs = [x for x in file_args['c'] if x.startswith('/std:c')]
+            if optargs:
+                ET.SubElement(clconf, 'LanguageStandard_C').text = optargs[0].replace("/std:c", "stdc")
\ No newline at end of file
diff --git a/mesonbuild/backend/vs2019backend.py b/mesonbuild/backend/vs2019backend.py
--- a/mesonbuild/backend/vs2019backend.py
+++ b/mesonbuild/backend/vs2019backend.py
@@ -45,3 +45,13 @@ def __init__(self, build: T.Optional[Build], interpreter: T.Optional[Interpreter
     def generate_debug_information(self, link):
         # valid values for vs2019 is 'false', 'true', 'DebugFastLink', 'DebugFull'
         ET.SubElement(link, 'GenerateDebugInformation').text = 'DebugFull'
+
+    def generate_lang_standard_info(self, file_args, clconf):
+        if 'cpp' in file_args:
+            optargs = [x for x in file_args['cpp'] if x.startswith('/std:c++')]
+            if optargs:
+                ET.SubElement(clconf, 'LanguageStandard').text = optargs[0].replace("/std:c++", "stdcpp")
+        if 'c' in file_args:
+            optargs = [x for x in file_args['c'] if x.startswith('/std:c')]
+            if optargs:
+                ET.SubElement(clconf, 'LanguageStandard_C').text = optargs[0].replace("/std:c", "stdc")


Test patch: