in a dedicated CMake file.
Following the CMake tutorial (http://www.cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file) some
-important module install *Config.cmake files facilitating the configuration of other dependent modules. When writing such
+important module install \*Config.cmake files facilitating the configuration of other dependent modules. When writing such
CMake files, care must be taken to use PROJECT_BINARY_DIR and PROJECT_SOURCE_DIR variables instead of CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR. This ensures that the project will also work properly when included as a sub-folder of a bigger project.
The use of the local (or global) CMake Registry (via the EXPORT(PACKAGE ...) command) is not recommended. This overrides
call the export command to generate the appropriate files.
With this setup, the project can be either:
+
* configured, built and installed in a standalone fashion
-* or directly be included as a sub-folder in the code of another bigger project. A simple ADD_SUBDIRECTORY in
-the root CMakeLists.txt of the encapsulating project will trigger the proper configuration/build of the sub-project.
+* or directly be included as a sub-folder in the code of another bigger project. A simple ADD_SUBDIRECTORY in the root CMakeLists.txt of the encapsulating project will trigger the proper configuration/build of the sub-project.
Care must be taken to explicitly request a target to be part of the export set in the code sub-folders, when installing it
-(EXPORT option):
-::
+(EXPORT option)::
+
INSTALL(TARGETS kerncompo kern_main
# IMPORTANT: Add the library kerncompo to the "export-set" so it will be available
# to dependent projects
============
CMake is a configuration tool generating the build chain (e.g. Makefiles on Linux)
of a software project.
-
This documentation describes the goals and the good practices to be applied when writing
the CMake files for the configuration of a SALOME module.
With a tool like cmake-gui or ccmake, the user must obtain useful messages to find what is wrong or missing.
The general philosophy is thus to allow a developper to build SALOME with a minimal effort, setting only the
-minimal environment.
+minimal set of variables (via the command line or the environment).
Basic usage
-----------
Once the sources have been retrieved (via a clone of the repository or an extraction of the tarball)
-once typically:
-* create a dedicated build directory, e.g. KERNEL_BUILD
-* switch to it, and invoke the ccmake (or cmake-gui) command
- ::
- ccmake ../KERNEL_SRC
-* sets all the xyz_ROOT_DIR to point to the root paths of the package <xyz>
-* sets the installation directory in the variable CMAKE_INSTALL_PREFIX
-* generates the build files (hiting 'g' under ccmake)
-* invoke the make command in the usual way:
- ::
- make
- make install
+one typically:
+
+* create a dedicated build directory, e.g. KERNEL_BUILD.
+* switch to it, and invoke the ccmake (or cmake-gui) command::
+
+ ccmake
+ ccmake
+
+* sets all the xyz_ROOT_DIR to point to the root paths of the package <xyz>.
+* sets the installation directory in the variable CMAKE_INSTALL_PREFIX.
+* generates the build files (hiting 'g' under ccmake).
+* invoke the make command in the usual way::
+
+ make
+ make install
If you want to use a specific Python installation to configure and build SALOME, you should ensure that:
-* the interpreter is in your path
-* the variables LD_LIBRARY_PATH (PATH under Windows) and PYTHONPATH are properly pointing to your
- desired Python installation.
+* the interpreter is in your path.
+* the variables LD_LIBRARY_PATH (PATH under Windows) and PYTHONPATH are properly pointing to your desired Python installation.
Overview of the logic (advanced)
--------------------------------
* Only take into account first order prerequisites.
For instance, CASCADE uses Tbb :
- * CASCADE is a prerequisite of first order of GUI,
- * Tbb is a prerequisite of second order of GUI,
- * GUI CMake files must reference explicitly CASCADE, but never Tbb. The detection logic of CASCADE should make sure Tbb gets included.
+
+ * CASCADE is a prerequisite of first order of GUI,
+ * Tbb is a prerequisite of second order of GUI,
+ * GUI CMake files must reference explicitly CASCADE, but never Tbb. The detection logic of CASCADE should make sure Tbb gets included.
+
* Being able to use different versions/installations of the same product, in the system, or generated by the user.
For instance, using the system python 2.7, or a user-compiled python 2.6.
-* The detection of prerequisites is driven by user options.
+* The detection of prerequisites is driven by user options.
For example MPI is detected only if option SALOME_USE_MPI is ON.
-* Detection of first order prerequisites is based on a <Product>_ROOT_DIR variable or on what has been detected in
- another dependency. For example if both HDF5 and MPI are needed by the current module, we try to detect
- with which MPI installation HDF5 was compiled, and to offer this one as a default choice for the package itself.
- Other variables (PATH, LD_LIBRARY_PATH, PYTHONPATH) should never be needed at compile time.
-* The only exception to the previous point is Python, which is so central to the process
- that we assume that LD_LIBRARY_PATH and PYTHONPATH are already correctly pointing to the correct
- Python installation.
+* Detection of first order prerequisites is based on a <Product>_ROOT_DIR variable or on what has been detected in another dependency. For example if both HDF5 and MPI are needed by the current module, we try to detect with which MPI installation HDF5 was compiled, and to offer this one as a default choice for the package itself. Other variables (PATH, LD_LIBRARY_PATH, PYTHONPATH) should never be needed at compile time.
+* The only exception to the previous point is Python, which is so central to the process that we assume that LD_LIBRARY_PATH and PYTHONPATH are already correctly pointing to the correct Python installation.
The detection is however guided through a variable of the form XYZ_ROOT_DIR which
gives the root directory of an installation of the package. For example, to indicate
-that we wish to use the Python installed on the host system, one sets PYTHON_ROOT_DIR to
-"/usr".
+that we wish to use the Python installed in our home directory, one sets PYTHON_ROOT_DIR to
+"/home/smith/Python-2.7.0".
+
+The variable guiding the detection is always builts as::
-The variable guiding the detection is always builts as
-::
XYZ_ROOT_DIR
where <XYZ> is the upper case name of the standard CMake module. For example, the
detection of Qt4 is guided by setting QT4_ROOT_DIR.
The order of priority for the detection of a package is (from high to low priority):
+
1. CMake variables explicitly set by the user (typically on the command line with -DXYZ_ROOT_DIR=...)
2. Environment variables set by the user (with the same name XYZ_ROOT_DIR)
3. Default value based on a previous dependency using the tool already
Writing the detection macro of a new SALOME prerequisite
--------------------------------------------------------
-All detection macros are located under the soure directory
-::
+All detection macros are located under the soure directory::
+
salome_adm/cmake_files
-or
-::
+or::
+
adm_local/cmake_files
All prerequisite detection in SALOME should be implemented by:
-* 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>)
-* typically this file looks like this:
- ::
+
+* 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>)
+* typically this file looks like this::
+
SALOME_FIND_PACKAGE_AND_DETECT_CONFLICTS(CppUnit CPPUNIT_INCLUDE_DIRS 1)
MARK_AS_ADVANCED(CPPUNIT_INCLUDE_DIRS CPPUNIT_LIBRARIES CPPUNIT_CONFIG_BIN CPPUNIT_SUBLIB_cppunit CPPUNIT_SUBLIB_dl)
- It invokes the SALOME macro SALOME_FIND_PACKAGE_AND_DETECT_CONFLICTS() which takes as
- first argument the name of the package (here CppUnit), as second argument, the name
- of a (path) variable set when the package is found properly, and as third argument, the number of
- levels this variable should be browsed up to reach the root directory of the package installation.
-* in the example above, 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.
- Going one level up from the include directory (typically /usr/include) gives the root directory of the
- installation (/usr)
+
+* It invokes the SALOME macro SALOME_FIND_PACKAGE_AND_DETECT_CONFLICTS() which takes:
+
+ * as first argument the name of the package (here CppUnit),
+ * as second argument, the name of a (path) variable set when the package is found properly,
+ * and as third argument, the number of levels this variable should be browsed up to reach the root directory of the package installation.
+
+* in the example above, 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. Going one level up from the include directory (typically /usr/include) gives the root directory of the installation (/usr)
* the reference variable may be a list, only its first element is then considered.
-* 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.
+* 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.
Writing a new generic detection macro (advanced)
------------------------------------------------
If you need to include in SALOME a prerequisite for which the standard CMake distribution
doesn't provide the FindXyz.cmake module, you will need to write it yourself.
-This also apply if you judge that the standard FindXyz.cmake CMake module doesn't do its job
-properly (yes it happens).
+This also applies if you judge that the standard FindXyz.cmake CMake module doesn't do its job
+properly (yes, it can happen).
The following guidelines apply:
-* 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
-* 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)
-* document properly which variables you are setting, respecting the CMake standard (see for example
- FindOmniORB.cmake)
-* use the CMake code found in many standard modules:
- ::
- # Handle the standard arguments of the find_package() command:
+
+* 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
+* 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)
+* document properly which variables you are setting, respecting the CMake standard (see for example FindOmniORB.cmake)
+* use the CMake code found in many standard modules::
+
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Graphviz REQUIRED_VARS GRAPHVIZ_EXECUTABLE)
- 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).
+
+
+* 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).
* the macro should be saved in the same directory as above
* respect the naming conventions for the variables you set (start with the package name, upper case)
-* here is a simple example of the detection of Sphinx:
- ::
+* here is a simple example of the detection of Sphinx::
+
# - Sphinx detection
#
# Output variable: SPHINX_EXECUTABLE
The macro signature is
::
+
SALOME_FIND_PACKAGE_DETECT_CONFLICTS(pkg referenceVariable upCount <component1> <component2> ...)
where:
-* pkg : name of the system package to be detected
-* referenceVariable: variable containing a path that can be browsed up to
-retrieve the package root directory (xxx_ROOT_DIR)
-* upCount : number of times we have to go up from the path <referenceVariable>
-to obtain the package root directory.
-* <component_n> : an optional list of components to be found.
-
-For example:
-::
+
+* *pkg* : name of the system package to be detected
+* *referenceVariable*: variable containing a path that can be browsed up to retrieve the package root directory (xxx_ROOT_DIR)
+* *upCount* : number of times we have to go up from the path <referenceVariable> to obtain the package root directory.
+* *<component_n>* : an optional list of components to be found.
+
+For example::
+
SALOME_FIND_PACKAGE_DETECT_CONFLICTS(SWIG SWIG_EXECUTABLE 2)
The macro has a significant size but is very linear:
+
1. Load a potential env variable XYZ_ROOT_DIR as a default choice for the cache entry XYZ_ROOT_DIR
If empty, load a potential XYZ_ROOT_DIR_EXP as default value (path exposed by another package depending
directly on XYZ)
2. Invoke FIND_PACKAGE() in this order:
- * in CONFIG mode first (if possible): priority is given to a potential
- "XYZ-config.cmake" file
- * then switch to the standard MODULE mode, appending on CMAKE_PREFIX_PATH
- the above XYZ_ROOT_DIR variable
+
+ * in CONFIG mode first (if possible): priority is given to a potential "XYZ-config.cmake" file.
+ * then switch to the standard MODULE mode, appending on CMAKE_PREFIX_PATH the above XYZ_ROOT_DIR variable.
+
3. Extract the path actually found into a temp variable _XYZ_TMP_DIR
4. Warn if XYZ_ROOT_DIR is set and doesn't match what was found (e.g. when CMake found the system installation
instead of what is pointed to by XYZ_ROOT_DIR - happens when a typo in the content of XYZ_ROOT_DIR).
-5. Conflict detection:
- * check the temp variable against a potentially existing XYZ_ROOT_DIR_EXP
+5. Conflict detection: check the temporary variable against a potentially existing XYZ_ROOT_DIR_EXP
6. Finally expose what was _actually_ found in XYZ_ROOT_DIR.
-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.
+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.
CMake generates a build process which is per default much less verbose than the Autotools one.
One doesn't see automatically the compilation/linking commands being invoked.
-Each of the following solutions displays the full command line for each build action:
-::
+Each of the following solutions displays the full command line for each build action::
+
make VERBOSE=1
env VERBOSE=1 make
export VERBOSE=1; make
General conventions
-------------------
-* Specify the languages used in the project
- ::
+* Specify the languages used in the project::
+
PROJECT(MyProject C CXX)
+
* the version of the module is specified in one place: the root CMakeLists.txt file via standard variables
-* never, I said NEVER, specify includes or libraries by overriding COMPILE_FLAGS. CMake provide standard commands
- for this (INCLUDE_DIRECTORIES, TARGET_LINK_LIBRARIES) and produces much more portable build files!
- If a directory includes two or more targets that compulsory need different set of include dir, split into
- several subdirectories, and put the different targets in them (MEDFile has plenty of this).
-* at present there is no management in SALOME of API versioning. So there is no need to deal
- with SO_VERSION in *.so libraries (*.so.1.2.3 …)
-* No use of GLOBS for sources (*.cxx), but GLOBS can be used for includes and *.i on installation
-* no *.hxx in <SMTH>_SOURCES variable
+* never, I said *NEVER*, specify includes or libraries by overriding COMPILE_FLAGS. CMake provide standard commands for this (INCLUDE_DIRECTORIES, TARGET_LINK_LIBRARIES) and produces much more portable build files! If a directory includes two or more targets that compulsory need different set of include dir, split into several subdirectories, and put the different targets in them (MEDFile has plenty of this).
+* at present there is no management in SALOME of API versioning. So there is no need to deal with SO_VERSION in \*.so libraries (\*.so.1.2.3 …)
+* No use of GLOBS for sources (\*.cxx), but GLOBS can be used for includes and \*.i on installation
+* no \*.hxx in <SMTH>_SOURCES variable
* FIND_PACKAGE() is called only in root <Module>/CMakeLists.txt
* INCLUDE(), if needed, must be first
-* ADD_SUBDIRECTORY, if needed, must be done just after INCLUDE and FIND_PACKAGE, then
- the specific part of subdirectory can be done
+* ADD_SUBDIRECTORY, if needed, must be done just after INCLUDE and FIND_PACKAGE, then the specific part of subdirectory can be done
* INSTALL should be called at the end of the CMakelists.txt
-* Create MACRO in *.cmake to factorize some repetitive lines. (Try to) comment them.
-* All <Module>/CMakeLists.txt (see KERNEL_SRC/CMakeLists.txt) contains the definition of the variables
- which specify the location of installation directories. Only these variables should be used in subdirectories,
- and the model given in KERNEL should be followed.
-* Use builtin WIN32 variable instead of WINDOWS variable to detect a Windows platform. Potentially avoid CYGWIN also:
- ::
+* Create MACRO in \*.cmake to factorize some repetitive lines. (Try to) comment them.
+* All <Module>/CMakeLists.txt (see KERNEL_SRC/CMakeLists.txt) contains the definition of the variables which specify the location of installation directories. Only these variables should be used in subdirectories, and the model given in KERNEL should be followed.
+* Use builtin WIN32 variable instead of WINDOWS variable to detect a Windows platform. Potentially avoid CYGWIN also::
+
IF(WIN32 AND NOT CYGWIN)
...
ENDIF()
-* Use FILE(TO_CMAKE_PATH) instead of REPLACE(“\\” “/”) and FILE(TO_NATIVE_PATH) to convert a path to the
- CMake internal format
+* Use FILE(TO_CMAKE_PATH) instead of REPLACE(“\\” “/”) and FILE(TO_NATIVE_PATH) to convert a path to the CMake internal format
* Use strictly python to execute portably a script
-* Use PROJECT_BINARY_DIR and PROJECT_SOURCE_DIR instead of CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR.
- This helps having a proper behavior when the module is included as a sub-folder in the code of a bigger project.
+* Use PROJECT_BINARY_DIR and PROJECT_SOURCE_DIR instead of CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR. This helps having a proper behavior when the module is included as a sub-folder in the code of a bigger project.
Naming conventions
------------------
They are few of them but its better to be consistent:
+
* use upper case for CMake commands. For vars, the case is free. Why? As targets are generally in lower case it allows discriminating more easily CMake commands from local vars and targets.
* for sources the convention <Target>_SOURCES is used to store sources needed by target <Target>.
* for headers the convention <Target>_HEADERS is used to store headers to be installed in pair with <Target>.
-* for all the variables set by a given package, the naming convention is based on a CMake prefix:
-<Product>_myVariable
+* for all the variables set by a given package, the naming convention is based on a CMake prefix::
+
+ <Product>_myVariable
+
* temporary variables (not used outside the macro or outside the module) should start with an underscore
Parallel compilation
Command specific conventions
----------------------------
-* INCLUDE(): only specify the name of the macro, e.g. INCLUDE(SalomeMacros). The directory is almost always
- already in the CMAKE_MODULE_PATH.
+
+* INCLUDE(): only specify the name of the macro, e.g. INCLUDE(SalomeMacros). The directory is almost always already in the CMAKE_MODULE_PATH.
*