[CMake] Interface Libraries allow include directories but not link directories.. Why?

Brian Davis bitminer at gmail.com
Wed Aug 23 16:50:21 EDT 2017


On Wed, Aug 23, 2017 at 2:07 AM, Clément Gregoire <lectem at gmail.com> wrote:

> I can't argue too much why paths or absolute on cmake as I don't know the
> rationale behind it is. While your point about command line limit makes
> sense, I feel like a system limiting command line size to this extent is
> dumb if it doesn't allow reading more arguments through a file. (again, I
> don't know the system at all).
>
My command line problem experience stems from two problems:

1) building ITK as a superproject/superbuild within my project and from
within VMTK which also used ITK in a superbuild.. well and building VMTK
superbuild inside my superbuild project.  Yes it's a Russian dolls/onion of
superbuilds.  Boy I would also like to comment on those problems, but that
will be for a different post.

2) My somewhat successful (I say somewhat as appose to ideal)
ExternalProject_Add build of boost from git repo where setting boost build
command at the cmd prompt vs within VS studio.  I had to resort to CMD
prompt to eak out those last bits-o-chars.

Ahh yes here it is from my CMake files:

    # Does not work as command path length is too long.
    #    add_custom_target(
    #       boost_build_target
    #       "echo ${BUILD_BOOST_CMD}; ${BUILD_BOOST_CMD}"
    #       WORKING_DIRECTORY ${BOOST_SOURCE_DIR} )


I kinda understand your point about not being able to set the libdir per
> target but (might have missed it in your previous mails) I don't know what
> kind of project would need that. At best I would need one version of the
> library per configuration, which is supported.
>
Ok here goes as I would really like people to understand my problems with
the current CMake impl then possibly I could be awed by the logic of CMake
and stand corrected .... or possibly ... just possibly I am correct and
CMake could change course.

First off there is some inconsistencies in the logic of the design / impl
of CMake from my perspective if we look at the new target/properties and
statements from 3rd parties (pdf mentioned earlier) as to the direction
/logic of CMake.

1) find_library forces user down a path of abs paths and does not allow the
return of the path in the event the user wants to pass the path to
LINK_DIRECTORIES.  Which coupled with my path problems I chose/forced not
to use find_library.  Ok so like I said I could build of off C:\ so I'll
give CMake that.  CMake forces full abs paths for every lib specified even
for those of us who don't want it / can't use it in find_library.  Why not
have find_library return two (2) VARS one for lib and other for path and
provide option to user and state the WHY the user should choose abs paths.
Then I could argue the WHY problem directly, but still have an out for
LINK_DIRECTORIES/LIBPATH use.  However CMake forced the abs full  path on
every lib issue and has not provide a *good* mechanism to the alternative.

2) find_library is as I am sure CMake would agree is not under the
target/property new design.  Say the target is targ and the property is the
library path, but find_library is all or nothing and a CMake variable.
Where CMake variables if pdf is to be believed is not under the new CMake
"don't use variables" design philosophy.  Not that I know what the actual
Design of CMake is or should be and I would certainly like to hear that and
have CMake resolve this discrepancy.

3) In VS (well in Linux for that matter) can set include paths and I can
set LIBPATH(s) on targets.   In CMake I can set include_directories on
targets but not lib paths.  However I can get around this and do by using
LIBRARY_PATH which is at the directory level.  CMake should expose always
the underlying abilities of the tools to the user and guide to the best use
for sure, but never force... and I am seemingly forced to do an illogical
end-around (go to directory scope to set what should be a target property).

As to:

"I kinda understand your point about not being able to set the libdir per
target but (might have missed it in your previous mails) I don't know what
kind of project would need that"

