[CMake] intercomponent link dependencies?

Ryan Pavlik rpavlik at iastate.edu
Thu Jan 7 16:54:33 EST 2010


Ah, so if those components are always necessary (that is, A always needs 
B, and B always needs C), there's no need to use the "components" 
option. Just zip through them in this way - _LIBRARY (cache var) is a 
single library, _LIBRARIES (not a cache var) is the list containing the 
library and all its dependencies.  If you use the _LIBRARIES variable, 
you don't need to even mess around with the imported targets thing, 
though you can if you really want to.

I've pasted an untested full example (done both ways - so actually 2 
examples) using what you've explained in your last email.  It's at the 
bottom of this email, after the quote.

Hope this helps!

Ryan

On 01/07/2010 02:20 PM, Nico Schlömer wrote:
> Hi Ryan,
>
> thanks very much for your answer.
>
> For clarification, the package I would like to link against has (say)
> three components A, B, C, where A at link time needs symbols of B
> needs symbols of C needs symbols of some external libs.
>
> I would like to make sure that the user can say
>
>     FIND_PACKAGE( mypackage COMPONENTS A )
>
> and then find in some variable *all* the dependencies that are
> required for linking, e.g.,
> MYPACKAGE_A_LIBRARY="a;b;c;/usr/local/lib/libblas.a".
> Right now (and which I'm not happy with), if a user would like to link
> against liba.a, he or she has to know that libb.a, libc.a, and
> /usr/local/lib/libblas.a have to be pulled in as well, and do so
> manually.
>
> If on the other hand I have the same dependency situation with
> libraries that I *built*, the TARGET_LINK_LIBRARIES mechanism works
> very well. If I understand correctly, this cannot be applied to
> components in a FINDmypackage.cmake
>
> Cheers,
> Nico
>
>
>    

# - try to find MyPackage library
#
# Example-FindMyPackage.cmake
#
# This example is for a fairly in-depth library that has four
# internal dependencies as well as an external dependency.
# The dependency tree is described below, in graphviz/dot format, and you
# can remove the #'s from the following lines and run it through graphviz,
# with this command: dot dependencies.dot -O -Tpdf
#
# --- start of dependencies.dot ---
# digraph {
#    BLAS;
#    subgraph cluster_mypackage {
#        label = "Components that are part of MyPackage";
#        libmypackagecore -> libmypackagea;
#        libmypackagea -> libmypackageb;
#        libmypackageb -> libmypackagec;
#        libmypackagec -> BLAS;
#    }
# }
# --- end of dependencies.dot ---
#
# Because our imaginary component "c" requires BLAS and BLAS needs some
# linker flags, MYPACKAGE_..._LINKER_FLAGS joins the usual group of
# _LIBRARY/_LIBRARIES and _INCLUDE_DIR/_INCLUDE_DIRS variables.  If
# you don't use a library like that, you don't need to include the
# lines dealing with that group of variables.
#
# Start of what would be a minimal module documentation blog:
#
# Cache Variables: (probably not for direct use in CMakeLists.txt)
#  MYPACKAGE_LIBRARY
#  MYPACKAGE_INCLUDE_DIR
#  MYPACKAGE_a_LIBRARY
#  MYPACKAGE_a_INCLUDE_DIR
#  MYPACKAGE_b_LIBRARY
#  MYPACKAGE_b_INCLUDE_DIR
#  MYPACKAGE_c_LIBRARY
#  MYPACKAGE_c_INCLUDE_DIR
#
# Non-cache variables you might use in your CMakeLists.txt:
#  MYPACKAGE_FOUND
#  MYPACKAGE_MARK_AS_ADVANCED - whether to mark our vars as advanced even
#    if we don't find this library.
#
#  MYPACKAGE_LIBRARIES
#  MYPACKAGE_INCLUDE_DIRS
#  MYPACKAGE_LINKER_FLAGS
#
#  MYPACKAGE_a_LIBRARIES
#  MYPACKAGE_a_INCLUDE_DIRS
#  MYPACKAGE_a_LINKER_FLAGS
#
#  MYPACKAGE_b_LIBRARIES
#  MYPACKAGE_b_INCLUDE_DIRS
#  MYPACKAGE_b_LINKER_FLAGS
#
#  MYPACKAGE_c_LIBRARIES
#  MYPACKAGE_c_INCLUDE_DIRS
#  MYPACKAGE_c_LINKER_FLAGS
#
# Use this module this way:
#  find_package(MyPackage)
#  include_directories(MYPACKAGE_INCLUDE_DIRS)
#  add_executable(myapp ${SOURCES})
#  target_link_libraries(myapp ${MYPACKAGE_LIBRARIES})
#  set_property(TARGET myapp PROPERTY LINK_FLAGS ${MYPACKAGE_LINKER_FLAGS})
#
# Requires these CMake modules:
#  FindPackageHandleStandardArgs (CMake standard module)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik at iastate.edu> <abiryan at ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC


find_library(MYPACKAGE_LIBRARY
     NAMES mypackagecore
     PATHS "${MYPACKAGE_ROOT}"
     PATH_SUFFIXES lib)

find_path(MYPACKAGE_INCLUDE_DIR
     NAMES mypackage/mypackage.h
     PATHS "${MYPACKAGE_ROOT}"
     PATH_SUFFIXES include)

# Assuming that the components are named libmypackagea, libmypackageb, etc
foreach(lib a b c)
     find_library(MYPACKAGE_${lib}_LIBRARY
         NAMES mypackage${lib}
         PATHS "${MYPACKAGE_ROOT}"
         PATH_SUFFIXES lib)

     find_path(MYPACKAGE_${lib}_INCLUDE_DIR
         NAMES mypackage/${lib}/${lib}.h
         PATHS "${MYPACKAGE_ROOT}"
         PATH_SUFFIXES include)

endforeach()

# see /usr/share/cmake-2.x/Modules/FindBLAS.cmake for the variables this 
will define
if(NOT BLAS_FOUND)
     find_package(BLAS QUIETLY)
endif()

# handle the QUIETLY and REQUIRED arguments and set xxx_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyPackage DEFAULT_MSG
     MYPACKAGE_LIBRARY
     MYPACKAGE_INCLUDE_DIR
     MYPACKAGE_a_LIBRARY
     MYPACKAGE_a_INCLUDE_DIR
     MYPACKAGE_b_LIBRARY
     MYPACKAGE_b_INCLUDE_DIR
     MYPACKAGE_c_LIBRARY
     MYPACKAGE_c_INCLUDE_DIR
     BLAS_FOUND
     )

