Template for H3DAPI dependent projects

From H3D.org

Jump to: navigation, search

This tutorial basically just create and explains how to create a file that CMake can use to generate a build which use H3DAPI. The builds created are called Foo and Foo_executable. The first one is a shared library and the other one is an executable.

The first thing to do is to create a file named CMakeLists.txt somewhere on the system. Next we start editing this file and start by creating a CMake project. The first line is just a way to keep track of which version of CMake is neccessary for this file. In our case it should be enough with 2.4.8 but we write 2.6.0 because we are lazy.

cmake_minimum_required(VERSION 2.6.0)
project(MyProject)

When using CMake with the CMakeLists.txt some CMake variables are created and set. The most important of these are the ProjectName_SOURCE_DIR and ProjectName_BINARY_DIR. In our case it is MyProject_SOURCE_DIR which is the location of the CMakeLists.txt we created and MyProject_BINARY_DIR which is the location of where we want to create the files of the generated build. The location of the files of the generated builds is choosen when running CMake with the CMakeLists.txt and is not important for this tutorial.

Next we create two variables which will contain the libraries which the generated builds need to be able to link properly.

# Optional libraries to link against are added to this variable.
SET(optionalLibs)

# Required libraries to link against are added to this variable.
SET(requiredLibs)

Since we want this CMakeLists.txt to be a bit more general we do not simply set hardcoded values for the variables above. Instead we will use the capability of CMake to use a "Find"-module. These modules are scripts which will search locations on the systems for the libraries and header files needed to compile with support for those libraries. Since H3DAPI comes with "Find"-modules for H3DAPI specific libraries we will use those "Find"-modules. In order to do this CMake need to know where those modules are located. To tell CMake about extra directories in which find-modules can be located simply set the variable CMAKE_MODULE_PATH to point to such directories. One way to set the directories of the find-modules is to copy the important modules from the H3DAPI installation to a location relative to the location of this CMakeLists.txt and set CMAKE_MODULE_PATH to point to that directory. We choose another approach since the environment variable H3D_ROOT should be defined when H3DAPI is installed on a system (if it should work as intended) we use that variable to find the directory in which the find-modules reside. The CMake commands to do that looks like this.

# Needed to convert from \ to / on windows.
SET( CONVERTED_H3D_ROOT "" )
IF( EXISTS $ENV{H3D_ROOT} )
  FILE( TO_CMAKE_PATH $ENV{H3D_ROOT} CONVERTED_H3D_ROOT )
ENDIF( EXISTS $ENV{H3D_ROOT} )
# Where to find modules used to find libraries.
SET(CMAKE_MODULE_PATH  ${CONVERTED_H3D_ROOT}/build/modules )

Next comes the commands that will find the needed H3DAPI libraries and set the variable "requiredLibs". The INCLUDE_DIRECTORIES statement adds directories to the include directories of the generated build(s). When using FIND_PACKAGE(x) the module used to find x will set a variable x_FOUND to TRUE if all the libraries and header file directories needed by the library are found.

#H3DAPI
FIND_PACKAGE(H3DAPI REQUIRED)

IF(H3DAPI_FOUND)
  INCLUDE_DIRECTORIES( ${H3DAPI_INCLUDE_DIR} ) 
  SET(requiredLibs ${requiredLibs} ${H3DAPI_LIBRARIES} )
ENDIF(H3DAPI_FOUND)

#H3DUtil
FIND_PACKAGE(H3DUtil REQUIRED)

IF(H3DUTIL_FOUND)
  INCLUDE_DIRECTORIES( ${H3DUTIL_INCLUDE_DIR} ) 
  SET(requiredLibs ${requiredLibs} ${H3DUTIL_LIBRARIES} )
ENDIF(H3DUTIL_FOUND)

#HAPI
FIND_PACKAGE(HAPI REQUIRED)

IF(HAPI_FOUND)
  INCLUDE_DIRECTORIES( ${HAPI_INCLUDE_DIR} ) 
  SET(requiredLibs ${requiredLibs} ${HAPI_LIBRARIES} )
ENDIF(HAPI_FOUND)

Next comes the command that specifies what type of build files should be generated by CMake. One CMakeLists can create several different builds, but they all have to have different names.

# Build files created.
# An executable is created like this.
ADD_EXECUTABLE(FooExe ${MyProject_SOURCE_DIR}/Foo_exe.cpp )

# A shared library is created like this.
# The library is assumed to have two source files.
ADD_LIBRARY( Foo SHARED ${MyProject_SOURCE_DIR}/Foo.cpp
                        ${MyProject_SOURCE_DIR}/Foo.h )

Next we set the libraries to link against for each build that should be generated by using the value of the variables requireLibs and optionalLibs (in our example optionalLibs is empty).

# Link against libraries.
TARGET_LINK_LIBRARIES( FooExe ${requiredLibs} ${optionalLibs} )
TARGET_LINK_LIBRARIES( Foo ${requiredLibs} ${optionalLibs} )

