Repository: conan-io/conan
Pull request #17230 (2024-10-28 08:22:01)

Test to show that a static-library recipe won't change its pkg_type when header_only option is used
Changelog: Omit
Docs: Omit

For https://github.com/conan-io/conan-center-index/pull/25741/, which tries just this pattern.
Maybe we could issue a warning at some point here, but for now this test validates the current behaviour


Patch:
diff --git a/conans/model/pkg_type.py b/conans/model/pkg_type.py
index 29c207952..d850d03d4 100644
--- a/conans/model/pkg_type.py
+++ b/conans/model/pkg_type.py
@@ -58,6 +58,11 @@ class PackageType(Enum):
                 if conanfile_type is PackageType.UNKNOWN:
                     raise ConanException(f"{conanfile}: Package type is 'library',"
                                          " but no 'shared' option declared")
+            elif any(option in conanfile.options for option in ["shared", "header_only"]):
+                conanfile.output.warning(f"{conanfile}: package_type '{conanfile_type}' is defined, "
+                                         "but 'shared' and/or 'header_only' options are present. "
+                                         "The package_type will have precedence over the options "
+                                         "regardless of their value.")
             conanfile.package_type = conanfile_type
         else:  # automatic default detection with option shared/header-only
             conanfile.package_type = deduce_from_options()


Test patch:
diff --git a/test/integration/graph/core/test_auto_package_type.py b/test/integration/graph/core/test_auto_package_type.py
index 01db28fe8..9e12c11cc 100644
--- a/test/integration/graph/core/test_auto_package_type.py
+++ b/test/integration/graph/core/test_auto_package_type.py
@@ -1,3 +1,5 @@
+import textwrap
+
 import pytest
 
 from conan.test.utils.tools import TestClient
@@ -36,6 +38,7 @@ def test_auto_package_type(conanfile):
     c.run("graph info . --filter package_type")
     assert "package_type: static-library" in c.out
     c.run("graph info . --filter package_type -o shared=True")
+    assert "The package_type will have precedence over the options" not in c.out
     assert "package_type: shared-library" in c.out
     c.run("graph info . --filter package_type -o shared=True -o header_only=False")
     assert "package_type: shared-library" in c.out
@@ -43,3 +46,21 @@ def test_auto_package_type(conanfile):
     assert "package_type: header-library" in c.out
     c.run("graph info . --filter package_type -o header_only=True -o shared=False")
     assert "package_type: header-library" in c.out
+
+def test_package_type_and_header_library():
+    """ Show that forcing a package_type and header_only=True does not change the package_type"""
+    tc = TestClient(light=True)
+    tc.save({"conanfile.py": textwrap.dedent("""
+    from conan import ConanFile
+
+    class Pkg(ConanFile):
+        package_type = "static-library"
+        options = {"header_only": [True, False]}
+
+    """)})
+    tc.run("graph info . --filter package_type -o &:header_only=False")
+    assert "package_type: static-library" in tc.out
+    assert "The package_type will have precedence over the options" in tc.out
+    tc.run("graph info . --filter package_type -o &:header_only=True")
+    assert "package_type: static-library" in tc.out
+    assert "The package_type will have precedence over the options" in tc.out
diff --git a/test/integration/py_requires/python_requires_test.py b/test/integration/py_requires/python_requires_test.py
index 007ed086d..ac032298a 100644
--- a/test/integration/py_requires/python_requires_test.py
+++ b/test/integration/py_requires/python_requires_test.py
@@ -832,6 +832,49 @@ class PyRequiresExtendTest(unittest.TestCase):
         assert "OptionBASE: True" in c.out
         assert "OptionDERIVED: False" in c.out
 
+    def test_options_default_update(self):
+        c = TestClient(light=True)
+        base = textwrap.dedent("""
+            from conan import ConanFile
+            class BaseConan:
+                options = {"base": [True, False]}
+                default_options = {"base": True}
+
+            class PyReq(ConanFile):
+                name = "base"
+                version = "1.0.0"
+                package_type = "python-require"
+                """)
+        derived = textwrap.dedent("""
+            import conan
+
+            class DerivedConan(conan.ConanFile):
+                name = "derived"
+                python_requires = "base/1.0.0"
+                python_requires_extend = "base.BaseConan"
+                options = {"derived": [True, False]}
+                default_options = {"derived": False}
+
+                def init(self):
+                    base = self.python_requires["base"].module.BaseConan
+                    self.options.update(base.options, base.default_options)
+                    self.options.base = False
+
+                def generate(self):
+                    self.output.info(f"OptionBASE: {self.options.base}")
+                    self.output.info(f"OptionDERIVED: {self.options.derived}")
+            """)
+        c.save({"base/conanfile.py": base,
+                "derived/conanfile.py": derived})
+        c.run("create base")
+        c.run("install derived")
+        assert "OptionBASE: False" in c.out
+        assert "OptionDERIVED: False" in c.out
+
+        c.run("install derived -o=&:base=True")
+        assert "OptionBASE: True" in c.out
+        assert "OptionDERIVED: False" in c.out
+
 
 def test_transitive_python_requires():
     # https://github.com/conan-io/conan/issues/8546