]> https://gitweb.dealii.org/ - dealii.git/commitdiff
CMake: Finalize overhaul:
authorMatthias Maier <tamiko@kyomu.43-1.org>
Thu, 15 May 2014 22:17:20 +0000 (22:17 +0000)
committerMatthias Maier <tamiko@kyomu.43-1.org>
Thu, 15 May 2014 22:17:20 +0000 (22:17 +0000)
  * Switch Boost as well.

  * Refactor configure/configure_* stuff

  * Update documentation

git-svn-id: https://svn.dealii.org/trunk@32915 0785d39b-7218-0410-832d-ea1e28bc413d

15 files changed:
deal.II/cmake/configure/configure_1_mpi.cmake
deal.II/cmake/configure/configure_1_threads.cmake
deal.II/cmake/configure/configure_2_metis.cmake
deal.II/cmake/configure/configure_2_umfpack.cmake
deal.II/cmake/configure/configure_3_petsc.cmake
deal.II/cmake/configure/configure_arpack.cmake
deal.II/cmake/configure/configure_boost.cmake
deal.II/cmake/configure/configure_hdf5.cmake
deal.II/cmake/configure/configure_mumps.cmake
deal.II/cmake/configure/configure_muparser.cmake
deal.II/cmake/configure/configure_p4est.cmake
deal.II/cmake/configure/configure_slepc.cmake
deal.II/cmake/macros/macro_configure_feature.cmake
deal.II/cmake/modules/FindBOOST.cmake [new file with mode: 0644]
deal.II/doc/developers/cmake-internals.html

index 8001da43184bfba6a839e0d81923a64367c2a375..7c0bda441df19d60a87221dba8641f7301610af1 100644 (file)
@@ -34,4 +34,5 @@ MACRO(FEATURE_MPI_ERROR_MESSAGE)
     )
 ENDMACRO()
 
+
 CONFIGURE_FEATURE(MPI)
index 4a697a835885b532403cfeedf078b0fc263db66c..f07f29725d8aa4363fea328d759795aec48c00fd 100644 (file)
 ##
 ## ---------------------------------------------------------------------
 
-
 #
 # Configuration for thread support in deal.II with the help of the tbb
 # library:
 #
 
-
 #
 # Set up general threading:
 # The macro will be included in CONFIGURE_FEATURE_THREADS_EXTERNAL/BUNDLED.
index 72a142286d6a1e4c84c78a2d299c7f38d611872c..4d499c0d6088064e99511a187073137fe3165e46 100644 (file)
 ##
 ## ---------------------------------------------------------------------
 
-IF(NOT FEATURE_MPI_PROCESSED)
-  MESSAGE(FATAL_ERROR "\n"
-    "Internal build system error:\n"
-    "configure_2_metis.cmake included before configure_1_mpi.cmake\n\n"
-    )
-ENDIF()
+SET(FEATURE_METIS_AFTER MPI)
 
 #
 # Configuration for the metis library:
index f1d0d7451351799f7f7cbc0f28939af4730349b4..5f0760ef3cbfefa445c45a9f9848e7d5e7aec65c 100644 (file)
@@ -18,7 +18,7 @@
 # Configuration for the umfpack library:
 #
 
