浏览代码

FindASPELL: Add components and imported targets

Components are added in a backward-compatible way:

* ASPELL component - adds the ASPELL::ASPELL imported target
* Executable component - adds the ASPELL::Executable imported target

If components are not specified in find_package() call, module, by
default, searches for both components and provides backward
compatibility with the find_package(ASPELL) usage via ASPELL_LIBRARIES,
ASPELL_INCLUDE_DIR, and ASPELL_EXECUTABLE variables.

The ASPELL_DEFINITIONS variable description removed from the
documentation as it was never defined by this module.

Additionally added a Pspell interface check (pspell.h header file) if
Aspell library provides it. It is checked separately because it might
be located in a subdirectory of pspell/pspell.h and code includes it as
`<pspell.h>`. Some distributions package pspell.h as part of the
libpspell development package and install also libaspell development
package as a dependency for BC.

Added also ASPELL_VERSION variable in case aspell executable can
determine it.

Issue: #26811
Peter Kokot 8 月之前
父节点
当前提交
dd2edc3497

+ 1 - 0
.gitlab/ci/configure_debian12_aarch64_ninja.cmake

@@ -16,6 +16,7 @@ set(CMake_TEST_CTestUpdate_GIT "ON" CACHE BOOL "")
 set(CMake_TEST_CTestUpdate_HG "ON" CACHE BOOL "")
 set(CMake_TEST_CTestUpdate_SVN "ON" CACHE BOOL "")
 set(CMake_TEST_FindALSA "ON" CACHE BOOL "")
+set(CMake_TEST_FindASPELL "ON" CACHE BOOL "")
 set(CMake_TEST_FindBLAS "${blas_lapack_cases}" CACHE STRING "")
 set(CMake_TEST_FindBoost "ON" CACHE BOOL "")
 set(CMake_TEST_FindBoost_Python "ON" CACHE BOOL "")

+ 1 - 0
.gitlab/ci/configure_debian12_ninja_common.cmake

@@ -11,6 +11,7 @@ if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
 endif()
 
 set(CMake_TEST_FindALSA "ON" CACHE BOOL "")
+set(CMake_TEST_FindASPELL "ON" CACHE BOOL "")
 set(CMake_TEST_FindBacktrace "ON" CACHE BOOL "")
 set(CMake_TEST_FindBLAS "All;static=1;Generic" CACHE STRING "")
 set(CMake_TEST_FindBoost "ON" CACHE BOOL "")

+ 1 - 0
.gitlab/ci/configure_fedora41_makefiles.cmake

@@ -11,6 +11,7 @@ endif()
 
 set(CMake_TEST_ASM_NASM "ON" CACHE BOOL "")
 set(CMake_TEST_FindALSA "ON" CACHE BOOL "")
+set(CMake_TEST_FindASPELL "ON" CACHE BOOL "")
 set(CMake_TEST_FindBacktrace "ON" CACHE BOOL "")
 set(CMake_TEST_FindBLAS "All;static=1;Generic" CACHE STRING "")
 set(CMake_TEST_FindBoost "ON" CACHE BOOL "")

+ 6 - 0
Help/release/dev/FindASPELL-imported-targets.rst

@@ -0,0 +1,6 @@
+FindASPELL
+----------
+
+* The :module:`FindASPELL` module now provides version variable, imported
+  targets, and components to optionally select Aspell library and executable
+  separately.

+ 285 - 15
Modules/FindASPELL.cmake

@@ -5,28 +5,298 @@
 FindASPELL
 ----------
 
-Try to find ASPELL
+Finds the GNU Aspell spell checker library.
 
-Once done this will define
+Components
+^^^^^^^^^^
 
-::
+This module supports the following components:
 
