I have a project with a structure
├── CMakeLists.txt
├── mzl.c
├── mzl.h
└── tests
├── CMakeLists.txt
├── mzl-communication-test.c
├── mzl-setup-test.c
├── mzl-test-errors.c
└── mzl-test-errors.h
Where the top directory CMakeLists.txt file is
project(mzl)
cmake_minimum_required(VERSION 2.8)
add_subdirectory(tests)
# Enable testing for the project
enable_testing()
# Find zmq
find_library(ZMQ_LIB zmq REQUIRED)
message(STATUS "ZMQ Library: ${ZMQ_LIB}")
# Find threading library
set(CMAKE_THREAD_PREFER_PTHREAD ON)
find_package(Threads REQUIRED)
message(STATUS "Threading Library: ${CMAKE_THREAD_LIBS_INIT}")
# Set include directories for headers
set (
MZL_INCLUDE_DIRS
${CMAKE_SOURCE_DIR}
CACHE STRING "MZL Include Directories"
)
include_directories(${MZL_INCLUDE_DIRS})
# Set source files
set (
MZL_SRC_FILES
mzl.c
)
# Add library
add_library(${PROJECT_NAME} STATIC ${MZL_SRC_FILES})
# Link to zmq
target_link_libraries(${PROJECT_NAME} ${ZMQ_LIB} ${CMAKE_THREAD_LIBS_INIT})
and tests/CMakeLists.txt is
# Use MZL Source Directories (mzl headers are in top directory)
include_directories(${CMAKE_SOURCE_DIR})
# Variable from here is empty
message(STATUS "MZL Include Directories: ${MZL_INCLUDE_DIRS}")
# Files common to all tests
set ( TEST_COMMON_SOURCES
mzl-test-errors.c
)
# Library setup/shutdown testing
set(SETUP_TEST_NAME mzl-setup-test)
add_executable(${SETUP_TEST_NAME} ${TEST_COMMON_SOURCES} ${SETUP_TEST_NAME}.c)
target_link_libraries(${SETUP_TEST_NAME} ${PROJECT_NAME} ${ZMQ_LIB})
add_test(${SETUP_TEST_NAME} ${SETUP_TEST_NAME})
# Communcations test
set(COMMUNICATION_TEST_NAME mzl-communication-test)
add_executable(${COMMUNICATION_TEST_NAME} ${TEST_COMMON_SOURCES}
${COMMUNICATION_TEST_NAME}.c)
target_link_libraries(${COMMUNICATION_TEST_NAME} ${PROJECT_NAME}
${CMAKE_THREAD_LIBS_INIT} ${ZMQ_LIB})
add_test(${COMMUNICATION_TEST_NAME} ${COMMUNICATION_TEST_NAME})
Everything worked fine before I added the second test mzl-communication-test. After adding it and the lines in the tests/CMakeLists.txt after # Communications test, running ctest did nothing extra -- it still only ran the first test.
After deleting the build directory and running cmake again, I get no errors for the initial CMake run, but running make runs CMake again, resulting in an error with CMake:
CMake Error: Parse error in cache file build/CMakeCache.txt. Offending entry: include
followed by a Make error:
Makefile:203: recipe for target 'cmake_check_build_system' failed
make: *** [cmake_check_build_system] Error 1
Running make again results in everything being built, including the tests; however, running ctest results in
Test project build
No tests were found!!!
The issue seems to be with something that I am doing with CMake, but can't figure out what to do from here as I can't see anything that I'm doing differently than when it was originally working. Even my last commit to git, which was working when I committed it, is no longer working.
You need to move the enable_testing() call to be before you do add_subdirectory(tests)
# Enable testing for the project
enable_testing()
add_subdirectory(tests)
Related
I have written a simple c++ program intended to be built and packaged with CMake. The simple program depends on a third-party (OpenCV) library which can be found by find_package(OpenCV REQUIRED) in my CMake project. I want to build and package my simple program including the runtime library (Prerequisite Shared Libraries from OpenCV) so that I can produce a Windows installer file that can be installed and run on other Windows machines.
My project structure is as follows:
HAND-POSE
│ CMakeLists.txt
│ handpose.cpp
│ README.md
├───cmake
│ FixBundle.cmake.in
├───data
│ video.mp4
└───models
pose_deploy.prototxt
pose_iter_102000.caffemodel
I spent some time and got some documentation (here & here) from the CMake website, and tried to adapt my project in the following ways:
The CMakeLists.txt file is as follows:
cmake_minimum_required(VERSION 3.0.0)
project(HandPose VERSION 0.1.0)
set(CMAKE_PREFIX_PATH C:\\OpenCV-4.6.0)
include(CTest)
enable_testing()
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
ADD_EXECUTABLE(handpose handpose.cpp)
TARGET_LINK_LIBRARIES(handpose ${OpenCV_LIBS})
include(InstallRequiredSystemLibraries)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/FixBundle.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/FixBundle.cmake
#ONLY
)
install(TARGETS handpose
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/FixBundle.cmake)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
The FixBundle.cmake.in file is as follows:
include(BundleUtilities)
# Set bundle to the full path name of the executable already
# existing in the install tree:
set(bundle "Release/handpose#CMAKE_EXECUTABLE_SUFFIX#")
# Set other_libs to a list of full path names to additional
# libraries that cannot be reached by dependency analysis.
# (Dynamically loaded PlugIns, for example.)
# set(other_libs "")
# Set dirs to a list of directories where prerequisite libraries
# may be found:
set(dirs
"#CMAKE_RUNTIME_OUTPUT_DIRECTORY#"
"#CMAKE_LIBRARY_OUTPUT_DIRECTORY#"
"C:\\OpenCV-4.6.0\\x64\\vc16\\bin"
)
fixup_bundle("${bundle}" \"\" "${dirs}")
I have a simple shared library libfool2.so with installed header fool2.h which are not from a CMake project. My project my_temp1 depends on fool2 so I write a FindFool2.cmake to make an imported target:
find_path(Fool2_INCLUDE_DIR fool2.h PATH_SUFFIXES fool2)
find_library(Fool2_LIB fool2)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Fool2
REQUIRED_VARS Fool2_INCLUDE_DIR Fool2_LIB
)
if(Fool2_FOUND AND NOT TARGET Fool2::Fool2)
add_library(Fool2::Fool2 SHARED IMPORTED)
set_target_properties(Fool2::Fool2 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Fool2_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${Fool2_LIB}"
)
endif()
The CMakeLists.txt for my_temp1 project is:
cmake_minimum_required(VERSION 3.3)
project(my_temp1)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/cmake_modules)
# FindFool2.cmake is in ${CMAKE_CURRENT_LIST_DIR}/cmake/cmake_modules
find_package(Fool2 REQUIRED)
if (TARGET Fool2::Fool2)
message(STATUS "target found")
endif()
add_executable(my_temp1 main.cpp)
target_link_libraries(my_temp1 Fool2::Fool2)
Now
$ tree ../__install
../__install/
├── include
│ └── fool2
│ ├── fool2.h
│ └── version.h
└── lib
└── libfool2.so
$ tree .
.
├── cmake
│ └── cmake_modules
│ └── FindFool2.cmake
├── CMakeLists.txt
└── main.cpp
$ cmake -H. -B_builds -DCMAKE_INSTALL_PREFIX=../__install
# some output omitted
-- target found
-- Configuring done
-- Generating done
-- Build files have been written to: /OMITTED/my_temp1/_builds
$ cmake --build _builds
CMakeFiles/my_temp1.dir/build.make:82: *** target pattern contains no '%'. Stop.
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/my_temp1.dir/all' failed
make[1]: *** [CMakeFiles/my_temp1.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
$ head -n 85 _builds/CMakeFiles/my_temp1.dir/build.make | tail -n 10
# External object files for target my_temp1
my_temp1_EXTERNAL_OBJECTS =
my_temp1: CMakeFiles/my_temp1.dir/main.cpp.o
my_temp1: CMakeFiles/my_temp1.dir/build.make
my_temp1: Fool2::Fool2-NOTFOUND
my_temp1: CMakeFiles/my_temp1.dir/link.txt
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/OMITTED/my_temp1/_builds/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Linking CXX executable my_temp1"
$(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/my_temp1.dir/link.txt --verbose=$(VERBOSE)
The command $ cmake -H. -B_builds -DCMAKE_INSTALL_PREFIX=../__install finds fool2 because find_* commands searches in the CMAKE_INSTALL_PREFIX as well.
But why is there weird output my_temp1: Fool2::Fool2-NOTFOUND in build.make?
CMake version is 3.11.3
For IMPORTED library target value -NOTFOUND corresponds to absent IMPORTED_LOCATION property, corresponded to the library's path. You need to set that property for correctly work with IMPORTED target.
If you want CMake target to be a placeholder just for link with other libraries, use INTERFACE library target instead: such library target doesn't have library location.
I'm learning CMake at the moment and I'm stuck with a problem.
I have a library(that I have created previously with CMake) named 'libLibraryName'(I know, not the best name). This library contains just one function that prints a message and was formed by combining two files(1 header file wtih the prototype of the function and one .cpp with it's implementation).
Now I put the function in a folder and I'm trying to make a .cpp file make use of this library. This is the structure of my folder(as you can see the library is in the .../Library folder).
.
├── build
├── CMakeLists.txt
├── include
│ └── header.h
├── Library
│ └── libLibraryName.so
├── main.cpp
└── src
└── header.cpp
I wrote this CMakeLists:
cmake_minimum_required(VERSION 3.5.1)
# Project name
project(Project_Name)
# Include the existing library's name and then link it's path
# Make sure to provide a valid library name
set( PROJECT_LINK_LIBS libLibraryName.so )
link_directories(/home/uidr0938/CMake_Exercises/Library)
# Add path of the header files
include_directories(include)
# Create an executable with your main application's code
add_executable(Application main.cpp)
# And link the library to that application
target_link_libraries(Application ${PROJECT_LINK_LIBS})
Then I went into build and ran 'cmake ..'. This worked. But then when I wrote 'make' I get this following error:
/usr/bin/ld: cannot find -lLibraryName
collect2: error: ld returned 1 exit status
CMakeFiles/Application.dir/build.make:94: recipe for target 'Application' failed
make[2]: *** [Application] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/Application.dir/all' failed
make[1]: *** [CMakeFiles/Application.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
It is if the program is looking for the library at a different path not the one I provide it with the link_directories command.
Please help me solve this so I can use that library with my main function.
Thank you.
I used a virtual linux machine for this example.
I'm trying to configure CMake and ninja as a build system for my project. Except the app itself I have an extra executable for unit tests powered by gtest. I thought it would be nice to have them executed automatically whenever they are built. Here's how I made it:
├── build
└── source
├── CMakeLists.txt
├── main.cc
└── ut
├── CMakeLists.txt
├── gtest
│ ├── ...
└── ut.cc
source/CMakeLists.txt...
cmake_minimum_required (VERSION 2.6)
project (trial)
add_subdirectory(ut)
add_executable(trial main.cc)
...and source/ut/CMakeLists.txt:
add_subdirectory(gtest)
include_directories ("gtest/include")
add_executable(ut ut.cc)
target_link_libraries(ut LINK_PUBLIC gtest_main)
add_custom_target(run_uts
COMMAND ut
DEPENDS ut
WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
)
Now when I build it, i.e.:
cd build
cmake -GNinja ../source
ninja run_uts
It works fine except that the output is colorless. When I run the ut binary by hand, i.e. build/ut/ut I get nice green and red colors. The colors are also there when I use Unix Makefiles as a genrator for CMake.
Since I'm only learning CMake, is there something I missed or is it an issue with Ninja?
I assume your automated code runs a gtest executable and directs the output to a file. By default, gtest adds color sequences only when sending output to a terminal. In order to force it to add color sequences to output sent to a file or a pipe, run your test executable with the --gtest_color=yes option.
I have just added google-test source code to libs/gtest-1.6.4 directory in my project. There is a libs/gtest-1.6.4/CMakeLists.txt file. In the top-most CMakeLists.txt, I have added add_subdirectory('libs/gtest-1.6.4'). The structure of the project is
|- CMakeLists.txt
|- src
|- CMakeLists.txt
|- *.h and *.cc
|- libs
|- gtest-1.6.4
|- CMakeLists.txt
|- gtest source code etc.
|- other subdirectories
Now I add #include "gtest/gtest.h" in one of the header file. Compilation fails with
gtest/gtest.h: No such file or directory
compilation terminated.
Here is the snippet of my src/CMakeLists.txt file.
set( Boost_USE_STATIC_LIBS ON )
find_package( Boost COMPONENTS graph regex system filesystem thread REQUIRED)
.. Normal cmake stuff ...
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS} )
# This line is added for google-test
INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS} ${COMMON_INCLUDES})
add_executable(Partitioner
print_function.cc
methods.cc
partitioner.cc
main.cc
)
TARGET_LINK_LIBRARIES(Partitioner ${Boost_LIBRARIES})
TARGET_LINK_LIBRARIES(Partitioner ${GTEST_LIBRARIES})
What am I missing?
Looking at GTest's CMakeLists.txt, it looks like their include path is ${gtest_SOURCE_DIR}/include. They also define the library as a CMake target called gtest (this is wrapped in a macro cxx_library(gtest ...) currently on line 70).
So it looks like you need to do:
...
# This line is added for google-test
INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS} ${COMMON_INCLUDES})
INCLUDE_DIRECTORIES(${gtest_SOURCE_DIR}/include ${COMMON_INCLUDES})
...
TARGET_LINK_LIBRARIES(Partitioner ${Boost_LIBRARIES})
TARGET_LINK_LIBRARIES(Partitioner ${GTEST_LIBRARIES})
TARGET_LINK_LIBRARIES(Partitioner ${Boost_LIBRARIES} gtest)
You'd also have to ensure that in your root CMakeLists.txt, you've called add_subdirectory(libs/gtest-1.6.4) before add_subdirectory(src) so that the GTest variables are correctly set when they're being used in "src/CMakeLists.txt".
As mentioned in accepted answer,
I did put my GoogleTest stuff up before my add_subdirectory() lines and it worked.
# The ROOT CMakeLists.txt
enable_testing()
include(CTest)
# https://google.github.io/googletest/quickstart-cmake.html
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/....zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)
add_subdirectory(some)
add_subdirectory(other)
add_subdirectory(another)
And in one of those sub directory, I see tests work.
# A CMakeLists.txt in a sub directory
#enable_testing() # NOT REQUIRED, hence, commented out
#include(CTest) # NOT REQUIRED, hence, commented out
#include(GoogleTest) # NOT REQUIRED, hence, commented out
add_executable(
mytest
test/mytest.cpp
)
target_link_libraries(
mytest
gtest_main
)
gtest_discover_tests(
mytest
)