Differences between revisions 2 and 3
Revision 2 as of 2007-11-06 13:41:56
Size: 14230
Editor: samson
Comment:
Revision 3 as of 2007-11-06 13:43:26
Size: 14268
Editor: samson
Comment:
Deletions are marked like this. Additions are marked like this.
Line 8: Line 8:
Line 9: Line 10:
A "configuration" CMakeLists.txt in every directory, where you find an old env.sh script by Roman.

A "configuration" CMakeLists.txt in every directory, where you find an old env.sh script by Roman.[[BR]]
Line 11: Line 14:
A "makefile like" CMakeLists.txt in the "src" directories
A "makefile like" CMakeLists.txt in the "src" directories[[BR]]
Line 14: Line 18:
The cmake diretory in the base directory of the package
The cmake diretory in the base directory of the package[[BR]]
Line 17: Line 22:
A template for the Config.cmake script: A template for the Config.cmake script:[[BR]]
Line 20: Line 25:
Line 21: Line 27:

Write CMakeLists.txt for the CALICE software

To write the CMake scripts, use the package calice_reco as template (mostly cut and paste).

Files you have to create (by copying from calice_reco + editing):

If the package consist of several sub packages:

( CMakeLists.txt from <calice_reco>/CMakeLists.txt )

A "configuration" CMakeLists.txt in every directory, where you find an old env.sh script by Roman.BR ( CMakeLists.txt from <calice_reco>/raw2calohit/CMakeLists.txt )

A "makefile like" CMakeLists.txt in the "src" directoriesBR ( CMakeLists.txt from <calice_reco>/raw2calohit/src/CMakeLists.txt )

The cmake diretory in the base directory of the packageBR ( cmake/ from <calice_reco>/cmake ; just copy the directory )

A template for the Config.cmake script:BR ( XXX/cmake/XXXConfigure.cmake.in from <calice_reco>/raw2calohit/cmake/RAW2CALOHITConfigure.cmake.in )

To write the scripts, just copy the files and try to start editing them. If there is something you don't understand, please ask.

To find all build options needed by a package, use

grep -i -r "#ifdef" * |cut -d":" -f2 |sort|uniq

to find all ifdef's in the source code. Please inspect the results manually to check which of the ifdef's change class definitions (the library API).

To understand the build system, this _might_ help:

This text explains the ideas and specific contents of these CMake
files to build the calice-userlib.

0) While these CMake scripts are aware of the ILC core software CMake
   scripts and uses them, where available to avoid to duplicate work,
   these scripts do not follow exactly the template of the core
   software scripts. The main reason for this are simplicity and
   control. The core software scripts are intended to provide a
   framework for users to quickly create a build system for a new
   project. To achieves this there are advances features, that hide
   some important things. E.g. calling cmake with -DBUILD_WITH="LCCD"
   option on core software packages links _all_ libraries and
   executables, that are build within this package against LCCD, iff
   LDDC is found. This happens without explicit knowledge of the
   actual CMake file. 
   Although this helps the user to easily add dependencies to their
   projects, this happens at the cost of loosing control and clear
   structures in the build system. Because the dependencies of a
   project like the CALICE software only change rarely, I choose to
   ignore these advanced features in this proposal for the CMake build
   system. The overall goal was to keep the build system simple but
   flexible.

1) The cmake build system for calice_userlib consists of:
   <calice_userlib>/CMakeLists.txt
   <calice_userlib>/cmake/BUILD_FLAG.cmake
   <calice_userlib>/cmake/CALICE_USERLIBConfig.cmake.in
   <calice_userlib>/src/CMakeLists.txt
   <calice_userlib>/examples/CMakeLists.txt
   <calice_userlib>/examples/src/CMakeLists.txt
   
   This follows the usual convention, for cmake build systems, that
   each directory containing code, (or subdirectories with code) has
   an own CMakeLists.txt. 
   The directory cmake contains an helper macro and a template file
   for cmake.
   In addition to this the "FindXXXX.cmake" modules of the core ILC
   software are used and have to be installed.
   The <calice_userlib>/CMakeLists.txt takes the role of a "configure"
   script, the CMakeLists.txt in the src subdirectories take the role
   of a Makefile(.am).
  
