How remove duplicate of the same dependiencies sources in dependent projects - c++

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.

Related

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 to get a VS solution with all the projects and solutions for single projects with CMake

TL;DR I basically want a modular solution of this question. Not only one solution with everything in it, but also a solution for each executable alone.
In my question here I wanted to know how I should split my CMakeLists.txt among different folders. Some folders contain code that will be a static library and some code will be executables or dynamic libraries that build on those static libraries.
Folder structure looks like this:
/path/to/base/
CMakeLists.txt
app1/
<src files for app1>
CMakeLists.txt
app2/
<src files for app2>
CMakeLists.txt
lib/
<src files for lib>
CMakeLists.txt
If I take the approach of having a CMakeLists.txt in the parent folder to all my libraries and executables and from the include all the directories I have the problem that when I generate VS projects/solutions that my projects for each target contains all the projects - not only the ones necessary for my intended target.
Contents of CMakeLists.txt in the base folder:
cmake_minimum_required(VERSION 3.1)
add_subdirectory(lib)
add_subdirectory(app1)
add_subdirectory(app2)
and the CMakeLists.txt in the app1 folder (app2 is equivalent)
cmake_minimum_required(VERSION 3.1)
project(app1)
add_executable(app1 <src of app1>)
target_link_libraries(app1 lib)
and CMakeLists.txt of lib:
add_library(lib <src of lib>)
If I run cmake on the CMakeLists.txt from base the solution contains all the projects. And even if I open just one of the projects; it also contains everything. VS project of app1 also builds app2 - which I don't want.
If I only run cmake on the CMakeLists.txt of app1 I get a solution which doesn't contain app2 but it also doesn't contain lib, because that's only mentioned for linking inside the cmake file and not as a target (it's in the base file)
CMake will create a solution for each call to project, which will then include all the targets of the current directory and its subdirectories (regardless whether they were defined before or after the actual call to project).
Here's what a well-behaved CMake script should do: Each CMakeLists that you want to be able to act as a root of its own sub-tree within the larger project should start with a cmake_minimum_required call, followed by the project call. Writing project in a CMakeLists basically means: This is a fully self-contained component that can be built independently, even if you delete all the files from its parent directories. As such, it makes sense to have a separate solution for each such project.
With this in mind we can see why this doesn't work in your case: Your apps are not fully self-contained, they depend on lib. The solution to this is to write the build scripts for the apps as if lib was provided as a third-party component, with find_package calls and everything.
In the compound build, you already have a target for lib, so the script invoked by the find_package call should be made to short-circuit to using that target and only actually go scavenging the system if it cannot find that existing target.
Also read up on how CMake's packaging system works, which provides some automation to handle such cases pretty elegantly.

Create build tree for different build types with CMake

I know how to have CMake output libs and bins depending on the build type (release, debug, etc), but, in order to reduce (re)compile times, I would like to have CMake build them in different subfolders.
Say I have this kind of tree
|- CMakeLists.txt
|- build/
|- src/
If I have debug, release, and relwithdebinfo builds, I want CMake to automatically create me a tree like
|- CMakeLists.txt
|- build/
|--- Debug/
|--- Release/
|--- RelWithDebInfo/
|- src/
and so on.
Is this possible, if yes how can I achieve my goal ?
I do not want answers like "you should run CMake from different folders", since for visual studio this would lead to multiple solutions, etc.
I want to be able to run CMake from only one folder, and have it handle subfolders by itself.
If you just leave CMake alone, it will do that automatically for generators that support multiple configurations (like Visual Studio).
If you override the default output locations, you should do so via the *_OUTPUT_DIRECTORY target properties, which support generator expressions:
set_property(TARGET my_lib
PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/$<CONFIG>/bin)
Note the $<CONFIG> generator expression, which will expand to the name of the configuration (Debug, Release, etc.).
Note also that if you want the configuration directory to be at the bottom of the directory tree, you may not even have to give the generator expression explicitly:
This property specifies the directory into which library target files
should be built. The property value may use generator expressions.
Multi-configuration generators (VS, Xcode) append a per-configuration
subdirectory to the specified directory unless a generator expression
is used.
The three properties that control output directories are ARCHIVE_OUTPUT_DIRECTORY, LIBRARY_OUTPUT_DIRECTORY and RUNTIME_OUTPUT_DIRECTORY. This page explains the difference.
In addition, you might want to also set the PDB_OUTPUT_DIRECTORY for builds with pdb debug symbols.
Now, as mentioned in the beginning, all of this is only true for generators that support multiple configurations. For single-config generators like Makefiles, things are different. Here you have to settle for one specific configuration when running CMake (by setting the CMAKE_BUILD_TYPE variable on the command line or the cmake-gui). If you want to switch configurations, you have to re-run CMake with a different setting for that variable.
These generators do not support having multiple configurations around at the same time. So if you use a single-config generator and you know that you need both debug and release builds regularly, it is best to keep separate build directories around for the different configurations and run cmake in each of them separately.

Create a cmake project testing another cmake project

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?