def cmake_configure(source_path='.'): import shlex from skbuild.cmaker import CMaker from skbuild.constants import CMAKE_BUILD_DIR cmaker = CMaker() cmake_args = shlex.split(os.getenv('CI_SETUP_CMAKE_ARGS', '')) cmaker.configure(cmake_args) return CMAKE_BUILD_DIR()
def test_check_for_bad_installs(tmpdir): with push_dir(str(tmpdir)): tmpdir.ensure(CMAKE_BUILD_DIR(), "cmake_install.cmake").write(textwrap.dedent( """ file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/../hello" TYPE FILE FILES "/path/to/hello/world.py") """ )) with pytest.raises(SKBuildError) as excinfo: CMaker.check_for_bad_installs() assert "CMake-installed files must be within the project root" in str(excinfo.value)
def build_extension(self, ext): extdir = os.path.abspath( os.path.dirname(self.get_ext_fullpath(ext.name))) cfg = 'Production' build_args = ['--config', cfg] cpu_count = max(2, multiprocessing.cpu_count() // 2) build_args += ['--', '-j{0}'.format(cpu_count)] project_src_path = get_project_src_path() build_dir = os.path.join(project_src_path, WORKING_DIR) # configure with the working directory python-build-wheel args = [ '--python-bindings', '--auto-download', '--lib-only', '--name=' + WORKING_DIR ] # find correct Python include directory and library # works even for nonstandard Python installations # (e.g., on pypa/manylinux) args.append('-DPYTHON_VERSION_STRING:STRING=' + \ sys.version.split(' ')[0]) python_version = CMaker.get_python_version() args.append('-DPYTHON_INCLUDE_DIR:PATH=' + \ CMaker.get_python_include_dir(python_version)) args.append('-DPYTHON_LIBRARY:FILEPATH=' + \ CMaker.get_python_library(python_version)) config_filename = os.path.join(project_src_path, "configure.sh") subprocess.check_call([config_filename] + args) # build the main library subprocess.check_call(['cmake', '--build', '.', "--target", "cvc5"] + build_args, cwd=build_dir) # build the python binding python_build_dir = os.path.join(build_dir, "src", "api", "python") subprocess.check_call(["make"], cwd=python_build_dir) # the build folder gets cleaned during the config, need to create it again # this is necessary since "build" is a python dist folder if not os.path.isdir(extdir): os.mkdir(extdir) # copy the library over. we need to consider other users that are not on linux # module is a directory called pycvc5 pycvc5_module = os.path.join(python_build_dir, "pycvc5") dst_name = os.path.join(extdir, "pycvc5") if os.path.isdir(dst_name): # remove, then replace shutil.rmtree(dst_name) shutil.copytree(pycvc5_module, dst_name)
def test_make_without_configure_fails(capfd): src_dir = _tmpdir('test_make_without_configure_fails') src_dir.ensure(CMAKE_BUILD_DIR, dir=1) with push_dir(str(src_dir)), pytest.raises(SKBuildError) as excinfo: CMaker().make() _, err = capfd.readouterr() assert "An error occurred while building with CMake." in str(excinfo.value) assert "Error: could not load cache" in err
def test_make(configure_with_cmake_source_dir, capfd): tmp_dir = _tmpdir('test_make') with push_dir(str(tmp_dir)): src_dir = tmp_dir.ensure('SRC', dir=1) src_dir.join('CMakeLists.txt').write(textwrap.dedent( """ cmake_minimum_required(VERSION 3.5.0) project(foobar NONE) file(WRITE "${CMAKE_BINARY_DIR}/foo.txt" "# foo") install(FILES "${CMAKE_BINARY_DIR}/foo.txt" DESTINATION ".") install(CODE "message(STATUS \\"Project has been installed\\")") message(STATUS "CMAKE_SOURCE_DIR:${CMAKE_SOURCE_DIR}") message(STATUS "CMAKE_BINARY_DIR:${CMAKE_BINARY_DIR}") """ )) src_dir.ensure(CMAKE_BUILD_DIR, dir=1) with push_dir(str(src_dir) if not configure_with_cmake_source_dir else str(tmp_dir.ensure('BUILD', dir=1))): cmkr = CMaker() config_kwargs = {} if configure_with_cmake_source_dir: config_kwargs['cmake_source_dir'] = str(src_dir) env = cmkr.configure(**config_kwargs) cmkr.make(env=env) messages = ["Project has been installed"] if configure_with_cmake_source_dir: messages += [ "/SRC", "/BUILD/{}".format(to_unix_path(CMAKE_BUILD_DIR)), "/BUILD/{}/./foo.txt".format(to_unix_path(CMAKE_INSTALL_DIR)) ] else: messages += [ "/SRC", "/SRC/{}".format(to_unix_path(CMAKE_BUILD_DIR)), "/SRC/{}/./foo.txt".format(to_unix_path(CMAKE_INSTALL_DIR)), ] out, _ = capfd.readouterr() for message in messages: assert message in out
def test_configure_with_cmake_args(capfd): tmp_dir = _tmpdir('test_configure_with_cmake_args') with push_dir(str(tmp_dir)): tmp_dir.join('CMakeLists.txt').write(textwrap.dedent( """ cmake_minimum_required(VERSION 3.5.0) project(foobar NONE) # Do not complain about missing arguments passed to the main # project foreach(unused_var IN ITEMS ${CMAKE_EXPECTED_BAR} ${CMAKE_EXPECTED_FOO} ${PYTHON_EXECUTABLE} ${PYTHON_INCLUDE_DIR} ${PYTHON_LIBRARY} ${PYTHON_VERSION_STRING} ${SKBUILD} ) endforeach() """ )) with push_dir(str(tmp_dir)): cmkr = CMaker() cmkr.configure(clargs=[ '-DCMAKE_EXPECTED_FOO:STRING=foo', '-DCMAKE_EXPECTED_BAR:STRING=bar' ], cleanup=False) cmakecache = tmp_dir.join( "_cmake_test_compile", "build", "CMakeCache.txt") assert cmakecache.exists() variables = get_cmakecache_variables(str(cmakecache)) assert variables.get('CMAKE_EXPECTED_FOO', (None, None))[1] == "foo" assert variables.get('CMAKE_EXPECTED_BAR', (None, None))[1] == "bar" unexpected = "Manually-specified variables were not used by the project" _, err = capfd.readouterr() assert unexpected not in err
def test_make_without_build_dir_fails(): src_dir = _tmpdir('test_make_without_build_dir_fails') with push_dir(str(src_dir)), pytest.raises(SKBuildError) as excinfo: CMaker().make() assert "Did you forget to run configure before make" in str(excinfo.value)
def test_get_python_library(): python_library = CMaker.get_python_library(CMaker.get_python_version()) assert python_library assert os.path.exists(python_library)
def test_get_python_version(): assert re.match(r'^[23](\.?)[0-9]$', CMaker.get_python_version())
def test_cmake_executable(): assert CMaker().cmake_executable == CMAKE_DEFAULT_EXECUTABLE
def test_get_python_include_dir(): python_include_dir = CMaker.get_python_include_dir(CMaker.get_python_version()) assert python_include_dir assert os.path.exists(python_include_dir)
def test_cmake_executable(): assert CMaker().cmake_executable == "cmake"
def build_extension(self, ext): extdir = os.path.abspath( os.path.dirname(self.get_ext_fullpath(ext.name))) if not os.path.isdir(extdir): os.mkdir(extdir) cfg = 'Release' build_args = ['--config', cfg] cpu_count = max(2, multiprocessing.cpu_count() // 2) build_args += ['--', '-j{0}'.format(cpu_count)] # call configure # default install everything? solvers = ["bitwuzla", "cvc5", "z3"] # , "msat"] solver_path = { "btor": "boolector", "bitwuzla": "bitwuzla", "cvc5": "cvc5", "msat": "mathsat", "z3": "z3" } root_path = os.path.dirname( os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) build_dir = os.path.join(root_path, "build") for solver in solvers: solver_dir = os.path.join(root_path, "deps", solver_path[solver]) if os.path.isdir(solver_dir): continue filename = os.path.join(root_path, "contrib", "setup-" + solver + ".sh") opts = ["--auto-yes"] if solver == "msat" else [] subprocess.check_call([filename] + opts) # to avoid multiple build, only call reconfigure if we couldn't find the makefile # for python python_make_dir = os.path.join(build_dir, "python") if not os.path.isfile(os.path.join(python_make_dir, "Makefile")): args = ["--" + solver for solver in solvers] + ["--python"] args.append('-DPYTHON_VERSION_STRING:STRING=' + \ sys.version.split(' ')[0]) python_version = CMaker.get_python_version() args.append('-DPYTHON_INCLUDE_DIR:PATH=' + \ CMaker.get_python_include_dir(python_version)) args.append('-DPYTHON_LIBRARY:FILEPATH=' + \ CMaker.get_python_library(python_version)) config_filename = os.path.join(root_path, "configure.sh") subprocess.check_call([config_filename] + args) # build the main library subprocess.check_call( ['cmake', '--build', '.', "--target", "smt-switch"] + build_args, cwd=build_dir) # build the python binding python_build_dir = os.path.join(os.path.join(build_dir, "python"), "smt_switch") subprocess.check_call(["make"], cwd=python_build_dir) # the build folder gets cleaned during the config, need to create it again # this is necessary since "build" is a python dist folder if not os.path.isdir(extdir): os.mkdir(extdir) # copy the library over. we need to consider other users that's not on linux lib_files = filter( lambda s: os.path.splitext(s)[1] != '.cxx', glob.glob(os.path.join(python_build_dir, "smt_switch.*"))) assert lib_files, 'Expecting library files but found none' for lib_filename in lib_files: print(f'Copying library: {lib_filename}') if os.path.splitext(lib_filename)[1] == ".cxx": continue dst_filename = os.path.join(extdir, os.path.basename(lib_filename)) shutil.copy(lib_filename, dst_filename)
# Top contributors (to current version): # Gereon Kremer # # This file is part of the cvc5 project. # # Copyright (c) 2009-2021 by the authors listed in the file AUTHORS # in the top-level source directory and their institutional affiliations. # All rights reserved. See the file COPYING in the top-level source # directory for licensing information. # ############################################################################ # # Run configure.sh and make cmake pick up whatever python interpreter this # script is run with. Additionally, all arguments passed to this script are # forwarded as well. ## import subprocess import sys from skbuild.cmaker import CMaker python_version = CMaker.get_python_version() args = [ '-DPYTHON_VERSION_STRING:STRING=' + sys.version.split(' ')[0], '-DPYTHON_INCLUDE_DIR:PATH=' + CMaker.get_python_include_dir(python_version), '-DPYTHON_LIBRARY:FILEPATH=' + CMaker.get_python_library(python_version), ] subprocess.check_call(['./configure.sh', *sys.argv[1:], *args])