How to shadow a header file with CMake for unit-testing - c++

This is the simplified folder structure I have:
+ production
+-- ClassToTest.cpp (contains '#includes "DragonHeader.h"')
+-- ClassToTest.h
+-- DragonHeader.h (has a lot of dependencies, ClassToTest only need one simple static function with no dependencies at all.)
+ tests
+-- tst_ClassToTest.cpp
+-- DragonHeader.h (which defines and implements the needed simple function)
So for the test case I'd like that tests/DragonHeader.h shadows production/DragonHeader.h. => ClassToTest.cpp includes tests/DragonHeader.h. How can that be achieved? (I am working with MSVC 2015 if it is relevant...)
The CMakeLists.txt in the tests folder looks like
project( tst_ClassToTest )
set( ${PROJECT_NAME}_SOURCES tst_ClassToTest.cpp DragonHeader.h ../production/ClassToTest.cpp )
# How to force ClassToTest.cpp to use DragonHeader.h, not production/DragonHeader.h?
add_executable( ${PROJECT_NAME} WIN32 ${${PROJECT_NAME}_SOURCES} )
Thanks!
Disclaimer: I seek for a solution that does not require me to touch ClassToTest.cpp or to touch the code in production including the related CMakeLists.txt files at all. One solution, however, is to use CMake to copy ClassToTest.cpp/h into the tests folder, but I consider it sub-optimal.

My first thought was to use different include_directory statements for both production and unit test. But in this case the other header file ClassToTest.h must be in a different folder. Or you have to moveDragonHeader.h into another folder.
# CMake for production
include_directory(production)
include_directory(production_dragon)
#CMake for test
include_directory(production)
include_directory(test_dragon)
Another way could be an
#ifndef USE_TEST_HEADERS
#include "DragonHeaderTest.h"
#else
#include "DragonHeader.h"
#endif
in ClassToTest.cpp. To set the define add into your test/CMakeLists.txt file the string -DUSE_TEST_HEADERS to the compiler flags.
Third solution is to replace production/DragonHeader.h by a copy of test/DragonHeader.h in advanced of make. This works only in case production/DragonHeader.h can be restored. Either from a file system copy or from your Configuration Mgmt. System. This can by achieved by wrap the bild into a script. Don't know whether MSVC 2015 can trigger such a script instead of build.
rem Build for tests
rem Run cmake
cmake PARAMETERS
rem Prepare unit test
cp WHATEVER
rem nmake
name PARAMETERS

Related

Cmake project with multiple executables

I'm having trouble organizing my project using CMake with multiple executables. I have the following structure:
CmakeLists.txt
main.cpp
somelib.cpp
somelib.h
dir1
main.cpp
file1.h
file1.cpp
...
dir2
main.cpp
lib1.h
lib2.cpp
...
In general, I want to be able to choose the executable in Clion and run any project independently including the outer one which depends on two other projects. In the outer main.cpp I include the headers from dir1 and dir2. The dir1, dir2 projects itself depend on different libraries like Boost, Eigen, Qt etc. What is the best way to make this structure work? I'm new to Cmake and multiple tries using add_subdirectory haven't brought me closer to a solution. I made it work only in case when I have outer CmakeLists.txt and include all libraries there while using dir1, dir2 just as folders without any CmakeLists.txt inside. I'd appreciate any help.
From a plain CMake perspective -- so I have no idea how this interacts with CLion, but you indicate in comments that writing-the-CMakeLists.txt is the important bits -- one way to do it is this:
have a top-level CMakeLists.txt which sets up CMake parameters, C++ standards, compiler flags, options, etc.
after all the setup, add_subdirectory(dir1/) and add_subdirectory(dir2/)
after that, whatever you need for the top-level target, such as add_executable(mytoplevelprogram main.cpp somelib.cpp). If the build of mytoplevelprogram needs headers from the libraries, use suitable target_include_directories(mytoplevelprogram ...) and/or link to artifacts created in the subdirectories
in each of the subdirectories dir1 and dir2, write a CMakeLists.txt that finds the dependencies and builds the executable for that subdirectory, with suitable add_executable() commands.
There's generally no reason to put more than one project() command in your source tree.

