[Cmake] Dependency handling problems with 1.8

Amitha Perera perera at cs . rpi . edu
Wed, 1 Oct 2003 17:14:21 -0400


On Wed 01 Oct 2003, Ken Martin wrote:
> The easiest is to make sure your
> directories are in the right order. I don't know if this will help but you
> might be able to do 
> 
> (toplevel CMakeLists.txt)
>     SUBDIRS( a )
>     SUBDIRS( b )
>     SUBDIRS( a/a_gui )

Unfortunately, this will be very difficult for the VXL project. As a
short term solution, I have put in a bug report requesting a mechanism
to supress this warning.

> Some more information on this issue.  This is a UNIX makefile issue where
> the subdirectories are processed in the order you specify.
[details snipped]

As I understand it, the main problem is that a "make" a top level (or
higher level) will traverse the build tree in a SUBDIRS order, which
may not match the dependency tree. A solution to this is to make sure
that "make all" in any given directory will visit the targets in that
directory and its subdirectories in dependency order and not in SUBDIRS
order. If the SUBDIRS have been ordered as you suggested above, the
dependency order is exactly equivalent to the SUBDIRS order, and
therefore we have backward compatibility.

Note that CMake already has all the information to generate these
makefiles. A small example below to illustrate:

The CMakeLists.txt files:

(toplevel)/CMakeLists.txt
   ADD_LIBRARY( root )
   SUBDIRS( a )
   SUBDIRS( b )

a/CMakeLists.txt
   ADD_LIBRARY( a )
   SUBDIRS( gui )

a/gui/CMakeLists.txt
   ADD_LIBRARY( a_gui )
   TARGET_LINK_LIBRARIES( a_gui b a )

b/CMakeLists.txt
   ADD_LIBRARY( b )
   TARGET_LINK_LIBRARIES( b a )


The dependency tree:
   a <--- b <--- a_gui


What would currently be in the makefiles:

(toplevel)/Makefile:
    all:
        $(MAKE) libroot.a
        (cd a && $(MAKE) all)
        (cd b && $(MAKE) all)

a/Makefile:
    all:
        $(MAKE) liba.a
        (cd gui && $(MAKE) all)

a/gui/Makefile:
    all:
        $(MAKE) liba_gui.a

b/Makefile:
    all:
        $(MAKE) libb.a



What I'm suggesting should be in the makefiles:


(toplevel)/Makefile:
    all:
        $(MAKE) libroot.a
        (cd a && $(MAKE) liba.a)
        (cd b && $(MAKE) libb.a)
        (cd a/gui && $(MAKE) liba_gui.a)

a/Makefile:
    all:
        $(MAKE) liba.a
        (cd gui && $(MAKE) libgui.a)

a/gui/Makefile:
    all:
        $(MAKE) liba_gui.a

b/Makefile:
    all:
        $(MAKE) libb.a




Notice that if you do "make all" in any directory, that directory and
it's subdirectories are processed in dependency order, but it'll not
jump to a parent directory for any reason.

> The other way is to include the full dependency tree of b into
> the Makefile for a_gui. This makes for huge Makefiles for large projects and
> more frequent rebuilding of Makefile (because they now depend on many more
> header files) 

The approach I describe above does mean that the makefiles will be
larger. For example, the toplevel makefile must list every target in
the whole project tree. However, it does *not* need to list every
header file. It need only list CMake targets (libraries and
executables). There is, I'd say less than 300 of these in a
project. So, the toplevel makefile will have 300 lines listing exactly
the order in which the libraries are to be built. The dependency
information, how to build the library, and all that information is
captured in the Makefile in that library's directory.

The makefile in a subdirectory will have fewer lines. It will only
explicitly list that targets found that subtree.

With this approach, the "magic" that jumps somewhere to build
non-existent libraries is not required. If you run "make all" at a
high enough level, the libraries will get built in the correct
order. If you jump to a sub-directory and try to build, for example,
a_gui, without first building b, then you will (rightfully) get an
error message.

Thoughts?

Amitha.