Skip to content

Commit c40c821

Browse files
committed
Improve ODBC driver selection
- MySQL_CONFIG_EXECUTABLE marked as advanced to not show in regular list of options in GUI - PHP/Set module adjusted to have choices validated by default - Fixed odbc extension build as these are still STATIC libraries for simplicity of usage but should probably be OBJECT otherwise PHP doesn't provide some symbols when linking.
1 parent 3c45c72 commit c40c821

File tree

4 files changed

+198
-127
lines changed

4 files changed

+198
-127
lines changed

cmake/cmake/modules/FindMySQL.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ find_program(
5555
NAMES mysql_config
5656
DOC "The mysql_config command-line tool for getting MySQL installation info"
5757
)
58+
mark_as_advanced(MySQL_CONFIG_EXECUTABLE)
5859

5960
# Find the Socket component.
6061
if("Socket" IN_LIST MySQL_FIND_COMPONENTS)

cmake/cmake/modules/PHP/Set.cmake

Lines changed: 124 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ php_set(
3131
<variable>
3232
TYPE <type>
3333
[CHOICES <string>...]
34+
[CHOICES_OPTIONAL]
35+
[CHOICES_CASE_SENSITIVE]
3436
[IF <condition> VALUE <value> [ELSE_VALUE <default>]] | [VALUE <value>]
3537
DOC <docstring>...
36-
[WARNING <warning>]
3738
)
3839
```
3940
@@ -45,6 +46,52 @@ It sets a CACHE `<variable>` of `<type>` to a `<value>`.
4546
a list of supported options to pick in the GUI. Under the hood, it sets the
4647
`STRINGS` CACHE variable property.
4748
49+
* When `CHOICES_OPTIONAL` is used, variable value will not be validated to
50+
match one of the list items. By default when using `CHOICES` variable value
51+
must match one of the list items otherwise a fatal error is thrown.
52+
53+
* When `CHOICES_CASE_SENSITIVE` is used, variable value passed by the user
54+
will need to be of the same case as defined in the `CHOICES` list. By
55+
default, choices are case insensitive.
56+
57+
For example:
58+
59+
```cmake
60+
php_set(
61+
VAR
62+
TYPE STRING
63+
CHOICES auto unixODBC iODBC
64+
IF TRUE
65+
VALUE auto
66+
DOC "Variable with a case insensitive list of choices"
67+
)
68+
message(STATUS "VAR=${VAR}")
69+
```
70+
71+
```sh
72+
cmake -S <source-dir> -B <build-dir> -DVAR=unixodbc
73+
```
74+
75+
Will output `VAR=unixODBC` and not `VAR=unixodbc`.
76+
77+
With `CHOICES_CASE_SENSITIVE`:
78+
79+
```cmake
80+
php_set(
81+
VAR
82+
TYPE STRING
83+
CHOICES auto unixODBC iODBC
84+
CHOICES_CASE_SENSITIVE
85+
IF TRUE
86+
VALUE auto
87+
DOC "Variable with a case sensitive list of choices"
88+
)
89+
message(STATUS "VAR=${VAR}")
90+
```
91+
92+
A fatal error will be thrown, if VAR is set to a case-sensitive value
93+
`unixodbc`, which is not defined in the `CHOICES` list.
94+
4895
* `VALUE` is the default variable value. There are two ways to set default
4996
value.
5097
@@ -68,10 +115,6 @@ It sets a CACHE `<variable>` of `<type>` to a `<value>`.
68115
69116
* `DOC` is a short variable help text visible in the GUIs. Multiple strings are
70117
joined together.
71-
72-
* `WARNING` is optional text that is emitted when setting a variable from the
73-
command line or CMake presets but its condition is not met. Otherwise, a
74-
default warning is emitted.
75118
#]=============================================================================]
76119

77120
include_guard(GLOBAL)
@@ -80,10 +123,10 @@ function(php_set)
80123
cmake_parse_arguments(
81124
PARSE_ARGV
82125
1
83-
parsed # prefix
84-
"" # options
126+
parsed # prefix
127+
"CHOICES_OPTIONAL;CHOICES_CASE_SENSITIVE" # options
85128
"TYPE;IF;VALUE;ELSE_VALUE" # one-value keywords
86-
"CHOICES;DOC;WARNING" # multi-value keywords
129+
"CHOICES;DOC" # multi-value keywords
87130
)
88131

89132
# The cmake_parse_arguments() before 3.31 didn't define one-value keywords
@@ -155,11 +198,17 @@ function(php_set)
155198
set(${varName} "${${bufferVarName}}" CACHE ${parsed_TYPE} "${doc}" FORCE)
156199
if(parsed_TYPE STREQUAL "STRING" AND parsed_CHOICES)
157200
set_property(CACHE ${varName} PROPERTY STRINGS ${parsed_CHOICES})
201+
if(NOT parsed_CHOICES_CASE_SENSITIVE)
202+
_php_set_fix_value(${varName})
203+
endif()
204+
if(NOT parsed_CHOICES_OPTIONAL)
205+
_php_set_validate_choices(${varName} ${parsed_CHOICES_CASE_SENSITIVE})
206+
endif()
158207
endif()
159208
unset(${bufferVarName} CACHE)
160209
unset(${bufferVarName}_OVERRIDDEN CACHE)
161210
else()
162-
_php_set_validate_input()
211+
_php_set_validate_input(${varName})
163212

164213
if(DEFINED parsed_ELSE_VALUE)
165214
set(${varName} "${parsed_ELSE_VALUE}" CACHE INTERNAL "${doc}" FORCE)
@@ -207,41 +256,78 @@ function(_php_set_validate_arguments arguments)
207256
endif()
208257
endfunction()
209258

210-
# Output warning when setting conditional variable and condition is not met.
211-
function(_php_set_validate_input)
212-
get_property(helpString CACHE ${varName} PROPERTY HELPSTRING)
259+
# Validate variable and output warning when a conditional variable is set by the
260+
# user (on command line or CMake presets) and the condition is not met.
261+
# This is for diagnostics purpose for user to be aware that some configuration
262+
# value was not taken into account.
263+
function(_php_set_validate_input var)
264+
get_property(helpString CACHE ${var} PROPERTY HELPSTRING)
213265
if(NOT helpString STREQUAL "No help, variable specified on the command line.")
214266
return()
215267
endif()
216268

217-
if(NOT parsed_WARNING)
218-
set(parsed_WARNING "Variable ${varName}")
219-
if(DEFINED parsed_ELSE_VALUE)
220-
string(
221-
APPEND
222-
parsed_WARNING
223-
" has been overridden (${varName}=${parsed_ELSE_VALUE})"
224-
)
225-
else()
226-
string(
227-
APPEND
228-
parsed_WARNING
229-
" has been overridden to an undefined state"
230-
)
231-
endif()
232-
string(
233-
APPEND
234-
parsed_WARNING
235-
" as it depends on the condition:\n"
236-
"${parsed_IF}\n"
237-
)
269+
if(${var} STREQUAL "${parsed_ELSE_VALUE}")
270+
return()
238271
endif()
239-
set(warning "")
240-
foreach(string ${parsed_WARNING})
241-
string(APPEND warning "${string}")
272+
273+
set(warning "Variable ${var}")
274+
if(DEFINED parsed_ELSE_VALUE)
275+
string(APPEND warning " has been overridden (${var}=${parsed_ELSE_VALUE})")
276+
else()
277+
string(APPEND warning " has been undefined")
278+
endif()
279+
string(
280+
APPEND
281+
warning
282+
" as it depends on the condition:\n"
283+
"${parsed_IF}\n"
284+
"You can probably remove the ${var} configuration value from the build "
285+
"command as it won't be utilized."
286+
)
287+
288+
message(WARNING "${warning}")
289+
endfunction()
290+
291+
# Reset the value passed by the user according to the case sensitivity given in
292+
# the choices list.
293+
function(_php_set_fix_value var)
294+
get_property(value CACHE ${var} PROPERTY VALUE)
295+
get_property(choices CACHE ${var} PROPERTY STRINGS)
296+
297+
string(TOLOWER "${value}" valueLower)
298+
list(TRANSFORM choices TOLOWER OUTPUT_VARIABLE choicesLower)
299+
300+
set(index 0)
301+
foreach(item IN LISTS choicesLower)
302+
if(valueLower STREQUAL "${item}")
303+
list(GET choices ${index} itemOriginal)
304+
if(NOT value STREQUAL "${itemOriginal}")
305+
set_property(CACHE ${var} PROPERTY VALUE ${itemOriginal})
306+
break()
307+
endif()
308+
endif()
309+
math(EXPR index "${index}+1")
242310
endforeach()
311+
endfunction()
312+
313+
# When CHOICES argument is set, validate variable value to match one of the
314+
# choices.
315+
function(_php_set_validate_choices var caseSensitive)
316+
get_property(value CACHE ${var} PROPERTY VALUE)
317+
get_property(choices CACHE ${var} PROPERTY STRINGS)
243318

244-
if(NOT ${varName} STREQUAL "${parsed_ELSE_VALUE}")
245-
message(WARNING "${warning}")
319+
if(NOT caseSensitive)
320+
string(TOLOWER "${value}" value)
321+
list(TRANSFORM choices TOLOWER)
322+
endif()
323+
324+
if(NOT value IN_LIST choices)
325+
list(JOIN choices ", " choices)
326+
327+
message(
328+
FATAL_ERROR
329+
"Unknown value: ${var}=${value}\n"
330+
"Please select one of: ${choices}."
331+
)
246332
endif()
247333
endfunction()

cmake/ext/odbc/CMakeLists.txt

Lines changed: 52 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -22,66 +22,55 @@ cmake_dependent_option(
2222
OFF
2323
)
2424

25-
block()
26-
set(
27-
types
28-
"auto"
29-
"adabas"
30-
"dbmaker"
31-
"empress-bcs"
32-
"empress"
33-
"esoob"
34-
"ibm-db2"
35-
"iODBC"
36-
"sapdb"
37-
"solid"
38-
"unixODBC"
39-
"custom"
40-
)
25+
php_set(
26+
EXT_ODBC_TYPE
27+
TYPE STRING
28+
CHOICES
29+
"auto"
30+
"adabas"
31+
"dbmaker"
32+
"empress-bcs"
33+
"empress"
34+
"esoob"
35+
"ibm-db2"
36+
"iODBC"
37+
"sapdb"
38+
"solid"
39+
"unixODBC"
40+
"custom"
41+
IF EXT_ODBC
42+
VALUE auto
43+
DOC "The ODBC type (library driving the ODBC)"
44+
)
4145

42-
php_set(
43-
EXT_ODBC_TYPE
44-
TYPE STRING
45-
CHOICES ${types}
46-
IF EXT_ODBC
47-
VALUE auto
48-
DOC "The ODBC type (library driving the ODBC)"
46+
# Validate ODBC type for odbc and pdo_odbc extensions. Ideally, the same ODBC
47+
# driver library should be used for both extensions.
48+
if(EXT_ODBC AND EXT_PDO_ODBC AND NOT EXT_ODBC_TYPE STREQUAL EXT_PDO_ODBC_TYPE)
49+
message(
50+
FATAL_ERROR
51+
"Different ODBC types detected for 'odbc' and 'pdo_odbc' PHP "
52+
"extensions:\n"
53+
"EXT_ODBC_TYPE=${EXT_ODBC_TYPE}\n"
54+
"EXT_PDO_ODBC_TYPE=${EXT_PDO_ODBC_TYPE}\n"
55+
"To prevent library symbol collisions when building both 'odbc' and "
56+
"'pdo_odbc' please link with the same ODBC library. Or disable one of "
57+
"the extensions by setting EXT_ODBC or EXT_PDO_ODBC to 'OFF'."
4958
)
59+
endif()
5060

51-
if(EXT_ODBC_TYPE AND NOT EXT_ODBC_TYPE IN_LIST types)
52-
list(JOIN types ", " typesString)
53-
54-
message(
55-
FATAL_ERROR
56-
"Unknown ODBC type value EXT_ODBC_TYPE=${EXT_ODBC_TYPE}. Please "
57-
"select one of: ${typeString}."
58-
)
59-
endif()
60-
61-
# Validate ODBC type.
62-
if(EXT_ODBC AND EXT_PDO_ODBC AND NOT EXT_ODBC_TYPE STREQUAL EXT_PDO_ODBC_TYPE)
63-
message(
64-
FATAL_ERROR
65-
"Different ODBC types detected for 'odbc' and 'pdo_odbc' PHP "
66-
"extensions:\n"
67-
"EXT_ODBC_TYPE=${EXT_ODBC_TYPE}\n"
68-
"EXT_PDO_ODBC_TYPE=${EXT_PDO_ODBC_TYPE}\n"
69-
"To prevent library symbol collisions when building both 'odbc' and "
70-
"'pdo_odbc' please link with the same ODBC library. Or disable one of "
71-
"the extensions by setting EXT_ODBC or EXT_PDO_ODBC to 'OFF'."
72-
)
73-
endif()
74-
75-
# Some ODBC drivers require setting ODBC_LIBRARY manually to find package.
76-
if(NOT EXT_ODBC_TYPE MATCHES "auto|unixODBC|iODBC" AND NOT ODBC_LIBRARY)
77-
message(
78-
FATAL_ERROR
79-
"When using EXT_ODBC_TYPE=${EXT_ODBC_TYPE}, please set also "
80-
"ODBC_LIBRARY and optionally ODBC_INCLUDE_DIR to locate the ODBC "
81-
"installation."
82-
)
83-
endif()
84-
endblock()
61+
# Some ODBC drivers require setting ODBC_LIBRARY manually to find package.
62+
if(
63+
EXT_ODBC
64+
AND NOT EXT_ODBC_TYPE MATCHES "auto|unixODBC|iODBC"
65+
AND NOT ODBC_LIBRARY
66+
)
67+
message(
68+
FATAL_ERROR
69+
"When using EXT_ODBC_TYPE=${EXT_ODBC_TYPE}, please set also "
70+
"ODBC_LIBRARY and optionally ODBC_INCLUDE_DIR to locate the ODBC "
71+
"installation."
72+
)
73+
endif()
8574

8675
php_set(
8776
EXT_ODBC_VERSION
@@ -128,6 +117,12 @@ target_sources(
128117

129118
target_compile_definitions(php_odbc PRIVATE ZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
130119

120+
# TODO: Can this be fixed better?
121+
get_target_property(extension_type php_odbc TYPE)
122+
if(NOT extension_type MATCHES "^(MODULE|SHARED)_LIBRARY$")
123+
target_link_libraries(php_odbc PRIVATE PHP::main)
124+
endif()
125+
131126
if(NOT EXT_ODBC_TYPE STREQUAL "auto")
132127
set(ODBC_USE_DRIVER "${EXT_ODBC_TYPE}")
133128
endif()

0 commit comments

Comments
 (0)