2) <calice_userlib>/CMakeLists.txt in detail (proceed to 3) if in a
   hurry ):
   
    PROJECT( CALICE_USERLIB )
      # This sets "${PROJECT_NAME} ${PROJECT_SOURCE_DIR},... see 
      # cmake --help-command IF
    SET( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE )
      # allows to write ENDIF() instead of ENDIF(...) 
      # see cmake --help-command IF
    SET( CMAKE_MODULE_PATH ${CALICE_USERLIB_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH} )
      # make the cmake directory of calice_userlib available without
      # user interaction

    #################
    # project version
    #################
    SET( ${PROJECT_NAME}_MAJOR_VERSION 4 )
    SET( ${PROJECT_NAME}_MINOR_VERSION 5 )
    SET( ${PROJECT_NAME}_PATCH_LEVEL   1 )
     
    # library Unix style versioning
    SET( ${PROJECT_NAME}_SOVERSION
        "${${PROJECT_NAME}_MAJOR_VERSION}" )
    SET( ${PROJECT_NAME}_VERSION
        "${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_LEVEL}" )
      # these variables are used to set the correct numbering of
      # shared libraries
      
      
    ############
    # options
    ############
      # this section provides switches, which you can see if you call
      # 'ccmake .' in the build directory after configuration
    INCLUDE( BUILD_FLAG )
      # this loads  <calice_userlib>/cmake/BUILD_FLAG.cmake and
      # provides the "BUILD_FLAG" macro
      
    # build shared library by default
    OPTION( BUILD_SHARED_LIBS "Create shared libraries" ON )
      # BUILD_SHARED_LIBS is a special CMake internal variable
      
    IF(NOT CMAKE_BUILD_TYPE)
      SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
          "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
          FORCE)
    ENDIF(NOT CMAKE_BUILD_TYPE)
      # CMAKE_BUILD_TYPE allows to use different optimization flags
      # RelWithDebInfo as default value provides '-O2 -g' flags
      
    ####################
    ## Macro BUILD_FLAG provides options "BUILD_WITH_<xyz>"
    BUILD_FLAG( BOUNDARY_CHECK      "additional boundary check" )
    ....
      # this macro provides BUILD_WITH_BOUNDARY_CHECK option and
      # toggles -DBOUNDARY_CHECK in a certain variable to change
      # compile time switches. See BUILD_FLAG.cmake for details

    OPTION( BUILD_EXAMPLES "build examples" OFF )
    IF( BUILD_EXAMPLES )
       BUILD_FLAG( HAVE_ROOT  "use ROOT in examples" ON )
    ENDIF( BUILD_EXAMPLES )
      # some flags are only needed if examples are build

    #These definitions change the library API and must be exported to other projects
    #Todo: issue warning, if user changes values from default
    BUILD_FLAG( DEPRECATED "use deprecated API" OFF ${PROJECT_NAME}_EXPORT_DEFINITIONS )
    MARK_AS_ADVANCED( ${PROJECT_NAME}_EXPORT_DEFINITIONS )
    ADD_DEFINITIONS( ${${PROJECT_NAME}_EXPORT_DEFINITIONS} )
      # some definitions change the API and thus must be known by
      # projects using this library. These definitions (-DDEPRECATED)
      # are stored in a special variable and set here to guarantee
      # that they are used.

    ###############################
    # find packages (dependencies)
    ###############################
    FIND_PACKAGE( LCIO REQUIRED )
    ...
       # find dependencies. These macros usually set
       # ${LCIO_INCLUDE_DIR}, ${LCIO_LIBRARIES} and 
       # ${LCIO_DEFINITIONS} nevertheless there is no strict
       # constrained on the name of the variables. When using
       # unknown FindXXX.cmake modules check these files 
       # to be sure about variable names.

    # change default install prefix
    IF( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
        SET( CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}" CACHE PATH "Install prefix" FORCE )
    ENDIF( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
        # CMAKE_INSTALL_PREFIX is the default install prefix

    # default destination for header files: ${CMAKE_INSTALL_PREFIX}/install
   SET( INCLUDE_INSTALL_DIR "include" CACHE PATH "Directory to install the header files" )
   MARK_AS_ADVANCED( INCLUDE_INSTALL_DIR )
        # this option will later be used, to allow the installation of
        # this library into exotic places. But this option will not be
        # shown to the default user

   # append link paths to rpath list
   SET( CMAKE_INSTALL_RPATH_USE_LINK_PATH 1 )
        # this builds in the RPATH to shared libraries/executables and
        # helps to avoid the need of LD_LIBRARY_PATH

   ############
   # subdirs
   ############
   ADD_SUBDIRECTORY( src )
         # configuration is done, now create the makefile....


   #########################
   # install configuration
   #########################
   CONFIGURE_FILE( ${CALICE_USERLIB_SOURCE_DIR}/cmake/CALICE_USERLIBConfig.cmake.in
                   ${CALICE_USERLIB_BINARY_DIR}/CALICE_USERLIBConfig.cmake  @ONLY   )
   INSTALL( FILES ${CALICE_USERLIB_BINARY_DIR}/CALICE_USERLIBConfig.cmake
            DESTINATION ${CONFIG_INSTALL_DIR}                               )
      # provide proper CMake configuration information for this package
      # other cmake based projects can use calice_userlib with help of
      # this


3) <calice_userlib>/src/CMakeLists.txt: This file more or less
   generates the Makefile itself. After the configuration is done
   properly this file is pretty simple:

   0) define a variable to conveniently change the library name
   SET( lib1name userlib )

   1) Tell CMake where to find the headers (${XXXX_INCLUDE_DIR} will be
   set by FIND_PACKAGE(XXXX)
   #####################
   # include directories
   #####################
   INCLUDE_DIRECTORIES( "${${PROJECT_NAME}_SOURCE_DIR}/include" )
   INCLUDE_DIRECTORIES( ${LCIO_INCLUDE_DIR} )
   INCLUDE_DIRECTORIES( ${LCCD_INCLUDE_DIR} ${Marlin_INCLUDE_DIR} )

   2) Pass compiler flags
   ###############
   # definitions
   ###############
   ADD_DEFINITIONS( "-Wall -ansi" )
   ADD_DEFINITIONS( ${PROJECT_DEFINITIONS} ) # definition set by BUILD_FLAGS macro
   ADD_DEFINITIONS( ${${PROJECT_NAME}_EXPORT_DEFINITIONS} )
   ADD_DEFINITIONS( ${LCCD_DEFINITIONS} ${Marlin_DEFINITIONS} )


   3) List the source files (save them in the variable userlib_src
   ####################
   # sources
   ####################
   AUX_SOURCE_DIRECTORY( . ${lib1name}_srcs )

   3b) this collects all source files in the current source directory
   (src) I prefer to give an explicit file list:
   SET( ${lib1name}_srcs source1.cc
                         source2.cc 
                         source3.cc )

   4) say cmake what to build (library) from which sources
   #########
   # target
   #########
   ADD_LIBRARY( ${lib1name} ${${lib1name}_srcs} )
   
   and set the library version numbers

   SET_TARGET_PROPERTIES( ${lib1name} PROPERTIES
                       VERSION ${${PROJECT_NAME}_VERSION}
                       SOVERSION ${${PROJECT_NAME}_SOVERSION}
                         )

   5) finally tell cmake on which libraries your target depends on:
   ###############
   # link against
   ###############
   TARGET_LINK_LIBRARIES( ${lib1name} ${LCIO_LIBRARIES}
                                      ${Marlin_LIBRARIES} )

   6) provide information, how to install header files and library.
   ####################
   # install
   ####################
   INSTALL( DIRECTORY "${${PROJECT_NAME}_SOURCE_DIR}/include/" DESTINATION ${INCLUDE_INSTALL_DIR}
            PATTERN "*~" EXCLUDE
            PATTERN "*CVS*" EXCLUDE )
 
   INSTALL( TARGETS ${lib1name}
           DESTINATION ${LIB_INSTALL_DIR}
           PERMISSIONS
           OWNER_READ OWNER_WRITE OWNER_EXECUTE
           GROUP_READ GROUP_EXECUTE
           WORLD_READ WORLD_EXECUTE  )