-SET(FEATURE_UMFPACK_DEPENDS DEAL_II_WITH_LAPACK)
+SET(FEATURE_UMFPACK_DEPENDS LAPACK)
 
 MACRO(FEATURE_UMFPACK_CONFIGURE_BUNDLED)
   SET(UMFPACK_BUNDLED_INCLUDE_DIRS
index ee95cd5a4a1a3e20d204c9b1dd3013050c2108ff..662c30f8a348b6ebbcd1dff457fb09a25a0fac53 100644 (file)
 # Configuration for the petsc library:
 #
 
+SET(FEATURE_PETSC_AFTER MPI)
 
-MACRO(FEATURE_PETSC_FIND_EXTERNAL var)
 
+MACRO(FEATURE_PETSC_FIND_EXTERNAL var)
   FIND_PACKAGE(PETSC)
 
   IF(PETSC_FOUND)
@@ -67,7 +68,6 @@ MACRO(FEATURE_PETSC_FIND_EXTERNAL var)
       SET(${var} FALSE)
     ENDIF()
 
-
     #
     # Petsc has to be configured with the same number of bits for indices as
     # deal.II.
index bf2f5f4acac233fe5c5f2cb84f5d20dabe53bc17..f631bec3bdff2280321508e48a10bcceda9318a0 100644 (file)
@@ -18,6 +18,6 @@
 # Configuration for the ARPACK library:
 #
 
-SET(FEATURE_ARPACK_DEPENDS DEAL_II_WITH_LAPACK)
+SET(FEATURE_ARPACK_DEPENDS LAPACK)
 
 CONFIGURE_FEATURE(ARPACK)
index ec72b800a282ef096e56e0c65873c59386712718..4ae786788b1fad84d737fb9c2a950ba3432eedee 100644 (file)
 # Configuration for the boost library:
 #
 
-#
-# This configure script has to be included after configure_threads.
-# We need some of the variables defined in SETUP_THREADING for
-# the setup of the bundled boost library (if used)
-#
-IF(NOT FEATURE_THREADS_PROCESSED)
-  MESSAGE(FATAL_ERROR "\n"
-    "Internal build system error:\n"
-    "configure_boost.cmake included before configure_1_threads.cmake\n\n"
-    )
-ENDIF()
-
-
 SET(DEAL_II_WITH_BOOST ON # Always true. We need it :-]
   CACHE BOOL "Build deal.II with support for boost." FORCE
   )
 
 
-MACRO(FEATURE_BOOST_FIND_EXTERNAL var)
-
-  #
-  # This mumbo jumbo is necessary because CMake won't let us test against
-  # BOOST_DIR directly. WTF?!
-  #
-  IF(NOT DEFINED BOOST_DIR)
-    SET(BOOST_DIR "$ENV{BOOST_DIR}")
-  ELSE()
-    SET_IF_EMPTY(BOOST_DIR "$ENV{BOOST_DIR}")
-  ENDIF()
-
-  IF(NOT "${BOOST_DIR}" STREQUAL "")
-    SET(BOOST_ROOT "${BOOST_DIR}")
-  ENDIF()
-
-  IF(DEAL_II_WITH_THREADS)
-    SET(_boost_components iostreams serialization system thread)
-  ELSE()
-    SET(_boost_components iostreams serialization system)
-  ENDIF()
-
-  #
-  # Prefer static libs if BUILD_SHARED_LIBS=OFF:
-  #
-  IF(NOT BUILD_SHARED_LIBS)
-    SET(Boost_USE_STATIC_LIBS TRUE)
-  ENDIF()
-
-  FIND_PACKAGE(Boost 1.44 COMPONENTS ${_boost_components})
-
-  #
-  # Fall back to dynamic libraries if no static libraries could be found:
-  #
-  IF(NOT Boost_FOUND AND Boost_USE_STATIC_LIBS)
-    SET(Boost_USE_STATIC_LIBS FALSE)
-    FIND_PACKAGE(Boost 1.44 COMPONENTS ${_boost_components})
-  ENDIF()
-
-  MARK_AS_ADVANCED(Boost_DIR)
-
-  IF(Boost_FOUND)
-    SET(BOOST_VERSION_MAJOR "${Boost_MAJOR_VERSION}")
-    SET(BOOST_VERSION_MINOR "${Boost_MINOR_VERSION}")
-    SET(BOOST_VERSION_SUBMINOR "${Boost_SUBMINOR_VERSION}")
-    SET(BOOST_VERSION
-      "${BOOST_VERSION_MAJOR}.${BOOST_VERSION_MINOR}.${BOOST_VERSION_SUBMINOR}"
-      )
-
-    #
-    # Remove "pthread" from Boost_LIBRARIES. Threading, if necessary, is
-    # already set up via configure_1_threads.cmake.
-    #
-    LIST(REMOVE_ITEM Boost_LIBRARIES "pthread")
-
-    SET(BOOST_INCLUDE_DIRS ${Boost_INCLUDE_DIRS})
-    SET(BOOST_LIBRARIES ${Boost_LIBRARIES})
-
-    MARK_AS_ADVANCED(BOOST_DIR)
-
-    SET(${var} TRUE)
-
-  ELSE()
-
-    SET(BOOST_DIR "" CACHE PATH "An optional hint to a boost directory")
-  ENDIF()
-ENDMACRO()
-
-
 MACRO(FEATURE_BOOST_CONFIGURE_BUNDLED)
   SET(BOOST_BUNDLED_INCLUDE_DIRS ${BOOST_FOLDER}/include)
 ENDMACRO()
@@ -112,10 +30,6 @@ ENDMACRO()
 
 CONFIGURE_FEATURE(BOOST)
 
-#
-# The user has to know the location of the boost headers as well:
-#
-SET(BOOST_USER_INCLUDE_DIRS ${BOOST_INCLUDE_DIRS})
 
 #
 # DEAL_II_WITH_BOOST is always required.
index abc66f4c04ad2053984e7c98ea8d496b17bbf8de..6a335a232c20aaa0304d02fbf4f87c00f817955f 100644 (file)
 ##
 ## ---------------------------------------------------------------------
 
-IF(NOT FEATURE_MPI_PROCESSED)
-  MESSAGE(FATAL_ERROR "\n"
-    "Internal build system error:\n"
-    "configure_hdf5.cmake included before configure_1_mpi.cmake\n\n"
-    )
-ENDIF()
-
 #
 # Configuration for the hdf5 library:
 #
 
+SET(FEATURE_HDF5_AFTER MPI)
+
+
 MACRO(FEATURE_HDF5_FIND_EXTERNAL var)
   FIND_PACKAGE(HDF5)
 
@@ -49,4 +45,5 @@ MACRO(FEATURE_HDF5_FIND_EXTERNAL var)
   ENDIF()
 ENDMACRO()
 
+
 CONFIGURE_FEATURE(HDF5)
index cfe08a2cdd6ab1f380dbed6b03a466636f89f2a9..ce1d2652b10b4a50073bda70e578a6c716b66136 100644 (file)
@@ -18,7 +18,7 @@
 # Configuration for the MUMPS library:
 #
 
-SET(FEATURE_MUMPS_DEPENDS DEAL_II_WITH_MPI DEAL_II_WITH_LAPACK)
+SET(FEATURE_MUMPS_DEPENDS MPI LAPACK)
 
 
 MACRO(FEATURE_MUMPS_FIND_EXTERNAL var)
index 29aab1f087378434c976fcbeba734b1c0aefd2cf..badb1c5b689de9ca854186b241ad924c705288c0 100644 (file)
@@ -22,4 +22,5 @@ MACRO(FEATURE_MUPARSER_CONFIGURE_BUNDLED)
   SET(MUPARSER_BUNDLED_INCLUDE_DIRS ${MUPARSER_FOLDER}/include)
 ENDMACRO()
 
+
 CONFIGURE_FEATURE(MUPARSER)
index 313b8359ef4d4ec5e5a5af062054b64ee5f481b2..25acd30d862478b6cf1b3f01d4eb761aee7bf7e9 100644 (file)
@@ -18,7 +18,8 @@
 # Configuration for the p4est and sc libraries:
 #
 
-SET(FEATURE_P4EST_DEPENDS DEAL_II_WITH_MPI)
+SET(FEATURE_P4EST_DEPENDS MPI)
+
 
 MACRO(FEATURE_P4EST_FIND_EXTERNAL var)
   FIND_PACKAGE(P4EST)
index 1f98ed4ecb8ad855335d52a8d5cf595ccbe96f36..c300f7ea7bfd6fc3269e1038154c6ca218f06b8e 100644 (file)
@@ -18,7 +18,8 @@
 # Configuration for the SLEPC library:
 #
 
-SET(FEATURE_SLEPC_DEPENDS DEAL_II_WITH_PETSC)
+SET(FEATURE_SLEPC_DEPENDS PETSC)
+
 
 MACRO(FEATURE_SLEPC_FIND_EXTERNAL var)
   FIND_PACKAGE(SLEPC)
index b42569ac1f946fe369e163f376573340a96f2885..2c1277d6ae439d7846b0b56e9f31e97c4af3a28f 100644 (file)
 # FEATURE_${feature}_DEPENDS    (a variable)
 #    a variable which contains an optional list of other features
 #    this feature depends on (and which have to be enbled for this feature
-#    to work.) The features must be given with the full option toggle:
-#    DEAL_II_WITH_[...]
+#    to work.)
+#    Features must be given with short name, i.e. without DEAL_II_WITH_
+#
+# FEATURE_${feature}_after      (a variable)
+#    a variable which contains an optional list of other features
+#    that have to be configured prior to this feature
+#    Features must be given with short name, i.e. without DEAL_II_WITH_
 #
 # FEATURE_${feature}_HAVE_BUNDLED   (a variable)
 #    which should either be set to TRUE if all necessary libraries of the
@@ -150,14 +155,18 @@ MACRO(CONFIGURE_FEATURE _feature)
 
   #
   # Check for correct include order of the configure_*.cmake files:
-  # If feature B depends on feature A, configure_A.cmake has to be
-  # included before configure_B.cmake:
+  # If feature B explicitly states to come after feature A, or if feature B
+  # depends on feature A, configure_A.cmake has to be included before
+  # configure_B.cmake:
   #
-  FOREACH(_dependency ${FEATURE_${_feature}_DEPENDS})
-    STRING(REGEX REPLACE "^DEAL_II_WITH_" "" _dependency ${_dependency})
+  FOREACH(_dependency
+      ${FEATURE_${_feature}_AFTER}
+      ${FEATURE_${_feature}_DEPENDS}
+      )
     IF(NOT FEATURE_${_dependency}_PROCESSED)
       MESSAGE(FATAL_ERROR "\n"
-        "Internal build system error: DEAL_II_WITH_${_feature} depends on "
+        "Internal build system error: The configuration of "
+        "DEAL_II_WITH_${_feature} depends on "
         "DEAL_II_WITH_${_dependency}, but CONFIGURE_FEATURE(${_feature}) "
         "was called before CONFIGURE_FEATURE(${_dependency}).\n\n"
         )
@@ -185,7 +194,7 @@ MACRO(CONFIGURE_FEATURE _feature)
     #
     SET(_dependencies_ok TRUE)
     FOREACH(_dependency ${FEATURE_${_feature}_DEPENDS})
-      IF(NOT ${_dependency})
+      IF(NOT DEAL_II_WITH_${_dependency})
         IF(DEAL_II_WITH_${_feature})
           MESSAGE(FATAL_ERROR "\n"
             "DEAL_II_WITH_${_feature} has unmet configuration requirements: "
diff --git a/deal.II/cmake/modules/FindBOOST.cmake b/deal.II/cmake/modules/FindBOOST.cmake
new file mode 100644 (file)
index 0000000..b14b063
--- /dev/null
@@ -0,0 +1,82 @@
+## ---------------------------------------------------------------------
+## $Id$
+##
+## Copyright (C) 2014 by the deal.II authors
+##
+## This file is part of the deal.II library.
+##
+## The deal.II library is free software; you can use it, redistribute
+## it, and/or modify it under the terms of the GNU Lesser General
+## Public License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+## The full text of the license can be found in the file LICENSE at
+## the top level of the deal.II distribution.
+##
+## ---------------------------------------------------------------------
+
+#
+# Try to find the boost libraries
+#
+# This module exports:
+#
+#     BOOST_FOUND
+#     BOOST_LIBRARIES
+#     BOOST_INCLUDE_DIRS
+#     BOOST_VERSION
+#     BOOST_VERSION_MAJOR
+#     BOOST_VERSION_MINOR
+#     BOOST_VERSION_SUBMINOR
+#
+
+SET(BOOST_DIR "" CACHE PATH "An optional hint to a BOOST installation")
+SET_IF_EMPTY(BOOST_DIR "$ENV{BOOST_DIR}")
+
+IF(NOT "${BOOST_DIR}" STREQUAL "")
+  SET(BOOST_ROOT "${BOOST_DIR}")
+ENDIF()
+
+#
+# Prefer static libs if BUILD_SHARED_LIBS=OFF:
+#
+IF(NOT BUILD_SHARED_LIBS)
+  SET(Boost_USE_STATIC_LIBS TRUE)
+ENDIF()
+
+FIND_PACKAGE(Boost 1.44 COMPONENTS iostreams serialization system thread)
+
+#
+# Fall back to dynamic libraries if no static libraries could be found:
+#
+IF(NOT Boost_FOUND AND Boost_USE_STATIC_LIBS)
+  SET(Boost_USE_STATIC_LIBS FALSE)
+  FIND_PACKAGE(Boost 1.44 COMPONENTS iostreams serialization system thread)
+ENDIF()
+
+IF(Boost_FOUND)
+  #
+  # Remove "pthread" from Boost_LIBRARIES. Threading, if necessary, is
+  # already set up via configure_1_threads.cmake.
+  #
+  LIST(REMOVE_ITEM Boost_LIBRARIES "pthread")
+
+  SET(BOOST_VERSION_MAJOR "${Boost_MAJOR_VERSION}")
+  SET(BOOST_VERSION_MINOR "${Boost_MINOR_VERSION}")
+  SET(BOOST_VERSION_SUBMINOR "${Boost_SUBMINOR_VERSION}")
+  SET(BOOST_VERSION
+    "${BOOST_VERSION_MAJOR}.${BOOST_VERSION_MINOR}.${BOOST_VERSION_SUBMINOR}"
+    )
+ENDIF()
+
+DEAL_II_PACKAGE_HANDLE(BOOST
+  LIBRARIES REQUIRED Boost_LIBRARIES
+  INCLUDE_DIRS REQUIRED Boost_INCLUDE_DIRS
+  USER_INCLUDE_DIRS Boost_INCLUDE_DIRS
+  CLEAR
+    Boost_INCLUDE_DIR Boost_IOSTREAMS_LIBRARY_DEBUG
+    Boost_IOSTREAMS_LIBRARY_RELEASE Boost_LIBRARY_DIR
+    Boost_SERIALIZATION_LIBRARY_DEBUG Boost_SERIALIZATION_LIBRARY_RELEASE
+    Boost_SYSTEM_LIBRARY_DEBUG Boost_SYSTEM_LIBRARY_RELEASE
+    Boost_THREAD_LIBRARY_DEBUG Boost_THREAD_LIBRARY_RELEASE
+    _Boost_COMPONENTS_SEARCHED _Boost_INCLUDE_DIR_LAST
+    _Boost_LIBRARY_DIR_LAST _Boost_USE_MULTITHREADED_LAST
+  )
index 391a11b52414e38a50078e236c9076a3bbee4945..dad7505cfb3a4f6e6e08c098ee77d32b44513af7 100644 (file)
@@ -331,60 +331,72 @@ RESET_CMAKE_REQUIRED()
       library (no deal.II specific dependency checking, no
       compatibility checking).
     <li>
-      It should do so by appropriate <code>FIND_LIBRARY</code> and
-      <code>FIND_PATH</code> calls. The results of this calls should be the
-      only cached variables.
-    <li>
-      <code>FIND_PACKAGE_HANDLE_STANDARD_ARGS</code> should be used for
-      setting <code>FEATURE_FOUND</code> as this already respects the
-      <code>QUIET</code> and <code>REQUIRED</code> keywords.
+      It should do so by appropriate <code>DEAL_II_FIND_LIBRARY</code>,
+      <code>DEAL_II_FIND_PATH</code> and <code>DEAL_II_FIND_FILE</code>
+      calls (same syntax as the native CMake functions; just a small
+      wrapper to provide some useful output). The results of this calls
+      should be the only cached variables.
     <li>
       A <code>WARNING</code>, <code>SEND_ERROR</code> or
       <code>FATAL_ERROR</code> must be avoided (the only exception is
       the <code>REQUIRED</code> keyword).
     <li>
-      If the feature is successfully found, a subset of the following
-      <b>uncached</b> variables might be set:
-<pre>
+      The following uncached variables are recognized by the feature
+      configuration mechanism:
+<pre class="cmake">
 FEATURE_FOUND
 FEATURE_LIBRARIES (with optimized, debug, release keywords)
 FEATURE_LIBRARIES(_DEBUG|_RELEASE)
-FEATURE_INCLUDE_DIRS
+FEATURE_INCLUDE_DIRS FEATURE_USER_INCLUDE_DIRS
 FEATURE_LINKER_FLAGS(|_DEBUG|_RELEASE)
 FEATURE_CXX_FLAGS(|_DEBUG|_RELEASE)
 FEATURE_DEFINITIONS(|_DEBUG|_RELEASE)
-
 FEATURE_VERSION
 FEATURE_VERSION(_MAJOR|_MINOR|_SUBMINOR)
 </pre>
-
-There are obviously valid exceptions from this rule, though.
+      The <code>DEAL_II_PACKAGE_HANDLE</code> macro should be exclusively
+      used for setting up these variables (except the version variants). An
+      example invocation is
+<pre class="cmake">
+DEAL_II_PACKAGE_HANDLE(UMFPACK
+  LIBRARIES
+    REQUIRED UMFPACK_LIBRARY
+    OPTIONAL CHOLMOD_LIBRARY CCOLAMD_LIBRARY COLAMD_LIBRARY CAMD_LIBRARY ${_suitesparse_config}
+    REQUIRED AMD_LIBRARY
+    OPTIONAL METIS_LIBRARIES LAPACK_LIBRARIES rt_LIBRARY
+  INCLUDE_DIRS
+    REQUIRED UMFPACK_INCLUDE_DIR AMD_INCLUDE_DIR
+    OPTIONAL SuiteSparse_config_INCLUDE_DIR
+  LINKER_FLAGS
+    OPTIONAL LAPACK_LINKER_FLAGS
+  CLEAR
+    UMFPACK_LIBRARY CHOLMOD_LIBRARY CCOLAMD_LIBRARY COLAMD_LIBRARY
+    CAMD_LIBRARY SuiteSparse_config_LIBRARY AMD_LIBRARY UMFPACK_INCLUDE_DIR
+    AMD_INCLUDE_DIR SuiteSparse_config_INCLUDE_DIR
+  )
+</pre>
+      The macro concatenates all specified variables into the final
+      <code>FEATURE_SUFFIX</code> variable. Hereby, a feature is
+      successfully found if all <code>REQUIRED</code> variables are
+      non-empty an not set to <code>"-NOTFOUND"</code>.
+      <code>OPTIONAL</code> variables are just filtered out in this case.
+      As a last set of parameters the full list of cached search result
+      variables must be specified after the <code>CLEAR</code> keyword -
+      this is used to provide a possibility to undo a feature search.
     <li>
       Only "local" variables "<code>_&lt;all lowercase&gt;</code>" or
       "global" variables prefixed by <code>FEATURE_</code> may be
       altered. Do not set <code>DEAL_II_*</code> or <code>CMAKE_*</code>
       variables directly!
-
-    <li>
-      The find module must define a macro <code>FEATURE_CLEAR</code> that
-      unsets all cached variables, so that a subsequent call to the find
-      module starts a completely fresh features search.
     <li>
       A hint with <code>FEATURE_DIR</code> can be set up for
       convenience. It is best to start the <code>Find</code> module by
-
 <pre class="cmake">
+SET(FEATURE_DIR "" CACHE PATH "short description")
 SET_IF_EMPTY(FEATURE_DIR "$ENV{FEATURE_DIR}")
 </pre>
-
-and use <code>FEATURE_DIR</code> as a hint. If the external
-library could be found, hide it via
-<code>MARK_AS_ADVANCED</code>, if the external library could not
-be found, set a cache value:
-<pre class="cmake">
-SET(FEATURE_DIR "" CACHE PATH "An optional hint to a FEATURE directory")
-</pre>
-  </ul>
+      and use <code>FEATURE_DIR</code> as a hint.
+</ul>
 
 
 <a name="configure"></a>
@@ -435,9 +447,14 @@ FEATURE_DEFINITIONS(|_DEBUG|_RELEASE)
 <pre>
 FEATURE_&lt;FEATURE&gt;_DEPENDS              (a variable)
   - a variable which contains an optional list of other features
-    this feature depends on (and which have to be enabled for this feature
-    to work.) The features must be given with the full option toggle:
-    DEAL_II_WITH_[...]
+    this feature depends on (and which have to be enbled for this feature
+    to work.)
+    Features must be given with short name, i.e. without DEAL_II_WITH_
+
+FEATURE_&lt;FEATURE&gt;_AFTER                (a variable)
+  - a variable which contains an optional list of other features
+    that have to be configured prior to this feature
+    Features must be given with short name, i.e. without DEAL_II_WITH_
 
 FEATURE_&lt;FEATURE&gt;_FIND_EXTERNAL(var)   (a macro)
   - which should set var to TRUE if all dependencies for the feature are

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.