-  ASPELL_FOUND - system has ASPELL
-  ASPELL_EXECUTABLE - the ASPELL executable
-  ASPELL_INCLUDE_DIR - the ASPELL include directory
-  ASPELL_LIBRARIES - The libraries needed to use ASPELL
-  ASPELL_DEFINITIONS - Compiler switches required for using ASPELL
+``ASPELL``
+  .. versionadded:: 4.1
+
+  Finds the Aspell library and its include paths.
+
+``Executable``
+  .. versionadded:: 4.1
+
+  Finds the Aspell command-line interactive spell checker executable.
+
+Components can be specified using the standard CMake syntax:
+
+.. code-block:: cmake
+
+  find_package(ASPELL [COMPONENTS <components>...])
+
+If no ``COMPONENTS`` are specified, the module searches for both the ``ASPELL``
+and ``Executable`` components by default.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module provides the following :ref:`Imported Targets` when
+:prop_gbl:`CMAKE_ROLE` is ``PROJECT``:
+
+``ASPELL::ASPELL``
+  .. versionadded:: 4.1
+
+  Target encapsulating the Aspell library usage requirements.  It is available
+  only when the ``ASPELL`` component is found.
+
+``ASPELL::Executable``
+  .. versionadded:: 4.1
+
+  Target encapsulating the Aspell command-line spell checker executable.  It is
+  available only when the ``Executable`` component is found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``ASPELL_FOUND``
+  Boolean indicating whether the requested Aspell components have been found.
+
+``ASPELL_VERSION``
+  .. versionadded:: 4.1
+
+  Version string of the found Aspell if any.  It may be only determined if the
+  ``Executable`` component is found.  If version isn't determined, version value
+  is not set.
+
+``ASPELL_INCLUDE_DIRS``
+  .. versionadded:: 4.1
+
+  Include directories needed to use Aspell.  They are available when the
+  ``ASPELL`` component is found.
+
+  The Aspell library may also provide a backward-compatible interface for Pspell
+  via the ``pspell.h`` header file.  If such an interface is found, it is also
+  added to the list of include directories.
+
+``ASPELL_LIBRARIES``
+  Libraries needed to link to Aspell.  They are available when the ``ASPELL``
+  component is found.
+
+  .. versionchanged:: 4.1
+    This variable is now set as a regular result variable instead of being a
+    cache variable.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``ASPELL_INCLUDE_DIR``
+  The directory containing the ``aspell.h`` header file when using the
+  ``Executable`` component.
+
+``ASPELL_LIBRARY``
+  .. versionadded:: 4.1
+
+  The path to the Aspell library when using the ``ASPELL`` component.
+
+``ASPELL_EXECUTABLE``
+  The path to the ``aspell`` command-line spell checker program when using the
+  ``Executable`` component.
+
+Examples
+^^^^^^^^
+
+Finding the Aspell library with CMake 4.1 or later and linking it to a project
+target:
+
+.. code-block:: cmake
+
+  find_package(ASPELL COMPONENTS ASPELL)
+  target_link_libraries(project_target PRIVATE ASPELL::ASPELL)
+
+When writing backward-compatible code that supports CMake 4.0 and earlier, a
+local imported target can be defined directly in the project:
+
+.. code-block:: cmake
+
+  find_package(ASPELL COMPONENTS ASPELL)
+  if(ASPELL_FOUND AND NOT TARGET ASPELL::ASPELL)
+    add_library(ASPELL::ASPELL INTERFACE IMPORTED)
+    set_target_properties(
+      ASPELL::ASPELL
+      PROPERTIES
+        INTERFACE_LINK_LIBRARIES "${ASPELL_LIBRARIES}"
+        INTERFACE_INCLUDE_DIRECTORIES "${ASPELL_INCLUDE_DIR}"
+    )
+  endif()
+  target_link_libraries(project_target PRIVATE ASPELL::ASPELL)
+
+Example, how to execute the ``aspell`` command-line spell checker in a project:
+
+.. code-block:: cmake
+
+  find_package(ASPELL COMPONENTS Executable)
+  execute_process(COMMAND ${ASPELL_EXECUTABLE} --help)
 #]=======================================================================]
 
-find_path(ASPELL_INCLUDE_DIR aspell.h )
+set(_ASPELL_REASON_FAILURE_MESSAGE "")
+set(_ASPELL_REQUIRED_VARS "")
 
