[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