Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support TOML lists in cmake.define #921

Merged
merged 12 commits into from
Oct 2, 2024
7 changes: 1 addition & 6 deletions src/scikit_build_core/builder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,7 @@ def configure(
cmake_defines["CMAKE_OSX_ARCHITECTURES"] = ";".join(archs)

# Add the pre-defined or passed CMake defines
cmake_defines.update(
{
k: ("TRUE" if v else "FALSE") if isinstance(v, bool) else v
for k, v in self.settings.cmake.define.items()
}
)
cmake_defines.update(self.settings.cmake.define)

self.config.configure(
defines=cmake_defines,
Expand Down
12 changes: 12 additions & 0 deletions src/scikit_build_core/resources/scikit-build.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
},
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
Expand All @@ -58,6 +64,12 @@
},
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
Expand Down
2 changes: 2 additions & 0 deletions src/scikit_build_core/settings/json_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ def convert_type(t: Any, *, normalize_keys: bool) -> dict[str, Any]:
}
if origin is Literal:
return {"enum": list(args)}
if hasattr(t, "json_schema"):
return convert_type(t.json_schema, normalize_keys=normalize_keys)

msg = f"Cannot convert type {t} to JSON Schema"
raise FailedConversionError(msg)
19 changes: 18 additions & 1 deletion src/scikit_build_core/settings/skbuild_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ def __dir__() -> List[str]:
return __all__


class CMakeSettingsDefine(str):
json_schema = Union[str, bool, List[str]]
LecrisUT marked this conversation as resolved.
Show resolved Hide resolved

def __new__(cls, raw: Union[str, bool, List[str]]) -> "CMakeSettingsDefine":
def escape_semicolons(item: str) -> str:
return item.replace(";", r"\;")

if isinstance(raw, bool):
value = "TRUE" if raw else "FALSE"
elif isinstance(raw, list):
value = ";".join(map(escape_semicolons, raw))
else:
value = raw

return super().__new__(cls, value)


@dataclasses.dataclass
class CMakeSettings:
minimum_version: Optional[Version] = None
Expand All @@ -49,7 +66,7 @@ class CMakeSettings:
in config or envvar will override toml. See also ``cmake.define``.
"""

define: Annotated[Dict[str, Union[str, bool]], "EnvVar"] = dataclasses.field(
define: Annotated[Dict[str, CMakeSettingsDefine], "EnvVar"] = dataclasses.field(
default_factory=dict
)
"""
Expand Down
20 changes: 20 additions & 0 deletions tests/packages/cmake_defines/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.26)
LecrisUT marked this conversation as resolved.
Show resolved Hide resolved
project(cmake_defines LANGUAGES NONE)

set(ONE_LEVEL_LIST
""
CACHE STRING "")
set(NESTED_LIST
""
CACHE STRING "")

set(out_file "${CMAKE_CURRENT_BINARY_DIR}/log.txt")
file(WRITE "${out_file}" "")

foreach(list IN ITEMS ONE_LEVEL_LIST NESTED_LIST)
list(LENGTH ${list} length)
file(APPEND "${out_file}" "${list}.LENGTH = ${length}\n")
foreach(item IN LISTS ${list})
file(APPEND "${out_file}" "${item}\n")
endforeach()
endforeach()
11 changes: 11 additions & 0 deletions tests/packages/cmake_defines/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[tool.scikit-build]
cmake.version = '>=3.26'

[tool.scikit-build.cmake.define]
ONE_LEVEL_LIST = [
"Foo",
"Bar",
"ExceptionallyLargeListEntryThatWouldOverflowTheLine",
"Baz",
]
NESTED_LIST = [ "Apple", "Lemon;Lime", "Banana" ]
38 changes: 38 additions & 0 deletions tests/test_cmake_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
import shutil
import sysconfig
from pathlib import Path
from textwrap import dedent
from typing import TYPE_CHECKING

import pytest
from packaging.specifiers import SpecifierSet
from packaging.version import Version

from scikit_build_core.builder.builder import Builder
from scikit_build_core.cmake import CMake, CMaker
from scikit_build_core.errors import CMakeNotFoundError
from scikit_build_core.settings.skbuild_read_settings import SettingsReader

if TYPE_CHECKING:
from collections.abc import Generator
Expand Down Expand Up @@ -201,6 +204,41 @@ def test_cmake_paths(
assert len(fp.calls) == 2


@pytest.mark.configure
def test_cmake_defines(
tmp_path: Path,
):
source_dir = DIR / "packages" / "cmake_defines"
binary_dir = tmp_path / "build"

config = CMaker(
CMake.default_search(),
source_dir=source_dir,
build_dir=binary_dir,
build_type="Release",
)

reader = SettingsReader.from_file(source_dir / "pyproject.toml")

builder = Builder(reader.settings, config)
builder.configure(defines={})

configure_log = Path.read_text(binary_dir / "log.txt")
assert configure_log == dedent(
"""\
ONE_LEVEL_LIST.LENGTH = 4
Foo
Bar
ExceptionallyLargeListEntryThatWouldOverflowTheLine
Baz
NESTED_LIST.LENGTH = 3
Apple
Lemon;Lime
Banana
"""
)


def test_get_cmake_via_envvar(monkeypatch: pytest.MonkeyPatch, fp):
monkeypatch.setattr("shutil.which", lambda x: x)
cmake_path = Path("some-prog")
Expand Down
8 changes: 4 additions & 4 deletions tests/test_skbuild_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,8 +541,8 @@ def test_skbuild_settings_pyproject_toml_envvar_defines(
"a": "1",
"b": "2",
"c": "empty",
"d": False,
"e": False,
"d": "FALSE",
"e": "FALSE",
}

monkeypatch.setenv("DEFAULT", "3")
Expand All @@ -552,8 +552,8 @@ def test_skbuild_settings_pyproject_toml_envvar_defines(
"a": "1",
"b": "2",
"c": "3",
"d": False,
"e": True,
"d": "FALSE",
"e": "TRUE",
}


Expand Down
Loading