I'm developing or maintaining a free software project Foo which uses CMake for a build system, as well as source control (e.g. Mercurial or Git), with the repository being available online.

Now, this project depends on another project, Bar - say, it uses include files that this other project provides. Bar exists independently, and is also FOSS and available from a public source-control repository.

Now, CMake has a mechanism for downloading, configuring and building such sub-projects: ExternalProject. However, I could also make Bar be a sub-repository of the Foo source repository, so that it is checked out together with Foo, and CMake can treat the composition of checked-out files and folders as though it was just one file hierarchy.

Would you recommend one approach over the other, generally? If not, what are the considerations for choosing one option over the other?

  • Do you know for sure that "Bar" is also available from a public source-control repository tomorrow? What if you need to checkout and compile an older version of "Foo" which relies on a specific, older version of "Bar"? Can you 100% rely on the public repo to provide the older version for the lifetime of "Foo"? If the answer is "yes" in both cases (or at least "its reliably enough for me"), then you don't need to manage copies of "Bar" by yourself. Otherwise, you will better off not just to make a sub-rep, but to set up a repo for copies of "Bar" by yourself, one you have under your control. – Doc Brown Nov 6 '18 at 4:13
  • "Do you know for sure" <- Yes, it's FOSS, but good point. I've edited accordingly. – einpoklum Nov 6 '18 at 8:00
  • I interpret your remark as "I am willing to rely on the existence of GitHub for the lifetime of Foo". That may be reasonable, or not, it depends . – Doc Brown Nov 6 '18 at 9:10
  • Usually I find ExternalProject much easier and more straight forward than a sub repo. Just make sure that you have a offline backup of the external repo somewhere locally, if they ever decide to shutdown their repo. – Simon Jan 6 '19 at 11:08
  • @Simon: Why? In what sense? Also - I would need offline back anyway, since the ExternalProject will check an the online version too... – einpoklum Feb 8 '19 at 16:35

Vendoring the other project can be a suitable stopgap measure in the absence of a suitable dependency management tool. In particular, operating in a SCM level can be appropriate if the other project is not a stable, versioned library. Vendoring or mono-repo style projects can be quite beneficial

  • to manage internal dependencies that are developed together,
  • when an external project does not provide suitable packages,
  • when an external project changes too rapidly so that you effectively have to maintain a snapshot,
  • or when an external project needs other modifications.

In most other cases using available dependency management tools is much easier. There is the slight caveat that your builds are now dependent on external systems and that the dependency management tool might not be particularly good so that it ends up causing more problems than it solves. But CMake specifically – despite its numerous flaws – is pretty good at avoiding outright incompatibility. OTOH you can always whip up a simple shell or Python script that downloads and compiles the dependency, if portability is not an issue.

I'd also like to point out that sub-repositories have problems. E.g. a git submodule requires extra steps during checkout of the main project, and can have confusing semantics.

  • Can you define, or link to a definition, of the terms "vendoring" and "mono-repo"? – einpoklum Nov 5 '18 at 22:05
  • 1
    @einpoklum Vendoring is the act of copying dependencies into your project's source tree, typically under a vendor/ directory. There are various definitions on SO. Outside of C/C++, this is also common in web development and (until recently) Go. A monorepo is a SCM repository that includes multiple projects. Arguably an outdated practice from the SVN era or a weird Googleism, it's sometimes much simpler than making changes across multiple related repos. – amon Nov 5 '18 at 22:15

A third option to consider is actually "neither".

CMake has a subsystem, if you will, of package registration and location through installed configuration .cmake files. A lot of these are bundled with CMake itself, but you can set things up so that other packages generate and install their own .cmake configuration files, in paths which your dependent package will search. When this is the case, the dependent package just needs to find_package(foo) in the CMakeLists.txt, and it is "not its problem" where foo comes from (it can also constrain the version if necessary).

Of course, this makes the whole thing less "turn-key", since the dependent package could well fail without you having built and installed the dependencies somewhere visible. On the other hand, this is quite the flexible solution, and fits very well when you need to override versions etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.