Create a cmake project testing another cmake project - c++

we have a cmake project which does not use automated tests. So I want to create another cmake project including the Boost-test framework to test the other project. I know, it would be perhaps better to add the test project within the other project, but we have to change the project structure for this purpose. So I want a non-invasive test project. Here is the structure of my idea:
+---Project_A
|
CMakeList.txt
src
modules
.
.
.
+---Test_Project
|
CMakeList.txt
I tried to use the cmake-include statement in the Test_Project to include Project_A. But CMake tries to compile the Project_A-files within the Test_Project. So how can I tell CMake to compile the files within Project_A? Do you know maybe a better way to test Project_A without changing it's project structure?

Related

CMake generating VS project files in the files with the CMakeLists.txt folders

I'm trying to learn CMake and am struggling to achieve the project layout that I'm used to making with visual studio.
I want to achieve something like the following directory structure,
where the .vcxproj and .sln are generated by CMake
Root
CMakeLists.txt
MySolution.sln
ProjectOne
CMakeLists.txt
ProjectOne.vcxproj
someSourceFile1.h
someSourceFile1.cpp
ProjectTwo
CMakeLists.txt
ProjectTwo.vcxproj
someSourceFile2.h
someSourceFile2.cpp
Binaries
Platform
Debug
ProjectOne.exe
ProjectTwo.dll
Release
ProjectOne.exe
ProjectTwo.dll
All the tutorials I seem to find seem to give an Examples where the structure turns out something like this:
Root
Source
CMakeLists.txt
ProjectOne
CMakeLists.txt
someSourceFile1.h
someSourceFile1.cpp
ProjectTwo
CMakeLists.txt
someSourceFile2.h
someSourceFile2.cpp
Build
MySolution.sln
ProjectTwo.vcxproj
ProjectOne.vcxproj
Platform
Debug
ProjectOne.exe
ProjectTwo.dll
Release
ProjectOne.exe
ProjectTwo.dll
Using commands like
mkdir Build
cd build
CMake ..\Source
CMake --Build .
Notable I have not added ALL_BUILD.vcxproj and ZERO_CHECK.vcxproj that get generated, which I am yet to understand my need for.
Is there just a command I'm missing in the CMakeList.txt to do this?
Is there a reason I shouldn't lay my project out the way I want to?
Doing some more research I have stumbled across this post Visual Studio puts new files into wrong directory
which made me think I could not mix my dev and dist builds with CMake.
Thanks to the helpful comments of fabian that you can actually build the structure I want and am used to doing something like this.
You can make it only use folders for specific builds if you want it for some and not others.
project(MySolution)
cmake_minimum_required(VERSION 3.2)
# Use solution folders if I'm using VS change to whatever your dev platform is
IF(MSVC)
SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON)
ENDIF()
add_subdirectory(MyFolderName)
Having a play with it, your dev build does need to call CMake from the \source folder where a distribution build would need to be called from the \Build directory to separate out the files.
I'm guessing there's ways to use more If() ... Else() ... Endif() to generate this in a specific folder based on build type as well.
Having a look around, I think the easiest way might just be to place another scripting language over the top that just calls the cmake commands from different directories based on build type.
Windows.scriptType
Linux.scriptType
etc...
Unless some kind soul can point me how to do this one in CMake

Cmake issue. Copying dll post build

