1

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.

skypjack
  • 49,335
  • 19
  • 95
  • 187
BartekPL
  • 2,290
  • 1
  • 17
  • 34

2 Answers2

2

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.

Community
  • 1
  • 1
Craig Scott
  • 9,238
  • 5
  • 56
  • 85
1

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.

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • So, if you think it will be better to have two independent copy of google test sources? – BartekPL Mar 06 '17 at 10:17
  • @BartekPL No, I think you can safely use `FindGTest` module. Why not? – skypjack Mar 06 '17 at 10:26
  • 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 unversal solution :) Do you have any ideas? – BartekPL Mar 06 '17 at 10:36
  • @BartekPL Let me integrate the answer. – skypjack Mar 06 '17 at 10:40
  • Thanks for your answer! If there will not be better answers I tag your answer as accepted :) – BartekPL Mar 06 '17 at 10:47
  • 1
    @BartekPL Don't worry. I'm here to help, not to gain reputation. Feel free to accept this answer or the one that fits your requirements. ;-) – skypjack Mar 06 '17 at 11:33