-find_program(ASPELL_EXECUTABLE
-  NAMES aspell
-)
+# Set default components, when 'COMPONENTS <components>...' are not specified in
+# the 'find_package(ASPELL ...)' call.
+if(NOT ASPELL_FIND_COMPONENTS)
+  set(ASPELL_FIND_COMPONENTS "ASPELL" "Executable")
+  set(ASPELL_FIND_REQUIRED_ASPELL TRUE)
+  set(ASPELL_FIND_REQUIRED_Executable TRUE)
+endif()
+
+if("ASPELL" IN_LIST ASPELL_FIND_COMPONENTS)
+  find_path(
+    ASPELL_INCLUDE_DIR
+    NAMES aspell.h
+    DOC "The directory containing <aspell.h>."
+  )
+  mark_as_advanced(ASPELL_INCLUDE_DIR)
+
+  if(NOT ASPELL_INCLUDE_DIR)
+    string(APPEND _ASPELL_REASON_FAILURE_MESSAGE "aspell.h could not be found. ")
+  endif()
+
+  # Find backward-compatibility interface for Pspell.
+  find_path(
+    ASPELL_PSPELL_INCLUDE_DIR
+    NAMES pspell.h
+    PATH_SUFFIXES pspell
+    DOC "Directory containing <pspell.h> BC interface header"
+  )
+  mark_as_advanced(ASPELL_PSPELL_INCLUDE_DIR)
+
+  # For backward compatibility in projects supporting CMake 4.0 or earlier.
+  # Previously the ASPELL_LIBRARIES was a cache variable storing the
+  # find_library result.
+  if(DEFINED ASPELL_LIBRARIES AND NOT DEFINED ASPELL_LIBRARY)
+    set(ASPELL_LIBRARY ${ASPELL_LIBRARIES})
+  endif()
+
+  find_library(
+    ASPELL_LIBRARY
+    NAMES aspell aspell-15 libaspell-15 libaspell
+    DOC "The path to the Aspell library."
+  )
+  mark_as_advanced(ASPELL_LIBRARY)
 
-find_library(ASPELL_LIBRARIES NAMES aspell aspell-15 libaspell-15 libaspell)
+  if(NOT ASPELL_LIBRARY)
+    string(APPEND _ASPELL_REASON_FAILURE_MESSAGE "Aspell library not found. ")
+  endif()
+
+  if(ASPELL_INCLUDE_DIR AND ASPELL_LIBRARY)
+    set(ASPELL_ASPELL_FOUND TRUE)
+  else()
+    set(ASPELL_ASPELL_FOUND FALSE)
+  endif()
+
+  if(ASPELL_FIND_REQUIRED_ASPELL)
+    list(APPEND _ASPELL_REQUIRED_VARS ASPELL_LIBRARY ASPELL_INCLUDE_DIR)
+  endif()
+endif()
+
+if("Executable" IN_LIST ASPELL_FIND_COMPONENTS)
+  find_program(
+    ASPELL_EXECUTABLE
+    NAMES aspell
+    DOC "The path to the aspell command-line utility program."
+  )
+  mark_as_advanced(ASPELL_EXECUTABLE)
+
+  if(NOT ASPELL_EXECUTABLE)
+    string(
+      APPEND
+      _ASPELL_REASON_FAILURE_MESSAGE
+      "Aspell command-line executable not found. "
+    )
+    set(ASPELL_Executable_FOUND FALSE)
+  else()
+    set(ASPELL_Executable_FOUND TRUE)
+
+    block(PROPAGATE ASPELL_VERSION)
+      execute_process(
+        COMMAND ${ASPELL_EXECUTABLE} --version
+        OUTPUT_VARIABLE output
+        RESULT_VARIABLE result
+        ERROR_QUIET
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+      )
+      if(result EQUAL 0 AND output MATCHES "([0-9.]+)[)]?$")
+        set(ASPELL_VERSION ${CMAKE_MATCH_1})
+      endif()
+    endblock()
+  endif()
+
+  if(ASPELL_FIND_REQUIRED_Executable)
+    list(APPEND _ASPELL_REQUIRED_VARS ASPELL_EXECUTABLE)
+  endif()
+endif()
 
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(ASPELL DEFAULT_MSG ASPELL_LIBRARIES ASPELL_INCLUDE_DIR ASPELL_EXECUTABLE)
+find_package_handle_standard_args(
+  ASPELL
+  REQUIRED_VARS ${_ASPELL_REQUIRED_VARS}
+  HANDLE_COMPONENTS
+  VERSION_VAR ASPELL_VERSION
+  REASON_FAILURE_MESSAGE "${_ASPELL_REASON_FAILURE_MESSAGE}"
+)
+
+unset(_ASPELL_REASON_FAILURE_MESSAGE)
+unset(_ASPELL_REQUIRED_VARS)
+
+if(NOT ASPELL_FOUND)
+  return()
+endif()
+
+get_property(_ASPELL_ROLE GLOBAL PROPERTY CMAKE_ROLE)
+
+if("ASPELL" IN_LIST ASPELL_FIND_COMPONENTS AND ASPELL_ASPELL_FOUND)
+  set(ASPELL_INCLUDE_DIRS ${ASPELL_INCLUDE_DIR})
+  if(ASPELL_PSPELL_INCLUDE_DIR)
+    list(APPEND ASPELL_INCLUDE_DIRS ${ASPELL_PSPELL_INCLUDE_DIR})
+    list(REMOVE_DUPLICATES ASPELL_INCLUDE_DIRS)
+  endif()
+  set(ASPELL_LIBRARIES ${ASPELL_LIBRARY})
+
+  if(_ASPELL_ROLE STREQUAL "PROJECT" AND NOT TARGET ASPELL::ASPELL)
+    if(IS_ABSOLUTE "${ASPELL_LIBRARY}")
+      add_library(ASPELL::ASPELL UNKNOWN IMPORTED)
+      set_target_properties(
+        ASPELL::ASPELL
+        PROPERTIES
+          IMPORTED_LOCATION "${ASPELL_LIBRARY}"
+      )
+    else()
+      add_library(ASPELL::ASPELL INTERFACE IMPORTED)
+      set_target_properties(
+        ASPELL::ASPELL
+        PROPERTIES
+          IMPORTED_LIBNAME "${ASPELL_LIBRARY}"
+      )
+    endif()
+
+    set_target_properties(
+      ASPELL::ASPELL
+      PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${ASPELL_INCLUDE_DIRS}"
+    )
+  endif()
+endif()
+
+if(
+  _ASPELL_ROLE STREQUAL "PROJECT"
+  AND "Executable" IN_LIST ASPELL_FIND_COMPONENTS
+  AND ASPELL_Executable_FOUND
+  AND NOT TARGET ASPELL::Executable
+)
+  add_executable(ASPELL::Executable IMPORTED)
+  set_target_properties(
+    ASPELL::Executable
+    PROPERTIES
+      IMPORTED_LOCATION "${ASPELL_EXECUTABLE}"
+  )
+endif()
 
