CMakeLists.txt revision 12037
112037Sandreas.sandberg@arm.com# CMakeLists.txt -- Build system for the pybind11 test suite
212037Sandreas.sandberg@arm.com#
312037Sandreas.sandberg@arm.com# Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
412037Sandreas.sandberg@arm.com#
512037Sandreas.sandberg@arm.com# All rights reserved. Use of this source code is governed by a
612037Sandreas.sandberg@arm.com# BSD-style license that can be found in the LICENSE file.
712037Sandreas.sandberg@arm.com
812037Sandreas.sandberg@arm.comcmake_minimum_required(VERSION 2.8.12)
912037Sandreas.sandberg@arm.com
1012037Sandreas.sandberg@arm.comoption(PYBIND11_WERROR  "Report all warnings as errors"  OFF)
1112037Sandreas.sandberg@arm.com
1212037Sandreas.sandberg@arm.comif (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
1312037Sandreas.sandberg@arm.com    # We're being loaded directly, i.e. not via add_subdirectory, so make this
1412037Sandreas.sandberg@arm.com    # work as its own project and load the pybind11Config to get the tools we need
1512037Sandreas.sandberg@arm.com    project(pybind11_tests)
1612037Sandreas.sandberg@arm.com
1712037Sandreas.sandberg@arm.com    find_package(pybind11 REQUIRED CONFIG)
1812037Sandreas.sandberg@arm.comendif()
1912037Sandreas.sandberg@arm.com
2011986Sandreas.sandberg@arm.comif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
2111986Sandreas.sandberg@arm.com  message(STATUS "Setting tests build type to MinSizeRel as none was specified")
2211986Sandreas.sandberg@arm.com  set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE)
2311986Sandreas.sandberg@arm.com  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
2411986Sandreas.sandberg@arm.com    "MinSizeRel" "RelWithDebInfo")
2511986Sandreas.sandberg@arm.comendif()
2611986Sandreas.sandberg@arm.com
2711986Sandreas.sandberg@arm.com# Full set of test files (you can override these; see below)
2811986Sandreas.sandberg@arm.comset(PYBIND11_TEST_FILES
2911986Sandreas.sandberg@arm.com  test_alias_initialization.cpp
3011986Sandreas.sandberg@arm.com  test_buffers.cpp
3111986Sandreas.sandberg@arm.com  test_callbacks.cpp
3211986Sandreas.sandberg@arm.com  test_chrono.cpp
3311986Sandreas.sandberg@arm.com  test_class_args.cpp
3411986Sandreas.sandberg@arm.com  test_constants_and_functions.cpp
3511986Sandreas.sandberg@arm.com  test_copy_move_policies.cpp
3611986Sandreas.sandberg@arm.com  test_docstring_options.cpp
3711986Sandreas.sandberg@arm.com  test_eigen.cpp
3811986Sandreas.sandberg@arm.com  test_enum.cpp
3911986Sandreas.sandberg@arm.com  test_eval.cpp
4011986Sandreas.sandberg@arm.com  test_exceptions.cpp
4111986Sandreas.sandberg@arm.com  test_inheritance.cpp
4211986Sandreas.sandberg@arm.com  test_issues.cpp
4311986Sandreas.sandberg@arm.com  test_keep_alive.cpp
4411986Sandreas.sandberg@arm.com  test_kwargs_and_defaults.cpp
4511986Sandreas.sandberg@arm.com  test_methods_and_attributes.cpp
4611986Sandreas.sandberg@arm.com  test_modules.cpp
4711986Sandreas.sandberg@arm.com  test_multiple_inheritance.cpp
4811986Sandreas.sandberg@arm.com  test_numpy_array.cpp
4911986Sandreas.sandberg@arm.com  test_numpy_dtypes.cpp
5011986Sandreas.sandberg@arm.com  test_numpy_vectorize.cpp
5111986Sandreas.sandberg@arm.com  test_opaque_types.cpp
5211986Sandreas.sandberg@arm.com  test_operator_overloading.cpp
5311986Sandreas.sandberg@arm.com  test_pickling.cpp
5411986Sandreas.sandberg@arm.com  test_python_types.cpp
5511986Sandreas.sandberg@arm.com  test_sequences_and_iterators.cpp
5611986Sandreas.sandberg@arm.com  test_smart_ptr.cpp
5711986Sandreas.sandberg@arm.com  test_stl_binders.cpp
5811986Sandreas.sandberg@arm.com  test_virtual_functions.cpp
5911986Sandreas.sandberg@arm.com)
6011986Sandreas.sandberg@arm.com
6111986Sandreas.sandberg@arm.com# Invoking cmake with something like:
6211986Sandreas.sandberg@arm.com#     cmake -DPYBIND11_TEST_OVERRIDE="test_issues.cpp;test_picking.cpp" ..
6311986Sandreas.sandberg@arm.com# lets you override the tests that get compiled and run.  You can restore to all tests with:
6411986Sandreas.sandberg@arm.com#     cmake -DPYBIND11_TEST_OVERRIDE= ..
6511986Sandreas.sandberg@arm.comif (PYBIND11_TEST_OVERRIDE)
6611986Sandreas.sandberg@arm.com  set(PYBIND11_TEST_FILES ${PYBIND11_TEST_OVERRIDE})
6711986Sandreas.sandberg@arm.comendif()
6811986Sandreas.sandberg@arm.com
6911986Sandreas.sandberg@arm.comstring(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
7011986Sandreas.sandberg@arm.com
7111986Sandreas.sandberg@arm.com# Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but
7211986Sandreas.sandberg@arm.com# keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed"
7311986Sandreas.sandberg@arm.com# skip message).
7411986Sandreas.sandberg@arm.comlist(FIND PYBIND11_TEST_FILES test_eigen.cpp PYBIND11_TEST_FILES_EIGEN_I)
7511986Sandreas.sandberg@arm.comif(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
7612037Sandreas.sandberg@arm.com  # Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake).
7712037Sandreas.sandberg@arm.com  # Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also
7812037Sandreas.sandberg@arm.com  # produces a fatal error if loaded from a pre-3.0 cmake.
7912037Sandreas.sandberg@arm.com  if (NOT CMAKE_VERSION VERSION_LESS 3.0)
8012037Sandreas.sandberg@arm.com    find_package(Eigen3 QUIET CONFIG)
8112037Sandreas.sandberg@arm.com    if (EIGEN3_FOUND)
8212037Sandreas.sandberg@arm.com      if (EIGEN3_VERSION_STRING AND NOT EIGEN3_VERSION_STRING VERSION_LESS 3.3.1)
8312037Sandreas.sandberg@arm.com        set(PYBIND11_EIGEN_VIA_TARGET 1)
8412037Sandreas.sandberg@arm.com      endif()
8512037Sandreas.sandberg@arm.com    endif()
8612037Sandreas.sandberg@arm.com  endif()
8712037Sandreas.sandberg@arm.com  if (NOT EIGEN3_FOUND)
8812037Sandreas.sandberg@arm.com    # Couldn't load via target, so fall back to allowing module mode finding, which will pick up
8912037Sandreas.sandberg@arm.com    # tools/FindEigen3.cmake
9012037Sandreas.sandberg@arm.com    find_package(Eigen3 QUIET)
9112037Sandreas.sandberg@arm.com  endif()
9211986Sandreas.sandberg@arm.com
9311986Sandreas.sandberg@arm.com  if(EIGEN3_FOUND)
9412037Sandreas.sandberg@arm.com    # Eigen 3.3.1+ cmake sets EIGEN3_VERSION_STRING (and hard codes the version when installed
9512037Sandreas.sandberg@arm.com    # rather than looking it up in the cmake script); older versions, and the
9612037Sandreas.sandberg@arm.com    # tools/FindEigen3.cmake, set EIGEN3_VERSION instead.
9712037Sandreas.sandberg@arm.com    if(NOT EIGEN3_VERSION AND EIGEN3_VERSION_STRING)
9812037Sandreas.sandberg@arm.com      set(EIGEN3_VERSION ${EIGEN3_VERSION_STRING})
9912037Sandreas.sandberg@arm.com    endif()
10011986Sandreas.sandberg@arm.com    message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}")
10111986Sandreas.sandberg@arm.com  else()
10211986Sandreas.sandberg@arm.com    list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
10311986Sandreas.sandberg@arm.com    message(STATUS "Building tests WITHOUT Eigen")
10411986Sandreas.sandberg@arm.com  endif()
10511986Sandreas.sandberg@arm.comendif()
10611986Sandreas.sandberg@arm.com
10712037Sandreas.sandberg@arm.com# Compile with compiler warnings turned on
10812037Sandreas.sandberg@arm.comfunction(pybind11_enable_warnings target_name)
10912037Sandreas.sandberg@arm.com  if(MSVC)
11012037Sandreas.sandberg@arm.com    target_compile_options(${target_name} PRIVATE /W4)
11112037Sandreas.sandberg@arm.com  else()
11212037Sandreas.sandberg@arm.com      target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual)
11312037Sandreas.sandberg@arm.com  endif()
11412037Sandreas.sandberg@arm.com
11512037Sandreas.sandberg@arm.com  if(PYBIND11_WERROR)
11612037Sandreas.sandberg@arm.com    if(MSVC)
11712037Sandreas.sandberg@arm.com      target_compile_options(${target_name} PRIVATE /WX)
11812037Sandreas.sandberg@arm.com    else()
11912037Sandreas.sandberg@arm.com      target_compile_options(${target_name} PRIVATE -Werror)
12012037Sandreas.sandberg@arm.com    endif()
12112037Sandreas.sandberg@arm.com  endif()
12212037Sandreas.sandberg@arm.comendfunction()
12312037Sandreas.sandberg@arm.com
12412037Sandreas.sandberg@arm.com
12511986Sandreas.sandberg@arm.com# Create the binding library
12612037Sandreas.sandberg@arm.compybind11_add_module(pybind11_tests THIN_LTO pybind11_tests.cpp
12711986Sandreas.sandberg@arm.com  ${PYBIND11_TEST_FILES} ${PYBIND11_HEADERS})
12811986Sandreas.sandberg@arm.com
12911986Sandreas.sandberg@arm.compybind11_enable_warnings(pybind11_tests)
13011986Sandreas.sandberg@arm.com
13111986Sandreas.sandberg@arm.comif(EIGEN3_FOUND)
13212037Sandreas.sandberg@arm.com  if (PYBIND11_EIGEN_VIA_TARGET)
13312037Sandreas.sandberg@arm.com    target_link_libraries(pybind11_tests PRIVATE Eigen3::Eigen)
13412037Sandreas.sandberg@arm.com  else()
13512037Sandreas.sandberg@arm.com    target_include_directories(pybind11_tests PRIVATE ${EIGEN3_INCLUDE_DIR})
13612037Sandreas.sandberg@arm.com  endif()
13711986Sandreas.sandberg@arm.com  target_compile_definitions(pybind11_tests PRIVATE -DPYBIND11_TEST_EIGEN)
13811986Sandreas.sandberg@arm.comendif()
13911986Sandreas.sandberg@arm.com
14012037Sandreas.sandberg@arm.comset(testdir ${CMAKE_CURRENT_SOURCE_DIR})
14111986Sandreas.sandberg@arm.com
14211986Sandreas.sandberg@arm.com# Always write the output file directly into the 'tests' directory (even on MSVC)
14311986Sandreas.sandberg@arm.comif(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
14411986Sandreas.sandberg@arm.com  set_target_properties(pybind11_tests PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir})
14511986Sandreas.sandberg@arm.com  foreach(config ${CMAKE_CONFIGURATION_TYPES})
14611986Sandreas.sandberg@arm.com    string(TOUPPER ${config} config)
14711986Sandreas.sandberg@arm.com    set_target_properties(pybind11_tests PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir})
14811986Sandreas.sandberg@arm.com  endforeach()
14911986Sandreas.sandberg@arm.comendif()
15011986Sandreas.sandberg@arm.com
15111986Sandreas.sandberg@arm.com# Make sure pytest is found or produce a fatal error
15211986Sandreas.sandberg@arm.comif(NOT PYBIND11_PYTEST_FOUND)
15312037Sandreas.sandberg@arm.com  execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import pytest; print(pytest.__version__)"
15412037Sandreas.sandberg@arm.com                  RESULT_VARIABLE pytest_not_found OUTPUT_VARIABLE pytest_version ERROR_QUIET)
15512037Sandreas.sandberg@arm.com  if(pytest_not_found)
15612037Sandreas.sandberg@arm.com    message(FATAL_ERROR "Running the tests requires pytest. Please install it manually"
15712037Sandreas.sandberg@arm.com                        " (try: ${PYTHON_EXECUTABLE} -m pip install pytest)")
15812037Sandreas.sandberg@arm.com  elseif(pytest_version VERSION_LESS 3.0)
15912037Sandreas.sandberg@arm.com    message(FATAL_ERROR "Running the tests requires pytest >= 3.0. Found: ${pytest_version}"
16012037Sandreas.sandberg@arm.com                        "Please update it (try: ${PYTHON_EXECUTABLE} -m pip install -U pytest)")
16111986Sandreas.sandberg@arm.com  endif()
16211986Sandreas.sandberg@arm.com  set(PYBIND11_PYTEST_FOUND TRUE CACHE INTERNAL "")
16311986Sandreas.sandberg@arm.comendif()
16411986Sandreas.sandberg@arm.com
16511986Sandreas.sandberg@arm.com# A single command to compile and run the tests
16612037Sandreas.sandberg@arm.comadd_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_PYTEST_FILES}
16711986Sandreas.sandberg@arm.com                  DEPENDS pybind11_tests WORKING_DIRECTORY ${testdir})
16811986Sandreas.sandberg@arm.com
16911986Sandreas.sandberg@arm.comif(PYBIND11_TEST_OVERRIDE)
17011986Sandreas.sandberg@arm.com  add_custom_command(TARGET pytest POST_BUILD
17111986Sandreas.sandberg@arm.com    COMMAND ${CMAKE_COMMAND} -E echo "Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect")
17211986Sandreas.sandberg@arm.comendif()
17311986Sandreas.sandberg@arm.com
17412037Sandreas.sandberg@arm.com# Add a check target to run all the tests, starting with pytest (we add dependencies to this below)
17512037Sandreas.sandberg@arm.comadd_custom_target(check DEPENDS pytest)
17612037Sandreas.sandberg@arm.com
17712037Sandreas.sandberg@arm.com# The remaining tests only apply when being built as part of the pybind11 project, but not if the
17812037Sandreas.sandberg@arm.com# tests are being built independently.
17912037Sandreas.sandberg@arm.comif (NOT PROJECT_NAME STREQUAL "pybind11")
18012037Sandreas.sandberg@arm.com  return()
18111986Sandreas.sandberg@arm.comendif()
18211986Sandreas.sandberg@arm.com
18312037Sandreas.sandberg@arm.com# Add a post-build comment to show the .so size and, if a previous size, compare it:
18411986Sandreas.sandberg@arm.comadd_custom_command(TARGET pybind11_tests POST_BUILD
18512037Sandreas.sandberg@arm.com  COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/libsize.py
18612037Sandreas.sandberg@arm.com  $<TARGET_FILE:pybind11_tests> ${CMAKE_CURRENT_BINARY_DIR}/sosize-$<TARGET_FILE_NAME:pybind11_tests>.txt)
18712037Sandreas.sandberg@arm.com
18812037Sandreas.sandberg@arm.com# Test CMake build using functions and targets from subdirectory or installed location
18912037Sandreas.sandberg@arm.comadd_custom_target(test_cmake_build)
19012037Sandreas.sandberg@arm.comif(NOT CMAKE_VERSION VERSION_LESS 3.1)
19112037Sandreas.sandberg@arm.com  # 3.0 needed for interface library for subdirectory_target/installed_target
19212037Sandreas.sandberg@arm.com  # 3.1 needed for cmake -E env for testing
19312037Sandreas.sandberg@arm.com
19412037Sandreas.sandberg@arm.com  include(CMakeParseArguments)
19512037Sandreas.sandberg@arm.com  function(pybind11_add_build_test name)
19612037Sandreas.sandberg@arm.com    cmake_parse_arguments(ARG "INSTALL" "" "" ${ARGN})
19712037Sandreas.sandberg@arm.com
19812037Sandreas.sandberg@arm.com    set(build_options "-DCMAKE_PREFIX_PATH=${PROJECT_BINARY_DIR}/mock_install"
19912037Sandreas.sandberg@arm.com                      "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
20012037Sandreas.sandberg@arm.com                      "-DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}"
20112037Sandreas.sandberg@arm.com                      "-DPYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}")
20212037Sandreas.sandberg@arm.com    if(NOT ARG_INSTALL)
20312037Sandreas.sandberg@arm.com      list(APPEND build_options "-DPYBIND11_PROJECT_DIR=${PROJECT_SOURCE_DIR}")
20412037Sandreas.sandberg@arm.com    endif()
20512037Sandreas.sandberg@arm.com
20612037Sandreas.sandberg@arm.com    add_custom_target(test_${name} ${CMAKE_CTEST_COMMAND}
20712037Sandreas.sandberg@arm.com      --quiet --output-log test_cmake_build/${name}.log
20812037Sandreas.sandberg@arm.com      --build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/test_cmake_build/${name}"
20912037Sandreas.sandberg@arm.com                       "${CMAKE_CURRENT_BINARY_DIR}/test_cmake_build/${name}"
21012037Sandreas.sandberg@arm.com      --build-config Release
21112037Sandreas.sandberg@arm.com      --build-noclean
21212037Sandreas.sandberg@arm.com      --build-generator ${CMAKE_GENERATOR}
21312037Sandreas.sandberg@arm.com      $<$<BOOL:${CMAKE_GENERATOR_PLATFORM}>:--build-generator-platform> ${CMAKE_GENERATOR_PLATFORM}
21412037Sandreas.sandberg@arm.com      --build-makeprogram ${CMAKE_MAKE_PROGRAM}
21512037Sandreas.sandberg@arm.com      --build-target check
21612037Sandreas.sandberg@arm.com      --build-options ${build_options}
21712037Sandreas.sandberg@arm.com    )
21812037Sandreas.sandberg@arm.com    if(ARG_INSTALL)
21912037Sandreas.sandberg@arm.com      add_dependencies(test_${name} mock_install)
22012037Sandreas.sandberg@arm.com    endif()
22112037Sandreas.sandberg@arm.com    add_dependencies(test_cmake_build test_${name})
22212037Sandreas.sandberg@arm.com  endfunction()
22312037Sandreas.sandberg@arm.com
22412037Sandreas.sandberg@arm.com  pybind11_add_build_test(subdirectory_function)
22512037Sandreas.sandberg@arm.com  pybind11_add_build_test(subdirectory_target)
22612037Sandreas.sandberg@arm.com
22712037Sandreas.sandberg@arm.com  if(PYBIND11_INSTALL)
22812037Sandreas.sandberg@arm.com    add_custom_target(mock_install ${CMAKE_COMMAND}
22912037Sandreas.sandberg@arm.com      "-DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/mock_install"
23012037Sandreas.sandberg@arm.com      -P "${PROJECT_BINARY_DIR}/cmake_install.cmake"
23112037Sandreas.sandberg@arm.com    )
23212037Sandreas.sandberg@arm.com
23312037Sandreas.sandberg@arm.com    pybind11_add_build_test(installed_function INSTALL)
23412037Sandreas.sandberg@arm.com    pybind11_add_build_test(installed_target INSTALL)
23512037Sandreas.sandberg@arm.com  endif()
23612037Sandreas.sandberg@arm.comendif()
23712037Sandreas.sandberg@arm.com
23812037Sandreas.sandberg@arm.comadd_dependencies(check test_cmake_build)
239