Salome HOME
CMake: documenting SALOME_UPDATE_FLAG_AND_LOG_PACKAGE
[tools/documentation.git] / dev / cmake / source / pkg.rst
1 .. _package:
2
3 Package detection mechanism
4 ===========================
5
6 SALOME modules need some external packages in order to compile and run properly. For example KERNEL relies on the Python libraries, on the Boost libraries, etc ... The correct detection of those prerequisites is a key point of the CMake build procedure.
7
8 Philosophy
9 ----------
10
11 The philosophy of the SALOME package detection is, first, to rely as 
12 much as possible on the standard CMake detection modules (FindXyz.cmake files, located in the standard CMake installation directory).
13 It is assumed those modules will get better and better with newer releases of CMake
14 and using them ensures future compatibility with newer versions of CMake.
15
16 Second, the implementation of the detection process relies exclusively
17 on the XYZ_ROOT_DIR variable giving the installation path of the package. This means the user compiling SALOME should not have to set anything else than those XYZ variables (no PATH override, no LD_LIBRARY_PATH override should be necessary). This is not strictly always possible, but should enforce as often as possible.
18
19 Root dir variables and priority order
20 -------------------------------------
21
22 The detection is however guided through a variable of the form XYZ_ROOT_DIR which
23 gives the root directory of an installation of the package. For example, to indicate
24 that we wish to use the Python installed in our home directory, one sets PYTHON_ROOT_DIR to
25 "/home/smith/Python-2.7.0".
26
27 The variable guiding the detection is always builts as::
28
29   XYZ_ROOT_DIR
30
31 where <XYZ> is (*exactly*) the upper case name of the standard CMake module. For example, the
32 detection of Qt4 is guided by setting QT4_ROOT_DIR. The variables \*_ROOT_DIR are only there to guide the process, not to force it. Typically under Linux, one would never set PTHREAD_ROOT_DIR, thus leaving the logic find the system installation. 
33
34 Beware that package names in the CMakeLists.txt are case-sensitive, but the corresponding variables are always upper-case (because on some platforms environment variables are not case-sensitive).
35
36 The order of priority for the detection of a package is (from high to low priority):
37
38 1. CMake variables explicitly set by the user (typically on the command line with -DXYZ_ROOT_DIR=...)
39 2. Environment variables set by the user (with the same name XYZ_ROOT_DIR)
40 3. Default value based on a previous dependency using the tool already
41 4. Detection direclty in the host system by the standard CMake logic
42
43 CMake has two possible modes of detection, CONFIG mode and MODULE mode. The order of priority is explicitly set in SALOME to:
44
45 1. CONFIG (also called NO_MODULE) mode: this tries to load a xyz-config.cmake file from the package installation itself. Note that by default, this mode doesn't look at a potential system installation. If you do want the CONFIG mode to also inspect your system, you have to explicitly set the XYZ_ROOT_DIR variable to your system's path (typically "/usr").
46 2. MODULE mode: this relies on the logic written in a FindXyz.cmake macro, looking directly for representative libraries, binaries or headers of the package.
47
48 The first mode is preferred as it allows to directly include the CMake targets of the prerequisite.
49
50 The package detection is only made in the root CMakeLists.txt, potentially conditionned on some
51 user options. 
52
53 Writing the detection macro of a new SALOME prerequisite
54 --------------------------------------------------------
55
56 All detection macros are located under the soure directory::
57
58   salome_adm/cmake_files
59
60 or::
61
62   adm_local/cmake_files
63
64 All prerequisite detection in SALOME should be implemented by:
65
66 * writing a file FindSalome<Xyz>.cmake (note the extra ''Salome''), where <Xyz> matches *exactly* the name of the standard CMake module (see below if there is no standard module for <Xyz>)
67 * invoking FIND_PACKAGE() command in the root CMakeLists.txt::
68   
69     FIND_PACKAGE(SalomeLibXml2 REQUIRED)
70
71 * potentially, a prerequisite might be optional. In this case the following syntax is preferred::
72   
73     FIND_PACKAGE(SalomeLibXml2)
74     SALOME_UPDATE_FLAG_AND_LOG_PACKAGE(LibXml2 SALOME_FOO_FEATURE)
75
76 * the custom macro SALOME_UPDATE_FLAG_AND_LOG_PACKAGE takes care of switching OFF the flag SALOME_FOO_FEATURE if the package was not found. The final status of what has been found or not can then be displayed by calling SALOME_PACKAGE_REPORT().
77
78 Typically the FindSalome<Xyz>.cmake file looks like this::
79
80     SALOME_FIND_PACKAGE_AND_DETECT_CONFLICTS(CppUnit CPPUNIT_INCLUDE_DIRS 1)
81     MARK_AS_ADVANCED(CPPUNIT_INCLUDE_DIRS CPPUNIT_LIBRARIES CPPUNIT_CONFIG_BIN CPPUNIT_SUBLIB_cppunit CPPUNIT_SUBLIB_dl)
82
83 It invokes the SALOME macro SALOME_FIND_PACKAGE_AND_DETECT_CONFLICTS() which takes:
84
85 * as first argument the name of the package (here CppUnit), 
86 * as second argument, the name of a (path) variable set when the package is found properly, 
87 * as third argument, the number of levels this variable should be browsed up to reach the root directory of the package installation.
88     
89
90 In the example above,
91
92 * we look for the package CppUnit (note that this is case-sensitive). There is already a standard CMake module to detect CppUnit, which sets the CMake variable CPPUNIT_INCLUDE_DIRS to the (list of) directories to include when compiling with CppUnit. 
93 * going one level up from the include directory (typically /usr/include) gives the root directory of the installation (/usr).
94 * all the variables exposed in the cache by the standard detection logic (CPPUNIT_INCLUDE_DIRS, CPPUNIT_LIBRARIES, etc ...) are marked as "advanced" so that they do not automatically appear in ccmake or cmake-gui.
95
96 Note that the reference variable may be a list, only its first element is then considered.
97
98 Writing a new generic detection macro (advanced)
99 ------------------------------------------------
100
101 If you need to include in SALOME a prerequisite for which the standard CMake distribution 
102 doesn't provide the FindXyz.cmake module, you will need to write it yourself.
103 This also applies if you judge that the standard FindXyz.cmake CMake module doesn't do its job
104 properly (yes, it can happen).
105
106 The following guidelines apply:
107
108 * make the module as generic as possible, considering that it should also run properly outside SALOME. This separates clearly the basic detection of the package from the SALOME logic. Basically the module represents the point 4. in the order of priority given above and should behave as much as possible like any standard CMake module
109 * invoking the FIND_LIBRARY(), FIND_PROGRAM(), FIND_PATH() and FIND_FILE() commands should be done without specifying an explicit PATH option to the command (this is not always possible - see for example FindOmniORBPy.cmake). The idea is that the root directory for the search is set by the SALOME encapsulation (by setting CMAKE_PREFIX_PATH)
110 * document properly which variables you are setting, respecting the CMake standard (see for example FindOmniORB.cmake)
111 * use the CMake code found in many standard modules::
112
113     INCLUDE(FindPackageHandleStandardArgs)
114     FIND_PACKAGE_HANDLE_STANDARD_ARGS(Graphviz REQUIRED_VARS GRAPHVIZ_EXECUTABLE)
115
116
117 * This macro takes care (among other things) of setting the XYZ_FOUND variable (upper case), and of displaying a message if not in QUIET mode (TBC).
118 * the macro should be saved in the same directory as above
119 * respect the naming conventions for the variables you set (start with the package name, upper case - see :ref:`naming_conventions`)
120 * do not do any ADD_DEFINITIONS() or INCLUDE_DIRECTORIES() in such a macro. This should be done by the caller or in a UseXYZ.cmake file. The purpose of a FindXXX.cmake macro is to detect, not to make usable. This rule does not apply to FindSalomeXXX.cmake macros where we know we are always in the SALOME context.
121 * here is a simple example of the detection of Sphinx::
122
123     # - Sphinx detection
124     #
125     # Output variable: SPHINX_EXECUTABLE
126     #                  
127     # 
128     # The executable 'sphinx-build' is looked for and returned in the above variable.
129     #
130
131     ###########################################################################
132     # Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
133     <...>
134     ###########################################################################
135
136     FIND_PROGRAM(SPHINX_EXECUTABLE sphinx-build)
137
138     # Handle the standard arguments of the find_package() command:
139     INCLUDE(FindPackageHandleStandardArgs)
140     FIND_PACKAGE_HANDLE_STANDARD_ARGS(Sphinx REQUIRED_VARS SPHINX_EXECUTABLE)
141
142
143 .. _pkg_impl:
144
145 Implementation details (advanced)
146 ---------------------------------
147
148 The core of the SALOME detection logic is located in the macro
149 SALOME_FIND_PACKAGE_AND_DETECT_CONFLICTS() implemented in KERNEL/salome_adm/cmake_files/SalomeMacros.cmake.
150
151 All the logic is thus concentrated in one (hopefully well documented) macro. This means: one place to fix if there is a bug, and better, one place to amend if we ever want to define a new behaviour (for example if we want to change the order of priorities between CONFIG and MODULE mode). The end user (someone developing in SALOME) just needs to call it. It is the responsability of the core SALOME developpers to understand and maintain this macro.
152
153 The reader is invited to have the code at hand when reading the following.
154
155 The macro signature is
156 ::
157
158   SALOME_FIND_PACKAGE_DETECT_CONFLICTS(pkg referenceVariable upCount)
159
160 where:
161
162 * *pkg*              : name of the system package to be detected
163 * *referenceVariable*: variable containing a path that can be browsed up to retrieve the package root directory (xxx_ROOT_DIR)
164 * *upCount*          : number of times we have to go up from the path <referenceVariable> to obtain the package root directory.
165
166 For example::  
167
168   SALOME_FIND_PACKAGE_DETECT_CONFLICTS(SWIG SWIG_EXECUTABLE 2) 
169
170 The macro has a significant size but is very linear:
171
172 1. Load a potential env variable XYZ_ROOT_DIR as a default choice for the cache entry XYZ_ROOT_DIR.
173    If empty, load a potential XYZ_ROOT_DIR_EXP as default value (path exposed by another package depending
174    directly on XYZ)
175 2. Invoke FIND_PACKAGE() in this order:
176
177   * in CONFIG mode first (if possible): priority is given to a potential "XYZ-config.cmake" file. In this mode, the standard system paths are skipped. If you however want to force a detection in CONFIG mode into a system path, you have to set explicitly the XYZ_ROOT_DIR variable to "/usr".
178   * then switch to the standard MODULE mode, appending on CMAKE_PREFIX_PATH the above XYZ_ROOT_DIR variable.
179
180 3. Extract the path actually found into a temp variable _XYZ_TMP_DIR
181 4. Warn if XYZ_ROOT_DIR is set and doesn't match what was found (e.g. when CMake found the system installation
182    instead of what is pointed to by XYZ_ROOT_DIR - happens when there is a typo in the content of XYZ_ROOT_DIR).
183 5. Conflict detection: check the temporary variable against a potentially existing XYZ_ROOT_DIR_EXP
184 6. Finally expose what was *actually* found in XYZ_ROOT_DIR.  This might be different from the initial XYZ_ROOT_DIR, but there has been a warning in such a case.
185
186
187 The specific stuff (for example exposing a prerequisite of XYZ to the rest of the world for future conflict detection) is added after the call to the macro by the callee. See for example the FindSalomeHDF5.cmake macro which exposes the MPI_ROOT_DIR if HDF5 was compiled with parallel support.
188
189 If the invokation of FIND_PACKAGE() was done with some options:
190
191 * QUIET, REQUIRED
192 * COMPONENTS
193 * VERSION [EXACT]
194
195 those options are completly handled through the analysis of the standard CMake variables (which are automatically set when those options are given):
196
197 * Xyz_FIND_QUIETLY and Xyz_FIND_REQUIRED
198 * Xyz_FIND_COMPONENTS
199 * Xyz_FIND_VERSION and Xyz_FIND_VERSION_EXACT
200
201
202
203
204