mesonbuild / meson

The Meson Build System
http://mesonbuild.com
Apache License 2.0
5.63k stars 1.64k forks source link

macOS: cpp_std does not accept all supported versions #11890

Closed tycho closed 1 year ago

tycho commented 1 year ago

Describe the bug If I set cpp_std=c++20 on macOS, Meson rejects the specified C++ standard after hitting the line add_languages('objcpp').

To Reproduce A simple repro:

project('repro', 'cpp',
    default_options: [
        'cpp_std=c++20'
    ]
)

add_languages('objcpp')
$ meson setup build .
The Meson build system
Version: 1.1.1
Source dir: ...
Build dir: .../build
Build type: native build
Project name: repro
Project version: undefined
C++ compiler for the host machine: ccache c++ (clang 15.0.0 "Apple clang version 15.0.0 (clang-1500.0.28.1.1)")
C++ linker for the host machine: c++ ld64 902.11
Host machine cpu family: aarch64
Host machine cpu: aarch64

meson.build:7:0: ERROR: Value "c++20" (of type "string") for combo option "C++ language standard to use" is not one of the choices. Possible choices are (as string): "none", "c++98", "c++11", "c++14", "c++17", "gnu++98", "gnu++11", "gnu++14", "gnu++17".

A full log can be found at .../meson-log.txt

The referenced meson-log.txt has nothing interesting to say about the failed check, presumably it doesn't shell out at all to do it.

Expected behavior Meson should accept the specified C++ standard version, especially since the compiler seems to have no problem with it.

In C++ mode:

$ clang -E -dM -xc++ -std=c++20 -o - /dev/null | grep cplus
#define __cplusplus 202002L

And even in Objective-C++ mode:

$ clang -E -dM -xobjective-c++ -std=c++20 -o - /dev/null | grep cplus
#define __cplusplus 202002L

I suspect what's happening is that Meson is using some hardcoded list of accepted C++ standard names. I don't know if there's a better way to query the supported -std= flags, but if you do provide a bogus one, it spews the valid values to stderr, in a human-readable form:

$ clang -E -dM -xc++ -std=nonsense -o - /dev/null
error: invalid value 'nonsense' in '-std=nonsense'
note: use 'c++98' or 'c++03' for 'ISO C++ 1998 with amendments' standard
note: use 'gnu++98' or 'gnu++03' for 'ISO C++ 1998 with amendments and GNU extensions' standard
note: use 'c++11' for 'ISO C++ 2011 with amendments' standard
note: use 'gnu++11' for 'ISO C++ 2011 with amendments and GNU extensions' standard
note: use 'c++14' for 'ISO C++ 2014 with amendments' standard
note: use 'gnu++14' for 'ISO C++ 2014 with amendments and GNU extensions' standard
note: use 'c++17' for 'ISO C++ 2017 with amendments' standard
note: use 'gnu++17' for 'ISO C++ 2017 with amendments and GNU extensions' standard
note: use 'c++20' for 'ISO C++ 2020 DIS' standard
note: use 'gnu++20' for 'ISO C++ 2020 DIS with GNU extensions' standard
note: use 'c++2b' for 'Working draft for ISO C++ 2023 DIS' standard
note: use 'gnu++2b' for 'Working draft for ISO C++ 2023 DIS with GNU extensions' standard

Given that upstream Clang has a test to ensure this output stays stable, it might be reasonable to parse it out to find the valid options instead of hardcoding them.

system parameters OS and Xcode version:

Also affects macOS 13.4 with Xcode 14.3.1.

Meson, ninja, and Python interpreter version:

$ meson --version
1.1.1
$ ninja --version
1.11.1
$ /opt/homebrew/opt/python@3.11/bin/python3.11 --version
Python 3.11.3
tristan957 commented 1 year ago

This doesn't make sense https://github.com/mesonbuild/meson/blob/master/mesonbuild/compilers/cpp.py#L213-L217

tycho commented 1 year ago

The list meson allows looks closer to this one:

https://github.com/mesonbuild/meson/blob/e869a09bc2e0fbd988fdc19014b8b0ad7e4b97c9/mesonbuild/compilers/cpp.py#L335-L338

Wonder if it's detecting Apple Clang incorrectly?

tristan957 commented 1 year ago

If you could do some debugging, that would be useful. I don't have a Mac to help out

tycho commented 1 year ago

Ah, ran with python -m trace --trace --module meson setup build . and the list comes from here, actually:

https://github.com/mesonbuild/meson/blob/e869a09bc2e0fbd988fdc19014b8b0ad7e4b97c9/mesonbuild/compilers/objcpp.py#L96-L102

So that makes more sense. Strange that the list excludes newer C++ standards, or that cpp_std is overloaded to imply both C++ and Objective-C++.

tristan957 commented 1 year ago

Then do we just need a PR which adds those things to the list

tycho commented 1 year ago

I think that would work for the short term.

Though I wonder if perhaps it should also respect some new objcpp_std option (and if that's not present, pull from cpp_std) or something like that.

tycho commented 1 year ago

This would probably do for the short-term fix to add all the missing C++ standard versions in the various compilers (including "c++2b", which will be c++23):

diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index dbdcb2fa2..89d385725 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -154,6 +154,8 @@ class CPPCompiler(CLikeCompiler, Compiler):
             'gnu++17': 'gnu++1z',
             'c++20': 'c++2a',
             'gnu++20': 'gnu++2a',
+            'c++23': 'c++2b',
+            'gnu++23': 'gnu++2b',
         }

         # Currently, remapping is only supported for Clang, Elbrus and GCC
@@ -212,8 +214,8 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler):
         })
         opts[key.evolve('std')].choices = [
             'none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z',
-            'c++2a', 'c++20', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z',
-            'gnu++2a', 'gnu++20',
+            'c++2a', 'c++20', 'c++2b', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z',
+            'gnu++2a', 'gnu++20', 'gnu++2b'
         ]
         if self.info.is_windows() or self.info.is_cygwin():
             opts.update({
@@ -388,8 +390,8 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler):
         })
         cppstd_choices = [
             'none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z',
-            'c++2a', 'c++20', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17',
-            'gnu++1z', 'gnu++2a', 'gnu++20',
+            'c++2a', 'c++20', 'c++2b', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17',
+            'gnu++1z', 'gnu++2a', 'gnu++20', 'gnu++2b'
         ]
         if version_compare(self.version, '>=12.2.0'):
             cppstd_choices.append('c++23')
diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py
index 1f9f75635..b46718e2e 100644
--- a/mesonbuild/compilers/objcpp.py
+++ b/mesonbuild/compilers/objcpp.py
@@ -96,7 +96,9 @@ class ClangObjCPPCompiler(ClangCompiler, ObjCPPCompiler):
         opts.update({
             OptionKey('std', machine=self.for_machine, lang='cpp'): coredata.UserComboOption(
                 'C++ language standard to use',
-                ['none', 'c++98', 'c++11', 'c++14', 'c++17', 'gnu++98', 'gnu++11', 'gnu++14', 'gnu++17'],
+                ['none', 'c++98', 'c++11', 'c++14', 'c++17', 'c++20', 'c++2b',
+                 'gnu++98', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++20',
+                 'gnu++2b'],
                 'none',
             )
         })
tristan957 commented 1 year ago

If you could come up with a PR, that would be great.

tycho commented 1 year ago

Sure, have some other work to do but I'll submit one soon

tristan957 commented 1 year ago

No need to rush. Would be great to have it for 1.2.0 however