if(MYPACKAGE_FOUND)
     # Set variables containing libraries and their dependencies
     # Always use the plural form for the variables defined by other 
find modules:
     # they might have dependencies too!

     set(MYPACKAGE_c_LIBRARIES ${MYPACKAGE_c_LIBRARY} ${BLAS_LIBRARIES})
     set(MYPACKAGE_c_INCLUDE_DIRS ${MYPACKAGE_c_INCLUDE_DIR}) # No 
include dir for BLAS?
     set(MYPACKAGE_c_LINKER_FLAGS ${BLAS_LINKER_FLAGS})

     set(MYPACKAGE_b_LIBRARIES ${MYPACKAGE_b_LIBRARY} 
${MYPACKAGE_c_LIBRARIES})
     set(MYPACKAGE_b_INCLUDE_DIRS ${MYPACKAGE_b_INCLUDE_DIR} 
${MYPACKAGE_c_INCLUDE_DIRS})
     set(MYPACKAGE_b_LINKER_FLAGS ${MYPACKAGE_c_LINKER_FLAGS})

     set(MYPACKAGE_a_LIBRARIES ${MYPACKAGE_a_LIBRARY} 
${MYPACKAGE_b_LIBRARIES})
     set(MYPACKAGE_a_INCLUDE_DIRS ${MYPACKAGE_a_INCLUDE_DIR} 
${MYPACKAGE_b_INCLUDE_DIRS})
     set(MYPACKAGE_a_LINKER_FLAGS ${MYPACKAGE_b_LINKER_FLAGS})

     set(MYPACKAGE_LIBRARIES ${MYPACKAGE_LIBRARY} ${MYPACKAGE_a_LIBRARIES})
     set(MYPACKAGE_INCLUDE_DIRS ${MYPACKAGE_INCLUDE_DIR} 
${MYPACKAGE_a_INCLUDE_DIRS})
     set(MYPACKAGE_LINKER_FLAGS ${MYPACKAGE_a_LINKER_FLAGS})

endif()

