CMake Add (Test) Executable - c++

I would like to create two executables: one executable for the application, and one for the testing of the application. To that end, I have the following in my CMakeLists.txt file:
include_directories(include)
file(GLOB SOURCE "src/*.cc")
file(GLOB TEST "test/*.cc")
add_executable(interest_calc ${SOURCE})
add_executable(interest_calc_test "src/interest_calc.cc" ${TEST})
Since both src and test directories contain main functions, I have to manually add source files to the "test" executable. Is there another, non-manual, way to add required source files to the "test" executable?
Further, is there a better way to test functionality than creating a separate test executable? If so, what/how?

One way to improve your process would be to pull the guts of your executable into a library, then have a nominal "main" executable which just calls into your library and a "test" executable which exercises the library however you want to test it.
This way, any changes you need to make go into the library and the executable build process is untouched.
Edit to show CMake with your example:
include_directories(include)
file(GLOB SOURCE "src/*.cc")
# Remove main from library, only needed for exec.
list(REMOVE_ITEM SOURCE "main.cc")
file(GLOB TEST "test/*.cc")
add_library(interest_calc_lib STATIC ${SOURCE})
add_executable(interest_calc "main.cc")
target_link_libraries(interest_calc interest_calc_lib)
add_executable(interest_calc_test ${TEST})
target_link_libraries(interest_calc_test interest_calc_lib)

There are already some good answers from Soeren and mascoj but I would like to give a more concrete recommendation.
When you already have a CMakeLists.txt for your executable and you like to add testing, I recommend adding a static dummy library. This library can have all the sources of the executable except the main method (it may be easiest to single out the main method in a separate file if you do not have that already). Using a static library will give you two benefits:
The final executable will behave exactly as your current one, so there is no need to deal with distribution of a new, shared library
You do not need to deal with exporting symbols or throwing exceptions across shared object boundaries
The changes to your CMakeLists.txt can be quite small. I will give an example here, assuming you use cmake 3.0 or newer. First, an example of CMakeLists.txt before adding the dummy library:
project(MyProject)
set(SOURCES src/First.cc src/Second.cc src/Third.cc)
add_executable(${PROJECT_NAME} ${SOURCES} src/Main.cc)
target_include_directories(${PROJECT_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR})
target_compile_options(${PROJECT_NAME}
$<$<CXX_COMPILER_ID:GNU>:-Wall;-pedantic)
target_compile_definitions(${PROJECT_NAME}
$<$<CONFIG:Debug>:DEBUG;_DEBUG>)
set_target_properties(${PROJECT_NAME}
PROPERTIES CXX_STANDARD 14)
target_link_libraries(${PROJECT_NAME}
Threads::Threads)
To add the dummy library and testing, you need to introduce a new target with a different name. I choose here to use ${PROJECT_NAME}_lib because this will be very non-intrusive on the CMakeLists.txt. Here is the updated version. Notice the use of ${PROJECT_NAME}_lib in place of ${PROJECT_NAME} in almost all places. Most properties are now passed down to the executable by making them PUBLIC. Only calls to set_target_properties() are not transitive and must be duplicated for library and executable.
project(MyProject)
set(SOURCES src/First.cc src/Second.cc src/Third.cc)
add_library(${PROJECT_NAME}_lib STATIC ${SOURCES})
add_executable(${PROJECT_NAME} src/Main.cc)
target_include_directories(${PROJECT_NAME}_lib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR})
target_compile_options(${PROJECT_NAME}_lib PUBLIC
$<$<CXX_COMPILER_ID:GNU>:-Wall;-pedantic)
target_compile_definitions(${PROJECT_NAME}_lib PUBLIC
$<$<CONFIG:Debug>:DEBUG;_DEBUG>)
set_target_properties(${PROJECT_NAME}_lib
PROPERTIES CXX_STANDARD 14)
set_target_properties(${PROJECT_NAME}
PROPERTIES CXX_STANDARD 14)
target_link_libraries(${PROJECT_NAME}
${PROJECT_NAME}_lib
Threads::Threads)
Now you can link your tests against ${PROJECT_NAME}_lib with a different main method.

You could do like this :
In the current CMakeLists.txt, put these lines :
add_subdirectory(src)
add_subdirectory(test)
and then, in each directories add a CMakeLists.txt that link correctly sources to each files.
About test, I've heard that CMake can do test automation, but I don't really know how it works.

In my opinion the best solution is to create a library (shared or static) and two executables (one for the main program and one for the test main). After that you should link the library against the two applications.
In this answer I write down a explanation with a little example how you could managed the project with cmake.

