From daefb0d56c155d9cedac55844a944edf70aeebf9 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Wed, 17 Jul 2024 23:58:35 -0400 Subject: [PATCH 1/2] refactor: Add helper functions and simplify processing of input --- src/cython_cmake/cmake/UseCython.cmake | 27 +++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/cython_cmake/cmake/UseCython.cmake b/src/cython_cmake/cmake/UseCython.cmake index 363a0ba..060de1f 100644 --- a/src/cython_cmake/cmake/UseCython.cmake +++ b/src/cython_cmake/cmake/UseCython.cmake @@ -127,15 +127,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 @@ -167,9 +161,24 @@ 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) + _set_output(${_source_file} generated_file) + _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) From a2d39efa197466e05ca0cb2b5b387eee35d42bc0 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 18 Jul 2024 00:50:58 -0400 Subject: [PATCH 2/2] feat: Add support for OUTPUT parameter Co-authored-by: Jean-Christophe Fillion-Robin --- src/cython_cmake/cmake/UseCython.cmake | 21 ++++++++++--- tests/packages/simple/CMakeLists.txt | 6 +++- tests/test_package.py | 43 +++++++++++++++++++++++++- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/cython_cmake/cmake/UseCython.cmake b/src/cython_cmake/cmake/UseCython.cmake index 060de1f..12ac109 100644 --- a/src/cython_cmake/cmake/UseCython.cmake +++ b/src/cython_cmake/cmake/UseCython.cmake @@ -10,6 +10,7 @@ # Cython_compile_pyx( # [LANGUAGE C | CXX] # [CYTHON_ARGS ...] +# [OUTPUT ] # [OUTPUT_VARIABLE ]) # # Options: @@ -23,10 +24,14 @@ # Specify additional arguments for the cythonization process. Will default to # the ``CYTHON_ARGS`` variable if not specified. # +# ``OUTPUT `` +# Specify a specific path for the output file as ````. By +# default, this will output into the current binary dir. A depfile will be +# created alongside this file as well. +# # ``OUTPUT_VARIABLE `` # Set the variable ```` in the parent scope to the path to the -# generated source file. By default, ```` is used as the output -# variable name. +# generated source file. # # Defined variables: # @@ -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 @@ -174,7 +179,15 @@ function(Cython_compile_pyx) set(generated_files) list(GET _source_files 0 _source_file) - _set_output(${_source_file} generated_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}) diff --git a/tests/packages/simple/CMakeLists.txt b/tests/packages/simple/CMakeLists.txt index a37134d..4999bb2 100644 --- a/tests/packages/simple/CMakeLists.txt +++ b/tests/packages/simple/CMakeLists.txt @@ -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) diff --git a/tests/test_package.py b/tests/test_package.py index 5325882..f7ddacb 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -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 @@ -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" @@ -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