Repository: conan-io/conan
Pull request #12002 (2022-09-01 09:36:08)

[PkgConfigDeps] Private classes
Changelog: omit
Docs: omit

Avoiding likely public imports in recipes.


Patch:
diff --git a/conan/tools/apple/xcodedeps.py b/conan/tools/apple/xcodedeps.py
index 4838df7a5..9ea6e03ce 100644
--- a/conan/tools/apple/xcodedeps.py
+++ b/conan/tools/apple/xcodedeps.py
@@ -79,7 +79,7 @@ class XcodeDeps(object):
         // Includes all configurations for each dependency
         {% for dep in deps %}
         // Includes for {{dep[0]}}::{{dep[1]}} dependency
-        #include "conan_{{dep[0]}}_{{dep[1]}}.xcconfig"
+        #include "conan_{{format_name(dep[0])}}_{{format_name(dep[1])}}.xcconfig"
         {% endfor %}
         #include "{{dep_xconfig_filename}}"
 
@@ -163,7 +163,8 @@ class XcodeDeps(object):
             content_multi = Template(content_multi).render({"pkg_name": pkg_name,
                                                             "comp_name": comp_name,
                                                             "dep_xconfig_filename": dep_xconfig_filename,
-                                                            "deps": reqs})
+                                                            "deps": reqs,
+                                                            "format_name": _format_name})
 
         if dep_xconfig_filename not in content_multi:
             content_multi = content_multi.replace('.xcconfig"',
diff --git a/conan/tools/cmake/toolchain/blocks.py b/conan/tools/cmake/toolchain/blocks.py
index 52608545e..3eb5865e5 100644
--- a/conan/tools/cmake/toolchain/blocks.py
+++ b/conan/tools/cmake/toolchain/blocks.py
@@ -523,8 +523,9 @@ class FindFiles(Block):
         os_ = self._conanfile.settings.get_safe("os")
         is_apple_ = is_apple_os(self._conanfile)
 
-        # Read information from host context
-        host_req = self._conanfile.dependencies.host.values()
+        # Read information from host context, also including test_requires, which are in host
+        # TODO: Add here in 2.0 the "skip": False trait
+        host_req = self._conanfile.dependencies.filter({"build": False}).values()
         host_build_paths_root = []
         host_build_paths_noroot = []
         host_lib_paths = []
diff --git a/conan/tools/cmake/toolchain/toolchain.py b/conan/tools/cmake/toolchain/toolchain.py
index 4227efae4..310648c41 100644
--- a/conan/tools/cmake/toolchain/toolchain.py
+++ b/conan/tools/cmake/toolchain/toolchain.py
@@ -17,6 +17,7 @@ from conan.tools.intel import IntelCC
 from conan.tools.microsoft import VCVars
 from conan.tools.microsoft.visual import vs_ide_version
 from conans.errors import ConanException
+from conans.model.options import PackageOption
 from conans.util.files import save
 
 
@@ -182,6 +183,13 @@ class CMakeToolchain(object):
         for name, value in self.cache_variables.items():
             if isinstance(value, bool):
                 cache_variables[name] = "ON" if value else "OFF"
+            elif isinstance(value, PackageOption):
+                if str(value).lower() in ["true", "false", "none"]:
+                    cache_variables[name] = "ON" if bool(value) else "OFF"
+                elif str(value).isdigit():
+                    cache_variables[name] = int(value)
+                else:
+                    cache_variables[name] = str(value)
             else:
                 cache_variables[name] = value
 
diff --git a/conan/tools/gnu/pkgconfigdeps.py b/conan/tools/gnu/pkgconfigdeps.py
index 2eb5a8ff8..38a7737d6 100644
--- a/conan/tools/gnu/pkgconfigdeps.py
+++ b/conan/tools/gnu/pkgconfigdeps.py
@@ -86,7 +86,7 @@ def _get_formatted_dirs(folders, prefix_path_):
 _PCInfo = namedtuple("PCInfo", ['name', 'requires', 'description', 'cpp_info', 'aliases'])
 
 
-class PCContentGenerator:
+class _PCContentGenerator:
 
     template = textwrap.dedent("""\
         {%- macro get_libs(libdirs, cpp_info, gnudeps_flags) -%}
@@ -198,13 +198,13 @@ class PCContentGenerator:
         return template.render(context)
 
 
-class PCGenerator:
+class _PCGenerator:
 
     def __init__(self, conanfile, dep, build_context_suffix=None):
         self._conanfile = conanfile
         self._build_context_suffix = build_context_suffix or {}
         self._dep = dep
-        self._content_generator = PCContentGenerator(self._conanfile, self._dep)
+        self._content_generator = _PCContentGenerator(self._conanfile, self._dep)
 
     def _get_cpp_info_requires_names(self, cpp_info):
         """
@@ -398,7 +398,7 @@ class PkgConfigDeps:
             if dep.is_build_context and dep.ref.name not in self.build_context_activated:
                 continue
 
-            pc_generator = PCGenerator(self._conanfile, dep, build_context_suffix=self.build_context_suffix)
+            pc_generator = _PCGenerator(self._conanfile, dep, build_context_suffix=self.build_context_suffix)
             pc_files.update(pc_generator.pc_files)
         return pc_files
 
diff --git a/conan/tools/system/package_manager.py b/conan/tools/system/package_manager.py
index a416d2db5..ef281980f 100644
--- a/conan/tools/system/package_manager.py
+++ b/conan/tools/system/package_manager.py
@@ -38,7 +38,7 @@ class _SystemPackageManagerTool(object):
                                    "almalinux", "rocky"],
                            "dnf": ["fedora", "rhel", "centos", "mageia"],
                            "brew": ["Darwin"],
-                           "pacman": ["arch", "manjaro", "msys2"],
+                           "pacman": ["arch", "manjaro", "msys2", "endeavouros"],
                            "choco": ["Windows"],
                            "zypper": ["opensuse", "sles"],
                            "pkg": ["freebsd"],
diff --git a/conans/client/build/cppstd_flags.py b/conans/client/build/cppstd_flags.py
index 650ecc89d..c086b3174 100644
--- a/conans/client/build/cppstd_flags.py
+++ b/conans/client/build/cppstd_flags.py
@@ -66,6 +66,8 @@ def cppstd_default(settings):
 
 
 def _clang_cppstd_default(compiler_version):
+    if Version(compiler_version) >= "16":
+        return "gnu17"
     # Official docs are wrong, in 6.0 the default is gnu14 to follow gcc's choice
     return "gnu98" if Version(compiler_version) < "6" else "gnu14"
 
diff --git a/conans/model/conf.py b/conans/model/conf.py
index 968bcd87b..4df28790e 100644
--- a/conans/model/conf.py
+++ b/conans/model/conf.py
@@ -6,7 +6,7 @@ import six
 from conans.errors import ConanException
 
 BUILT_IN_CONFS = {
-    "core:required_conan_version": "Raise if current version does not match the defined range.",
+    "core:required_conan_version": "Raise if current version does not match the defined range",
     "core.package_id:msvc_visual_incompatible": "Allows opting-out the fallback from the new msvc compiler to the Visual Studio compiler existing binaries",
     "core:default_profile": "Defines the default host profile ('default' by default)",
     "core:default_build_profile": "Defines the default build profile (None by default)",
@@ -46,14 +46,24 @@ BUILT_IN_CONFS = {
     "tools.apple:enable_bitcode": "(boolean) Enable/Disable Bitcode Apple Clang flags",
     "tools.apple:enable_arc": "(boolean) Enable/Disable ARC Apple Clang flags",
     "tools.apple:enable_visibility": "(boolean) Enable/Disable Visibility Apple Clang flags",
-    # Flags configuration
     "tools.build:cxxflags": "List of extra CXX flags used by different toolchains like CMakeToolchain, AutotoolsToolchain and MesonToolchain",
     "tools.build:cflags": "List of extra C flags used by different toolchains like CMakeToolchain, AutotoolsToolchain and MesonToolchain",
     "tools.build:defines": "List of extra definition flags used by different toolchains like CMakeToolchain and AutotoolsToolchain",
     "tools.build:sharedlinkflags": "List of extra flags used by CMakeToolchain for CMAKE_SHARED_LINKER_FLAGS_INIT variable",
     "tools.build:exelinkflags": "List of extra flags used by CMakeToolchain for CMAKE_EXE_LINKER_FLAGS_INIT variable",
+    "tools.microsoft.bash:subsystem": "Set subsystem to use for Windows. Possible values: 'msys2', 'msys', 'cygwin', 'wsl' and 'sfu'",
+    "tools.microsoft.bash:path": "Path to the shell executable. Default: 'bash'",
+    "tools.apple:sdk_path": "Path for the sdk location. This value will be passed as SDKROOT or -isysroot depending on the generator used",
+    "tools.cmake.cmaketoolchain:toolset_arch": "Will add the ',host=xxx' specifier in the 'CMAKE_GENERATOR_TOOLSET' variable of 'conan_toolchain.cmake' file",
+    "tools.gnu:pkg_config": "Define the 'pkg_config' executable name or full path",
+    "tools.env.virtualenv:powershell": "Opt-in to generate Powershell '.ps1' scripts instead of '.bat'",
+    "tools.meson.mesontoolchain:backend": "Set the Meson backend. Possible values: 'ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'vs2019', 'xcode'",
+    "tools.files.download:download_cache": "Location for the download cache",
+    "tools.build.cross_building:can_run": "Set the return value for the 'conan.tools.build.can_run()' tool",
 }
 
+BUILT_IN_CONFS = {key: value for key, value in sorted(BUILT_IN_CONFS.items())}
+
 
 def _is_profile_module(module_name):
     # These are the modules that are propagated to profiles and user recipes
diff --git a/conans/model/new_build_info.py b/conans/model/new_build_info.py
index 78c27a83e..b05b026d6 100644
--- a/conans/model/new_build_info.py
+++ b/conans/model/new_build_info.py
@@ -72,6 +72,27 @@ class _NewComponent(object):
         setattr(self, attribute, default)
         return default
 
+    @property
+    def bindir(self):
+        bindirs = self.bindirs
+        assert bindirs
+        assert len(bindirs) == 1
+        return bindirs[0]
+
+    @property
+    def libdir(self):
+        libdirs = self.libdirs
+        assert libdirs
+        assert len(libdirs) == 1
+        return libdirs[0]
+
+    @property
+    def includedir(self):
+        includedirs = self.includedirs
+        assert includedirs
+        assert len(includedirs) == 1
+        return includedirs[0]
+
 
 class NewCppInfo(object):
 
diff --git a/conans/model/options.py b/conans/model/options.py
index 642c4afe2..8c2702380 100644
--- a/conans/model/options.py
+++ b/conans/model/options.py
@@ -231,6 +231,12 @@ class OptionsValues(object):
             return None
         return getattr(self._package_values, attr)
 
+    def rm_safe(self, attr):
+        try:
+            delattr(self._package_values, attr)
+        except ConanException:
+            pass
+
     def __getitem__(self, item):
         return self._reqs_options.setdefault(item, PackageOptionValues())
 
@@ -425,6 +431,12 @@ class PackageOptions(object):
     def get_safe(self, field, default=None):
         return self._data.get(field, default)
 
+    def rm_safe(self, field):
+        try:
+            delattr(self, field)
+        except ConanException:
+            pass
+
     def validate(self):
         for child in self._data.values():
             child.validate()
@@ -584,6 +596,9 @@ class Options(object):
         except ConanException:
             pass
 
+    def rm_safe(self, field):
+        self._package_options.rm_safe(field)
+
     @property
     def values(self):
         result = OptionsValues()
diff --git a/conans/model/settings.py b/conans/model/settings.py
index 8a7e697aa..096483ed3 100644
--- a/conans/model/settings.py
+++ b/conans/model/settings.py
@@ -213,6 +213,19 @@ class Settings(object):
             return str(tmp)
         return default
 
+    def rm_safe(self, name):
+        try:
+            tmp = self
+            attr_ = name
+            if "." in name:
+                fields = name.split(".")
+                attr_ = fields.pop()
+                for prop in fields:
+                    tmp = getattr(tmp, prop)
+            delattr(tmp, attr_)
+        except ConanException:
+            pass
+
     def copy(self):
         """ deepcopy, recursive
         """


Test patch:
diff --git a/conans/test/assets/pkg_cmake.py b/conans/test/assets/pkg_cmake.py
index 60d53943c..7234d8c58 100644
--- a/conans/test/assets/pkg_cmake.py
+++ b/conans/test/assets/pkg_cmake.py
@@ -86,7 +86,7 @@ def pkg_cmake_test(require_name):
                 cmake.build()
 
             def test(self):
-                cmd = os.path.join(self.cpp.build.bindirs[0], "test")
+                cmd = os.path.join(self.cpp.build.bindir, "test")
                 self.run(cmd, env="conanrun")
         """)
 
diff --git a/conans/test/functional/toolchains/apple/test_xcodedeps_components.py b/conans/test/functional/toolchains/apple/test_xcodedeps_components.py
index 2a50ab1e0..85a962e2f 100644
--- a/conans/test/functional/toolchains/apple/test_xcodedeps_components.py
+++ b/conans/test/functional/toolchains/apple/test_xcodedeps_components.py
@@ -105,10 +105,10 @@ def test_xcodedeps_components():
         self.cpp_info.components["core"].includedirs.append("include")
         self.cpp_info.components["core"].libdirs.append("lib")
 
-        self.cpp_info.components["client"].libs = ["client"]
-        self.cpp_info.components["client"].includedirs.append("include")
-        self.cpp_info.components["client"].libdirs.append("lib")
-        self.cpp_info.components["client"].requires.extend(["core", "tcp::tcp"])
+        self.cpp_info.components["client-test"].libs = ["client"]
+        self.cpp_info.components["client-test"].includedirs.append("include")
+        self.cpp_info.components["client-test"].libdirs.append("lib")
+        self.cpp_info.components["client-test"].requires.extend(["core", "tcp::tcp"])
 
         self.cpp_info.components["server"].libs = ["server"]
         self.cpp_info.components["server"].includedirs.append("include")
@@ -136,7 +136,7 @@ def test_xcodedeps_components():
         self.cpp_info.libs = ["chat"]
         self.cpp_info.includedirs.append("include")
         self.cpp_info.libdirs.append("lib")
-        self.cpp_info.requires.append("network::client")
+        self.cpp_info.requires.append("network::client-test")
     """
 
     cmakelists_chat = textwrap.dedent("""
@@ -146,7 +146,7 @@ def test_xcodedeps_components():
         add_library(chat src/chat.cpp include/chat.h)
         target_include_directories(chat PUBLIC include)
         set_target_properties(chat PROPERTIES PUBLIC_HEADER "include/chat.h")
-        target_link_libraries(chat network::client)
+        target_link_libraries(chat network::client-test)
         install(TARGETS chat)
         """)
 
@@ -184,7 +184,7 @@ def test_xcodedeps_components():
     client.run("install chat/1.0@ -g XcodeDeps --install-folder=conan -s build_type=Debug "
                "--build=missing")
     chat_xcconfig = client.load(os.path.join("conan", "conan_chat_chat.xcconfig"))
-    assert '#include "conan_network_client.xcconfig"' in chat_xcconfig
+    assert '#include "conan_network_client_test.xcconfig"' in chat_xcconfig
     assert '#include "conan_network_server.xcconfig"' not in chat_xcconfig
     assert '#include "conan_network_network.xcconfig"' not in chat_xcconfig
     host_arch = client.get_default_host_profile().settings['arch']
diff --git a/conans/test/integration/layout/test_layout_generate.py b/conans/test/integration/layout/test_layout_generate.py
new file mode 100644
index 000000000..e5d59b213
--- /dev/null
+++ b/conans/test/integration/layout/test_layout_generate.py
@@ -0,0 +1,50 @@
+import os
+import textwrap
+
+from conans.test.utils.tools import TestClient
+
+
+def test_layout_generate():
+    """ Trying to leverage the layout knowledge at generate() time and put some files
+    in the bindirs folders where executables will be built, like some dll from other
+    dependencies.
+    https://github.com/conan-io/conan/issues/12003
+    """
+    c = TestClient()
+    conanfile = textwrap.dedent("""
+        import os
+        from conan import ConanFile
+        from conan.tools.files import save, load
+        class Pkg(ConanFile):
+            name = "pkg"
+            version = "1.0"
+            def layout(self):
+                self.folders.build = "mybuild"
+                self.folders.generators = "mybuild/generators"
+                self.cpp.build.bindirs = ["bin"]
+                self.cpp.build.libdirs = ["lib"]
+                self.cpp.build.includedirs = ["include"]
+            def generate(self):
+                f = os.path.join(self.build_folder, self.cpp.build.bindir, "myfile.txt")
+                save(self, f, "mybin!!!")
+                f = os.path.join(self.build_folder, self.cpp.build.libdir, "myfile.txt")
+                save(self, f, "mylib!!!")
+                f = os.path.join(self.build_folder, self.cpp.build.includedir, "myfile.txt")
+                save(self, f, "myinclude!!!")
+
+            def build(self):
+                self.output.info(load(self, os.path.join(self.cpp.build.libdir, "myfile.txt")))
+                self.output.info(load(self, os.path.join(self.cpp.build.bindir, "myfile.txt")))
+                self.output.info(load(self, os.path.join(self.cpp.build.includedir, "myfile.txt")))
+        """)
+    c.save({"conanfile.py": conanfile})
+    c.run("create . ")
+    assert "pkg/1.0: mybin!!!" in c.out
+    assert "pkg/1.0: mylib!!!" in c.out
+    assert "pkg/1.0: myinclude!!!" in c.out
+    c.run("install .")
+    assert os.path.exists(os.path.join(c.current_folder, "mybuild", "bin", "myfile.txt"))
+    assert os.path.exists(os.path.join(c.current_folder, "mybuild", "lib", "myfile.txt"))
+    assert os.path.exists(os.path.join(c.current_folder, "mybuild", "include", "myfile.txt"))
+
+
diff --git a/conans/test/integration/settings/remove_subsetting_test.py b/conans/test/integration/settings/remove_subsetting_test.py
index 5c8e6d8a2..209838e1b 100644
--- a/conans/test/integration/settings/remove_subsetting_test.py
+++ b/conans/test/integration/settings/remove_subsetting_test.py
@@ -1,4 +1,5 @@
 import os
+import textwrap
 import unittest
 
 from conans.test.utils.tools import TestClient
@@ -144,3 +145,57 @@ class ConanLib(ConanFile):
         client.run("package .")
         self.assertIn("ERROR: PACKAGE 'settings.compiler.libcxx' doesn't exist for 'gcc'",
                       client.out)
+
+
+def test_settings_and_options_rm_safe():
+    client = TestClient()
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+    class Pkg(ConanFile):
+        settings = "os", "build_type", "compiler"
+        options = {"opt1": [True, False], "opt2": [True, False]}
+        default_options = "opt1=True", "opt2=False"
+
+        def configure(self):
+            # setting
+            self.settings.rm_safe("build_type")
+            # sub-setting
+            self.settings.rm_safe("compiler.version")
+            # wrong settings
+            self.settings.rm_safe("fake_field")
+            self.settings.rm_safe("fake_field.version")
+
+        def config_options(self):
+            # option
+            self.options.rm_safe("opt2")
+            # wrong option
+            self.options.rm_safe("opt15")
+
+        def build(self):
+            try:
+                self.settings.build_type
+            except Exception as exc:
+                self.output.warn(str(exc))
+            try:
+                self.settings.compiler.version
+            except Exception as exc:
+                self.output.warn(str(exc))
+            try:
+                self.options.opt2
+            except Exception as exc:
+                self.output.warn(str(exc))
+            assert "opt2" not in self.options
+    """)
+    client.save({"conanfile.py": conanfile})
+    build_folder = os.path.join(client.current_folder, "build")
+    mkdir(build_folder)
+    client.current_folder = build_folder
+
+    client.run("install ..")
+    client.run("build ..")
+    assert "'settings.build_type' doesn't exist" in client.out
+    assert "'settings' possible configurations are ['compiler', 'os']" in client.out
+    assert "'settings.compiler.version' doesn't exist" in client.out
+    assert "'settings.compiler' possible configurations are [" in client.out
+    assert "option 'opt2' doesn't exist" in client.out
+    assert "Possible options are ['opt1']" in client.out
diff --git a/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py b/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
index 8b6f35791..2b6382672 100644
--- a/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
+++ b/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
@@ -227,7 +227,6 @@ def test_find_builddirs():
 
                 def generate(self):
                     cmake = CMakeToolchain(self)
-                    {}
                     cmake.generate()
             """)
 
@@ -237,6 +236,30 @@ def test_find_builddirs():
         contents = f.read()
         assert "/path/to/builddir" in contents
 
+    conanfile = textwrap.dedent("""
+       import os
+       from conans import ConanFile
+       from conan.tools.cmake import CMakeToolchain
+
+       class Conan(ConanFile):
+           name = "mydep"
+           version = "1.0"
+           settings = "os", "arch", "compiler", "build_type"
+
+           def build_requirements(self):
+               self.test_requires("dep/1.0")
+
+           def generate(self):
+               cmake = CMakeToolchain(self)
+               cmake.generate()
+       """)
+
+    client.save({"conanfile.py": conanfile})
+    client.run("install . ")
+    with open(os.path.join(client.current_folder, "conan_toolchain.cmake")) as f:
+        contents = f.read()
+        assert "/path/to/builddir" in contents
+
 
 @pytest.mark.skipif(platform.system() != "Darwin", reason="Only OSX")
 def test_cmaketoolchain_cmake_system_processor_cross_apple():
@@ -447,17 +470,22 @@ def test_cmake_presets_singleconfig():
 def test_toolchain_cache_variables():
     client = TestClient()
     conanfile = textwrap.dedent("""
-        from conans import ConanFile
-        from conan.tools.cmake import CMakeToolchain, CMake
+        from conan import ConanFile
+        from conan.tools.cmake import CMakeToolchain
 
         class Conan(ConanFile):
             settings = "os", "arch", "compiler", "build_type"
+            options = {"enable_foobar": [True, False], "qux": ["ANY"], "number": [1,2]}
+            default_options = {"enable_foobar": True, "qux": "baz", "number": 1}
 
             def generate(self):
                 toolchain = CMakeToolchain(self)
                 toolchain.cache_variables["foo"] = True
                 toolchain.cache_variables["foo2"] = False
                 toolchain.cache_variables["var"] = "23"
+                toolchain.cache_variables["ENABLE_FOOBAR"] = self.options.enable_foobar
+                toolchain.cache_variables["QUX"] = self.options.qux
+                toolchain.cache_variables["NUMBER"] = self.options.number
                 toolchain.cache_variables["CMAKE_SH"] = "THIS VALUE HAS PRIORITY"
                 toolchain.cache_variables["CMAKE_POLICY_DEFAULT_CMP0091"] = "THIS VALUE HAS PRIORITY"
                 toolchain.cache_variables["CMAKE_MAKE_PROGRAM"] = "THIS VALUE HAS NO PRIORITY"
@@ -476,6 +504,9 @@ def test_toolchain_cache_variables():
     assert cache_variables["CMAKE_POLICY_DEFAULT_CMP0091"] == "THIS VALUE HAS PRIORITY"
     assert cache_variables["CMAKE_MAKE_PROGRAM"] == "MyMake"
     assert cache_variables["BUILD_TESTING"] == 'OFF'
+    assert cache_variables["ENABLE_FOOBAR"] == 'ON'
+    assert cache_variables["QUX"] == 'baz'
+    assert cache_variables["NUMBER"] == 1
 
 
 def test_android_c_library():
diff --git a/conans/test/unittests/client/build/cpp_std_flags_test.py b/conans/test/unittests/client/build/cpp_std_flags_test.py
index 078663845..79d60d674 100644
--- a/conans/test/unittests/client/build/cpp_std_flags_test.py
+++ b/conans/test/unittests/client/build/cpp_std_flags_test.py
@@ -147,6 +147,10 @@ class CompilerFlagsTest(unittest.TestCase):
         self.assertEqual(_make_cppstd_default("clang", "10"), "gnu14")
         self.assertEqual(_make_cppstd_default("clang", "11"), "gnu14")
         self.assertEqual(_make_cppstd_default("clang", "12"), "gnu14")
+        self.assertEqual(_make_cppstd_default("clang", "13"), "gnu14")
+        self.assertEqual(_make_cppstd_default("clang", "14"), "gnu14")
+        self.assertEqual(_make_cppstd_default("clang", "15"), "gnu14")
+        self.assertEqual(_make_cppstd_default("clang", "16"), "gnu17")
 
     def test_apple_clang_cppstd_flags(self):
         self.assertEqual(_make_cppstd_flag("apple-clang", "3.9", "98"), None)