11#[=============================================================================[
22Find the ODBC library.
33
4- Module defines the following `IMPORTED` target(s):
4+ This module is based on the upstream
5+ [FindODBC](https://cmake.org/cmake/help/latest/module/FindODBC.html) with some
6+ enhancements and adjustments for the PHP build workflow.
57
6- * `ODBC::ODBC` - The package library, if found.
8+ Modifications from upstream:
79
8- Result variables:
10+ * New result variables:
911
10- * `ODBC_FOUND` - Whether the package has been found.
11- * `ODBC_INCLUDE_DIRS` - Include directories needed to use this package.
12- * `ODBC_LIBRARIES` - Libraries needed to link to the package library.
13- * `ODBC_VERSION` - Package version, if found.
12+ * `ODBC_DRIVER`
1413
15- Cache variables:
14+ Name of the found driver, if any. For example, `unixODBC`, `iODBC`.
1615
17- * `ODBC_INCLUDE_DIR` - Directory containing package library headers.
18- * `ODBC_LIBRARY` - The path to the package library.
16+ * `ODBC_VERSION`
1917
20- Hints:
18+ Version of the found ODBC library if it was retrieved from config utilities.
2119
22- * The `ODBC_ROOT` variable adds custom search path.
23- * The `ODBC_TYPE` variable adds ODBC library name to look for.
20+ * New hints:
21+
22+ * `ODBC_USE_DRIVER`
23+
24+ Set to `unixODBC` or `iODBC` to limit searching for specific ODBC driver
25+ instead of any driver.
26+
27+ * Added pkg-config integration.
28+
29+ * It fixes the limitation where the upstream module can't (yet) select which
30+ specific ODBC driver to use. Except on Windows, where the driver searching is
31+ the same as upstream.
32+
33+ * Added package meta-data for FeatureSummary (not relevant for upstream module).
2434#]=============================================================================]
2535
2636include (FeatureSummary)
27- include (FindPackageHandleStandardArgs)
2837
29- set_package_properties(
30- ODBC
31- PROPERTIES
32- URL "https://en.wikipedia.org/wiki/Open_Database_Connectivity"
33- DESCRIPTION "Open Database Connectivity library"
34- )
38+ # Define internal variables
39+ set (_odbc_include_paths)
40+ set (_odbc_lib_paths)
41+ set (_odbc_lib_names)
42+ set (_odbc_required_libs_names)
43+ set (_odbc_config_names)
44+ set (_reason)
3545
36- set (_reason "" )
46+ ### Try Windows Kits ##########################################################
47+ if (WIN32 )
48+ # List names of ODBC libraries on Windows
49+ if (NOT MINGW)
50+ set (ODBC_LIBRARY odbc32.lib)
51+ else ()
52+ set (ODBC_LIBRARY libodbc32.a)
53+ endif ()
54+ set (_odbc_lib_names odbc32;)
3755
38- # Use pkgconf, if available on the system.
39- find_package (PkgConfig QUIET )
40- pkg_check_modules(PC_ODBC QUIET odbc)
56+ # List additional libraries required to use ODBC library
57+ if (MSVC OR CMAKE_CXX_COMPILER_ID MATCHES "Intel" )
58+ set (_odbc_required_libs_names odbccp32;ws2_32)
59+ elseif (MINGW)
60+ set (_odbc_required_libs_names odbccp32)
61+ endif ()
62+ endif ()
4163
42- find_path (
43- ODBC_INCLUDE_DIR
44- NAMES sql.h
45- PATHS ${PC_ODBC_INCLUDE_DIRS}
46- DOC "Directory containing ODBC library headers"
47- )
64+ ### Try unixODBC or iODBC config program ######################################
65+ if (UNIX )
66+ if (ODBC_USE_DRIVER MATCHES "^(unixODBC|unixodbc|UNIXODBC)$" )
67+ set (_odbc_config_names odbc_config)
68+ elseif (ODBC_USE_DRIVER MATCHES "^(iODBC|iodbc|IODBC)$" )
69+ set (_odbc_config_names iodbc-config)
70+ else ()
71+ set (_odbc_config_names odbc_config iodbc-config)
72+ endif ()
4873
49- if (NOT ODBC_INCLUDE_DIR)
50- string (APPEND _reason "ODBC sql.h not found. " )
74+ find_program (ODBC_CONFIG
75+ NAMES ${_odbc_config_names}
76+ DOC "Path to unixODBC or iODBC config program" )
77+ mark_as_advanced (ODBC_CONFIG)
5178endif ()
5279
53- if (NOT ODBC_TYPE)
54- set (ODBC_TYPE "" )
80+ if (UNIX AND ODBC_CONFIG)
81+ # unixODBC and iODBC accept unified command line options
82+ execute_process (COMMAND ${ODBC_CONFIG} --cflags
83+ OUTPUT_VARIABLE _cflags OUTPUT_STRIP_TRAILING_WHITESPACE)
84+ execute_process (COMMAND ${ODBC_CONFIG} --libs
85+ OUTPUT_VARIABLE _libs OUTPUT_STRIP_TRAILING_WHITESPACE)
86+
87+ # Collect paths of include directories from CFLAGS
88+ separate_arguments (_cflags NATIVE_COMMAND "${_cflags} " )
89+ foreach (arg IN LISTS _cflags)
90+ if ("${arg} " MATCHES "^-I(.*)$" )
91+ list (APPEND _odbc_include_paths "${CMAKE_MATCH_1} " )
92+ endif ()
93+ endforeach ()
94+ unset (_cflags)
95+
96+ # Collect paths of library names and directories from LIBS
97+ separate_arguments (_libs NATIVE_COMMAND "${_libs} " )
98+ foreach (arg IN LISTS _libs)
99+ if ("${arg} " MATCHES "^-L(.*)$" )
100+ list (APPEND _odbc_lib_paths "${CMAKE_MATCH_1} " )
101+ elseif ("${arg} " MATCHES "^-l(.*)$" )
102+ set (_lib_name ${CMAKE_MATCH_1} )
103+ string (REGEX MATCH "odbc" _is_odbc ${_lib_name} )
104+ if (_is_odbc)
105+ list (APPEND _odbc_lib_names ${_lib_name} )
106+ else ()
107+ list (APPEND _odbc_required_libs_names ${_lib_name} )
108+ endif ()
109+ unset (_lib_name)
110+ endif ()
111+ endforeach ()
112+ unset (_libs)
55113endif ()
56114
57- find_library (
58- ODBC_LIBRARY
59- NAMES ${ODBC_TYPE} odbc
60- PATHS ${PC_ODBC_LIBRARY_DIRS}
61- DOC "The path to the ODBC library"
62- )
115+ ### Try pkg-config ############################################################
116+ if (NOT ODBC_CONFIG)
117+ find_package (PkgConfig QUIET )
118+ if (PKG_CONFIG_FOUND)
119+ if (ODBC_USE_DRIVER MATCHES "^(unixODBC|unixodbc|UNIXODBC)$" )
120+ pkg_check_modules(PC_ODBC QUIET odbc)
121+ elseif (ODBC_USE_DRIVER MATCHES "^(iODBC|iodbc|IODBC)$" )
122+ pkg_check_modules(PC_ODBC QUIET libiodbc)
123+ else ()
124+ pkg_search_module(PC_ODBC QUIET odbc libiodbc)
125+ endif ()
126+ endif ()
127+ endif ()
128+
129+ ### Try unixODBC or iODBC in include/lib filesystems ##########################
130+ if (UNIX AND NOT ODBC_CONFIG)
131+ if (ODBC_USE_DRIVER MATCHES "^(unixODBC|unixodbc|UNIXODBC)$" )
132+ set (_odbc_lib_names odbc;unixodbc;)
133+ elseif (ODBC_USE_DRIVER MATCHES "^(iODBC|iodbc|IODBC)$" )
134+ set (_odbc_lib_names iodbc;)
135+ else ()
136+ # List names of both ODBC libraries, unixODBC and iODBC
137+ set (_odbc_lib_names odbc;iodbc;unixodbc;)
138+ endif ()
139+ endif ()
63140
141+ ### Find include directories ##################################################
142+ find_path (ODBC_INCLUDE_DIR
143+ NAMES sql.h
144+ PATHS ${_odbc_include_paths}
145+ HINTS ${PC_ODBC_INCLUDE_DIRS} )
146+
147+ if (NOT ODBC_INCLUDE_DIR AND WIN32 )
148+ set (ODBC_INCLUDE_DIR "" )
149+ endif ()
150+
151+ ### Find libraries ############################################################
64152if (NOT ODBC_LIBRARY)
65- string (APPEND _reason "ODBC library not found. " )
153+ find_library (ODBC_LIBRARY
154+ NAMES ${_odbc_lib_names}
155+ PATHS ${_odbc_lib_paths}
156+ PATH_SUFFIXES odbc
157+ HINTS ${PC_ODBC_LIBRARY_DIRS} )
158+
159+ foreach (_lib IN LISTS _odbc_required_libs_names)
160+ find_library (_lib_path
161+ NAMES ${_lib}
162+ PATHS ${_odbc_lib_paths} # system parths or collected from ODBC_CONFIG
163+ PATH_SUFFIXES odbc)
164+ if (_lib_path)
165+ list (APPEND _odbc_required_libs_paths ${_lib_path} )
166+ endif ()
167+ unset (_lib_path CACHE )
168+ endforeach ()
66169endif ()
67170
68- # Get version.
171+ # Unset internal lists as no longer used
172+ unset (_odbc_include_paths)
173+ unset (_odbc_lib_paths)
174+ unset (_odbc_lib_names)
175+ unset (_odbc_required_libs_names)
176+ unset (_odbc_config_names)
177+
178+ ### Get version ###############################################################
69179block(PROPAGATE ODBC_VERSION)
70- # ODBC headers don't provide version. Try pkgconf version, if found.
180+ # ODBC headers don't provide version. Try pkg-confing version, if found.
71181 if (PC_ODBC_VERSION)
72182 cmake_path(
73183 COMPARE
@@ -79,36 +189,126 @@ block(PROPAGATE ODBC_VERSION)
79189 set (ODBC_VERSION ${PC_ODBC_VERSION} )
80190 endif ()
81191 endif ()
192+
193+ if (NOT ODBC_VERSION AND ODBC_CONFIG)
194+ execute_process (
195+ COMMAND ${ODBC_CONFIG} --version
196+ OUTPUT_VARIABLE _odbc_version
197+ OUTPUT_STRIP_TRAILING_WHITESPACE
198+ ERROR_QUIET
199+ )
200+ if (_odbc_version MATCHES "[0-9]+\. [0-9.]*" )
201+ set (ODBC_VERSION ${_odbc_version} )
202+ endif ()
203+ endif ()
82204endblock()
83205
84- mark_as_advanced (ODBC_LIBRARY ODBC_INCLUDE_DIR)
206+ ### Set result variables ######################################################
207+ set (_odbc_required_vars ODBC_LIBRARY)
208+ if (NOT WIN32 )
209+ list (APPEND _odbc_required_vars ODBC_INCLUDE_DIR)
210+ endif ()
211+
212+ if (NOT ODBC_INCLUDE_DIR)
213+ string (APPEND _reason "ODBC sql.h not found. " )
214+ endif ()
85215
216+ if (NOT ODBC_LIBRARY)
217+ string (APPEND _reason "ODBC library not found. " )
218+ endif ()
219+
220+ include (FindPackageHandleStandardArgs)
86221find_package_handle_standard_args(
87222 ODBC
88- REQUIRED_VARS
89- ODBC_LIBRARY
90- ODBC_INCLUDE_DIR
223+ REQUIRED_VARS ${_odbc_required_vars}
91224 VERSION_VAR ODBC_VERSION
92225 REASON_FAILURE_MESSAGE "${_reason} "
93226)
94227
228+ unset (_odbc_required_vars)
95229unset (_reason)
96230
97- if (NOT ODBC_FOUND)
98- return ()
99- endif ()
231+ mark_as_advanced (ODBC_LIBRARY ODBC_INCLUDE_DIR)
100232
101233set (ODBC_INCLUDE_DIRS ${ODBC_INCLUDE_DIR} )
102- set (ODBC_LIBRARIES ${ODBC_LIBRARY} )
103-
104- if (NOT TARGET ODBC::ODBC)
105- add_library (ODBC::ODBC UNKNOWN IMPORTED )
106-
107- set_target_properties (
108- ODBC::ODBC
109- PROPERTIES
110- IMPORTED_LOCATION "${ODBC_LIBRARY} "
111- INTERFACE_INCLUDE_DIRECTORIES "${ODBC_INCLUDE_DIR} "
112- INTERFACE_COMPILE_OPTIONS "${PC_ODBC_CFLAGS_OTHER} "
113- )
234+ list (APPEND ODBC_LIBRARIES ${ODBC_LIBRARY} )
235+ list (APPEND ODBC_LIBRARIES ${_odbc_required_libs_paths} )
236+
237+ ### Import targets ############################################################
238+ if (ODBC_FOUND)
239+ if (NOT TARGET ODBC::ODBC)
240+ if (IS_ABSOLUTE "${ODBC_LIBRARY} " )
241+ add_library (ODBC::ODBC UNKNOWN IMPORTED )
242+ set_target_properties (ODBC::ODBC PROPERTIES
243+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
244+ IMPORTED_LOCATION "${ODBC_LIBRARY} " )
245+ else ()
246+ add_library (ODBC::ODBC INTERFACE IMPORTED )
247+ set_target_properties (ODBC::ODBC PROPERTIES
248+ IMPORTED_LIBNAME "${ODBC_LIBRARY} " )
249+ endif ()
250+ set_target_properties (ODBC::ODBC PROPERTIES
251+ INTERFACE_INCLUDE_DIRECTORIES "${ODBC_INCLUDE_DIR} " )
252+
253+ if (_odbc_required_libs_paths)
254+ set_property (TARGET ODBC::ODBC APPEND PROPERTY
255+ INTERFACE_LINK_LIBRARIES "${_odbc_required_libs_paths} " )
256+ endif ()
257+ endif ()
258+
259+ if (NOT ODBC_DRIVER)
260+ if (ODBC_CONFIG)
261+ execute_process (
262+ COMMAND ${ODBC_CONFIG}
263+ OUTPUT_VARIABLE _output
264+ ERROR_VARIABLE _output
265+ OUTPUT_STRIP_TRAILING_WHITESPACE
266+ ERROR_QUIET
267+ )
268+ if (_output MATCHES "^iODBC" )
269+ set (ODBC_DRIVER "iODBC" )
270+ elseif (_output MATCHES "^Usage: odbc_config" )
271+ set (ODBC_DRIVER "unixODBC" )
272+ endif ()
273+ unset (_output)
274+ elseif (PC_ODBC_FOUND)
275+ if (PC_ODBC_MODULE_NAME STREQUAL "libiodbc" )
276+ set (ODBC_DRIVER "iODBC" )
277+ elseif (PC_ODBC_MODULE_NAME STREQUAL "odbc" )
278+ set (ODBC_DRIVER "unixODBC" )
279+ endif ()
280+ elseif (WIN32 )
281+ set (ODBC_DRIVER "Windows" )
282+ endif ()
283+
284+ if (NOT ODBC_DRIVER)
285+ if (ODBC_LIBRARY MATCHES "libiodbc" )
286+ set (ODBC_DRIVER "iODBC" )
287+ elseif (ODBC_LIBRARY MATCHES "odbc" )
288+ set (ODBC_DRIVER "unixODBC" )
289+ endif ()
290+ endif ()
291+ endif ()
292+ endif ()
293+
294+ unset (_odbc_required_libs_paths)
295+
296+ ### Set package metadata ######################################################
297+ if (ODBC_DRIVER STREQUAL "unixODBC" OR ODBC_USE_DRIVER STREQUAL "unixODBC" )
298+ set (_odbc_url "https://www.unixodbc.org/" )
299+ set (_odbc_description "Open Database Connectivity library for *nix systems" )
300+ elseif (ODBC_DRIVER STREQUAL "iODBC" OR ODBC_USE_DRIVER STREQUAL "iODBC" )
301+ set (_odbc_url "https://www.iodbc.org" )
302+ set (_odbc_description "Independent Open Database Connectivity library" )
303+ else ()
304+ set (_odbc_url "https://en.wikipedia.org/wiki/Open_Database_Connectivity" )
305+ set (_odbc_description "Open Database Connectivity library" )
114306endif ()
307+ set_package_properties(
308+ ODBC
309+ PROPERTIES
310+ URL "${_odbc_url} "
311+ DESCRIPTION "${_odbc_description} "
312+ )
313+ unset (_odbc_url)
314+ unset (_odbc_description)
0 commit comments