[CMake] link_libraries vs target_link_libraries

Fernando Cacciola fernando.cacciola at gmail.com
Tue Nov 11 13:13:43 EST 2008


Hi Andreas,

> On 11.11.08 14:12:39, Fernando Cacciola wrote:
>> Hi Andreas,
>>
>>> On 10.11.08 12:01:13, Fernando Cacciola wrote:
>>>> The CGAL library (www.cgal.org) uses cmake as build system. Thus, our 
>>>>  users do:
>>>>
>>>> find_package(CGAL REQUIRED)
>>>> include( ${CGAL_USE_FILE} )
>>>> ...
>>>>
>>>>
>>>> UseCGAL.cmake, as all such files, call include_directories,   
>>>> add_definitions and overrides (under certain circumstances) the   
>>>> compiler/linker flags that were used to build the CGAL library.
>>>>
>>>> These are all settings that affect any target added after the 
>>>> inclusion  of UseCGAL.cmake.
>>>>
>>>> However, following the recommended practice (according to the   
>>>> documentation of the deprecated link_libraries command), UseCGAL DOES 
>>>>  NOT call link_libraries. Instead, it realies on the user calling   
>>>> target_link_libraries himself.
>>>>
>>>> Well, I'm questioning this recommended practice because it's half 
>>>> baked:  It makes sense to allow users to control which targets are 
>>>> linked  against CGAL, but NOT if OTOH they cannot control which 
>>>> targets are  given the CGAL include directories, definitions and 
>>>> flags.
>>>>
>>>> That is, IMO, target_link_libraries makes little sense in the absence 
>>>> of  target_include_directories, target_add_definitions and 
>>>> target_*_FLAGS.
>>>>
>>>> What it's so special about linking that only that command can be made 
>>>>  target specific???
>>>>
>>>> Or am I missing something?
>>> There are projects that have headers that are usable without linking
>>> against any library. There are also projects installing their headers into
>>> a common place, that have multiple libraries. In that latter case you'd
>>> have include_directories() point to the common place for the headers, but
>>> obviously you can't know which of the libraries needs to be linked in.
>>>
>> Who is you in your sentence?
>>
>> The UseXYZ modules which depends on the parameters to find_package(XYZ)  
>> certainly knows it.
> 
> No it doesn't. UseXXX is a "global" thing, so it can't know which of the
> targets in a project need which files.
> 
Right, but the again a typical UseXYZ would do:

   include_directories( ${XYZ_INCLUDE_DIR} )
   add_definitions( ${XYZ_DEFINITIOS} )
   set( CMAKE_CXX_FLAGS "$XYZ_CXX_FLAGS") )

So it doesn't know which of your targets need the include dirs, the 
definitions and the flags.. and it doesn't care.

>>> Boost is a good example (albeit it doesn't use cmake to build itself).
>>> There are various libraries shipped with it, they all install their headers
>>> into <includedir>/boost/<libraryname>/ and the libs are of course directly
>>> in <libdir>. And its common practice to have only <includedir>/boost in the
>>> include-directories.
>>>
>> And BOOST_LIBRARIES is defined as a list of all libraries indicated by  
>> the user as boost components.
> 
> Right, but those are all I'm going to use in my project, which might or
> might not be different from those that I want on target A and B.
> 
Right.

>> So, if there where a UseBoost.cmake file  
>> which would do
>>
>>   include_directories( ${BOOST_INCLUDE_DIR} )
>>   add_definitions( ${BOOST_DEFINITIONS} )
>>
>> then wouldn't it make sense for it to do
>>
>>   link_libraries( ${BOOST_LIBRARIES} )
>>
>> as well?
> 
> That would mean _all_ my targets link against those libraries, which is
> completely wrong.

Right.

> In fact I don't understand why include_directories and
> add_definitions are not deprecated as well

Which is precisely my point!! :)

target_link_libraries, which is GREAT, is actually pretty useless 
without target_include_directories, target_add_definitions and 
<TARGET>_CMAKE_CXX_FLAGS.

Yet OTOH given that those do not exists, it is just plain silly to 
recommend not using link_libraries, because it gets less than half the 
story right.

And IMO is equally silly to follow the recomendation and end up doing 
what most Use files typically do: to set so much that affects all 
subsequent targets, even compiler and linker flags, BUT simply define a 
variable XYZ_LIBRARY so a user can decide which target to link againt 
XYZ_LIBRARY.

I mean, being able to control this is cool, sure, but why can I only 
control that and not the other equally critical settings???

IMO, if a user won't have real control over which targets actually use 
XYZ (in all the extent to which using XYZ, as defined by 
find_package(XYZ), means) then I rather don't bother them requiring 
users to call target_link_libraries by hand (while everything else is 
setup by the Use file itself). It's just silly.

So to restat my point, if a UseFile does this:

   include_directories( ${XYZ_INCLUDE_DIR} )
   add_definitions( ${XYZ_DEFINITIOS} )
   set( CMAKE_CXX_FLAGS "$XYZ_CXX_FLAGS") )

which shouldn't under the argument of "what if I don't want that for all 
my targets", then it should do this as well:

   link_libraries( ${XYZ_LIBRARIES} )


Best

Fernando



More information about the CMake mailing list