4) Although for every package (LCIO, LCCD, ... ) more or less the same
   action is needed in the "Makefile" ( adding includes, adding
   definitions, adding libraries), I choose not to write a fancy macro
   for this because of reasons given in 0) and because of the fact,
   that such a macro would to the right thing only in most of the
   cases. As I mentioned before, there are common conventions for the
   FindXXX.cmake scripts to provide information about the found
   package, but these conventions are by no means unique.

5) A)-C) contains some additional useful information on cmake.

6) good luck


      
A) Documentation can by found by calling cmake --help-command-list and
   cmake --help-command <COMMAND>

B) while the command are case insensitive, some (most) of the options
   are not. => always use capital letters for CMake buildin stuff...

C) Remarks on CMake Variables: Variables can be set with CMake's
   SET(...) command, via -D options in the command line or by editing
   the CMakeCache file. There are some important implications of the
   different methods, that are not well documented.

   a) If you set a variable via SET( VARNAME contents ) the content of
     the variable will be set to contents in any case. This means the
     usage of ${VARNAME} will be substituted in any case by contents in
     _all_ lines following the definition and in _all_ files that are
     recursively processed ( via ADD_SUBDIRECTORY ). But the variable
     will not be propagated back to a "calling" file. (i.E. the
     ${VARNAME} will be "oldcontents" if you return to a "parent"
     file.

   b) If you use SET( VARNAME contents CACHE <TYPE> "documentation" )
     the result will be equivalent to the following pseudo code:
     if( cmake command line option -DVARNAME is given )
          do SET( VARNAME <contents given in command line> )
          write <contents given in command line> into cache
     else if (VARNAME is already set)
           do nothing  (this might be a bug )
     else if ( there is an entry for TEST in CMakeCache.txt ) 
           do SET( VARNAME <contents of VARNAME in cache> )
     else
           do SET( VARNAME contents )
           write "contents" as value for VARNAME into cache

    c) If you use SET( VARNAME contents CACHE <TYPE> "documentation"
                          FORCE )
       the following is done:
           write contents as value for VARNAME into cache
           do SET( VARNAME contents )
    d) If you pass options via command line this is equivalent to
      placing additional lines in the beginning of the CMakeLists.txt:
      SET( VARNAME "contents from command line" ).
      If the variable you pass in the command line is already in the
      CMakeCache.txt, the corresponding value will be changed there.

HCAL Write Calice CMake (last edited 2009-06-16 18:32:16 by localhost)