Sometimes it's good to check that certain things fail to build, e.g.:
// Next line should fail to compile: can't convert const iterator to iterator. my_new_container_type::iterator it = my_new_container_type::const_iterator();
Is it possible to incorporate these types of things into CMake/CTest? I'm looking for something like this in CMakeLists.txt
:
add_build_failure_executable( test_iterator_conversion_build_failure iterator_conversion_build_failure.cpp) add_build_failure_test( test_iterator_conversion_build_failure test_iterator_conversion_build_failure)
(Of course, these specific CMake directives don't exist, to the best of my knowledge.)
¶ CMake facilitates testing your software through special testing commands and the CTest executable. First, we will discuss the key testing commands in CMake. To add testing to a CMake-based project, simply include(CTest) and use the add_test command.
enable_testing() Enables testing for this directory and below. This command should be in the source directory root because ctest expects to find a test file in the build directory root. This command is automatically invoked when the CTest module is included, except if the BUILD_TESTING option is turned off.
To build with just cmake change directory into where you want the binaries to be placed. For an in-place build you then run cmake and it will produce a CMakeCache. txt file that contains build options that you can adjust using any text editor.
CMake is a cross-platform build system generator. Projects specify their build process with platform-independent CMake listfiles included in each directory of a source tree with the name CMakeLists. txt. Users build a project by using CMake to generate a build system for a native tool on their platform.
You can do this more or less as you described. You can add a target which will fail to compile, then add a test which invokes cmake --build
to try to build the target. All that remains is to set the test property WILL_FAIL
to true.
So, say you have your tests in a file named "will_fail.cpp" which contains:
#if defined TEST1 non-compiling code for test 1 #elif defined TEST2 non-compiling code for test 2 #endif
Then you can have something like the following in your CMakeLists.txt:
cmake_minimum_required(VERSION 3.0) project(Example) include(CTest) # Add a couple of failing-to-compile targets add_executable(will_fail will_fail.cpp) add_executable(will_fail_again will_fail.cpp) # Avoid building these targets normally set_target_properties(will_fail will_fail_again PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE) # Provide a PP definition to target the appropriate part of # "will_fail.cpp", or provide separate files per test. target_compile_definitions(will_fail PRIVATE TEST1) target_compile_definitions(will_fail_again PRIVATE TEST2) # Add the tests. These invoke "cmake --build ..." which is a # cross-platform way of building the given target. add_test(NAME Test1 COMMAND ${CMAKE_COMMAND} --build . --target will_fail --config $<CONFIGURATION> WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_test(NAME Test2 COMMAND ${CMAKE_COMMAND} --build . --target will_fail_again --config $<CONFIGURATION> WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) # Expect these tests to fail (i.e. cmake --build should return # a non-zero value) set_tests_properties(Test1 Test2 PROPERTIES WILL_FAIL TRUE)
You can obviously wrap all of this into a function or macro if you have a lot of these to write.
@Fraser's answer is a good approach, in particular the WILL_FAIL
property is good advice. There is an alternative to making the failing target part of the main project though. The use case in the question is pretty much what the ctest --build-and-test
mode is meant for. Rather than making the expected-to-fail target part of the main build, you can put it in its own separate mini project which is then built as part of a test. An example of how this might look in the main project goes something like this:
add_test(NAME iter_conversion COMMAND ${CMAKE_CTEST_COMMAND} --build-and-test ${CMAKE_CURRENT_LIST_DIR}/test_iter ${CMAKE_CURRENT_BINARY_DIR}/test_iter --build-generator ${CMAKE_GENERATOR} --test-command ${CMAKE_CTEST_COMMAND} ) set_tests_properties(iter_conversion PROPERTIES WILL_FAIL TRUE)
This has the advantage that it will be part of the project's test results and will therefore be more likely to get executed regularly as part of normal testing processes. In the above example, the test_iter
directory is essentially it's own separate project. If you need to pass information to it from the main build, you can do that by adding --build-options
to define cache variables to pass to it's CMake run. Check the latest docs for recently corrected/clarified help on this area.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With