diff --git a/.gitlab/ci/configure_debian12_aarch64_ninja.cmake b/.gitlab/ci/configure_debian12_aarch64_ninja.cmake index 00843d5742..b53382280b 100644 --- a/.gitlab/ci/configure_debian12_aarch64_ninja.cmake +++ b/.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 "") diff --git a/.gitlab/ci/configure_debian12_ninja_common.cmake b/.gitlab/ci/configure_debian12_ninja_common.cmake index 3912daabde..3022725255 100644 --- a/.gitlab/ci/configure_debian12_ninja_common.cmake +++ b/.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 "") diff --git a/.gitlab/ci/configure_fedora41_makefiles.cmake b/.gitlab/ci/configure_fedora41_makefiles.cmake index 2a57087c35..e84dcbd646 100644 --- a/.gitlab/ci/configure_fedora41_makefiles.cmake +++ b/.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 "") diff --git a/Help/release/dev/FindASPELL-imported-targets.rst b/Help/release/dev/FindASPELL-imported-targets.rst new file mode 100644 index 0000000000..0d8a0e0116 --- /dev/null +++ b/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. diff --git a/Modules/FindASPELL.cmake b/Modules/FindASPELL.cmake index 10d61ac815..2c5cb93e36 100644 --- a/Modules/FindASPELL.cmake +++ b/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 ...]) + +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 ...' 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() -find_library(ASPELL_LIBRARIES NAMES aspell aspell-15 libaspell-15 libaspell) +if("ASPELL" IN_LIST ASPELL_FIND_COMPONENTS) + find_path( + ASPELL_INCLUDE_DIR + NAMES aspell.h + DOC "The directory containing ." + ) + 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 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) + + 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}" +) -mark_as_advanced(ASPELL_INCLUDE_DIR ASPELL_LIBRARIES ASPELL_EXECUTABLE) +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() + +unset(_ASPELL_ROLE) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index b03c827736..5f8a8af4ee 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1468,6 +1468,7 @@ if(BUILD_TESTING) _mod IN ITEMS ALSA + ASPELL Backtrace BLAS Boost diff --git a/Tests/FindASPELL/CMakeLists.txt b/Tests/FindASPELL/CMakeLists.txt new file mode 100644 index 0000000000..a6a8236991 --- /dev/null +++ b/Tests/FindASPELL/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindASPELL.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $ + --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 $ + ) diff --git a/Tests/FindASPELL/Test/CMakeLists.txt b/Tests/FindASPELL/Test/CMakeLists.txt new file mode 100644 index 0000000000..df4859c8a9 --- /dev/null +++ b/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) diff --git a/Tests/FindASPELL/Test/main.c b/Tests/FindASPELL/Test/main.c new file mode 100644 index 0000000000..319ec7b7c9 --- /dev/null +++ b/Tests/FindASPELL/Test/main.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +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; +} diff --git a/Tests/FindASPELL/Test/version.c b/Tests/FindASPELL/Test/version.c new file mode 100644 index 0000000000..da8c020963 --- /dev/null +++ b/Tests/FindASPELL/Test/version.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int main(void) +{ + char const* aspell_version = aspell_version_string(); + assert(strcmp(aspell_version, CMAKE_EXPECTED_ASPELL_VERSION) == 0); + return 0; +}