From: bruneton Date: Wed, 10 Jul 2013 12:58:02 +0000 (+0000) Subject: CMake: completing documentation X-Git-Tag: V7_4_0a1~19 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=8df27951bacb4cd2d118e8a4444d7928f5fc6e32;p=tools%2Fdocumentation.git CMake: completing documentation --- diff --git a/dev/cmake/source/config.rst b/dev/cmake/source/config.rst new file mode 100644 index 0000000..4d7388b --- /dev/null +++ b/dev/cmake/source/config.rst @@ -0,0 +1,37 @@ +Exposing a module's configuration (advanced) +============================================ + +(to be completed) + +Most important SALOME modules (KERNEL, GUI, MED) exposes their configuration +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 +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 +some of the FIND_PACKAGE mechanisms and quickly becomes a mess when compiling several versions of the same package on the +same machine (typically the case for SALOME developers). + +Only level one dependencies configuration are exported in the XXXConfig.cmake files (direct dependencies). + +The rules are a bit lengthy but very generic. The idea is to define a set of targets to be exported, and to then explicitly +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. + +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): +:: + INSTALL(TARGETS kerncompo kern_main + # IMPORTANT: Add the library kerncompo to the "export-set" so it will be available + # to dependent projects + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" + RUNTIME DESTINATION "${INSTALL_BIN_DIR}") + + diff --git a/dev/cmake/source/index.rst b/dev/cmake/source/index.rst index 478fe65..68feb61 100644 --- a/dev/cmake/source/index.rst +++ b/dev/cmake/source/index.rst @@ -12,6 +12,9 @@ Contents: :maxdepth: 2 intro.rst + pkg.rst + config.rst + various.rst Indices and tables diff --git a/dev/cmake/source/intro.rst b/dev/cmake/source/intro.rst index e4f020e..070363e 100644 --- a/dev/cmake/source/intro.rst +++ b/dev/cmake/source/intro.rst @@ -1,98 +1,72 @@ Introduction ============ +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. -This documentation is best browsed with the KERNEL sources at hand, in order to be able to +This documentation is best browsed with the SALOME KERNEL sources at hand, in order to be able to take a look at code snipets. Most references in this document points to KERNEL sources. -Motivations: CMake must be user friendly -======================================== - -Every beginner should be able to build SALOME, without any previous knowledge of SALOME. With a tool like cmake-gui, the user must obtain useful messages to find what is wrong or missing. - -* 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: - :: - make VERBOSE=1 - env VERBOSE=1 make - export VERBOSE=1; make - - To have this by default for every build, this can be specified at the configuration step by setting the - CMAKE_VERBOSE_MAKEFILE to ON. - -* 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. For detection and link, Tbb library may be needed in LD_LIBRARY_PATH in the environment of CMake. - -* Take into account several versions of the same product, in the system, or generated by the user. -For instance, system with python 2.7 and 3.2, and user python 2.6. - -* Detection of prerequisite is driven by user options. -For example MPI is detected only if option SALOME_USE_MPI is ON. -For prerequisites variables, the naming convention is based on a CMake prefix: -_myVariable -_ROOT_DIR designing the root directory of the product in environment and CMake variables. - -* Detection of first order prerequisites is based on a _ROOT_DIR variable or on what has been detected in another dependencr. 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) are not needed, except in very specific cases (Python…). - - -Package detection mechanism -=========================== +The section marked as ADVANCED need not be read by someone only trying to compile SALOME. Those +sections are intented to the core SALOME developpers, to help them understand/fix/improve +the process. -Philosophy and priority order ------------------------------ +Motivations and overview +======================== -The philosophy of the SALOME package detection is to rely as -much as possible on the standard CMake modules. -It is assumed those modules will get better and better with newer releases of CMake -and doing so ensures future compatibility with newer versions of CMake. +CMake must be user-friendly +--------------------------- -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". +Every beginner should be able to build SALOME, without any previous knowledge of SALOME. +With a tool like cmake-gui or ccmake, the user must obtain useful messages to find what is wrong or missing. -The variable guiding the detection is always builts as -:: - XYZ_ROOT_DIR - -where is the upper case name of the standard CMake module. For example, the -detection of Qt4 is guided by setting QT4_ROOT_DIR. - -Thus the priority for the detection of a package is (from high to low priority): -1. CMake variables explicitly set by the user on the command line -2. Environment variables set by the user (typically XYZ_ROOT_DIR, with WYZ the package to be detected) -3. Default value based on a previous dependency using the tool already -4. Detection in the host system - -Writing the detection macro of a new prerequisite -------------------------------------------------- - -All prerequisite detection in SALOME should be implemented by: -* writing a file FindSalome.cmake, where matches *exactly* the - - - - -Implementation details ----------------------- +The general philosophy is thus to allow a developper to build SALOME with a minimal effort, setting only the +minimal 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 +* 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. -This detection is guided using the XYZ_ROOT_DIR. Those variables -overr +Overview of the logic (advanced) +-------------------------------- -If the standard FindXYZ.cmake macro exists (and works fine!) -it should be used as much as possible to ensure future -compatibility with newer versions of CMake. -The assumption is that those will become better and better -and we should automatically benefit from the enhancements. +Here are the general principles guiding the implementation: -All packages +* 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. +* 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. + For example MPI is detected only if option SALOME_USE_MPI is ON. +* Detection of first order prerequisites is based on a _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. diff --git a/dev/cmake/source/pkg.rst b/dev/cmake/source/pkg.rst new file mode 100644 index 0000000..673626d --- /dev/null +++ b/dev/cmake/source/pkg.rst @@ -0,0 +1,163 @@ +Package detection mechanism +=========================== + +Philosophy and priority order +----------------------------- + +The philosophy of the SALOME package detection is to rely as +much as possible on the standard CMake modules. +It is assumed those modules will get better and better with newer releases of CMake +and doing so ensures future compatibility with newer versions of CMake. + +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". + +The variable guiding the detection is always builts as +:: + XYZ_ROOT_DIR + +where 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 +4. Detection direclty in the host system by the standard CMake logic + +The package detection is only made in the root CMakeLists.txt, potentially conditionned on some +user options. Package names are case-sensitive, but the corresponding variables are always upper-case. + +Writing the detection macro of a new SALOME prerequisite +-------------------------------------------------------- + +All detection macros are located under the soure directory +:: + salome_adm/cmake_files + +or +:: + adm_local/cmake_files + +All prerequisite detection in SALOME should be implemented by: +* writing a file FindSalome.cmake (note the extra ''Salome''), where matches *exactly* the + name of the standard CMake module (see below if there is no standard module for ) +* 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) +* 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. + +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). + +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: + 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). +* 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: + :: + # - Sphinx detection + # + # Output variable: SPHINX_EXECUTABLE + # + # + # The executable 'sphinx-build' is looked for and returned in the above variable. + # + + ########################################################################### + # Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE + <...> + ########################################################################### + + FIND_PROGRAM(SPHINX_EXECUTABLE sphinx-build) + + # Handle the standard arguments of the find_package() command: + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Sphinx REQUIRED_VARS SPHINX_EXECUTABLE) + + +Implementation details (advanced) +--------------------------------- + +The core of the SALOME detection logic is located in the macro +SALOME_FIND_PACKAGE_AND_DETECT_CONFLICTS() implemented in KERNEL/salome_adm/cmake_files/SalomeMacros.cmake. + +The reader is invited to read the have the code at hand when reading the following. + +The macro signature is +:: + SALOME_FIND_PACKAGE_DETECT_CONFLICTS(pkg referenceVariable upCount ...) + +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 +to obtain the package root directory. +* : 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 +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 +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. + + + diff --git a/dev/cmake/source/various.rst b/dev/cmake/source/various.rst new file mode 100644 index 0000000..dae22e0 --- /dev/null +++ b/dev/cmake/source/various.rst @@ -0,0 +1,74 @@ +Various guidelines and conventions (advanced) +============================================= + +Debugging CMake +--------------- + +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: +:: + make VERBOSE=1 + env VERBOSE=1 make + export VERBOSE=1; make + +To have this by default for every build, one can specify this setting at the configuration +step by toggling the CMAKE_VERBOSE_MAKEFILE to ON. + +General conventions +------------------- +* 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 _SOURCES variable +* FIND_PACKAGE() is called only in root /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 +* 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 /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 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. + +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 _SOURCES is used to store sources needed by target . +* for headers the convention _HEADERS is used to store headers to be installed in pair with . +* for all the variables set by a given package, the naming convention is based on a CMake prefix: +_myVariable +* temporary variables (not used outside the macro or outside the module) should start with an underscore + +Parallel compilation +-------------------- +Contrary to Autotools, CMake is working by targets and not by directories. If parallel compilation fails, it means that some dependencies are missing. The linked libraries of the target are automatically considered as dependency by CMake. But, for instance, when a library needs only generated includes from Kernel idl (no link needed with the generated code for a CORBA client), the dependency should be explicitly added by the ADD_DEPENDENCIES( SalomeIDLKernel) command in the CMakeLists.txt. +To check parallel compilation (i.e. dependencies) of a target, the developer must start from an empty, generated by CMake build directory and use the “make (-jX) ”. + +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. +* + +