[CMake] Linking archives in a sibling directory

Michael Hertling mhertling at online.de
Fri Dec 3 05:13:12 EST 2010


On 12/02/2010 03:13 PM, Raymond Wan wrote:
> Hi Michael,
> 
> 
> On Thu, Dec 2, 2010 at 19:40, Michael Hertling <mhertling at online.de> wrote:
>> On 12/01/2010 06:03 PM, Raymond Wan wrote:
>>> Ah!  I see.  Then is it recommended that this top-level CMakeLists.txt
>>> have just these lines, or should I move the ADD_EXECUTABLE, etc. lines
>>> here as well?  Or is this really "up to me" and there isn't a
>>> suggested paradigm?
>>
>> Basically, IMO, a CMakeLists.txt with ADD_EXECUTABLE() et al. should be
>> placed in the same directory as the related source files unless there's
>> a reason not to do so; this makes for modularity and a well organized
>> code base. The above-mentioned directory structure with its top-level
>> CMakeLists.txt containing just ADD_SUBDIRECTORY() commands keeps the
>> modules main, dir-A and dir-B separate with minimal interconnections.
>> In the previous structure, e.g., main/CMakeLists.txt had to know that
>> dir-A resides in "../dir-A"; now, such information is concentrated in
>> the top-level CMakeLists.txt, and the sole reference of main to dir-A
>> is the target "subprogA_ar". Due to CMake's capabilities to track the
>> dependencies among targets, it doesn't matter where dir-A is placed
>> within the project's source tree. So, in short, don't move the
>> ADD_EXECUTABLE() etc. to the top-level CMakeLists.txt.
> 
> 
> I see -- I did not realize this point you made about CMake's
> dependency tracking abilities.  So, basically the only thing I need to
> worry about is the order of the ADD_SUBDIRECTORY ()'s.  As long as I
> put
> 
> ADD_SUBDIRECTORY (dir-A)
> 
> before
> 
> ADD_SUBDIRECTORY (main)
> 
> then "main" will be built correctly?

Even this is not necessary if the only reference of main to dir-A is
TARGET_LINK_LIBRARIES(... subprogA_ar) in main/CMakeLists.txt since
TARGET_LINK_LIBARIES(), AFAIK, does a lazy evaluation of the targets'
dependencies, i.e. they are evaluated when all CMakeLists.txt files
have been processed and, hence, all dependencies are known. If you
refer to subprogA_ar in another way, e.g. SET_TARGET_PROPERTIES(),
then you will get an error if dir-A hasn't been configured yet.

> But, if I am not mistaken and following what you are saying, I can
> only build "main" using the top-level CMakeLists.txt.  The lower
> CMakeLists.txt in main/ does not know the location of "dir-A".  The
> only way for both to work is to have this in main/CMakeLists.txt:
> 
> ADD_SUBDIRECTORY(../dir-A ${CMAKE_CURRENT_BINARY_DIR}/dir-A)
> 
> yet this kind of duplication should be an error at worse; unnecessary
> repetition at best?

Each invocation of ADD_SUBDIRECTORY() for a source directory must be
associated with an own binary directory, so the above-mentioned line
would allow you to use both alternatives. However, when configuring
the top-level CMakeLists.txt, you will get an error due to multiple
definitions of the subprogA_ar target. In main/CMakeLists.txt, you
might protect ADD_SUBDIRECTORY() against multiple invocations like

IF(NOT TARGET subprogA_ar)
   ADD_SUBDIRECTORY(../dir-A ${CMAKE_CURRENT_BINARY_DIR}/dir-A)
ENDIF()

or

IF(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR})
   ADD_SUBDIRECTORY(../dir-A ${CMAKE_CURRENT_BINARY_DIR}/dir-A)
ENDIF()

but this does not appear really appropriate to me.

Nevertheless, I wonder why you want to build "main" by configuring its
own source directory and alternatively via the top-level directory. If
this is because you'd like to exclude some modules from building, you
should handle such things in the top-level CMakeLists.txt, e.g. like:

# Define options:
OPTION(WITH_MAIN "Build module main" ON)
OPTION(WITH_A "Build module A" ON)
OPTION(WITH_B "Build module B" ON)

# Handle dependencies:
IF(WITH_MAIN)
    SET(WITH_A ON)
ENDIF()

# Enable modules:
IF(WITH_B)
    ADD_SUBDIRECTORY(dir-B)
ENDIF()
IF(WITH_A)
    ADD_SUBDIRECTORY(dir-A)
ENDIF()
IF(WITH_MAIN)
    ADD_SUBDIRECTORY(main)
ENDIF()

So, you can conveniently enable/disable the modules on the command line
or in the GUI, e.g. with "cmake -DWITH_B=OFF <path/to/top-level-dir>"
if you don't want to build module B.

As an alternative, you might consider to move dir-A to main/dir-A if
dir-A is essentially a submodule of main, but referring to a sibling
dir-A from main indicates that the latter is not sufficiently self-
contained to be built on its own with a "cmake <path/to/main>", so
the modules' relationships should be handled by other means, IMO.

Regards,

Michael

>> The top-level directory of non-trivial projects should not contain any
>> source files, perhaps a config.h header or the like. Usually, there're
>> enough things gathering in a project's root, e.g. READMEs, subdirs for
>> documentation, resources or CMake stuff, a CMakeLists.txt file ;) etc.
>> The sources, however, should be organized in their own subdirectories,
>> so the top-level CMakeLists.txt typically contains ADD_SUBDIRECTORY()
>> commands along with configurational stuff like setting up compiler
>> flags, processing options or investigating the underlying system,
>> but no ADD_EXECUTABLE() or the like.
>>
>> Of course, there're exceptions and probably strong different opinions.
> 
> 
> I see!  Thank you for this!  I'll stick with standard practice for now
> and leave the exceptions and stronger opposing opinions to people who
> know more about CMake than me.  :-)
> 
> Thank you very much for the explanation!
> 
> Ray


More information about the CMake mailing list