Difference between revisions of "CMake:How To Find Installed Software"

From KitwarePublic
Jump to navigationJump to search
Line 1: Line 1:
 +
{{CMake/Template/Obsolete}}
 +
The information in the '''How to write a FindFoo.cmake module''' section is somewhat dated.
 +
 
If your software uses external libraries (i.e. libraries not coming with your software), you don't know in advance where its headers and libraries will be located on the system where your software will be compiled.
 
If your software uses external libraries (i.e. libraries not coming with your software), you don't know in advance where its headers and libraries will be located on the system where your software will be compiled.
 
Depending on the location appropriate include directories and library search paths will have to be added to the compile commands.
 
Depending on the location appropriate include directories and library search paths will have to be added to the compile commands.

Revision as of 01:53, 16 January 2009

CAUTION: The contents of this page may be obsolete
120px-Old finnish stop sign.svg.png The information in the How to write a FindFoo.cmake module section is somewhat dated.

If your software uses external libraries (i.e. libraries not coming with your software), you don't know in advance where its headers and libraries will be located on the system where your software will be compiled. Depending on the location appropriate include directories and library search paths will have to be added to the compile commands.

CMake helps you with this by providing so-called modules. Let's say you want to use the PNG-Library, here's how you would do this with cmake:

FIND_PACKAGE(PNG)

IF(PNG_FOUND)
   INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR})

   ADD_EXECUTABLE(imageviewer main.c image.c)
   TARGET_LINK_LIBRARIES(imageviewer ${PNG_LIBRARY})

ENDIF(PNG_FOUND)

Every module is provided in the form Find<name>.cmake, they are located in the CMake module directory, on UNIX usualy /usr/local/share/CMake/Modules/ It is then used in the CMakeLists.txt with the FIND_PACKAGE(<name>) command. For details see the regular CMake documentation. Every module will define the following variables:

  • <name>_FOUND
  • <name>_INCLUDE_DIR or <name>_INCLUDES
  • <name>_LIBRARY or <name>_LIBRARIES

As you can see, with PNG_FOUND you can test whether the package you need has actually been found. If that's the case, you have to add the include directories and link to the libraries which make up the package, in this case PNG_INCLUDE_DIR and PNG_LIBRARIES.

If the package is not optional but your software can't be built at all without the package, you should use the REQUIRED argument for FIND_PACKAGE(). This will have the effect that cmake will abort with an error if it can't find the software.

Another way how you can deal with optional packages you can see here:


SET(mySources main.cpp viewer.cpp)
SET(optionalSources)
SET(optionalLibs)

IF(JPEG_FOUND)
   SET(optionalSources ${optionalSources} jpegview.cpp)
   INCLUDE_DIRECTORIES( ${JPEG_INCLUDE_DIR} )
   SET(optionalLibs ${optionalLibs} ${JPEG_LIBRARIES} )
ENDIF(JPEG_FOUND)

IF(PNG_FOUND)
   SET(optionalSources ${optionalSources} pngview.cpp)
   INCLUDE_DIRECTORIES( ${PNG_INCLUDE_DIR} )
   SET(optionalLibs ${optionalLibs} ${PNG_LIBRARIES} )
ENDIF(PNG_FOUND)

ADD_EXECUTABLE(viewer ${mySources} ${optionalSources} )
TARGET_LINK_LIBRARIES(viewer ${optionalLibs} )

This way you can organize your CMakeLists.txt and they should stay clean and readable.

What to do if cmake doesn't find the package although it exists on the system ?

Let's say the PNG library hasn't been found. If that's the case, cmake apparently didn't look good enough :-) There are several things you can do about this. The simple method, which involves quite a lot of manual work, is to just tell cmake explicitly where the software is located. To do this, you have three options:

  • edit the file CMakeCache.txt and search for the entries named PNG_INCLUDE_DIR and PNG_LIBRARY. They will be set to NOTFOUND. Edit these entries and enter the correct path to the PNG include directory on your system, e.g. c:stuff/png/include/ and do the same for PNG_LIBRARY: c:/stuff/png/png.dll .Then save the file and run cmake again
  • you can use the cmake GUIs ccmake or CMakeSetup to enter these options. This is basically the same as the point above, but with a GUI.
  • you can tell cmake the correct values via the command line: cmake -DPNG_INCLUDE_DIR=c:/stuff/png/include -DPNG_LIBRARY=c:/stuff/png/png.dll

There are also two environment variables which you can set to help cmake find the package. These are the variables CMAKE_INCLUDE_PATH and CMAKE_LIBRARY_PATH. You can set these to the directories where the additional headers and libraries are located and then cmake will find them if they are really there.

How to write a FindFoo.cmake module

Let's say, you have a library named foo, i.e. the library file is called libfoo.so on UNIX and foo.dll on Windows. Now you want to use this library in a cmake-based software project. You probably want to write a FindFoo.cmake, so that you can simply do

FIND_PACKAGE(Foo) 

in your CMakeLists.txt. Writing such a module is easy:

* find out the name of a significant header
* find out the name of the library, possibly it can have more than one name. (e.g. on Windows there might be a zlib.dll, which is a libz.so on UNIX)

cmake provides the FIND_FILE(), FIND_LIBRARY(), FIND_PATH() and FIND_PROGRAM() commands for this task. So you can start and create a FindFoo.cmake:

FIND_PATH(FOO_INCLUDE_DIR foo.h /usr/include/foo /usr/local/include/foo)

FIND_LIBRARY(FOO_LIBRARY NAMES foo PATH /usr/lib /usr/local/lib) 

IF (FOO_INCLUDE_DIR AND FOO_LIBRARY)
   SET(FOO_FOUND TRUE)
ENDIF (FOO_INCLUDE_DIR AND FOO_LIBRARY)


IF (FOO_FOUND)
   IF (NOT Foo_FIND_QUIETLY)
      MESSAGE(STATUS "Found Foo: ${FOO_LIBRARY}")
   ENDIF (NOT Foo_FIND_QUIETLY)
ELSE (FOO_FOUND)
   IF (Foo_FIND_REQUIRED)
      MESSAGE(FATAL_ERROR "Could not find Foo")
   ENDIF (Foo_FIND_REQUIRED)
ENDIF (FOO_FOUND)

The variables Foo_FIND_QUIETLY and Foo_FIND_REQUIRED get defined if FIND_PACKAGE() is called with the REQUIRED or QUIET parameters.

In order to be able to use the newly written FindFoo package, the location of the FindFoo.cmake file must be added to the cmake modules list from within a CMakeLists.txt file as follows:

set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules/")

Assuming that FindFoo.cmake exists within a directory called cmake_modules within the top-level source directory. Note that this does not overwrite the existing, default, module path, but rather augments the path with the new user-defined extensions.


For more information, have a look at the cmake manpage and the modules which come with cmake, e.g. FindJPEG.cmake. In the cmake module directory you can also find a readme.txt, which contains some more guidelines for writing cmake modules.



CMake: [Welcome | Site Map]