I am using CTest. I have all my tests in a folder
target
src
test
|- featureA.c
|- featureB.c
It's quite annoying that the tests are generated in a target folder within that test folder, I would rather all my tests get added to the global target folder.
How would I go about doing that?
You can pass your folder as an option to add_test command.
Related
For a project I am autogenerating multiple Fortran source files using add_custom_command. To my knowledge this results in CMake creating a GENERATED source file that I can add to a target such as a library or executable. However, since the file does not exist at CMake compile time CMake cannot use the source_group command to group these generated files for the IDE (Visual Studio).
Is there another way to achieve the same result as source_group that I cannot find? For example when using CMake with Qt you can set the AUTOGEN_SOURCE_GROUP to change the source group for the automoc and autorcc generated files.
Example.
# Creates a command to generate the 'a.f90' file using 'mytool.exe' and 'a.f90.in'.
add_custom_command(
OUTPUT a.f90
COMMAND mytool.exe a.f90.in
DEPENDS a.f90.in
)
add_executable(example a.f90 b.f90 c.f90) # Where b.f90 and c.f90 are not generated
source_group("Source Files/Not Generated" FILES "b.f90 c.f90")
source_group("Source Files/Generated" FILES a.f90) # Does nothing
This results in the following visual studio filters,
Source Files
|- Non Generated Files
|- b.f90
|- c.f90
|- a.f90
instead of
Source Files
|- Non Generated Files
|- b.f90
|- c.f90
|- Generated Files
|- a.f90
To help others who might be trying the same thing. Here's my workaround. I couldn't find a way to group autogenerated files using add_custom_command. This leaves a possible solution. If you are fine with not having the files autogenerated when your code is compiled you may instead use the execute_process command. With execute_process the command will be run when CMake creates the build tree instead of when you compile your source code. Since the files will already exist may be added as normal source files and can be grouped using source_group.
Example
# Generates 'a.f90'
execute_process(COMMAND mytool.exe a.f90.in ${CMAKE_CURRENT_BINARY_DIR}/a.f90)
add_executable(main "${CMAKE_CURRENT_BINARY_DIR}/a.f90" b.f90 c.f90)
source_group("Source Files/Not Generated" FILES "b.f90 c.f90")
source_group("Source Files/Generated" FILES a.f90)
With this the visual studio filters look like
Source Files
|- Generated
|- a.f90
|- Not Generated
|- b.f90
|- c.f90
The top-level CMakeLists.txt contains:
include(CTest)
add_subdirectory(lib)
add_subdirectory(demo)
add_subdirectory(test)
lib/CMakeLists.txt is essentially:
add_library(MyLib <sources>)
demo/CMakeLists.txt is essentially:
add_executable(Demo demo.c)
target_link_libraries(Demo MyLib)
test/CMakeLists.txt is just:
add_test(NAME Demo COMMAND Demo)
From a gitlab-runner, we execute:
cmake -G "Ninja" -DCMAKE_INSTALL_PREFIX=C:\opt\x64 -B. ..
cmake --build
ctest --output-on-failure
The first two steps succeed; the third one fails with:
Start 1: Demo
1/1 Test #1: Demo .......................Exit code 0xc0000135
***Exception: 0.03 sec
If I retry:
cmake --install
ctest
then the test succeeds. So the sole problem is that build/lib/mylib.dll is not found when running ctest. Whereas C:\opt\x64\lib is in PATH, and therefore the DLL is found after cmake --install. Which, however, is not what we want: ctest shall always use the fresh DLL from the current build, not the installed version.
Under Linux, everything works correctly. Why doesn't it for Windows and MinGW? Is this a bug in CMake? How can we work around this so that ctest executes correctly on all platforms?
Your issue seems to be the Windows DLL search procedure failing to find mylib.dll when your Demo executable is run by ctest. The Windows DLL search order is specified here:
The directory from which the application loaded.
The system directory. Use the GetSystemDirectory function to get the path of this directory.
The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
The current directory.
The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by
the App Paths registry key. The App Paths key is not used when
computing the DLL search path.
So, you could modify your PATH environment variable to also include the location of the fresh DLL from the current build.
A better, less error-prone solution might be to place the DLL in the same directory as the Demo executable. You can force CMake to use the same binary directory for both the DLL and executable by modifying your top-level CMake file:
include(CTest)
add_subdirectory(lib ${CMAKE_BINARY_DIR}/demo)
add_subdirectory(demo ${CMAKE_BINARY_DIR}/demo)
add_subdirectory(test)
Alternatively, as a less localized approach, you can place the DLL in the same directory as the executable by setting CMAKE_RUNTIME_OUTPUT_DIRECTORY:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
Yet another alternative:
add_test(NAME Demo COMMAND Demo WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
Is it possible to specify build directory within CMakeLists file? If yes, how.
My aim is to be able to call "cmake" within top level source directory and have cmake figure out the build directory.
Afaik, with CMake the build directory is always the directory from where you invoke the cmake or ccmake command. So if you want to change the build directory, you have to change directories before running CMake.
To control the location where executables, static and shared libraries are placed once finished, you can modifiy CMAKE_RUNTIME_OUTPUT_DIRECTORY, CMAKE_ARCHIVE_OUTPUT_DIRECTORY, and CMAKE_LIBRARY_OUTPUT_DIRECTORY respectively.
By design, there is not a way to specify that in CMakeLists.txt. It is designed for the user to be able to build the project in whatever directory they want. The typical workflow is:
Check out the project source code.
Go to desired build directory, or the source dir if you plan to do an in-source build.
Run cmake or ccmake to configure the project in that build directory.
Build your project.
All of the directories specified within your CMakeLists.txt should be relative to the ${PROJECT_BINARY_DIR} and ${PROJECT_SOURCE_DIR} variables. In this way, your code becomes buildable across different platforms, which is the goal of CMake.
Using CMake, I have a series of executables that are built, then added as tests, like this:
set(TestID 1)
add_executable (Test${TestID} Test${TestID}.cpp)
# Create test
configure_file(${TestID}.endf ${TestID}.endf COPYONLY)
add_test( NAME ${TestID} COMMAND Test${TestID} )
This works fineāthe executables are created and the tests are correctly added. However, I don't want the test executables to be added to the all target.
Instead of having my tests built along with everything else, I would like them built right before the execution of the tests; maybe as part of make test or as part of ctest.
How can I do this?
Set the EXCLUDE_FROM_ALL flag upon creating the test executable target to exclude the target from the all target:
add_executable (Test${TestID} EXCLUDE_FROM_ALL Test${TestID}.cpp)
Making sure that the test targets are built before the execution of the tests is more tricky. You cannot add a dependency to the built-in test target with add_dependencies, because the test target belongs to a group of reserved targets (like all, clean and a few others) that only exist in the created build system.
As a work-around you can use the TEST_INCLUDE_FILES directory property to trigger the build of the required test executables before the tests are run. Create a file BuildTestTargets.cmake.in in the source directory with the following contents:
execute_process(COMMAND "#CMAKE_COMMAND#" --build . --target Test1)
execute_process(COMMAND "#CMAKE_COMMAND#" --build . --target Test2)
Then add the following code to your CMakeLists.txt:
configure_file("BuildTestTargets.cmake.in" "BuildTestTargets.cmake")
set_directory_properties(PROPERTIES TEST_INCLUDE_FILES
"${CMAKE_CURRENT_BINARY_DIR}/BuildTestTargets.cmake")
CTest will then include and run the file BuildTestTargets.cmake as a first step before the tests are run.
Is it possible to specify build directory within CMakeLists file? If yes, how.
My aim is to be able to call "cmake" within top level source directory and have cmake figure out the build directory.
Afaik, with CMake the build directory is always the directory from where you invoke the cmake or ccmake command. So if you want to change the build directory, you have to change directories before running CMake.
To control the location where executables, static and shared libraries are placed once finished, you can modifiy CMAKE_RUNTIME_OUTPUT_DIRECTORY, CMAKE_ARCHIVE_OUTPUT_DIRECTORY, and CMAKE_LIBRARY_OUTPUT_DIRECTORY respectively.
By design, there is not a way to specify that in CMakeLists.txt. It is designed for the user to be able to build the project in whatever directory they want. The typical workflow is:
Check out the project source code.
Go to desired build directory, or the source dir if you plan to do an in-source build.
Run cmake or ccmake to configure the project in that build directory.
Build your project.
All of the directories specified within your CMakeLists.txt should be relative to the ${PROJECT_BINARY_DIR} and ${PROJECT_SOURCE_DIR} variables. In this way, your code becomes buildable across different platforms, which is the goal of CMake.