Related

Why are files not found from parallel folders CMake

To have my .cpp and .h files a little bit sorted up pending on their responsibilitie I decided to put them into seperate folders
I used the following structure:
root
|
-CMakeLists.txt [rootCmakeList]
src
|
-main.cpp
.......|
....... math
.......|
.......-CMakeLists.txt[mathCmakeList]
.......-Algebra.h
.......-Algebra.cpp
.......XML[xmlCmakeList]
.......|
.......-CMakeLists.txt
.......-AwesomeXML.h
.......-AwesomeXML.cpp
The [rootCmakeList] looks:
cmake_minimum_required(VERSION 3.11.3)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS_DEBUG "-g")
project(myProject)
#add exectuable
add_executable(myProject src/main.cpp)
target_include_directories(myProject PUBLIC "${src/XML}")
target_include_directories(myProject PUBLIC "${src/math}")
add_subdirectory(src/XML)
add_subdirectory(src/math)
target_link_libraries(myProject xml)#needed?
target_link_libraries(myProject math)#needed?
The [mathCmakeList] looks:
include_directories(${myProject}src/math)
add_library(math Algebra.cpp)
The [xmlCmakeList] looks:
include_directories(${myProject}src/xml)
add_library(xml AwesomeXML.cpp)
So far so good and no problems. But if I want to #include Algebra.h into
AweseomeXML.cpp I can not find the file.
To being honest I am not even sure if the cmake command add_library and target_link_libraries makes really sense here because I do not want to create own libraries of it just want to tidy up a little bit my files pending on their topic.
myProject doesn't seem to be a variable you set. Furthermore if you properly set up the library targets, you won't need to add any of the include directories to myProject manually.
First set up the CMakeLists.txt file for math, since it doesn't depend on other projects. I recommend moving headers linking libraries use to a subdirectory. I myself usually use include and any path that you want the linking library to use in #includes starts there. Set the include dirs in a way that adds them to the INTERFACE_INCLUDE_DIRECTORIES target property of math.
add_library(math Algebra.cpp
include/Algebra.h # for IDEs
)
target_include_directories(math # should be static here, since you don't want to deploy the lib by itself
PUBLIC include # available to both math and linking libs
PRIVATE . # only available to math; only necessary, if there are "private" headers
)
Then do the same thing for xml, but since you're using functionality from math, you need to link it giving you access to its include dirs automatically, since they are available via INTERFACE_INCLUDE_DIRECTORIES:
add_library(xml STATIC
AwesomeXML.cpp
include/AwesomeXML.h
)
target_include_directories(xml PUBLIC include)
target_link_libraries(xml PRIVATE math) # change PRIVATE to PUBLIC, if Algebra.h is included in a public header
Now at the toplevel we should make sure that any dependencies of a target are available before the target is defined. Also linking a lib gives you access to their respective public include directories and the public include dirs of dependencies linked publicly:
cmake_minimum_required(VERSION 3.11.3)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS_DEBUG "-g")
project(myProject)
add_subdirectory(src/math)
add_subdirectory(src/XML)
#add exectuable
add_executable(myProject src/main.cpp)
target_link_libraries(myProject PRIVATE math xml)

How can I use Catch2 to test my CMake static library project?

