Repository: conan-io/conan
Pull request #12269 (2022-10-07 14:59:05)

Add stdcpp_library to conan.tools.build
Changelog: Add stdcpp_library to conan.tools.build to get name of C++ standard library to be linked.
Docs: https://github.com/conan-io/docs/pull/XXXX

Close https://github.com/conan-io/conan/issues/11912


Patch:
diff --git a/conan/tools/build/__init__.py b/conan/tools/build/__init__.py
index c7a2e667b..829886a8d 100644
--- a/conan/tools/build/__init__.py
+++ b/conan/tools/build/__init__.py
@@ -2,3 +2,4 @@ from conan.tools.build.cpu import build_jobs
 from conan.tools.build.cross_building import cross_building, can_run
 from conan.tools.build.cppstd import check_min_cppstd, valid_min_cppstd, default_cppstd, \
     supported_cppstd
+from conan.tools.build.stdcpp_library import stdcpp_library
diff --git a/conan/tools/build/stdcpp_library.py b/conan/tools/build/stdcpp_library.py
new file mode 100644
index 000000000..646f1cfc0
--- /dev/null
+++ b/conan/tools/build/stdcpp_library.py
@@ -0,0 +1,16 @@
+
+def stdcpp_library(conanfile):
+    """ Returns the name of the C++ standard library that can be passed
+    to the linker, based on the current settings. Returs None if the name 
+    of the C++ standard library file is not known.
+    """
+    libcxx = conanfile.settings.get_safe("compiler.libcxx")
+    if libcxx in ["libstdc++", "libstdc++11"]:
+        return "stdc++"
+    elif libcxx in ["libc++"]:
+        return "c++"
+    elif libcxx in ["c++_shared"]:
+        return "c++_shared"
+    elif libcxx in ["c++_static"]:
+        return "c++_static"
+    return None
diff --git a/conans/client/cmd/uploader.py b/conans/client/cmd/uploader.py
index f4e02f9cf..cf1f91024 100644
--- a/conans/client/cmd/uploader.py
+++ b/conans/client/cmd/uploader.py
@@ -109,7 +109,14 @@ class _UploadCollecter(object):
 
                 # TODO: This search of binary packages has to be improved, more robust
                 # So only real packages are retrieved
-                if all_packages or query:
+                if conanfile.upload_policy == "skip":
+                    # TODO: This build_policy CANNOT be conditional, so all binaries will be skipped
+                    #   this could be a future feature, but will require annotating/metadata of the
+                    #   binaries created with this policy value for each binary
+                    self._output.info("{}: Skipping upload of binaries, because "
+                                      "upload_policy='skip'".format(ref))
+                    packages_ids = []
+                elif all_packages or query:
                     if all_packages:
                         query = None
                     # better to do a search, that will retrieve real packages with ConanInfo
diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py
index 4e09e5f40..d3dcae176 100644
--- a/conans/model/conan_file.py
+++ b/conans/model/conan_file.py
@@ -110,6 +110,7 @@ class ConanFile(object):
     topics = None
     homepage = None
     build_policy = None
+    upload_policy = None
     short_paths = False
     apply_env = True  # Apply environment variables from requires deps_env_info and profiles
     exports = None


Test patch:
diff --git a/conans/test/functional/only_source_test.py b/conans/test/functional/only_source_test.py
index a3d64afd0..8a769cbcd 100644
--- a/conans/test/functional/only_source_test.py
+++ b/conans/test/functional/only_source_test.py
@@ -163,3 +163,23 @@ class MyPackage(ConanFile):
 
         other_client.run("install %s" % str(ref))
         self.assertNotIn("Copying sources to build folder", other_client.out)
+
+
+def test_build_policy_installer():
+    c = TestClient(default_server_user=True)
+    conanfile = GenConanfile("pkg", "1.0").with_class_attribute('build_policy = "missing"')\
+                                          .with_class_attribute('upload_policy = "skip"')
+    c.save({"conanfile.py": conanfile})
+    c.run("export .")
+    c.run("install pkg/1.0@")
+    assert "pkg/1.0: Calling build()" in c.out
+    assert "pkg/1.0: Building package from source as defined by build_policy='missing'" in c.out
+
+    # If binary already there it should do nothing
+    c.run("install pkg/1.0@")
+    assert "pkg/1.0: Calling build()" not in c.out
+    assert "pkg/1.0: Building package from source" not in c.out
+
+    c.run("upload * -r=default -c --all")
+    assert "Uploading package" not in c.out
+    assert "pkg/1.0: Skipping upload of binaries, because upload_policy='skip'" in c.out
diff --git a/conans/test/unittests/tools/build/test_stdcpp_library.py b/conans/test/unittests/tools/build/test_stdcpp_library.py
new file mode 100644
index 000000000..563284da8
--- /dev/null
+++ b/conans/test/unittests/tools/build/test_stdcpp_library.py
@@ -0,0 +1,18 @@
+import pytest
+from conan.tools.build import stdcpp_library
+from conans.test.utils.mocks import MockSettings, MockConanfile
+
+
+@pytest.mark.parametrize("libcxx,expected_library", [
+    ("libstdc++", "stdc++"),
+    ("libstdc++11", "stdc++"),
+    ("libc++", "c++"),
+    ("c++_shared", "c++_shared"), 
+    ("c++_static", "c++_static"),
+    ("foobar", None)
+])
+def test_stdcpp_library(libcxx, expected_library):
+    settings = MockSettings({"compiler.libcxx": libcxx})
+    conanfile = MockConanfile(settings)
+
+    assert stdcpp_library(conanfile) == expected_library