Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 34 additions & 12 deletions src/cython_cmake/cmake/UseCython.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# Cython_compile_pyx(<pyx_file>
# [LANGUAGE C | CXX]
# [CYTHON_ARGS <args> ...]
# [OUTPUT <OutputFile>]
# [OUTPUT_VARIABLE <OutputVariable>])
#
# Options:
Expand All @@ -23,10 +24,14 @@
# Specify additional arguments for the cythonization process. Will default to
# the ``CYTHON_ARGS`` variable if not specified.
#
# ``OUTPUT <OutputFile>``
# Specify a specific path for the output file as ``<OutputFile>``. By
# default, this will output into the current binary dir. A depfile will be
# created alongside this file as well.
#
# ``OUTPUT_VARIABLE <OutputVariable>``
# Set the variable ``<OutputVariable>`` in the parent scope to the path to the
# generated source file. By default, ``<Name>`` is used as the output
# variable name.
# generated source file.
#
# Defined variables:
#
Expand Down Expand Up @@ -72,7 +77,7 @@ endif()

function(Cython_compile_pyx)
set(_options )
set(_one_value LANGUAGE OUTPUT_VARIABLE)
set(_one_value LANGUAGE OUTPUT OUTPUT_VARIABLE)
set(_multi_value CYTHON_ARGS)

cmake_parse_arguments(_args
Expand Down Expand Up @@ -127,15 +132,9 @@ function(Cython_compile_pyx)
set(_language_arg ${_language_${_language}_arg})
set(_language_extension ${_language_${_language}_extension})

set(generated_files)

foreach(_source_file IN LISTS _source_files)
function(_compile_pyx _source_file generated_file)

# Can use cmake_path for CMake 3.20+
# cmake_path(GET _source_file STEM _name)
get_filename_component(_name "${_source_file}" NAME_WE)

set(generated_file "${CMAKE_CURRENT_BINARY_DIR}/${_name}.${_language_extension}")
set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE)

# Generated depfile is expected to have the ".dep" extension and be located along
Expand Down Expand Up @@ -167,9 +166,32 @@ function(Cython_compile_pyx)
VERBATIM
COMMENT ${comment}
)
list(APPEND generated_files ${generated_file})
endforeach()
endfunction()

function(_set_output _input_file _output_var)
# Can use cmake_path for CMake 3.20+
# cmake_path(GET _input_file STEM basename)
get_filename_component(_basename "${_input_file}" NAME_WE)

set(${_output_var} "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.${_language_extension}" PARENT_SCOPE)
endfunction()

set(generated_files)

list(GET _source_files 0 _source_file)

# Place the cython files in the current binary dir if no path given
if(NOT _args_OUTPUT)
_set_output(${_source_file} _args_OUTPUT)
elseif(NOT IS_ABSOLUTE ${_args_OUTPUT})
set(_args_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${_args_OUTPUT}")
endif()

set(generated_file ${_args_OUTPUT})
_compile_pyx(${_source_file} ${generated_file})
list(APPEND generated_files ${generated_file})

# Output variable only if set
if(_args_OUTPUT_VARIABLE)
set(_output_variable ${_args_OUTPUT_VARIABLE})
set(${_output_variable} ${generated_files} PARENT_SCOPE)
Expand Down
6 changes: 5 additions & 1 deletion tests/packages/simple/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ find_package(
find_package(Cython MODULE REQUIRED VERSION 3.0)
include(UseCython)

cython_compile_pyx(simple.pyx LANGUAGE C OUTPUT_VARIABLE simple_c)
cython_compile_pyx(simple.pyx
LANGUAGE C
# OUTPUT_ARG
OUTPUT_VARIABLE simple_c
)

python_add_library(simple MODULE "${simple_c}" WITH_SOABI)

Expand Down
43 changes: 42 additions & 1 deletion tests/test_package.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from __future__ import annotations

import importlib.metadata
import shutil
import zipfile
from pathlib import Path

import pytest
from scikit_build_core.build import build_wheel

import cython_cmake as m
Expand All @@ -15,7 +17,7 @@ def test_version():
assert importlib.metadata.version("cython_cmake") == m.__version__


def test_scikit_build_core(monkeypatch, tmp_path):
def test_simple(monkeypatch, tmp_path):
monkeypatch.chdir(DIR / "packages/simple")
build_dir = tmp_path / "build"

Expand All @@ -30,3 +32,42 @@ def test_scikit_build_core(monkeypatch, tmp_path):
build_files = {x.name for x in build_dir.iterdir()}
assert "simple.c.dep" in build_files
assert "simple.c" in build_files


@pytest.mark.parametrize("output_arg", ["empty", "relative", "absolute"])
def test_output_argument(monkeypatch, tmp_path, output_arg):
package_dir = tmp_path / "pkg2"
shutil.copytree(DIR / "packages/simple", package_dir)
monkeypatch.chdir(package_dir)

build_dir = tmp_path / "build"

output_values = {
"empty": "",
"relative": "relative-custom.c",
"absolute": (build_dir / "absolute-custom.c").as_posix(),
}

cmakelists = Path("CMakeLists.txt")
txt = cmakelists.read_text().replace(
"# OUTPUT_ARG", f'OUTPUT "{output_values[output_arg]}"'
)
cmakelists.write_text(txt)

wheel = build_wheel(
str(tmp_path), {"build-dir": str(build_dir), "wheel.license-files": []}
)

with zipfile.ZipFile(tmp_path / wheel) as f:
file_names = set(f.namelist())
assert len(file_names) == 4

generated_file = {
"empty": "simple.c",
"relative": "relative-custom.c",
"absolute": "absolute-custom.c",
}[output_arg]

build_files = {x.name for x in build_dir.iterdir()}
assert f"{generated_file}.dep" in build_files
assert generated_file in build_files