Customizing search paths for find modules

Hello,

  1. What is the recommended CMake way to customize paths, where some external library should be searched (for example, when developing and having a custom, local installation somewhere)?

    For example, when using module such as FindPostgreSQL:

    # Using CMAKE_PREFIX_PATH variable?
    cmake -S <source-dir> -B <build-dir> -DCMAKE_PREFIX_PATH=/path/to/postgresql-installation
    
    # Or using the PostgreSQL_ROOT variable?
    cmake -S <source-dir> -B <build-dir> -DPostgreSQL_ROOT=/path/to/postgresql-installation
    
    # Or using the POSTGRESQL_ROOT variable?
    cmake -S <source-dir> -B <build-dir> -DPOSTGRESQL_ROOT=/path/to/postgresql-installation
    
  2. What about FindIntl and FindIconv? These two libraries can be either built in to
    C library, while they can be also part of an external library, such as GNU libiconv.

    Is this considered the intended search way by also setting the Iconv_IS_BUILT_IN variable?

    cmake -S <source-dir> -B <build-dir> -DCMAKE_PREFIX_PATH=/path/to/libiconv -DIconv_IS_BUILT_IN=FALSE
    

    Or should FindIntl and FindIconv modules be adjusted further in CMake to have possibility to only specify variables such as CMAKE_PREFIX_PATH, Iconv_ROOT, or ICONV_ROOT?

diff --git a/Modules/FindIconv.cmake b/Modules/FindIconv.cmake
index d49c2dbaaf..af60bda29e 100644
--- a/Modules/FindIconv.cmake
+++ b/Modules/FindIconv.cmake
@@ -104,6 +104,50 @@ else()
   set(Iconv_IS_BUILT_IN FALSE)
 endif()

+# Disable searching for built-in iconv when overriding search paths.
+if(
+  NOT DEFINED Iconv_IS_BUILT_IN
+  AND NOT DEFINED Iconv_INCLUDE_DIR
+  AND NOT DEFINED Iconv_LIBRARY
+  AND (
+    CMAKE_PREFIX_PATH
+    OR Iconv_ROOT
+    OR ICONV_ROOT
+    OR DEFINED ENV{Iconv_ROOT}
+    OR DEFINED ENV{ICONV_ROOT}
+  )
+)
+  find_path(
+    Iconv_INCLUDE_DIR
+    NAMES iconv.h
+    PATH_SUFFIXES
+      gnu-libiconv # GNU libiconv on Alpine Linux has header in a subdirectory.
+    DOC "iconv include directory"
+    NO_CMAKE_ENVIRONMENT_PATH
+    NO_SYSTEM_ENVIRONMENT_PATH
+    NO_CMAKE_INSTALL_PREFIX
+    NO_CMAKE_SYSTEM_PATH
+  )
+
+  find_library(
+    Iconv_LIBRARY
+    NAMES iconv libiconv
+    NAMES_PER_DIR
+    DOC "iconv library (if not in the C library)"
+    NO_CMAKE_ENVIRONMENT_PATH
+    NO_SYSTEM_ENVIRONMENT_PATH
+    NO_CMAKE_INSTALL_PREFIX
+    NO_CMAKE_SYSTEM_PATH
+  )
+
+  if(Iconv_INCLUDE_DIR AND Iconv_LIBRARY)
+    set(Iconv_IS_BUILT_IN FALSE)
+  else()
+    unset(Iconv_INCLUDE_DIR CACHE)
+    unset(Iconv_LIBRARY CACHE)
+  endif()
+endif()
+
 # iconv can only be provided in libc on a POSIX system.
 # If any cache variable is already set, we'll skip this test.
 if(NOT DEFINED Iconv_IS_BUILT_IN)

Reason, why I’m asking about built-in libraries specifics is that only setting something like Iconv_ROOT variable, will always find the built-in iconv first and not the wanted libiconv custom installation path.

The details are spelled out in the documentation for the find_package command. If you’re using a find module and not the CONFIG version of find_package then you need to consult the documentation for the individual find modules, e.g. cmake --help-module findintl). In very rare cases where the documentation is vague, you may need to consult the implementation of the find module itself to see how it locates the package. (The standard find modules are just a CMake script distributed with CMake.)

I’m not familiar with these specific libraries, but the general advice above still applies. If you need to differentiate between those features being included in the C library runtime provided by your compiler, then you should use a compile test to learn that.

1 Like

Thanks so much for taking time and helping out. I see. I’ll open also an issue for this and suggest clarifying this in the find modules documentation. Because, this I believe is crucial part from the user perspective (user who doesn’t develop application or its CMake-based build system and needs to know how to build some app). Having 3 ways to select some path for some library is confusing (specially these <PackageNam>_ROOT and <PACKAGENAME>_ROOT variables).