-mark_as_advanced(ASPELL_INCLUDE_DIR ASPELL_LIBRARIES ASPELL_EXECUTABLE)
+unset(_ASPELL_ROLE)

+ 1 - 0
Tests/CMakeLists.txt

@@ -1468,6 +1468,7 @@ if(BUILD_TESTING)
   _mod
   IN ITEMS
       ALSA
+      ASPELL
       Backtrace
       BLAS
       Boost

+ 10 - 0
Tests/FindASPELL/CMakeLists.txt

@@ -0,0 +1,10 @@
+add_test(NAME FindASPELL.Test COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindASPELL/Test"
+  "${CMake_BINARY_DIR}/Tests/FindASPELL/Test"
+  ${build_generator_args}
+  --build-project TestFindASPELL
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )

+ 27 - 0
Tests/FindASPELL/Test/CMakeLists.txt

@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindASPELL C)
+include(CTest)
+
+find_package(ASPELL COMPONENTS ASPELL)
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt ASPELL::ASPELL)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${ASPELL_INCLUDE_DIR})
+target_link_libraries(test_var PRIVATE ${ASPELL_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
+
+set_tests_properties(
+  test_tgt test_var
+  PROPERTIES PASS_REGULAR_EXPRESSION "^Word \"[^\"]+\" is spelled correctly"
+)
+
+find_package(ASPELL)
+add_executable(test_version version.c)
+target_link_libraries(test_version ASPELL::ASPELL)
+target_compile_definitions(
+  test_version PRIVATE -DCMAKE_EXPECTED_ASPELL_VERSION="${ASPELL_VERSION}"
+)
+add_test(NAME test_version COMMAND test_version)

+ 27 - 0
Tests/FindASPELL/Test/main.c

@@ -0,0 +1,27 @@
+#include <aspell.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(void)
+{
+  AspellConfig* config = new_aspell_config();
+  assert(config && "Failed creating AspellConfig");
+
+  AspellCanHaveError* result = new_aspell_speller(config);
+  delete_aspell_config(config);
+  AspellSpeller* speller = to_aspell_speller(result);
+  assert(aspell_error_number(result) == 0 && "Failed creating AspellSpeller");
+
+  char const* word = "conjunction";
+
+  if (aspell_speller_check(speller, word, (int)strlen(word))) {
+    printf("Word \"%s\" is spelled correctly\n", word);
+  } else {
+    printf("Word \"%s\" is misspelled\n", word);
+  }
+
+  delete_aspell_speller(speller);
+
+  return 0;
+}

+ 10 - 0
Tests/FindASPELL/Test/version.c

@@ -0,0 +1,10 @@
+#include <aspell.h>
+#include <assert.h>
+#include <string.h>
+
+int main(void)
+{
+  char const* aspell_version = aspell_version_string();
+  assert(strcmp(aspell_version, CMAKE_EXPECTED_ASPELL_VERSION) == 0);
+  return 0;
+}