if(MYPACKAGE_FOUND OR MYPACKAGE_MARK_AS_ADVANCED)
     foreach(_cachevar
             MYPACKAGE_LIBRARY
             MYPACKAGE_INCLUDE_DIR
             MYPACKAGE_a_LIBRARY
             MYPACKAGE_a_INCLUDE_DIR
             MYPACKAGE_b_LIBRARY
             MYPACKAGE_b_INCLUDE_DIR
             MYPACKAGE_c_LIBRARY
             MYPACKAGE_c_INCLUDE_DIR)

         mark_as_advanced(${_cachevar})
     endforeach()
endif()

# End of Example-FindMyPackage.cmake



-------------------------------------------------------------------




# - try to find MyPackage library
#
# Example-FindMyPackage-UsingImportedTargets.cmake
#
# This module does the same thing as Example-FindMyPackage.cmake
# except that rather than passing along full path names for libraries,
# it creates imported targets.  The end result is roughly the same to
# the end-user.  Please see that other file for the full documentation
# of the example.
#
#
# Start of what would be a minimal module documentation blog:
#
# Cache Variables: (probably not for direct use in CMakeLists.txt)
#  MYPACKAGE_LIBRARY
#  MYPACKAGE_INCLUDE_DIR
#  MYPACKAGE_a_LIBRARY
#  MYPACKAGE_a_INCLUDE_DIR
#  MYPACKAGE_b_LIBRARY
#  MYPACKAGE_b_INCLUDE_DIR
#  MYPACKAGE_c_LIBRARY
#  MYPACKAGE_c_INCLUDE_DIR
#
# Non-cache variables you might use in your CMakeLists.txt:
#  MYPACKAGE_FOUND
#  MYPACKAGE_MARK_AS_ADVANCED - whether to mark our vars as advanced even
#    if we don't find this library.
#
#  MYPACKAGE_LIBRARIES
#  MYPACKAGE_INCLUDE_DIRS
#  MYPACKAGE_LINKER_FLAGS
#
#  MYPACKAGE_a_LIBRARIES
#  MYPACKAGE_a_INCLUDE_DIRS
#  MYPACKAGE_a_LINKER_FLAGS
#
#  MYPACKAGE_b_LIBRARIES
#  MYPACKAGE_b_INCLUDE_DIRS
#  MYPACKAGE_b_LINKER_FLAGS
#
#  MYPACKAGE_c_LIBRARIES
#  MYPACKAGE_c_INCLUDE_DIRS
#  MYPACKAGE_c_LINKER_FLAGS
#
# Use this module this way:
#  find_package(MyPackage)
#  include_directories(MYPACKAGE_INCLUDE_DIRS)
#  add_executable(myapp ${SOURCES})
#  target_link_libraries(myapp ${MYPACKAGE_LIBRARIES})
#  set_property(TARGET myapp PROPERTY LINK_FLAGS ${MYPACKAGE_LINKER_FLAGS})
#
# Requires these CMake modules:
#  FindPackageHandleStandardArgs (CMake standard module)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik at iastate.edu> <abiryan at ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC


find_library(MYPACKAGE_LIBRARY
     NAMES mypackagecore
     PATHS "${MYPACKAGE_ROOT}"
     PATH_SUFFIXES lib)

find_path(MYPACKAGE_INCLUDE_DIR
     NAMES mypackage/mypackage.h
     PATHS "${MYPACKAGE_ROOT}"
     PATH_SUFFIXES include)

# Assuming that the components are named libmypackagea, libmypackageb, etc
foreach(lib a b c)
     find_library(MYPACKAGE_${lib}_LIBRARY
         NAMES mypackage${lib}
         PATHS "${MYPACKAGE_ROOT}"
         PATH_SUFFIXES lib)

     find_path(MYPACKAGE_${lib}_INCLUDE_DIR
         NAMES mypackage/${lib}/${lib}.h
         PATHS "${MYPACKAGE_ROOT}"
         PATH_SUFFIXES include)

endforeach()

# see /usr/share/cmake-2.x/Modules/FindBLAS.cmake for the variables this 
will define
if(NOT BLAS_FOUND)
     find_package(BLAS QUIETLY)
endif()

