Skip to content

Commit 3b9c36a

Browse files
committed
Support TOML lists in cmake.define
Fixes #874
1 parent 7636e7b commit 3b9c36a

File tree

5 files changed

+86
-7
lines changed

5 files changed

+86
-7
lines changed

src/scikit_build_core/builder/builder.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,7 @@ def configure(
245245
cmake_defines["CMAKE_OSX_ARCHITECTURES"] = ";".join(archs)
246246

247247
# Add the pre-defined or passed CMake defines
248-
cmake_defines.update(
249-
{
250-
k: ("TRUE" if v else "FALSE") if isinstance(v, bool) else v
251-
for k, v in self.settings.cmake.define.items()
252-
}
253-
)
248+
cmake_defines.update(self.settings.cmake.define)
254249

255250
self.config.configure(
256251
defines=cmake_defines,

src/scikit_build_core/settings/skbuild_model.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ def __dir__() -> List[str]:
2727
return __all__
2828

2929

30+
class CMakeSettingsDefine(str):
31+
def __new__(cls, raw: Union[str, bool, List[str]]) -> "CMakeSettingsDefine":
32+
def escape_semicolons(item: str) -> str:
33+
return item.replace(";", r"\;")
34+
35+
if isinstance(raw, bool):
36+
value = "TRUE" if raw else "FALSE"
37+
elif isinstance(raw, list):
38+
value = ";".join(map(escape_semicolons, raw))
39+
else:
40+
value = raw
41+
42+
return super().__new__(cls, value)
43+
44+
3045
@dataclasses.dataclass
3146
class CMakeSettings:
3247
minimum_version: Optional[Version] = None
@@ -49,7 +64,7 @@ class CMakeSettings:
4964
in config or envvar will override toml. See also ``cmake.define``.
5065
"""
5166

52-
define: Annotated[Dict[str, Union[str, bool]], "EnvVar"] = dataclasses.field(
67+
define: Annotated[Dict[str, CMakeSettingsDefine], "EnvVar"] = dataclasses.field(
5368
default_factory=dict
5469
)
5570
"""
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
cmake_minimum_required(VERSION 3.26)
2+
project(cmake_defines LANGUAGES NONE)
3+
4+
set(ONE_LEVEL_LIST
5+
""
6+
CACHE STRING "")
7+
set(NESTED_LIST
8+
""
9+
CACHE STRING "")
10+
11+
set(out_file "${CMAKE_CURRENT_BINARY_DIR}/log.txt")
12+
file(WRITE "${out_file}" "")
13+
14+
foreach(list IN ITEMS ONE_LEVEL_LIST NESTED_LIST)
15+
list(LENGTH ${list} length)
16+
file(APPEND "${out_file}" "${list}.LENGTH = ${length}\n")
17+
foreach(item IN LISTS ${list})
18+
file(APPEND "${out_file}" "${item}\n")
19+
endforeach()
20+
endforeach()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[tool.scikit-build]
2+
cmake.version = '>=3.26'
3+
4+
[tool.scikit-build.cmake.define]
5+
ONE_LEVEL_LIST = [
6+
"Foo",
7+
"Bar",
8+
"ExceptionallyLargeListEntryThatWouldOverflowTheLine",
9+
"Baz",
10+
]
11+
NESTED_LIST = [ "Apple", "Lemon;Lime", "Banana" ]

tests/test_cmake_config.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44
import shutil
55
import sysconfig
66
from pathlib import Path
7+
from textwrap import dedent
78
from typing import TYPE_CHECKING
89

910
import pytest
1011
from packaging.specifiers import SpecifierSet
1112
from packaging.version import Version
1213

14+
from scikit_build_core.builder.builder import Builder
1315
from scikit_build_core.cmake import CMake, CMaker
1416
from scikit_build_core.errors import CMakeNotFoundError
17+
from scikit_build_core.settings.skbuild_read_settings import SettingsReader
1518

1619
if TYPE_CHECKING:
1720
from collections.abc import Generator
@@ -201,6 +204,41 @@ def test_cmake_paths(
201204
assert len(fp.calls) == 2
202205

203206

207+
@pytest.mark.configure
208+
def test_cmake_defines(
209+
tmp_path: Path,
210+
):
211+
source_dir = DIR / "packages" / "cmake_defines"
212+
binary_dir = tmp_path / "build"
213+
214+
config = CMaker(
215+
CMake.default_search(),
216+
source_dir=source_dir,
217+
build_dir=binary_dir,
218+
build_type="Release",
219+
)
220+
221+
reader = SettingsReader.from_file(source_dir / "pyproject.toml")
222+
223+
builder = Builder(reader.settings, config)
224+
builder.configure(defines={})
225+
226+
configure_log = Path.read_text(binary_dir / "log.txt")
227+
assert configure_log == dedent(
228+
"""\
229+
ONE_LEVEL_LIST.LENGTH = 4
230+
Foo
231+
Bar
232+
ExceptionallyLargeListEntryThatWouldOverflowTheLine
233+
Baz
234+
NESTED_LIST.LENGTH = 3
235+
Apple
236+
Lemon;Lime
237+
Banana
238+
"""
239+
)
240+
241+
204242
def test_get_cmake_via_envvar(monkeypatch: pytest.MonkeyPatch, fp):
205243
monkeypatch.setattr("shutil.which", lambda x: x)
206244
cmake_path = Path("some-prog")

0 commit comments

Comments
 (0)