diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c64580..db32732 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ project( LANGUAGES CXX VERSION ${VERSION_STRIPPED} ) +include(GNUInstallDirs) add_subdirectory(src) diff --git a/meson.build b/meson.build index e305ec1..b73f325 100644 --- a/meson.build +++ b/meson.build @@ -40,7 +40,7 @@ foreach t : [['cps integration tests', 'cps-config.toml'], ['pkg-config compatib test( t[0], python_interpreter, - args: [files('tests/runner.py'), cps_config, 'tests/cases/' + t[1]], + args: [files('tests/runner.py'), cps_config, 'tests/cases/' + t[1], '--libdir', get_option('libdir')], protocol : 'tap', env : {'CPS_PREFIX_PATH' : meson.current_source_dir() / 'tests' / 'cps-files' }, ) diff --git a/src/cps/config.hpp.in b/src/cps/config.hpp.in index 6a96f53..df0b403 100644 --- a/src/cps/config.hpp.in +++ b/src/cps/config.hpp.in @@ -1,3 +1,5 @@ #pragma once #define CPS_CONFIG_VERSION "${CMAKE_PROJECT_VERSION}" +#define CPS_CONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}" +#define CPS_CONFIG_DATADIR "${CMAKE_INSTALL_DATADIR}" diff --git a/src/cps/meson.build b/src/cps/meson.build index d3e3e31..74a7769 100644 --- a/src/cps/meson.build +++ b/src/cps/meson.build @@ -3,6 +3,8 @@ conf = configuration_data() conf.set_quoted('CPS_CONFIG_VERSION', meson.project_version()) +conf.set_quoted('CPS_CONFIG_LIBDIR', get_option('libdir')) +conf.set_quoted('CPS_CONFIG_DATADIR', get_option('datadir')) conf_h = configure_file( configuration : conf, diff --git a/src/cps/platform.cpp b/src/cps/platform.cpp index ec72f15..1e85bd2 100644 --- a/src/cps/platform.cpp +++ b/src/cps/platform.cpp @@ -2,11 +2,12 @@ // Copyright © 2024 Dylan Baker #include "cps/platform.hpp" +#include "cps/config.hpp" namespace cps::platform { - fs::path libdir() { return "lib"; } + fs::path libdir() { return CPS_CONFIG_LIBDIR; } - fs::path datadir() { return "share"; } + fs::path datadir() { return CPS_CONFIG_DATADIR; } } // namespace cps::platform diff --git a/src/cps/search.cpp b/src/cps/search.cpp index c1accb7..4b5b66d 100644 --- a/src/cps/search.cpp +++ b/src/cps/search.cpp @@ -318,11 +318,11 @@ namespace cps::search { if (split.back() == "cps") { split.pop_back(); } - if (split.back() == "share") { + if (split.back() == platform::datadir()) { split.pop_back(); } // TODO: this needs to be generic - if (split.back() == "lib") { + if (split.back() == platform::libdir()) { split.pop_back(); } fs::path p{"/"}; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b68a3de..d468671 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,6 +32,6 @@ foreach (test_name test_case IN ZIP_LISTS test_names test_cases) COMMAND ${CMAKE_COMMAND} -E env CPS_PREFIX_PATH=${CMAKE_CURRENT_SOURCE_DIR}/cps-files ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/runner.py - $ ${test_case} + $ ${test_case} --libdir "${CMAKE_INSTALL_LIBDIR}" ) endforeach () diff --git a/tests/runner.py b/tests/runner.py index d56f57f..4db68e8 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -6,10 +6,13 @@ import argparse import asyncio +import contextlib import dataclasses import enum import os +import shutil import sys +import tempfile import tomllib import typing @@ -19,6 +22,7 @@ class Arguments(typing.Protocol): runner: str cases: str + libdir: str class TestCase(typing.TypedDict): @@ -99,15 +103,7 @@ async def test(runner: str, case_: TestCase) -> Result: return Result(case_['name'], result, out, err, returncode, expected, cmd) -async def main() -> None: - parser = argparse.ArgumentParser() - parser.add_argument('runner', help="The compiled cps-config binary") - parser.add_argument('cases', help="A toml file containing case descriptions") - args: Arguments = parser.parse_args() - - with open(os.path.join(SOURCE_DIR, args.cases), 'rb') as f: - tests = typing.cast('TestDescription', tomllib.load(f)) - +async def run_tests(args: Arguments, tests: TestDescription) -> bool: print(f'1..{len(tests["case"])}') results = typing.cast( @@ -129,8 +125,47 @@ async def main() -> None: encountered_failure = True - if encountered_failure: - exit(1) + return encountered_failure + + +async def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument('runner', help="The compiled cps-config binary") + parser.add_argument('cases', help="A toml file containing case descriptions") + parser.add_argument('--libdir', default='lib', help="the build system configured libdir") + args: Arguments = parser.parse_args() + + with open(os.path.join(SOURCE_DIR, args.cases), 'rb') as f: + tests = typing.cast('TestDescription', tomllib.load(f)) + + with contextlib.ExitStack() as stack: + # If the libdir is not "lib" (which tests assume), create a symlink to + # the expected libdir + if args.libdir != 'lib': + prefix = str(os.environ['CPS_PREFIX_PATH']) + tmpdir = tempfile.mkdtemp() + stack.callback(shutil.rmtree, tmpdir) + os.environ['CPS_PREFIX_PATH'] = tmpdir + + # Handle libdir with multiple paths, like lib/x86_64-linux-gnu + root, libdir = os.path.split(args.libdir) + if root: + tmpdir = os.path.join(tmpdir, root) + os.makedirs(tmpdir, exist_ok=True) + + source = os.path.join(prefix, 'lib') + dest = os.path.join(tmpdir, libdir) + os.symlink(source, dest) + stack.callback(os.unlink, dest) + + # Also override the PREFIX, which is used to calculate @prefix@ + global PREFIX + PREFIX = os.path.join(tmpdir, libdir) + + failed = await run_tests(args, tests) + + sys.exit(1 if failed else 0) + if __name__ == "__main__": asyncio.run(main())