# handle the QUIETLY and REQUIRED arguments and set xxx_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyPackage DEFAULT_MSG
     MYPACKAGE_LIBRARY
     MYPACKAGE_INCLUDE_DIR
     MYPACKAGE_a_LIBRARY
     MYPACKAGE_a_INCLUDE_DIR
     MYPACKAGE_b_LIBRARY
     MYPACKAGE_b_INCLUDE_DIR
     MYPACKAGE_c_LIBRARY
     MYPACKAGE_c_INCLUDE_DIR
     BLAS_FOUND
     )

if(MYPACKAGE_FOUND)
     # Set variables containing libraries and their dependencies
     # Always use the plural form for the variables defined by other 
find modules:
     # they might have dependencies too!

     add_library(mypackage_c IMPORTED)
     set_target_properties(mypackage_c PROPERTIES
         IMPORTED_LOCATION ${MYPACKAGE_c_LIBRARY}
         IMPORTED_LINK_INTERFACE_LIBRARIES  ${BLAS_LIBRARIES})
     set(MYPACKAGE_c_LIBRARIES mypackage_c)
     set(MYPACKAGE_c_INCLUDE_DIRS ${MYPACKAGE_c_INCLUDE_DIR}) # No 
include dir for BLAS?
     set(MYPACKAGE_c_LINKER_FLAGS ${BLAS_LINKER_FLAGS})

     add_library(mypackage_b IMPORTED)
     set_target_properties(mypackage_b PROPERTIES
         IMPORTED_LOCATION ${MYPACKAGE_b_LIBRARY}
         IMPORTED_LINK_INTERFACE_LIBRARIES  ${MYPACKAGE_c_LIBRARIES})
     set(MYPACKAGE_b_LIBRARIES mypackage_b)
     set(MYPACKAGE_b_INCLUDE_DIRS ${MYPACKAGE_b_INCLUDE_DIR} 
${MYPACKAGE_c_INCLUDE_DIRS})
     set(MYPACKAGE_b_LINKER_FLAGS ${MYPACKAGE_c_LINKER_FLAGS})

     add_library(mypackage_a IMPORTED)
     set_target_properties(mypackage_a PROPERTIES
         IMPORTED_LOCATION ${MYPACKAGE_a_LIBRARY}
         IMPORTED_LINK_INTERFACE_LIBRARIES  ${MYPACKAGE_b_LIBRARIES})
     set(MYPACKAGE_a_LIBRARIES mypackage_a)
     set(MYPACKAGE_a_INCLUDE_DIRS ${MYPACKAGE_a_INCLUDE_DIR} 
${MYPACKAGE_b_INCLUDE_DIRS})
     set(MYPACKAGE_a_LINKER_FLAGS ${MYPACKAGE_b_LINKER_FLAGS})

     add_library(mypackage_core IMPORTED)
     set_target_properties(mypackage_core PROPERTIES
         IMPORTED_LOCATION ${MYPACKAGE_LIBRARY}
         IMPORTED_LINK_INTERFACE_LIBRARIES ${MYPACKAGE_a_LIBRARIES})
     set(MYPACKAGE_LIBRARIES mypackage_core)
     set(MYPACKAGE_INCLUDE_DIRS ${MYPACKAGE_INCLUDE_DIR} 
${MYPACKAGE_a_INCLUDE_DIRS})
     set(MYPACKAGE_LINKER_FLAGS ${MYPACKAGE_a_LINKER_FLAGS})

endif()

if(MYPACKAGE_FOUND OR MYPACKAGE_MARK_AS_ADVANCED)
     foreach(_cachevar
             MYPACKAGE_LIBRARY
             MYPACKAGE_INCLUDE_DIR
             MYPACKAGE_a_LIBRARY
             MYPACKAGE_a_INCLUDE_DIR
             MYPACKAGE_b_LIBRARY
             MYPACKAGE_b_INCLUDE_DIR
             MYPACKAGE_c_LIBRARY
             MYPACKAGE_c_INCLUDE_DIR)

         mark_as_advanced(${_cachevar})
     endforeach()
endif()

# End of Example-FindMyPackage-UsingImportedTargets.cmake

-- 
Ryan Pavlik
HCI Graduate Student
Virtual Reality Applications Center
Iowa State University

rpavlik at iastate.edu
http://academic.cleardefinition.com
Internal VRAC/HCI Site: http://tinyurl.com/rpavlik



More information about the CMake mailing list