How about projects for which boost and find_package(Boost) (<- Beware of
caps when using boost and find_package yes it's case sensitive)  is used?

#+-----------------------------------------------------------------------------
set(
        BOOST_LIBS
        Boost::boost
        Boost::system
        Boost::date_time
        Boost::filesystem
        Boost::serialization
        )

add_library( boost_interface INTERFACE )
target_include_directories(
    boost_interface
    INTERFACE
        ${BOOST_INCLUDE_DIR}
)

target_link_libraries(
    boost_interface
    INTERFACE
        ${BOOST_LIBS}
)

#+-----------------------------------------------------------------------------

And yes all my boost use needs at least those libs other opts to create
another interface for inheritance based on other lib use is certainly
possible.

I have a mixed mode CMake generated vsprojs and existing vsprojs files
where include_external_msproject is used for some projects:

#------------------------------------------------------------------------------
add_library( 4duiplugin_interface INTERFACE )

target_include_directories(
    4duiplugin_interface
    INTERFACE
         ${4DUI_PLUGIN_DIR}
)



add_library( utilities_interface INTERFACE )

target_link_libraries(
    utilities_interface
    INTERFACE
    optimized ${TOP}/build/x64/Release/Libraries/Utilities.lib
    debug ${TOP}/build/x64/Debug/Libraries/Utilities.lib
)

target_include_directories(
    utilities_interface
    INTERFACE
     ${4DFUTILITIES_INCLUDE_DIR}
)


add_library( dicomreader_interface INTERFACE )

target_link_libraries(
   dicomreader_interface
    INTERFACE
    optimized ${TOP}/build/x64/Release/Libraries/DicomReader.lib
    debug ${TOP}/build/x64/Debug/Libraries/DicomReader.lib
)
#------------------------------------------------------------------------------

Why cannot I set say:

target_library_directories(
    utilities_interface
    INTERFACE
    optimized ${TOP}/build/x64/Release/Libraries
    debug ${TOP}/build/x64/Debug/Libraries
)

Note use of only directories above and use of unavailable
target_library_directory to set LIBPATH where it could search out duplicate
paths before chucking at the linker.  find_library certainly can't do it as
is uses abs paths.  While abs paths are used above and certainly could by
target/property'izing LIB_DR this could give CMake an "out" to the command
line length problem by filtering for unique before setting LIBPATH.  Hey
CMake could even provide an ABSOLUTE command in target_link_directories and
state some gibberish as to how/why absolute long paths for every library is
better... not that I buy it now and will not then either.


Then used sometime later:

target_link_libraries(
    ${SOME_LIB}
    4dfutilities_interface
    4dfdicomreader_interface
    cuda_sdk_interface
    boost_interface
    shaderslib_interface
#    vtk_interface
    vmtk_interface
)


Also cmake 3.7/3.8//3.9 started to support CUDA as a first class language.
Now the question: do I use:

project( prjname CXX CUDA)

or

find_package(CUDA 9.0)

or both?

well I in the spirit of new CMake I chose project.

But now the question... how does CMake 3.9 support finding the cudart.lib
(or cudafft) or say libs in the SDK( such as gluts or glews or FreeImage).
Well the answer as far as I can tell ... it does not.  It's not documented
and so I checked out the 3.9 source and I am reverse engineering it to
figure out how it works or what works and does not and what is impled/not
impled.  So what's a CMake 3.+'er (me) to do?  (well after crying as to the
state of things)  I could:

#
-----------------------------------------------------------------------------
add_library( cuda_toolkit_interface INTERFACE )
target_include_directories(
    cuda_toolkit_interface
    INTERFACE
         ${CUDA_TOOLKIT_LIB_DIR}
)

target_link_libraries(
    cuda_toolkit_interface
    INTERFACE
        cuda_rt_static
)

add_library( cuda_sdk_interface INTERFACE )
target_include_directories(
    cuda_sdk_interface
    INTERFACE
        ${CUDA_SDK_INCLUDE_DIR}
)
#
-----------------------------------------------------------------------------

then when linking a target that needs said inherited build properties I
could:

target_link_libraries(
    rendertest
    PRIVATE
    cuda_toolkit_interface
    cuda_sdk_interface
    boost_interface
    opengl_interface
    shaderslib
)

say for any target needing cuda.


I entirely agree with for the rest. CMake badly documenting good practices
> or even giving tutorials is an issue. Probably the biggest issue I found. I
> myself still fight after years of using and experimenting with it. This
> lead to a plethora of badly written cmakelists.txt or module scripts, that
> even people in this list still advocates without understanding the problems
> behind it. Even some tutorial series found on github.com or used by
> coverage websites do it wrong.
>
Yes glad and at the same time sorry to hear someone has had some of the
same experience I have had and I say these things in hopes CMake will get
fixed/better, but hey again maybe I am wrong.

I have been rewriting my CMake files to support new target/properties and
for the most part I no longer have to use my parameterized variables and
custom project macros (add_project_config, add_project_executable, and
add_project_library - which sadly had to use LINK_DIRECTORIES)  with VAR
ARGS parsing to get the concept of "inherited build properties" based on my
jam experience from Boost.Build... so kudos to CMake for that if only for
LIBPATH an hence the post.

Sadly I knew the answer even before I asked the question based on using
CMake since 2009 and even giving a teaching lecture on it to promote it's
use where I also promoted inherited build properties even though CMake at
at the time did not support it directly.



> At the moment the only reference I trust is Daniel's presentation and some
> of the internal cmake scripts.
>
> While not solving your problem, I documented most of my findings in this
> small template /reference https://github.com/Lectem/cpp-boilerplate
> (which might still do things the wrong way)
>

Yes just at line 22 I already have a problem.... that did not take long.

1) project does not specify VERSION and project name  "CPP-BoilerPlate" does
not incorporate ver string such as


SET(MAJOR_VERSION 1)
SET(MINOR_VERSION 2)
SET(MAINTENANCE_VERSION 3)

and then

project( "CPP-BoilerPlate-${MAJOR_VERSION}.${MINOR_VERSION}.${MAINTENANCE
_VERSION}" VERSION ${MAJOR_VERSION}.${MINOR_VERSION}.${MAINTENANCE_VERSION}
C CXX)

as what is CMAKE_INSTALL_PREFIX by default across versions?  What does
VERSION do in project?  Well I know what it does not affect... yep
CMAKE_INSTALL_PREFIX.
Try compiling and installing on Windows multiple versions of this project
see what you get.

3rd party package developers end up blasting away prior versions... maybe
by design but who knows in my experience (IME).

Again though not as though CMake discusses "best practices" here or make
VERSION actually do something useful as say append to CMAKE_INSTALL_PREFIX
${MAJOR_VERSION}.${MINOR_VERSION}.${MAINTENANCE_VERSION}.

Thanks for the link/resource I take form it any good bits I can use at 157
lines it is not all that realistic of a full blown project with multiple
dependencies mixed mode VS projs and CMake gen projs and other real world
shenanigans.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/cmake/attachments/20170823/eddc8312/attachment-0001.html>


More information about the CMake mailing list