Cmake issue. Copying dll post build - c++

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.

Related

Nested CMakeLists.txt files in CLion

Using CLion, I have a project structure that looks like this:
You'll see that in the root there are an include directory, a src directory, a lib directory, a cmake-build-debug directory, a CMakeLists.txt file (see red arrow), and a tests directory. The project builds a shared object into lib using the root-level CMakeLists.txt file and the various source, header, and external files.
I can successfully run the root-level CMakeList.txt file and build the library. So far, so good.
Here is the issue. In addition to the above, I am now interested -- on an informal, exploratory basis -- in testing some of the code in the project. To that end, as an initial example, I have created a test_nnls directory with its own CMakeLists.txt (see yellow arrow) file and a test_nnls.cpp file. The code in test_nnls.cpp creates some dummy data, calls a function in src/nnls.cpp, and prints the results. The build process here just creates an executable that does this. This approach is not meant to be part of any formal test framework and I do not want the test to run as part of the root-level build. This is just me adding a simple test program in the overall project that I would like to compile and run on an independent basis when I feel the need. I plan to possibly implement a formal test framework later, but at present I don't know how to do this and for now just need to print some simple output to see if the chosen code is working correctly.
The problem is that I cannot seem to execute the CMakeLists.txt file (yellow arrow) to build the test. It does not appear to be possible in CLion to set up a build for the test program using cmake. How do I structure all of this to get what I want? Thanks.
You don't execute a CMakeLists.txt. It is read by cmake (the root CMaksLists.txt file), which is called by CLion. However, CLion only passes the root CMaksLists.txt file to cmake. Even if you call cmake yourself you would only pass this root CMaksLists.txt file.
If you want to define targets (or anything) in other CMaksLists.txt files located in other folders, then you must add add_subdirectory(folder_name_that_contains_another_CMakeLists_file) to your root CMaksLists.txt file. Only then targets in these other CMaksLists.txt files will appear in CLion.
Note that a few things should appear in the root CMaksLists.txt file, but not in the other ones. Particularly, the two lines below should only be in the root file
cmake_minimum_required(VERSION 3.14) # Choose the minimum cmake version
project(name_of_your_project)

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.

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.

CMake - Depending on another cmake project

I have the following structure to a project I am working on:
---Library1
------build
------include
------src
------CMakeLists.txt
---Library2
------build
------include
------src
------CMakeLists.txt
---Executable1
------build
------include
------src
------CMakeLists.txt
Library1 is a library I am developing that needs to link with Library2 which is a 3rd party library. When I build Library1, I need it to automatically build Library2 and link with it. Executable1 will need to build and link with Library1. I'm not sure how to do with with Cmake, and I was wondering if anyone could guide me in the right direction. I think I may need to use the add_dependencies command or add_subdirectory but I'm not sure how to go about using them and making sure they are linked to my library. Any help would be appreciated.
I'd think the best commands here are likely to be add_subdirectory (as you suspected) and target_link_libraries.
I guess with your directory structure, I'd expect to see a "top-level" CMakeLists.txt in the root. In that CMake file, you'd invoke the subdirectories' CMakeLists using add_subdirectory.
I imagine both Library1 and Library2 are actual CMake targets, included via add_library, and similarly you have add_executable(Executable1 ...). In this case, you can add the following to Library1/CMakeLists.txt:
target_link_libraries(Library1 Library2)
CMake now automatically links Library2 whenever Library1 is specified as a dependency. If Library2 is modified, then it will be rebuilt automatically before being linked to Library1 again.
Likewise in Executable1/CMakeLists.txt you can then do:
target_link_libraries(Executable1 Library1)
Probably the only thing to watch for here is that the order of the add_subdirectory commands would need to be
add_subdirectory(Library2)
add_subdirectory(Library1)
add_subdirectory(Executable1)
so that the dependencies are defined before they're referred to in the target_link_libraries calls.
A final point which seems odd to me is that you have a build directory per target. Normally there should only be a need for a single build directory (preferably outside the source tree).

Working with Multiple Projects in CMake

I am currently working on transitioning over a Visual C++ project (that has multiple subprojects inside of it) over to CMake.
There is one thing that I am not sure about – basically, to include the subprojects from the top level CMakeLists.txt file, I just utilize the add_subdirectory command, and reference the directories that these various subprojects are stored under.
However, I have one project that is in the same directory as my top level CMakeLists.txt file, and so I am wondering if it is still possible to include this file somehow? CMake does not allow me to call add_subdirectory on the existing PROJECT_BINARY_DIR (see below):
add_subdirectory(${PROJECT_BINARY_DIR}) #not allowed in CMake
I cannot think of another way for me to include this subproject into my CMake build. Any ideas?
All add_subdirectory does is add a subdirectory with a CMakeLists.txt file in it, and so it would not make sense to allow you to add the current directory. You can simply add the CMake logic to build that part of your project in the CMakeLists.txt file. If you would like to separate the logic, then you could put it in build_project.cmake, and then use include,
include(build_project.cmake)
You can include as many other CMake files as you like, and that CMake code will be evaluated as if it was pasted inline. So all the normal add_executable and similar commands would work.