blob: d58e8a9c693a51a4d0251572fcf1d0ba9ae7bff0 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Tests for the tvm-ffi-config command line utility."""
import subprocess
import sys
from pathlib import Path
from typing import Callable
import pytest
from tvm_ffi import libinfo
def _stdout_for(*args: str) -> str:
"""Invoke tvm-ffi-config with the provided arguments and return stdout with trailing whitespace removed."""
result = subprocess.run(
[
sys.executable,
"-m",
"tvm_ffi.config",
*args,
],
check=True,
capture_output=True,
text=True,
)
assert result.stderr == ""
return result.stdout.strip()
@pytest.mark.parametrize(
("flag", "expected_fn", "is_dir"),
[
("--includedir", libinfo.find_include_path, True),
("--dlpack-includedir", libinfo.find_dlpack_include_path, True),
("--cmakedir", libinfo.find_cmake_path, True),
("--sourcedir", libinfo.find_source_path, True),
("--cython-lib-path", libinfo.find_cython_lib, False),
],
)
def test_basic_path_flags(flag: str, expected_fn: Callable[[], str], is_dir: bool) -> None:
output = _stdout_for(flag)
assert output == expected_fn()
path = Path(output)
assert path.exists()
assert path.is_dir() if is_dir else path.is_file()
def test_libdir_matches_library_parent() -> None:
expected_dir = Path(libinfo.find_libtvm_ffi()).parent
output = _stdout_for("--libdir")
assert output == str(expected_dir)
assert Path(output).is_dir()
assert Path(libinfo.find_libtvm_ffi()).is_file()
def test_libfiles_reports_platform_library() -> None:
output = _stdout_for("--libfiles")
if sys.platform.startswith("win32"):
expected = libinfo.find_windows_implib()
else:
expected = libinfo.find_libtvm_ffi()
assert output == expected
assert Path(output).is_file()
def test_libs_reports_link_target() -> None:
output = _stdout_for("--libs")
if sys.platform.startswith("win32"):
assert output == libinfo.find_windows_implib()
else:
assert output == "-ltvm_ffi"
def test_cxxflags_include_paths_and_standard() -> None:
include_dir = libinfo.find_include_path()
dlpack_dir = libinfo.find_dlpack_include_path()
assert _stdout_for("--cxxflags") == f"-I{include_dir} -I{dlpack_dir} -std=c++17"
def test_cflags_include_paths() -> None:
include_dir = libinfo.find_include_path()
dlpack_dir = libinfo.find_dlpack_include_path()
assert _stdout_for("--cflags") == f"-I{include_dir} -I{dlpack_dir}"
def test_ldflags_only_on_unix() -> None:
output = _stdout_for("--ldflags")
if sys.platform.startswith("win32"):
assert output == ""
else:
libdir = Path(libinfo.find_libtvm_ffi()).parent
assert output == f"-L{libdir}"
assert libdir.is_dir()
def test_cmakedir_contains_config_file() -> None:
cmake_dir = Path(_stdout_for("--cmakedir"))
assert (cmake_dir / "tvm_ffi-config.cmake").is_file()
def test_find_python_helper_include_path() -> None:
path = libinfo.find_python_helper_include_path()
assert Path(path).is_dir()
assert (Path(path) / "tvm_ffi_python_helpers.h").is_file()
def _platform_lib_filename(target_name: str) -> str:
"""Return the platform-appropriate shared library filename for ``target_name``."""
if sys.platform.startswith("win32"):
return f"{target_name}.dll"
if sys.platform.startswith("darwin"):
return f"lib{target_name}.dylib"
return f"lib{target_name}.so"
def test_find_library_by_basename_extra_lib_paths(tmp_path: Path) -> None:
"""A directory passed via ``extra_lib_paths`` is searched in the dev fallback."""
lib_file = tmp_path / _platform_lib_filename("dummy")
lib_file.write_bytes(b"")
result = libinfo._find_library_by_basename(
"nonexistent-dist-name", "dummy", extra_lib_paths=[tmp_path]
)
assert isinstance(result, Path)
assert result.resolve() == lib_file.resolve()
# Sanity: the result must live under the temp tree, not tvm_ffi's own tree.
assert tmp_path.resolve() in result.resolve().parents
def test_find_library_by_basename_extra_lib_paths_type_error(tmp_path: Path) -> None:
"""Non-Path elements in ``extra_lib_paths`` raise a TypeError naming the offender."""
with pytest.raises(TypeError, match=r"extra_lib_paths\[1\] must be a pathlib\.Path"):
libinfo._find_library_by_basename(
"apache-tvm-ffi",
"tvm_ffi",
extra_lib_paths=[tmp_path, str(tmp_path)], # ty: ignore[invalid-argument-type]
)