Skip to content

Commit f2a3033

Browse files
committed
refactor(readline): better FindReadline module
The readline library is now searched with pkg-config first. If pkg-config is not installed, the search is manual. In both cases, the Readline::readline target is created, embedding transitive requirements. The readline library depends on the ncurses library on UNIX. A dedicated find module for Ncurses was added. Find modules were written with the help of Le Chat AI (https://chat.mistral.ai/chat)
1 parent aca3819 commit f2a3033

3 files changed

Lines changed: 154 additions & 32 deletions

File tree

cmake/FindNcurses.cmake

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#.rst:
2+
# FindNcurses
3+
# ------------
4+
#
5+
# Find the ncurses library.
6+
#
7+
# This module uses pkg-config to find ncurses if available, and falls back
8+
# to manual search if pkg-config is not found or fails.
9+
#
10+
# Imported Targets
11+
# ^^^^^^^^^^^^^^^
12+
#
13+
# This module defines the following :prop_tgt:`IMPORTED` target:
14+
#
15+
# ``Ncurses::ncurses``
16+
# The ncurses library, if found.
17+
#
18+
# Result Variables
19+
# ^^^^^^^^^^^^^^
20+
#
21+
# This module defines the following variables:
22+
#
23+
# ``Ncurses_LIBRARIES``
24+
# The ncurses libraries to link against.
25+
# ``Ncurses_INCLUDE_DIRS``
26+
# The ncurses include directories.
27+
# ``Ncurses_FOUND``
28+
# True if the ncurses library is found.
29+
30+
# Try to use pkg-config first
31+
find_package(PkgConfig QUIET)
32+
if(PkgConfig_FOUND)
33+
pkg_check_modules(Ncurses QUIET IMPORTED_TARGET ncurses)
34+
if(Ncurses_FOUND)
35+
# pkg-config found ncurses, create the imported target
36+
add_library(Ncurses::ncurses ALIAS PkgConfig::Ncurses)
37+
return()
38+
endif()
39+
endif()
40+
41+
# Fallback to manual search if pkg-config fails
42+
find_path(Ncurses_INCLUDE_DIR
43+
NAMES ncurses.h curses.h
44+
DOC "ncurses include directory"
45+
)
46+
47+
find_library(Ncurses_LIBRARY
48+
NAMES ncursesw ncurses curses
49+
DOC "ncurses library"
50+
)
51+
52+
include(FindPackageHandleStandardArgs)
53+
find_package_handle_standard_args(Ncurses
54+
DEFAULT_MSG
55+
Ncurses_INCLUDE_DIR
56+
Ncurses_LIBRARY
57+
)
58+
59+
if(Ncurses_FOUND)
60+
set(Ncurses_LIBRARIES ${Ncurses_LIBRARY})
61+
set(Ncurses_INCLUDE_DIRS ${Ncurses_INCLUDE_DIR})
62+
63+
if(NOT TARGET Ncurses::ncurses)
64+
add_library(Ncurses::ncurses UNKNOWN IMPORTED)
65+
set_target_properties(Ncurses::ncurses PROPERTIES
66+
IMPORTED_LOCATION "${Ncurses_LIBRARY}"
67+
INTERFACE_INCLUDE_DIRECTORIES "${Ncurses_INCLUDE_DIRS}"
68+
)
69+
endif()
70+
endif()
71+
72+
mark_as_advanced(
73+
Ncurses_INCLUDE_DIR
74+
Ncurses_LIBRARY
75+
)

cmake/FindReadline.cmake

Lines changed: 77 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,96 @@
1-
# Code copied from sethhall@github
1+
#.rst:
2+
# FindReadline
3+
# ------------
24
#
3-
# - Try to find readline include dirs and libraries
5+
# Find the readline library and its dependency (ncurses).
46
#
57
# Usage of this module as follows:
68
#
7-
# find_package(Readline)
9+
# find_package(Readline [REQUIRED] [QUIET])
10+
# target_link_libraries(<target> PRIVATE Readline::readline)
811
#
9-
# Variables used by this module, they can change the default behaviour and need
10-
# to be set before calling find_package:
12+
# Variables used by this module:
1113
#
12-
# Readline_ROOT_DIR Set this variable to the root installation of
13-
# readline if the module has problems finding the
14-
# proper installation path.
14+
# Readline_ROOT - Root directory to search for readline (e.g., /usr/local or the vcpkg installation path).
15+
# If not set, the module will search in standard system paths.
1516
#
16-
# Variables defined by this module:
17+
# Imported Targets
18+
# ^^^^^^^^^^^^^^^
1719
#
18-
# READLINE_FOUND System has readline, include and lib dirs found
19-
# Readline_INCLUDE_DIR The readline include directories.
20-
# Readline_LIBRARY The readline library.
20+
# This module defines the following :prop_tgt:`IMPORTED` target:
21+
#
22+
# ``Readline::readline``
23+
# The readline library, if found, with ncurses as a dependency.
24+
#
25+
# Result Variables
26+
# ^^^^^^^^^^^^^^
27+
#
28+
# ``Readline_FOUND`` - True if readline is found.
29+
# ``Readline_INCLUDE_DIRS`` - The readline include directories.
30+
# ``Readline_LIBRARIES`` - The readline libraries (including ncurses if found).
2131

22-
find_path(Readline_ROOT_DIR
23-
NAMES include/readline/readline.h
24-
)
32+
# --- Step 1: Try pkg-config first ---
33+
find_package(PkgConfig QUIET)
34+
if(PkgConfig_FOUND)
35+
pkg_check_modules(Readline QUIET IMPORTED_TARGET readline)
36+
if(Readline_FOUND)
37+
# pkg-config found readline (and handles ncurses automatically)
38+
add_library(Readline::readline ALIAS PkgConfig::Readline)
39+
return()
40+
endif()
41+
endif()
42+
43+
# --- Step 2: Manual search if pkg-config fails ---
44+
# Uses Readline_ROOT if defined (CMake convention: <PackageName>_ROOT)
45+
set(_Readline_SEARCH_PATHS)
46+
if(Readline_ROOT)
47+
list(APPEND _Readline_SEARCH_PATHS "${Readline_ROOT}")
48+
endif()
2549

2650
find_path(Readline_INCLUDE_DIR
27-
NAMES readline/readline.h
28-
HINTS ${Readline_ROOT_DIR}/include
51+
NAMES readline/readline.h
52+
HINTS ${_Readline_SEARCH_PATHS}
53+
PATH_SUFFIXES include
54+
DOC "readline include directory"
2955
)
3056

3157
find_library(Readline_LIBRARY
32-
NAMES readline
33-
HINTS ${Readline_ROOT_DIR}/lib
58+
NAMES readline
59+
HINTS ${_Readline_SEARCH_PATHS}
60+
PATH_SUFFIXES lib lib64
61+
DOC "readline library"
3462
)
3563

36-
if(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
37-
set(READLINE_FOUND TRUE)
38-
else(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
39-
find_library(Readline_LIBRARY NAMES readline)
40-
include(FindPackageHandleStandardArgs)
41-
find_package_handle_standard_args(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY )
42-
mark_as_advanced(Readline_INCLUDE_DIR Readline_LIBRARY)
43-
endif(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
64+
# Managing results with FindPackageHandleStandardArgs
65+
include(FindPackageHandleStandardArgs)
66+
find_package_handle_standard_args(Readline
67+
DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY
68+
)
69+
70+
if(Readline_FOUND)
71+
set(Readline_INCLUDE_DIRS ${Readline_INCLUDE_DIR})
72+
set(Readline_LIBRARIES ${Readline_LIBRARY})
73+
74+
if(NOT TARGET Readline::readline)
75+
add_library(Readline::readline UNKNOWN IMPORTED)
76+
set_target_properties(Readline::readline PROPERTIES
77+
IMPORTED_LOCATION "${Readline_LIBRARY}"
78+
INTERFACE_INCLUDE_DIRECTORIES "${Readline_INCLUDE_DIRS}"
79+
)
80+
81+
# --- ncurses management (Unix only) ---
82+
if(UNIX)
83+
find_package(Ncurses MODULE REQUIRED)
84+
set_property(TARGET Readline::readline PROPERTY
85+
INTERFACE_LINK_LIBRARIES Ncurses::ncurses
86+
)
87+
endif(UNIX)
88+
endif()
89+
endif()
4490

91+
# Hide internal variables
4592
mark_as_advanced(
46-
Readline_ROOT_DIR
47-
Readline_INCLUDE_DIR
48-
Readline_LIBRARY
93+
Readline_INCLUDE_DIR
94+
Readline_LIBRARY
95+
Readline_ROOT
4996
)

src/cli/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ target_link_libraries(text_stream PUBLIC Qt6::Core)
2121
add_library(line_reader STATIC LineReader.cpp)
2222
target_link_libraries(line_reader PUBLIC Qt6::Core)
2323
find_package(Readline MODULE)
24-
if(READLINE_FOUND)
24+
if(Readline_FOUND)
2525
target_compile_definitions(line_reader PRIVATE "USE_READLINE")
26-
target_link_libraries(line_reader PRIVATE ${Readline_LIBRARY})
26+
target_link_libraries(line_reader PRIVATE Readline::readline)
2727
else()
2828
target_link_libraries(line_reader PRIVATE text_stream)
2929
endif()

0 commit comments

Comments
 (0)