CMake target_include_directories does not affect header files

My project is roughly structured like this:
├CMakeLists.txt
|
├───ExampleApp
| ├───CMakeLists.txt
| ├───header.hpp
| └───main.cpp
|
└───ExampleLibrary
├───CMakeLists.txt
├───mylib.hpp
└───mylib.cpp
In the root CMakeLists.txt I call
add_subdirectory(ExampleLibrary)
add_subdirectory(ExampleApp)
To build the library I call:
add_library(ExampleLibrary
mylib.hpp mylib.cpp
)
And finally, in the executable, I try to do:
add_executable(ExampleApp
header.hpp main.cpp
)
target_include_directories(ExampleApp
PRIVATE ${PROJECT_SOURCE_DIR}/ExampleLibrary
)
target_link_libraries(ExampleApp
Path/To/The/Binary/Directory
)
Now the build files generate just fine, and the project also builds with no errors. However, when I now try to include mylib.hpp in header.hpp, I get build errors because it can't find the file mylib.hpp. But I actually can include mylib.hpp in main.cpp and the project builds and compiles.
Am I missing something? I thought target_include_directories() works for both .cpp and .hpp files.
It seems like you may not have added the correct directory as an include directory for the ExampleApp. The PROJECT_SOURCE_DIR variable evaluates to the directory in which the last project() call was made in your CMake project. You have not shown where this is, but you could use the root directory of the CMake project to be sure it is correct; try using ${CMAKE_SOURCE_DIR}/ExampleLibrary in the target_include_directories call instead:
target_include_directories(ExampleApp
PRIVATE ${CMAKE_SOURCE_DIR}/ExampleLibrary
)
A couple more notes:
If you aren't using an IDE such as Visual Studio for compilation, there is no need to add header files to calls like add_library() and add_executable(). Doing this only ensures they are shown in an IDE.
Instead, specify directories within which the headers can be found, using target_include_directories(). In your case, it sounds like you should have both directories listed here.
To link the ExampleLibrary target to the executable, you can simply use the target name in target_link_libraries(). There is no need to list out the binary directory (unless you are linking other libraries from there).
So with this in mind, the ExampleApp CMake file could look something like this:
add_executable(ExampleApp
main.cpp
)
target_include_directories(ExampleApp PRIVATE
${PROJECT_SOURCE_DIR}/ExampleLibrary
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(ExampleApp PRIVATE
ExampleLibrary
)

CMake with gmock

I just want to make sure that my understanding about CMakeLists.txt is correct. My dummy project structure:
|-+ dummy
|-+ CMakeLists.txt
|-+ src
|-- CMakeLists.txt
|-- Converter.cpp
|-- Converter.hpp
|-- main.cpp
|-+ tests
|-- CMakeLists.txt
|-- Converter_ut.cpp
|-+ thirdparty
|-+ gmock-1.7.0
My goal is to create build process with CMake. This is my first attempt so I assume that there are some mistakes. It works but I am not sure if I understand everything correctly and I would be thankful if you could share with some comments / suggestions.
dummy/CMakeLists.txt
cmake_minimum_required (VERSION 2.8.11)
project (SUB)
add_subdirectory (src)
add_subdirectory (tests)
cmake_minimum_required is pretty self-explanatory,
project (SUB) sets project variables like ${SUB_SOURCE_DIR} and ${SUB_BINARY_DIR},
add_subdirectory, tells CMake to go and process CMakeLists.txt in the following directories
src/CMakeLists.txt
add_library (Sub
main.cpp
Converter.cpp)
target_include_directories (Sub PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
# Executable
add_executable (converter
Converter.cpp)
target_link_libraries (converter Sub)
add_library, creates library called "Sub" from two source files,
target_include_directories, tells the compiler where are the header files for "Sub" library (is that "PUBLIC" really needed here?),
add_executable, creates "converter" executable from Converter.cpp (why main.cpp is not needed here?),
target_link_libraries, links "Sub" library with "converter" executable
tests/CMakeLists.txt
# GMOCK
set (GMOCK_DIR "../thirdparty/gmock-1.7.0")
add_subdirectory(${GMOCK_DIR} ${CMAKE_BINARY_DIR}/gmock)
include_directories(SYSTEM ${GMOCK_DIR}/include ${GMOCK_DIR}/gtest/include)
# Executable
add_executable (tests
Converter_ut.cpp)
target_link_libraries (tests gmock_main Sub)
set (GMOCK_DIR ...), sets local variable "GMOCK_DIR" with my gmock folder location,
add_subdirectory, tells CMake to jump into gmock location and run their CMakeLists.txt, what is the second argument? {CMAKE_BINARY_DIR}/gmock?
add_executable, creates second executable file
target_link_libraries, links gmock_main library with second executable, "Sub" library is needed here because Converter_ut.cpp
needs to include "Converter.hpp" from src directory
Thank you in advance. I have read plenty of sites / tutorials already but I am still not sure about that.
One more thing - I cannot really imagine project with plenty of source files. Isn't there a better way to add source files to add_library and add_executable functions than listing it manually? Something like "take all *.cpp files from current directory"?
Thanks.
Cmake is not properly a programming language supporting a full paradigm, so use it, but if possible never start creating "a framework with it" (it would be cumbersome without proper syntactic sugar), it is intended to make small scripts not to write thousand lines of code (and despite few good frameworks exists, I tend to not use them: "If I cannot code it in few lines, then it's not job for CMAKE").
The important parts are (not that it is slightly different, I copy-pasted the improved version i still have to commit):
cmake_minimum_required( VERSION 2.8)
project( Infectorpp2)
# find additional cmake scripts (I'm driving away from this)
set( CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# create list of files from a glob
file( GLOB INFECTOR_SOURCE_FILES
"include/Infectorpp/priv/*.cpp")
# create list of files from a glob
file( GLOB INFECTOR_HEADER_FILES
"include/Infectorpp/priv/*.hpp"
"include/Infectorpp/*.hpp")
# or just "add_executable" the dollar "${}" just expand the list
add_library( libInfectorpp2 STATIC
${INFECTOR_SOURCE_FILES}
${INFECTOR_HEADER_FILES})
If you are not using 3rd party libraries, then you do not need to add target_include_directories because for your own application relative paths suffice.
For the testing part you are mostly ok to me, but I would do:
enable_testing()
## details omitted...
# create list of files from a glob
file( GLOB GMOCK_TESTS_SOURCE_FILES
"locationToTestFiles/*.cpp")
# Executable
add_executable (tests
${GMOCK_TESTS_SOURCE_FILES})
target_link_libraries (tests gmock_main Sub)
add_test(tests tests)
Also note that CMAKE is the only reason why I find useful having different extensions for C++ files, because of GLOBS, if you want to exclude some file you have to change its extension (to cc, c++, cxx or what your prefer).
You can do mostly anything following the same pattern, note that with GLOB you have to re-configure CMake to detect newly added files, however still better than adding them manually to build script (and anyway that will not cause a whole recompilation, CMake keep track of data and will avoid to re-compile old files)
Some people find useful adding files manually to CMake scripts because "I can keep old file there". Don't do that, move old files into an "old" folder, or just let your subversion system keep memory of them for you.
You will catch most errors earlier, and you will have a "ready to ship" project (you won't accidentally left wrong files that users will attempt to compile)
Another important point:
Do out of source builds, from your script I guess you are still not doing that.

CMake changing a library include directory based off of calling project

Here is my current project structure:
ProjectX
|_ projs
|_ A ( builds an external project POO version 1 )
add_executable(A ${A_HDRS} ${A_SRCS} $<TARGET_OBJECTS:libbar>)
|_ B ( builds an external project POO version 2 )
add_executable(B ${B_HDRS} ${B_SRCS} $<TARGET_OBJECTS:libbar>)
|
|_ libs
|_ libbar (objects only - no linking)
(needs POO either v1 or v2 depending on calling project)
issue lives here -->INCLUDE_DIRECTORIES(${POO_BUILD_DIR}/include)
add_library(bar OBJECT ${LIB_BAR_HDRS} ${LIB_BAR_SRCS})
GOAL:
I would like to be able to build from the top level including all projects and have libbar to be built with the correct dependencies. I would like to be able to have a continuous build process.
DETAILS:
When project A build builds, it needs to compile libbar with POO version1 and when project B builds it needs to compile libbar wtih POO version2. In either case it is still a version of POO. I would like to be able to pass the path to libbar from A or B.
ISSUE:
The POO_BUILD_DIR path is different depending on the project building libbar. When I build from the top level, make tries to build libbar first and doesn't find the correct includes.
QUESTION:
Does anyone know how to achieve this in cmake or how can I achieve finer grained control over the build order?
UPDATE and SOLUTION:
The problem that I was having could have been solved with Chris's solution below. However, my problem (that I should have realized earlier) is that even though it lives in a library directory and is called a library it's not a library. The naming and directory structure I can't change b/c I don't own the code base. However, I can change how I build it! My quote-unquote solution was to just include the files to the compilation like this: add_executable(A ... ${libbar_hdrs} ${libbar_srcs}
Moral of the Story
If someone tells you it's a library and names it a library - it still may not be. Or expressed in a colloquialism "Don't always believe what you're told".
Well there's lots of ways that you could do that, but one way that I have done it in a cmake C++ project is, for each library (each folder inside of /lib in my project root) I have a secondary Cmake script which builds that library, and I use add_subdirectory within my primary cmake script to invoke those secondary cmake scripts.
Here's an (open source) example from my project: https://github.com/cbeck88/cegui-emscripten
For instance, if you look here you'll see how I do "in tree" (what you are talking about) libs using add_subdirectory, vs. "out of tree" (user provided) libs which I find using find_package. https://github.com/cbeck88/cegui-emscripten/blob/17f0d097f989862035e977a6b9e0b1bbb1fcdf21/CMakeLists.txt#L58
if (FREETYPE_IN_TREE)
add_subdirectory(lib/freetype-2.5.5 freetype-2.5.5)
else()
LIST(APPEND CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib/freetype-2.5.5-old )
find_package(freetype NO_CMAKE_FIND_ROOT_PATH)
MESSAGE ( STATUS "FREETYPE found = " ${FREETYPE_FOUND} )
endif()
This is what my secondary cmake script (in folder freetype-2.5.5) looks like, it will look very different in your case but at least it's an example. https://github.com/cbeck88/cegui-emscripten/blob/d24fcd6a5dc4697b8718564fadb25d76c255bce2/lib/freetype-2.5.5/CMakeLists.txt
Note especially some of these lines at the very end SET(FREETYPE_INCLUDE_DIRS ${INCL} PARENT_SCOPE) which you might need to use if you do it this way.

Help needed while setting up basic multiplatform cmake-enabled project

tl;dr the questions are at the bottom.
I am a developer trying something new - my last poison is c++. As I am spending half of my time on my linux laptop and the other half on Win XP PC, I tried to find a way to create basic, barebone project, using good c++ practices (well, I don't know them from experience, I just read about them). Right now my project almost works while using cmake . && make on linux (it works when header and source files are in the same folder, fails when I separate them to include / src folders). I am using nuwen's distribution of mingw on windows (and I know that the toolchain is working, it compiles projects from within Eclipse without any problems).
My project directory looks like this:
engine
|
|- main
|
|- include
|
|- App.h
|- CMakeLists.txt (2)
|- src
|
|- main.cc
|- App.cc
|- CMakeLists.txt (3)
|- CMakLists.txt (1)
The contents of the files are very simple (I will remove the include guards, etc for clarity)
App.h:
class App {
public:
App();
int onExecute();
};
App.cc:
#include <iostream>
#include "App.h"
App::App() {
}
int App::onExecute() {
std::cout << "inside app.." << '\n';
return 0;
}
main.cc:
#include <iostream>
#include "App.h"
using namespace std;
int main(int argc, char* argv[]) {
App a;
a.onExecute();
std::cout << "inside main.." << '\n';
}
CMakeLists.txt (1) - the main one:
cmake_minimum_required (VERSION 2.6)
set (CMAKE_CXX_COMPILER "g++")
project (gameengine)
add_definitions ( "-Wall -ansi -pedantic")
add_subdirectory (${CMAKE_SOURCE_DIR}/main/include)
add_subdirectory (${CMAKE_SOURCE_DIR}/main/src)
add_executable (engine ${CMAKE_SOURCE_DIR}/main/src/main.cc)
target_link_libraries (engine Application)
CMakeLists.txt (2) - inside the include directory
add_library (Application App)
set_target_properties (Application PROPERTIES LINKER_LANGUAGE CXX)
CMakeLists.txt (3) - inside the src directory
include_directories (../include)
And this is as far as I got - with some changes (i.e. moving App.cc to the include directory) the whole thing compiles and runs fine on linux - but I can't get the mingw generator to work on Win XP. I hand tuned the CMAKE_MAKE_PROGRAM in the file CMakeCache.txt to point to the proper make.exe (I know that this should be defined as a system variable but as I am working on many different PC's, I don't want to leave junk after me).
My questions are:
1) what are the guidelines for writing multiplatform CMakeLists.txt file (which will work independly of the os and the location of the project files), which preferably will allow me to easy swich my project configuration from one os the other one?
2) how can I address the error of not finding the header file (make gives: (...)\engine\main\src\main.cc:2:17: fatal error: App.h: No such file or directory) ?
Thank you for your time and help.
1) what are the guidelines for writing multiplatform CMakeLists.txt file (which will work independly of the os and the location of the project files), which preferably will allow me to easy swich my project configuration from one os the other one?
Well, I'm certainly no expert, but I can share my 10-month experience with a cross-platform cmake-based project.
Right off the bat I think you really should be using out of source builds. This means that you don't run cmake in the same directory where your code is; instead, you create a new folder, e.g. engine/build and run cmake ../main from there. This way you don't clobber your source files with cmake stuff, such as CMakeCache.txt etc. There are even some macros you can use to forbid your users from doing in-source builds.
I also find it useful to create a set of macro files to help set compiler options for different platforms. Here at work we have macros such as ADD_GCC_FLAG or ADD_MSVC_FLAG which check the current compiler and add flags accordingly.
I think it is good practice to have a single .cmake file which concentrates all your project configurations in one place. At work all our CMakeLists.txt start with include( ../cmake/configs.cmake ). This file sets all sorts of options, such as standard include directories, default compiler flags etc.
To assuage your problem with include directories, I suggest you use absolute rather than relative paths in your source files. Define a standard include directory, for instance engine/main/include and always #include files relative to that path. In your example, if you wanted to include engine/main/include/somefolder/header.h, you'd write #include <somefolder/header.h> (using <> instead of quotes tells the C++ preprocessor to skip the current directory when looking for the file).
2) how can I address the error of not finding the header file (make gives: (...)\engine\main\src\main.cc:2:17: fatal error: App.h: No such file or directory) ?
There are a number of issues with your cmake layout, but the reason you were getting that error is because you need to call include_directories in CMakeLists.txt (1) as well.
Besides that, your other CMakeLists.txt files have problems too. In CMakeLists.txt (2), the arguments to add_library are wrong; it should be ../src/App.cc, otherwise you're just adding an empty library. And you don't need that set_target_properties either, at least not if you got the add_library arguments right. You also need a include_directory call in that same CMakeLists.txt that's adding the library; putting it in (3) doesn't really do anything.
Actually, you don't need a CMakeLists.txt file in the include directory, since there's nothing to build there. It's better to put the add_library call in CMakeLists.txt (3), right after calling include_directories.
I hope this clears some of your doubts.
This is probably not the answer you expect but since you didn't stated whether you'd like alternative solutions, I will suggest it anyway:
For multi-platform projects I would recommend SConstruct which is really a great and flexible tool. I don't know CMake well so I can really provide a detailed comparison.
However, here are the reasons why I love this tool:
It's Python. So you can do almost anything you want regarding customization and/or special needs
It's really easy to learn and for simple projects, it takes only a few lines of code to get started.
It depends solely on Python so on Linux its very often already installed and on Windows it take 5 minutes to download and install.
It has a very good automatic dependency tree generation and parallel compilation support.