[CMake] Making it easier for downstreams to use my library

Michael Wild themiwi at gmail.com
Fri Apr 9 05:07:35 EDT 2010


On 9. Apr, 2010, at 9:53 , Stephen Kelly wrote:

> Hi,
> 
> I've just tagged and tarballed a release candidate of Grantlee version 
> 0.1.0. Grantlee is a Free Software string template system written in Qt and 
> using CMake for its build system.[1]
> 
> Most of my CMake knowledge is about writing simple CMakeLists.txt files to 
> consume other libraries. Writing the necessary CMake files to so that 
> downstreams can use my library is harder and I'm not sure I've done it 
> right.
> 
> I'd appreciate some review of the CMake stuff if anyone has the time and 
> inclination. 
> 
> In particular, I'm not sure I'm doing the GrantleeUse.cmake file stuff 
> correctly. I'm include()ing the Use file in my CMakeLists.txt file so that I 
> can use its macros. Is that the usual way to do these things?[3]
> 
> Also, the GrantleeConfig.cmake file looks wrong to me, but I don't know the 
> right way to implement it. There's a lot of if(UNIX) etc for things which 
> CMake must already know. I believe the solution I need there is importing 
> and exporting the library, but I haven't figured out how to do it. [3]
> 
> I'd like to know if any of this stuff should be a release blocker for me or 
> will cause problems down the line, and get some information of what I'm 
> doing wrong or what I could be doing better. Otherwise I'll probably make 
> the 0.1.0 release as-is and fix the ugly-but-works stuff later.
> 
> All the best,
> 
> Steve.
> 
> 
> [1] http://www.grantlee.org
> [2] 
> http://gitorious.org/grantlee/grantlee/blobs/master/cmake/modules/GrantleeUse.cmake
> [3] 
> http://gitorious.org/grantlee/grantlee/blobs/master/cmake/modules/GrantleeConfig.cmake.in

Hi

I had a look through your GrantleeConfig.cmake.in file. Most of the stuff looks fine, except where you set the library names:

if (UNIX)
  if (APPLE)
    set(Grantlee_CORE_LIBRARY "${Grantlee_LIBRARY_DIR}/libgrantlee_core.dylib")
    set(Grantlee_GUI_LIBRARY "${Grantlee_LIBRARY_DIR}/libgrantlee_gui.dylib")
  else (APPLE)
    set(Grantlee_CORE_LIBRARY "${Grantlee_LIBRARY_DIR}/libgrantlee_core.so")
    set(Grantlee_GUI_LIBRARY "${Grantlee_LIBRARY_DIR}/libgrantlee_gui.so")
  endif (APPLE)
else (UNIX)
  if (MINGW)
    set(Grantlee_CORE_LIBRARY "${Grantlee_LIBRARY_DIR}/libgrantlee_core.dll")
    set(Grantlee_GUI_LIBRARY "${Grantlee_LIBRARY_DIR}/libgrantlee_gui.dll")
  else(MINGW)
    set(Grantlee_CORE_LIBRARY "${Grantlee_LIBRARY_DIR}/grantlee_core.lib")
    set(Grantlee_GUI_LIBRARY "${Grantlee_LIBRARY_DIR}/grantlee_gui.lib")
  endif(MINGW)
endif (UNIX)

As you suspected, there's a much easier, more flexible and reliable way of doing things. E.g. in corelib/CMakeLists.txt do:

install(TARGETS grantlee_core EXPORTS GrantleeExports
         RUNTIME DESTINATION ${BIN_INSTALL_DIR}
         LIBRARY DESTINATION ${LIB_INSTALL_DIR}
         ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
         COMPONENT Devel
)

This will add the grantlee_core library to the export set GrantleeExports. You can the write this export-set to a file using the following in your top-level CMakeLists.txt:

install(EXPORT GrantLeeExports DESTINATION "${LIB_INSTALL_DIR}/grantlee")

In your GrantleeConfig.cmake.in then replace the stuff from above with:

include("@LIB_INSTALL_DIR@/grantlee/GrantleeExports.cmake")

which will create IMPORTED targets with the same names as in the Grantlee project. So you can then set the variables

set(Grantlee_CORE_LIBRARIES grantlee_core ${QT_QTCORE_LIBRARIES})
set(Grantlee_GUI_LIBRARIES grantlee_gui ${QT_QTGUI_LIBRARIES})


Also, you should make sure that Qt is available in your GrantleeConfig.cmake file, e.g. by calling find_package(Qt4 COMPONENTS QtCore QtGui REQUIRED). Don't call this in your GrantleeUse.cmake file, that's too late already. Also you might want to rename PARSE_ARGUMENT to GRANTLEE_PARSE_ARGUMENTS to avoid possible collisions with downstream packages.


Things get a tad more complicated if you want this to also work from the build-tree. In that case you need to call the EXPORT(TARGETS ...) function and write the stuff to ${CMAKE_BINARY_DIR}/GrantleeExports.cmake. Things are trickier with the GrantleeConfig.cmake now, since you need to different versions: One for the install-tree and one for the build tree. I usually configure the former into ${CMAKE_BINARY_DIR}/InstallFiles/GrantleeConfig.cmake and the latter into ${CMAKE_BINARY_DIR}/GrantleeConfig.cmake. Also, recent versions of CMake have the very handy EXPORT(PACKAGE Grantlee) function which enables other projects to easily find the build tree.

One last thing to consider: When you install GrantleeConfig.cmake, make sure it can be found easily by FIND_PACKAGE (as documented in the man-page) on all platforms you target.


HTH

Michael


More information about the CMake mailing list