I'm trying to explain the issue with my current knowledge, however I'm
still learning how to use CMake's ExternalProject features and the
DownloadProject function described and used by Robin. Please note that
parts of the following are educated guesses only. That said:
Such a "unified" build is somewhat similar to our FLTK build. The
standard autoconf/make build consists of a "super project" (say: fltk)
in the root directory and other projects: src (the FLTK libs), fluid,
and test (let's not talk about the bundled libs). If you run make from
the top level directory everything is built. However if you want to
build only the 'hello' test program with all its dependencies you have
to build the libs (in src) first, then 'cd test; make hello' will work
and build only the 'hello' target.
CMake is different. You can run 'make hello' or 'ninja hello' in the top
level build directory and it will build only the libs and target 'hello'
in the test directory (no fluid), like so (here with with ninja):
...
[174/177] Building CXX object
src/CMakeFiles/fltk.dir/drivers/PostScript/Fl_PostScript_image.cxx.o
[175/177] Linking CXX static library lib/libfltk.a
[176/177] Building CXX object test/CMakeFiles/hello.dir/hello.cxx.o
[177/177] Linking CXX executable bin/examples/hello
If you also want to build the tabs demo, then 'ninja tabs' (in the top
directory) builds some other FLTK image libs, fluid (required by tabs),
and the tabs demo:
...
[36/41] Building CXX object fluid/CMakeFiles/fluid.dir/widget_panel.cxx.o
[37/41] Building CXX object ...
[38/41] Linking CXX executable bin/fluid
[39/41] Generating tabs.cxx, tabs.h
[40/41] Building CXX object test/CMakeFiles/tabs.dir/tabs.cxx.o
[41/41] Linking CXX executable bin/examples/tabs
This explains why CMake requires unique targets in one build. It's a
design decision and very comfortable.
The CMake answer to doing a "unified" build of *different* projects (a
master project and its dependencies, i.e. libraries) is a so-called
super-build with ExternalProject_Add and related functions. I read a lot
about this in the CMake user mailing list. I believe that this approach
does NOT need unique target names over all external projects. This would
be impossible to achieve, as you can see in Robin's attempt to build
CinePaint, and from real life experience as you, Ian, noted: several
projects have their own 'install' and 'uninstall' targets and certainly
other targets like hello, help, doc, docs, documentation, and more.
But why did Robin experience this although I wrote that CMake's
ExternalProject feature doesn't suffer from the restriction of unique
target names?
Well, he said that using ExternalProject_Add directly was too
complicated so he used DownloadProject as a wrapper.
https://github.com/Crascit/DownloadProject
The docs of DownloadProject state:
"The primary advantage of this is that the project's source code can
then be included directly in the main CMake build using the
add_subdirectory() command, making all of the external project's
targets, etc. available without any further effort. The technique is
fully explained in the article available at:
https://crascit.com/2015/07/25/cmake-gtest/
"
The main points are:
(1) DownloadProject uses ExternalProject_Add in a special way to
download the external sources in the configure step rather than in the
build step.
I see no problem with this part.
(2) The external project is "included directly in the main CMake build
using the add_subdirectory() command, making all of the external
project's targets, etc. available without any further effort".
The difference to "normal" usage of ExternalProject_Add seems to be that
the author suggests to use add_subdirectory() which _includes_ the
entire external project in the main build. Hence the requirement of
unique target names. Robin tried to use this technique to build CinePaint.
I believe that the usage of add_subdirectory() is the cause of trouble.
*All* targets of *all* external projects are directly _included_ in the
main build which means that all these targets _must_ have unique names.
The global namespace is polluted with target names of all external projects.
[Side note: This can be compared with an "amalgamation" build of a
library where all source files are included in one file and compiled
together. In this case all static functions of all modules must have
unique names which is usually not enforced for good reasons (in
single-module builds). But here it is even worse because modules of
different authors are combined.]
The author writes that this is an advantage because you can now directly
access the targets of the external projects like (in our example) the
FLTK library "without any further effort". This seems to be true, but at
the price that all target names must be unique.
In the case of CinePaint we have at least two projects with identical
target names 'uninstall', but there may be all kinds of name collisions
with other projects. FLTK has, for instance, target names like 'hello',
'utf8', 'tabs', and such.
Taking my _little_ knowledge of (how to use) CMake's "original"
ExternalProject_Add and the additional function DownloadProject into
account my analysis may be wrong - but you have been warned.
I'll try to investigate further, and I have access to Robin's work on
CinePaint so I can test, but I certainly won't be able to post more
qualified answers or suggestions before Monday next week (or even later).
Besides that: add_subdirectory() of external projects has other issues
we solved recently (see subject of this thread:
CMAKE_CURRENT_SOURCE_DIR). Projects that are not designed to be included
with add_subdirectory(), i.e. projects that "assume" they are the main
projects, will fail to build when included with add_subdirectory(). This
is still true for FLTK 1.3.4 but was recently changed by me for FLTK
1.4.0. Other projects (libraries) may not be compatible with
add_subdirectory() usage.