Since the H3DAPI debug libraries have _d appended to its name we decided to show how to do this for the builds generated by this CMakeLists.txt.

# We want debug versions to have _d postfix.
SET_TARGET_PROPERTIES( FooExe PROPERTIES DEBUG_POSTFIX "_d" )
SET_TARGET_PROPERTIES( Foo PROPERTIES DEBUG_POSTFIX "_d" )

The last thing to do is to decide where the executable and library goes when installing them on the system (after building them). On Windows systems we have a default location which we wish them to go so additional commands are needed for Windows. For other systems the default location is fine in our case.

# If it is desired to install the project and change the default installation
# path then the following part is needed. It will check if the
# CMAKE_INSTALL_PREFIX is initialized to its default value. If it is, then
# change it to another default value.
IF( WIN32 AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
  # This command will only be run once for each new cache.
  SET( CMAKE_INSTALL_PREFIX ${MyProject_SOURCE_DIR}/.. CACHE PATH
       "Install path prefix, prepended onto install directories." FORCE )
ENDIF( WIN32 AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )

# Install to these directories.
INSTALL( TARGETS Foo FooExe
         LIBRARY DESTINATION lib
         RUNTIME DESTINATION bin
         ARCHIVE DESTINATION lib )

That is about it. CMake can of course handle a lot more configuration of projects and sometimes it is needed to set properties of different builds. Please see the CMake wiki for more information about configuring CMake.

The complete finished file looks like this (put here to make it easier to copy and paste):

cmake_minimum_required(VERSION 2.6.0)
project(MyProject)

# Optional libraries to link against are added to this variable.
SET(optionalLibs)

# Required libraries to link against are added to this variable.
SET(requiredLibs)

# Needed to convert from \ to / on windows.
SET( CONVERTED_H3D_ROOT "" )
IF( EXISTS $ENV{H3D_ROOT} )
  FILE( TO_CMAKE_PATH $ENV{H3D_ROOT} CONVERTED_H3D_ROOT )
ENDIF( EXISTS $ENV{H3D_ROOT} )
# Where to find modules used to find libraries.
SET(CMAKE_MODULE_PATH  ${CONVERTED_H3D_ROOT}/build/modules )

#H3DAPI
FIND_PACKAGE(H3DAPI REQUIRED)

IF(H3DAPI_FOUND)
  INCLUDE_DIRECTORIES( ${H3DAPI_INCLUDE_DIR} ) 
  SET(requiredLibs ${requiredLibs} ${H3DAPI_LIBRARIES} )
ENDIF(H3DAPI_FOUND)

#H3DUtil
FIND_PACKAGE(H3DUtil REQUIRED)

IF(H3DUTIL_FOUND)
  INCLUDE_DIRECTORIES( ${H3DUTIL_INCLUDE_DIR} ) 
  SET(requiredLibs ${requiredLibs} ${H3DUTIL_LIBRARIES} )
ENDIF(H3DUTIL_FOUND)

#HAPI
FIND_PACKAGE(HAPI REQUIRED)

IF(HAPI_FOUND)
  INCLUDE_DIRECTORIES( ${HAPI_INCLUDE_DIR} ) 
  SET(requiredLibs ${requiredLibs} ${HAPI_LIBRARIES} )
ENDIF(HAPI_FOUND)

# Build files created.
# An executable is created like this.
ADD_EXECUTABLE(FooExe ${MyProject_SOURCE_DIR}/Foo_exe.cpp )

# A shared library is created like this.
# The library is assumed to have two source files.
ADD_LIBRARY( Foo SHARED ${MyProject_SOURCE_DIR}/Foo.cpp
                        ${MyProject_SOURCE_DIR}/Foo.h )
                        
# Link against libraries.
TARGET_LINK_LIBRARIES( FooExe ${requiredLibs} ${optionalLibs} )
TARGET_LINK_LIBRARIES( Foo ${requiredLibs} ${optionalLibs} )

# We want debug versions to have _d postfix.
SET_TARGET_PROPERTIES( FooExe PROPERTIES DEBUG_POSTFIX "_d" )
SET_TARGET_PROPERTIES( Foo PROPERTIES DEBUG_POSTFIX "_d" )

# If it is desired to install the project and change the default installation
# path then the following part is needed. It will check if the
# CMAKE_INSTALL_PREFIX is initialized to its default value. If it is, then
# change it to another default value.
IF( WIN32 AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
  # This command will only be run once for each new cache.
  SET( CMAKE_INSTALL_PREFIX ${MyProject_SOURCE_DIR}/.. CACHE PATH
       "Install path prefix, prepended onto install directories." FORCE )
ENDIF( WIN32 AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )

# Install to these directories.
INSTALL( TARGETS Foo FooExe
         LIBRARY DESTINATION lib
         RUNTIME DESTINATION bin
         ARCHIVE DESTINATION lib )
Personal tools
go to