I'm writing a static library which contains some shared code between several projects. In order to verify that the code in this library functions properly I'd like to use Catch2 to do some unit testing on it.
Unfortunately, when attempting to run the tests I run into the problem that the compilation's output file is a shared library (.a), rather than an executable.
I'm sure I can create a separate project which uses the functions from my static library, and subsequently run tests that way, but ideally I'd like to keep the tests and build configurations as close as possible to one another.
So my question is:
what's the best way to set up my project such that I can use Catch2 for unit testing my static library code?
Here's my project's CMakeLists.txt file for reference:
project(sharedLib CXX)
find_package(OpenMP)
if (CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp -lpthread -Wall -Wextra -Wpedantic -std=c++17")
endif()
if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fopenmp /W4 /std:c++latest")
endif()
include_directories (
src/
lib/Catch2/single_include/
)
file (GLOB_RECURSE LIBRARY_SOURCES src/*.cpp
src/*.c
tests/*.cpp)
add_library(${PROJECT_NAME} STATIC ${LIBRARY_SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC src/)
A common pattern for testing static libraries is to have a separate executable which contains all the tests, and then consumes your library. for example
file (GLOB_RECURSE TEST_SOURCES tests/*.cpp)
add_executable(my_lib_tests test_main.cpp ${TEST_SOURCES})
target_link_libraries(my_lib_tests PRIVATE sharedLib)
target_include_directories(my_lib_tests PRIVATE ../path/to/secret/impl/details)
Here I also have added some include some directories to implementation details of your shared lib which you may need to test, but don't want to expose to clients via a public header.
test_main.cpp need only be:
#define CONFIG_CATCH_MAIN
#include <catch2/catch.hpp>
Then you don't have to include things in your library's build that are unrelated to the library itself, speeding up compilation time for clients, while you can work from the perspective of the test fixture

how to use cmake to compile modern c++ project code

here's my source code directory structure.
some project
libs
mylib1
...
3rdlibs1
...
apps
myapp1
...
My requirments are as follows:
3rdlibs1 should be compiled when using command. like "cmake -G ...".
3rdlibs1 should be compiled as static library.
mylib1 should be modular.
mylib1 depends on 3rdlibs.
myapp depends on mylib1, and it should only link to mylib1. It shouldn't depends on 3rdlibs or system libraries.
Can you give me some sample code. I know ExternalProject_Add can help me to compile 3rdlibs. But I really don't know how to do it.
I think other people may also be interesting to this question.
If you have all your sources in single file system tree, it is better to use add_subdirectory than ExternalProject. ExternalProject is for projects which are truly external, e.g. on remote server or VCS repository. Unlike add_subdirectory which can create target of any type, ExternalProject can create only UTILITY target, similar to add_custom_target command. UTILITY targets have limitations, e.g. you can not use them in target_link_libraries command. Using add_subdirectory is much simpler.
Top-level:
cmake_minimum_required(VERSION 3.7)
project("some_project")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(libs/3rdlibs1)
add_subdirectory(libs/mylib1)
add_subdirectory(apps/myapp1)
App:
project("myapp1")
set(SRC_FILES ...)
add_executable(myapp1 ${SRC_FILES})
target_link_libraries(myapp1 PRIVATE mylib1)
Lib. As I understand from your description, 3rdlibs1 is optional dependency of mylib1. Otherwise, how can myapp use mylib1 without 3rdlibs1?
project("mylib1")
option(THIRD_LIBS_SUPPORT "description" OFF)
set(SRC_FILES ...)
add_library(mylib1 STATIC ${SRC_FILES})
#PUBLIC means that both mylib1 and its dependents use the headers
target_include_directories(mylib1 PUBLIC "${PROJECT_SOURCE_DIR}/include")
if(THIRD_LIBS_SUPPORT)
#PUBLIC means that 3rdlibs1 will be linked to mylib1 dependents
target_link_libraries(mylib1 PUBLIC 3rdlibs1)
target_compile_definitions(mylib1 PUBLIC -DTHIRD_LIBS_SUPPORT)
endif()

Right way of creating a library, installing it and linking to another project using CMake

I have a set of files that I want to make into a library and then use that library in another project. This it how it looks like right now
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
SET(CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -fPIC")
add_library (helperlibs lib1.cpp lib2.cpp lib3.cpp lib4.cpp )
INSTALL(TARGETS helperlibs
DESTINATION "${HOME}/lib"
)
INSTALL(FILES lib1.h lib2.h lib3.h lib4.h helperheader.h
DESTINATION "${HOME}/include/helperlibs"
)
In this code Lib4 depends on Lib1-3 and Lib3 depends on Lib1-2 and Lib2 depends on Lib1. Each of these cpp files also depend on a helperheader.h file that contains some definitions and structs.
In my project I have the following CMake file
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
SET( CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -fPIC")
SET(MYINCS ${HOME}/include/helperlibs)
SET(MYLIBDIR ${HOME}/lib)
SET(MYLIBS ${MYLIBDIR}/libhelperlibs.a )
include_directories(${MYINCS})
add_executable(main main.cpp)
target_link_libraries(main ${MYLIBS})
So what I am wondering if you want to create a static library and link to from a another project using cmake is this the way you should write?
Embed the search paths into the library target as properties and create an export.
This way executables in the same build tree will find the library and its include files without you having to specify paths (they become implicit).
I needed to read the cmake documentation carefully a few times before it dawned on me how it should work.
http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html#creating-packages
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
excerpt from a live example:
add_library(trustportal-util ${CMAKE_CURRENT_LIST_FILE} ${_source_files} ${_disabled_source_files} )
target_link_libraries(trustportal-util ${Boost_LIBRARIES})
if(APPLE)
find_library(SECURITY_FRAMEWORK Security)
target_link_libraries(trustportal-util ${SECURITY_FRAMEWORK})
else()
find_library(LIB_SSL ssl)
find_library(LIB_CRYPTO crypto)
target_link_libraries(trustportal-util ${LIB_SSL} ${LIB_CRYPTO})
endif()
target_compile_definitions(trustportal-util PUBLIC BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE)
target_include_directories(trustportal-util PUBLIC ${Boost_INCLUDE_DIRS})
target_include_directories(trustportal-util PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_include_directories(trustportal-util SYSTEM PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
install(TARGETS trustportal-util
EXPORT trustportal-utilExport
DESTINATION lib
INCLUDES DESTINATION include
)
INSTALL(EXPORT trustportal-utilExport DESTINATION lib)
One option is to do what you are currently doing where you place the includes and libs in a common location, perhaps /usr/include and /usr/lib on linux, or ${HOME} on both Windows/Linux, up to you.
Another option is available if you use git. You can include the project inside another using submodules. Then use include_directory(${submodule}) and build and link directly for every project. The advantage of this approach is that dependencies are more localised. One problem with this method is if you recursively do this, you may end up with duplicates of some projects and cmake will complain that two libraries have the same name.

CMake with Google Protocol Buffers

I'm trying to use cmake to build my little project using protocol buffers.
There's a root directory with a number of subdirectories with a number of libraries and executables. My first thought was to have my .proto-files in a subdirectory, but when I read this answer I made a library out of it instead. But when I try to include a messages header in my executable it can't find it.
Error message:
fatal error: msgs.pb.h: No such file or directory
#include "msgs.pb.h"
^
compilation terminated.
I'm running it by creating a dir "build" and then "cmake .. && make" from inside it.
I've looked and it seems the generated files get put in build/messages, so I could do include_directories(build/messages) but that doesn't seem...proper. Is there a proper way of doing this with protobuf? The reason I want the messages file in their own folder is they they'll be used in a lot of different small executables.
Any other general tips for improvements to my CMake-structure is also appreciated :)
Directories:
root
messages
core
server
root/CMakeLists.txt:
project(lillebror)
cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0015 NEW)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost COMPONENTS date_time log thread system)
find_package(Protobuf REQUIRED)
if(Boost_FOUND)
add_definitions(-std=c++11)
add_subdirectory(messages)
add_subdirectory(core)
add_subdirectory(server)
add_subdirectory(testserver)
endif()
messages/CMakeLists.txt:
file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles})
add_library(messages STATIC ${ProtoSources} ${ProtoHeaders})
target_link_libraries(messages ${Boost_LIBRARIES} ${PROTOBUF_LIBRARY})
core/CMakeLists.txt:
aux_source_directory(src SRC_LIST)
add_library(core STATIC ${SRC_LIST})
target_link_libraries(core messages ${Boost_LIBRARIES})
server/CMakeLists.txt:
aux_source_directory(src SRC_LIST)
include_directories(../messages) <---- I thought this would sove my problem
include_directories(../core/src)
link_directories(../core/build)
add_executable(server ${SRC_LIST})
target_link_libraries(server core ${Boost_LIBRARIES})
server/main.cpp:
#include "msgs.pb.h"
int main()
{
return 0;
}
I think the problem here is that the PROTOBUF_GENERATE_CPP function sets up the .pb.h and .pb.cc files to exist in the build tree, not in the source tree.
This is good practice (not polluting the source tree), but it means that your call include_directories(../messages) is adding the wrong value to the search paths. This is adding the source directory "root/messages", whereas you want "[build root]/messages".
You could probably just replace that line with:
include_directories(${CMAKE_BINARY_DIR}/messages)
However, a more robust, maintainable way might be to set the required include path inside the messages/CMakeLists.txt. To expose this value to the parent scope, this would need to either use set(... PARENT_SCOPE) or:
set(ProtobufIncludePath ${CMAKE_CURRENT_BINARY_DIR}
CACHE INTERNAL "Path to generated protobuf files.")
Then in the top-level CMakeLists.txt, you can do:
include_directories(${ProtobufIncludePath})
If your messages library itself needs to #include the generated protobuf files (this would be normal), then it too should have a similar include_directories call.
Having said all that, if you can specify CMake v2.8.12 as the minimum, you can use the target_include_directories command instead.
In messages/CMakeLists.txt after the add_library call, you'd simply do:
target_include_directories(messages PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
Then any other target which depends on messages automatically has the appropriate "messages" include dirs added to its own - you don't need to explicitly call include_directories at all.