I'm struggling again with cmake.
What I'm trying to achieve is this:
I have a project, say ProjectA, which contains a submodule with a CMakeLists.txt, say ProjectB.
ProjectA adds ProjectB as subdirectory.
ProjectB outputs a shared library (.dll).
ProjectA has a post build script that copies the dll into its output directory in order to use it.
The problem is that when i change a few things inside ProjectB, this one gets built, but since no modifications are made in ProjectA, it wont build nor copy the dll.
The solution would be to move the post build script inside ProjectB, but if i do that my submodule will be incompatible in other scenarios and tied to ProjectA implementation (what I mean is that the Cmakelists file of projectB should copy the dll in a folder outside it's directory, which is something I want to avoid).
I can't really find a way to avoid manually rebuilding the whole project every time.
To make the situation more clear, the project hierarchy is something like
ProjectA/
CMakeLists.txt
src/
vendor/
ProjectB/
CMakeLists.txt
src/
The First CMakeLists.txt adds Project B as subdirectory.
This cmakelists file also apply a post build script to the target in project A that copies content of ProjectB/bin (dll).
I managed to solve this by myself.
For those who has the same issue and want to find a good solution, just do not use a post build script.
Instead you can add a second parameter to add_subdirectory specifying the build folder of the subproject.

Cmake building two projects

I want to build two projects using cmake (A library and sandbox application using that library).
I'm currently having the following folder structure:
-- yanthra_engine
|
-- CMakeLists.txt
-- lib
-- ...
-- sandbox
|
-- CMakeLists.txt
-- out
-- ...
The yantra_engine builds a library where as sandbox builds an executable(using the above mentioned library).
Should I keep full fledged CMakeLists files for both the projects? Is there any efficient folder structure to follow?
I would like the library to build automatically when building my sandbox application, but not vice-versa.
You should keep seperate CMakeLists.txt files. It's good practice to use one CMakeLists.txt file per unrelated target. (Unrelated in the sense of not being different builds of the same library, e.g. one shared one static.)
Whether to add both targets to the same project is basically up to you. If the library is properly set up, you could create a seperate project for the library and use it's install target to install the library including cmake configuration files on your machine making it easy to import the installed library as a target to the sandbox project. This requires you to add the appropriate install commands to the library.
If you want to be able to build both the library and the sandbox via the same build files, basically all you need to do is to make sure both CMakeLists.txt files are reachable from a CMakeLists.txt file.
Without location of any of the files you could e.g.
Create a CMakeLists.txt file in the parent folder adding both subdirectories
cmake_minimum_required(VERSION 3.0)
project(CommonProject)
add_subdirectory(yanthra_engine)
add_subdirectory(sandbox EXCLUDE_FROM_ALL) # targets in sandbox not built by default.
You could also include the yanthra_engine directory from sandbox/CMakeLists.txt
...
add_subdirectory(../yanthra_engine "${CMAKE_BINARY_DIR}/yanthra_engine_build")
...
Both approaches allow you to either set up a build project for the lib on its own or set up a build project for both. In approach 1 the source directory for building both would be the parent directory of yanthra_engine and sandbox and in approach 2 it would be sandbox.
For both approaches you don't need to wory about unnecessarily building the sandbox project though as long as you specify the target you want to build. Since sandbox links the lib but there is no dependnecy established the other way round building sandbox makes sure the lib is up to date, but building the lib only builds the lib and its dependencies which excludes the sandbox.
One thing you can try is to let yanthra be a subdirectory of sandbox. Then you can do this in sandbox:
add_subdirectory(yanthra_engine)

How remove duplicate of the same dependiencies sources in dependent projects

I have two cmake projects. One of them use googletest and second of them use it also. What's more, I used first project in second project.
I have second project on github and googletest is also on github. So I wanna download them when I build my first project by using
ExternalProject_Add
command.
This is simpified folder structure:
ProjectA
| build/
| include/
| src/
| modules/
| | ProjectB/
| | | CMakeLists.txt
| | googletest/
| | | CMakeLists.txt
| CMakeLists.txt
And simplified structure for ProjectB:
ProjectB/
| build/
| include/
| src/
| modules/
| | googletest/
| | | CMakeLists.txt
| CMakeLists.txt
And now I have important question : It is possible to download googletest code once? For now I download it twice, one time for ProjectA, and second time for ProjectB.
I can add simplified CMakeLists.txt code, but I don't think it is needed here.
You could treat googletest as a third external project, then pass its location into both of your projects as CMake cache variables. That would ensure you only had to download googletest once, but it might be a bit less convenient than having googletest built directly as part of a project. You could create a fourth top level project to pull together each of the three projects (googletest, projectA and projectB) so that you can ensure googletest is built before you need to configure projectA or projectB. The ExternalProject for googletest would install gtest and gmock targets to its install area. You then pass that directory into projectA's and projectB's ExternalProjects as the location to look into for google test. You could use the FindGTest module inside projectA and projectB for this, having your top level project set the GTEST_ROOT cache variable for projectA and projectB. This is probably the easiest option.
Another choice would be to download and build googletest as part of projectA (see here for the method I'd recommend to do this), then get projectB to re-use the googletest source or better still, the built targets from projectA. You could bring projectA into projectB in the same way as the above link brings googletest into projectA if you want. We use an arrangement like this at work to pull together a number of different projects, each of which can be built standalone or as part of other projects. An advantage of this method is that if you are using an IDE like Visual Studio, Xcode or Qt Creator, you get to see the sources of all the projects in your source list and the IDE's problem detection, refactoring tools, etc. tend to have a more complete view of the overall build. It also tends to minimise the information that has to be manually passed between projects, since CMake sees the whole set of sources and targets in the one build and therefore there's no need to explicitly deal with platform-specific library names, different build output directory structures, etc.
If you want to keep projectA as an ExternalProject of projectB, then you can still re-use the googletest source from projectA, but you will have to set up inter-target dependencies very carefully to ensure projectA is built before anything that needs the googletest sources. You will probably also end up have to manually work out where things get downloaded to and built in projectA and that could be a pain if your project is built on more than one platform. It sounds like this is the closest to what you are asking how to do, but I'd probably suggest trying one of the two approaches above.
There are other choices, such as using a package manager like hunter, but that may be straying a bit too far from the original focus of the question.
If you don't want to download Google C++ testing framework twice, you can simply use the proper find module of cmake and let it find what you need from your environment.
See FindGTest.
Example usage from the linked above:
enable_testing()
find_package(GTest REQUIRED)
add_executable(foo foo.cc)
target_link_libraries(foo GTest::GTest GTest::Main)
add_test(AllTestsInFoo foo)
That being said, they are different projects with their own modules. It would be better to be explicit about them.
You can still put a custom cmake find module in ProjectB that looks for gtest within ProjectA. Anyway it's a fragile solution, for it will break as soon as dependencies in ProjectA change.
Question in the comments:
It seems really good for gtest, but I wonder if I have different projects than gtest (e.g. ProjectC), then what should I do? I looking for more universal solution.
If I can't look up dependencies in my system through a proper find module (along with versions when needed), I usually prefer to be explicit about them. Therefore I add the required dependencies to each project, even if it means to recompile them twice.
A question that can answer the whys: what if ProjectA depends on tag x for the given module and ProjectB requires tag y to work? If the two tags break the API of each other (unfortunately sometimes it happens), you will be in trouble unless you are explicit about dependencies for each project.

qmake checking for library

I have a qt project setup as a subdirs project with my source code in a src directory and unit testing code setup in a test directory. Each has its own project file. I want to be able to compile the source on other computers, but they may not have the googletest library setup. I have looked at the qmake test function "requires()" and "packagesExist()" however, they do not seem to be built to handle external libraries.
How can I instruct qmake to skip the test project if the testing library is not found?
It is not possible without checking typical locations if the library is present in there.
Unfortunately, googletest does not seem to ship package-config ".pc" files either, so that is why you cannot use the packagesExist() qmake function.
So, I would use a bunch of exist call to work this around, or switch away from qmake to something better like cmake.
!exists("/foo/bar/baz.so"):!exists("/hello/world/baz.so"):...: message("Google test is not installed on your system")
If the libraries you're trying to link to do not have pkgconfig information, you can make a qmake config test for each of these libraries using qtCompileTest(). I'll show you here how to use this feature of qmake.
qtCompileTest qmake config tests will run at qmake time. If the test compiles, config_ will be added to the CONFIG variable and qmake will print Checking for <testname>... yes or Checking for <testname>... no depending on whether or not the test compiled.
In your project dir, create a directory with the name config_tests, and under that create a directory for the library or feature you're going to test, a starting simple qmake project and main.cpp file, ending up like so:
myproject/
myproject.pro
<source files, etc>
config_tests/
googletest/
googletest.pro
main.cpp
Make the googletest project be very simple, with just the bare minimum to link an executable to the googletest library, and test including necessary headers for using it. Load this project directly into Qt Creator and test that it actually compiles in the scenarios you expect it to work, and not in others (i.e. test for the various platforms you'll be using that contain and don't contain the googletest library)
Next, use this qmake config test project in your main project by adding the following to the top of your project. load(configure) below loads in the qmake support for qtCompileTest - as it's not normally built-in:
load(configure)
qtCompileTest(googletest)
In the places where you will be compiling features that require googletest, you can wrap them in the following qmake test:
CONFIG(config_googletest) {
}