Repository: scikit-build/scikit-build-core
Pull request #432 (2023-07-16 21:49:55)

feat: add build target support
Adding build target support.



Patch:
diff --git a/README.md b/README.md
index 9175854..ebe569e 100644
--- a/README.md
+++ b/README.md
@@ -137,6 +137,9 @@ cmake.verbose = false
 # This controls the CMake build type
 cmake.build-type = "Release"
 
+# The targets to build - empty builds all default targets.
+cmake.targets = []
+
 # Display logs at or above this level.
 logging.level = "WARNING"
 
diff --git a/docs/configuration.md b/docs/configuration.md
index 43e0766..6b88883 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -229,11 +229,53 @@ wheel.expand-macos-universal-tags = false
 
 You can select only specific components to install:
 
+````{tab} pyproject.toml
+
 ```toml
 [tool.scikit-build]
 install.components = ["python"]
 ```
 
+````
+
+`````{tab} config-settings
+
+
+````{tab} pip
+
+```console
+$ pip install . --config-settings=install.components=python
+```
+
+````
+
+````{tab} build
+
+```console
+$ pipx run build --wheel -Cinstall.components=python
+```
+
+````
+
+````{tab} cibuildwheel
+
+```toml
+[tool.cibuildwheel.config-settings]
+"install.components" = "python"
+```
+
+````
+
+`````
+
+````{tab} Environment
+
+```yaml
+SKBUILD_INSTALL_COMPONENTS: python
+```
+
+````
+
 And you can turn off binary stripping:
 
 ```toml
@@ -343,7 +385,7 @@ SKBUILD_CMAKE_DEFINES: SOME_DEFINE=ON
 
 ````
 
-You can also manually specify the exact cmake args. Beyond the normal
+You can also manually specify the exact CMake args. Beyond the normal
 `SKBUILD_CMAKE_ARGS`, the `CMAKE_ARGS` space-separated environment variable is
 also supported (with some filtering for options scikit-build-core doesn't
 support overriding).
@@ -399,6 +441,56 @@ CMAKE_ARGS: -DSOME_DEFINE=ON -DOTHER=OFF
 
 ````
 
+You can also specify only specific targets to build (leaving this off builds the
+default targets):
+
+````{tab} pyproject.toml
+
+```toml
+[tool.scikit-build]
+cmake.targets = ["python"]
+```
+
+````
+
+`````{tab} config-settings
+
+
+````{tab} pip
+
+```console
+$ pip install . --config-settings=cmake.targets=python
+```
+
+````
+
+````{tab} build
+
+```console
+$ pipx run build --wheel -Ccmake.targets=python
+```
+
+````
+
+````{tab} cibuildwheel
+
+```toml
+[tool.cibuildwheel.config-settings]
+"cmake.targets" = "python"
+```
+
+````
+
+`````
+
+````{tab} Environment
+
+```yaml
+SKBUILD_CMAKE_TARGETS: python
+```
+
+````
+
 ## Dynamic metadata
 
 Scikit-build-core 0.3.0 supports dynamic metadata with two built-in plugins.
diff --git a/src/scikit_build_core/builder/builder.py b/src/scikit_build_core/builder/builder.py
index e4aff95..69d1b59 100644
--- a/src/scikit_build_core/builder/builder.py
+++ b/src/scikit_build_core/builder/builder.py
@@ -188,7 +188,11 @@ class Builder:
         )
 
     def build(self, build_args: list[str]) -> None:
-        self.config.build(build_args=build_args, verbose=self.settings.cmake.verbose)
+        self.config.build(
+            build_args=build_args,
+            targets=self.settings.cmake.targets,
+            verbose=self.settings.cmake.verbose,
+        )
 
     def install(self, install_dir: Path) -> None:
         components = self.settings.install.components
diff --git a/src/scikit_build_core/cmake.py b/src/scikit_build_core/cmake.py
index 95309c3..996d060 100644
--- a/src/scikit_build_core/cmake.py
+++ b/src/scikit_build_core/cmake.py
@@ -209,13 +209,24 @@ class CMaker:
             yield "--config"
             yield self.build_type
 
-    def build(self, build_args: Sequence[str] = (), *, verbose: bool = False) -> None:
+    def build(
+        self,
+        build_args: Sequence[str] = (),
+        *,
+        targets: Sequence[str] = (),
+        verbose: bool = False,
+    ) -> None:
         local_args = self._compute_build_args(verbose=verbose)
+        if not targets:
+            self._build(*local_args, *build_args)
+            return
 
+        for target in targets:
+            self._build(*local_args, "--target", target, *build_args)
+
+    def _build(self, *args: str) -> None:
         try:
-            Run(env=self.env).live(
-                self.cmake, "--build", self.build_dir, *build_args, *local_args
-            )
+            Run(env=self.env).live(self.cmake, "--build", self.build_dir, *args)
         except subprocess.CalledProcessError:
             msg = "CMake build failed"
             raise FailedLiveProcessError(msg) from None
@@ -223,7 +234,7 @@ class CMaker:
     def install(
         self, prefix: Path, *, strip: bool = False, components: Sequence[str] = ()
     ) -> None:
-        opts: list[str] = ["--prefix", str(prefix)]
+        opts = ["--prefix", str(prefix)]
         if not self.single_config and self.build_type:
             opts += ["--config", self.build_type]
         if strip:
diff --git a/src/scikit_build_core/settings/skbuild_model.py b/src/scikit_build_core/settings/skbuild_model.py
index 074231f..0a05850 100644
--- a/src/scikit_build_core/settings/skbuild_model.py
+++ b/src/scikit_build_core/settings/skbuild_model.py
@@ -48,10 +48,14 @@ class CMakeSettings:
     #: "", etc.
     build_type: str = "Release"
 
-    #: The source directory to use when building the project. Currently only affects
-    #: the native builder (not the setuptools plugin).
+    #: The source directory to use when building the project. Currently only
+    #: affects the native builder (not the setuptools plugin).
     source_dir: str = ""
 
+    #: The build targets to use when building the project. Empty builds the
+    #: default target.
+    targets: List[str] = dataclasses.field(default_factory=list)
+
 
 @dataclasses.dataclass
 class LoggingSettings:


Test patch:
diff --git a/tests/test_pyproject_pep517.py b/tests/test_pyproject_pep517.py
index 475d126..a351da6 100644
--- a/tests/test_pyproject_pep517.py
+++ b/tests/test_pyproject_pep517.py
@@ -148,7 +148,7 @@ def test_pep517_sdist_time_hash_set_epoch(
 @pytest.mark.usefixtures("package_simple_pyproject_ext")
 def test_pep517_wheel(virtualenv):
     dist = Path("dist")
-    out = build_wheel("dist")
+    out = build_wheel("dist", {"cmake.targets": ["cmake_example"]})  # Could leave empty
     (wheel,) = dist.glob("cmake_example-0.0.1-*.whl")
     assert wheel == dist / out
 
diff --git a/tests/test_skbuild_settings.py b/tests/test_skbuild_settings.py
index 21eeefd..71ed0db 100644
--- a/tests/test_skbuild_settings.py
+++ b/tests/test_skbuild_settings.py
@@ -30,6 +30,7 @@ def test_skbuild_settings_default(tmp_path):
     assert not settings.cmake.verbose
     assert settings.cmake.build_type == "Release"
     assert not settings.cmake.source_dir
+    assert settings.cmake.targets == []
     assert settings.logging.level == "WARNING"
     assert settings.sdist.include == []
     assert settings.sdist.exclude == []
@@ -68,6 +69,7 @@ def test_skbuild_settings_envvar(tmp_path, monkeypatch):
     monkeypatch.setenv("SKBUILD_CMAKE_DEFINE", "a=1;b=2")
     monkeypatch.setenv("SKBUILD_CMAKE_BUILD_TYPE", "Debug")
     monkeypatch.setenv("SKBUILD_CMAKE_SOURCE_DIR", "a/b/c")
+    monkeypatch.setenv("SKBUILD_CMAKE_TARGETS", "a;b;c")
     monkeypatch.setenv("SKBUILD_LOGGING_LEVEL", "DEBUG")
     monkeypatch.setenv("SKBUILD_SDIST_INCLUDE", "a;b; c")
     monkeypatch.setenv("SKBUILD_SDIST_EXCLUDE", "d;e;f")
@@ -103,6 +105,7 @@ def test_skbuild_settings_envvar(tmp_path, monkeypatch):
     assert settings.cmake.verbose
     assert settings.cmake.build_type == "Debug"
     assert settings.cmake.source_dir == "a/b/c"
+    assert settings.cmake.targets == ["a", "b", "c"]
     assert not settings.ninja.make_fallback
     assert settings.logging.level == "DEBUG"
     assert settings.sdist.include == ["a", "b", "c"]
@@ -143,6 +146,7 @@ def test_skbuild_settings_config_settings(tmp_path, monkeypatch):
         "cmake.verbose": "true",
         "cmake.build-type": "Debug",
         "cmake.source-dir": "a/b/c",
+        "cmake.targets": ["a", "b", "c"],
         "logging.level": "INFO",
         "sdist.include": ["a", "b", "c"],
         "sdist.exclude": "d;e;f",
@@ -175,6 +179,7 @@ def test_skbuild_settings_config_settings(tmp_path, monkeypatch):
     assert settings.cmake.verbose
     assert settings.cmake.build_type == "Debug"
     assert settings.cmake.source_dir == "a/b/c"
+    assert settings.cmake.targets == ["a", "b", "c"]
     assert settings.logging.level == "INFO"
     assert settings.sdist.include == ["a", "b", "c"]
     assert settings.sdist.exclude == ["d", "e", "f"]
@@ -213,6 +218,7 @@ def test_skbuild_settings_pyproject_toml(tmp_path, monkeypatch):
             cmake.build-type = "Debug"
             cmake.verbose = true
             cmake.source-dir = "a/b/c"
+            cmake.targets = ["a", "b", "c"]
             logging.level = "ERROR"
             sdist.include = ["a", "b", "c"]
             sdist.exclude = ["d", "e", "f"]
@@ -251,6 +257,7 @@ def test_skbuild_settings_pyproject_toml(tmp_path, monkeypatch):
     assert settings.cmake.verbose
     assert settings.cmake.build_type == "Debug"
     assert settings.cmake.source_dir == "a/b/c"
+    assert settings.cmake.targets == ["a", "b", "c"]
     assert settings.logging.level == "ERROR"
     assert settings.sdist.include == ["a", "b", "c"]
     assert settings.sdist.exclude == ["d", "e", "f"]