jdbc/cmake/DepFindMySQL.cmake (457 lines of code) (raw):
# Copyright (c) 2008, 2024, Oracle and/or its affiliates.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0, as
# published by the Free Software Foundation.
#
# This program is designed to work with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms, as
# designated in a particular file or component or in included license
# documentation. The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have either included with
# the program or referenced in the documentation.
#
# Without limiting anything contained in the foregoing, this file,
# which is part of Connector/C++, is also subject to the
# Universal FOSS Exception, version 1.0, a copy of which can be found at
# https://oss.oracle.com/licenses/universal-foss-exception.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
##########################################################################
#
# Input:
#
# WITH_MYSQL | MYSQL_DIR | MYSQL_INCLUDE_DIR + MYSQL_LIB_DIR
# MYSQL_CONFIG_EXECUTABLE
# MYSQL_LIB_STATIC - Determines meaning of MySQL::client target
#
# Output:
#
# MySQL::client-shared - target for shared library (not implemented yet)
# MySQL::client-static - target for static library
# MySQL::client - points at shared library, or static library if
# MYSQL_LIB_STATIC is set
#
# MYSQL_VERSION, MYSQL_VERSION_ID
# MYSQL_INCLUDE_DIR
# MYSQL_LIB_DIR
# MYSQL_PLUGIN_DIR
# MYSQL_EXTERNAL_DEPENDENCIES
# MYSQL_EXTERNAL_SEARCHPATH
#
##########################################################################
add_config_option(MYSQL_CONFIG_EXECUTABLE PATH ADVANCED
"Location of mysql_config program."
)
add_config_option(WITH_MYSQL PATH
"Base location of (monolithic) MySQL installation."
)
add_config_option(MYSQL_INCLUDE_DIR PATH ADVANCED "Path to MYSQL headers.")
add_config_option(MYSQL_LIB_DIR PATH ADVANCED "Path to MYSQL libraries.")
add_config_option(MYSQL_PLUGIN_DIR PATH ADVANCED "Path to MYSQL plugin libraries.")
function(main)
if(TARGET MySQL::client)
return()
endif()
message("Looking for MySQL Client library:")
if(MYSQL_CONFIG_EXECUTABLE)
use_mysql_config()
else()
# Note: legacy behavior (use MYSQL_DIR env. variable if set)
if(NOT DEFINED MYSQL_DIR AND DEFINED ENV{MYSQL_DIR})
set(MYSQL_DIR "$ENV{MYSQL_DIR}")
endif()
if(DEFINED WITH_MYSQL)
set(MYSQL_DIR "${WITH_MYSQL}")
endif()
if(NOT DEFINED MYSQL_INCLUDE_DIR OR NOT DEFINED MYSQL_LIB_DIR)
# Try using mysql_config, if available
if(MYSQL_DIR)
find_program(MYSQL_CONFIG_EXECUTABLE
NAMES mysql_config
PATHS ${MYSQL_DIR}/bin
NO_DEFAULT_PATH
)
else()
find_program(MYSQL_CONFIG_EXECUTABLE
NAMES mysql_config
)
endif()
if(MYSQL_CONFIG_EXECUTABLE)
use_mysql_config()
endif()
# If paths still not set, try default locations
if(NOT DEFINED MYSQL_INCLUDE_DIR AND MYSQL_DIR)
set(MYSQL_INCLUDE_DIR "${MYSQL_DIR}/include")
endif()
if(NOT DEFINED MYSQL_LIB_DIR AND MYSQL_DIR)
set(MYSQL_LIB_DIR "${MYSQL_DIR}/lib")
endif()
if(NOT DEFINED MYSQL_PLUGIN_DIR AND MYSQL_LIB_DIR)
set(MYSQL_PLUGIN_DIR "${MYSQL_LIB_DIR}/plugin")
endif()
endif()
endif(MYSQL_CONFIG_EXECUTABLE)
if(NOT MYSQL_INCLUDE_DIR OR NOT EXISTS "${MYSQL_INCLUDE_DIR}/mysql.h")
message(FATAL_ERROR
"Could not find MySQL headers at: ${MYSQL_INCLUDE_DIR}\n"
"Point at MySQL client library location using WITH_MYSQL or"
" MYSQL_INCLUDE_DIR, MYSQL_LIB_DIR settings."
)
endif()
#
# Update cached values to the computed ones
#
set(MYSQL_INCLUDE_DIR "${MYSQL_INCLUDE_DIR}"
CACHE PATH "Path to MYSQL headers (computed)."
FORCE
)
set(MYSQL_LIB_DIR "${MYSQL_LIB_DIR}"
CACHE PATH "Path to MYSQL libraries (computed)."
FORCE
)
set(MYSQL_PLUGIN_DIR "${MYSQL_PLUGIN_DIR}"
CACHE PATH "Path to MYSQL plugin libraries (computed)."
FORCE
)
#
# Searching for library.
#
# TODO: lib64/?
# TODO: Handle both static and dynamic library
find_library(MYSQL_LIB
NAMES ${CMAKE_STATIC_LIBRARY_PREFIX}mysqlclient${CMAKE_STATIC_LIBRARY_SUFFIX}
PATHS ${MYSQL_LIB_DIR}
NO_DEFAULT_PATH
)
find_library(MYSQL_LIB_DEBUG
NAMES ${CMAKE_STATIC_LIBRARY_PREFIX}mysqlclient${CMAKE_STATIC_LIBRARY_SUFFIX}
PATHS "${MYSQL_LIB_DIR}/debug"
NO_DEFAULT_PATH
)
if(NOT WIN32)
find_library(MYSQL_DLL
NAMES ${CMAKE_DYNAMIC_LIBRARY_PREFIX}mysqlclient${CMAKE_DYNAMIC_LIBRARY_SUFFIX}
PATHS ${MYSQL_LIB_DIR}
NO_DEFAULT_PATH
)
find_library(MYSQL_DLL_DEBUG
NAMES ${CMAKE_DYNAMIC_LIBRARY_PREFIX}mysqlclient${CMAKE_DYNAMIC_LIBRARY_SUFFIX}
PATHS "${MYSQL_LIB_DIR}/debug"
NO_DEFAULT_PATH
)
else() #WIN32
find_library(MYSQL_DLL
NAMES libmysql
PATHS ${MYSQL_LIB_DIR}
NO_DEFAULT_PATH
)
find_library(MYSQL_DLL_DEBUG
NAMES libmysql
PATHS "${MYSQL_LIB_DIR}/debug"
NO_DEFAULT_PATH
)
find_library(MYSQL_DLL_IMP
NAMES libmysql.lib
PATHS ${MYSQL_LIB_DIR}
NO_DEFAULT_PATH
)
find_library(MYSQL_DLL_IMP_DEBUG
NAMES libmysql.lib
PATHS "${MYSQL_LIB_DIR}/debug"
NO_DEFAULT_PATH
)
endif()
#message("-- static lib: ${MYSQL_LIB}")
#message("-- debug lib: ${MYSQL_LIB_DEBUG}")
#
# Unless we are on Win, we try using optimized lib also for debug builds if
# debug variant was not found, and the other way around.
#
# On Windows this is not going to work. If correct variant of the client lib
# is not available, build will fail.
#
if(NOT WIN32)
if (NOT MYSQL_LIB_DEBUG)
set(MYSQL_LIB_DEBUG "${MYSQL_LIB}")
endif()
if (NOT MYSQL_LIB)
set(MYSQL_LIB "${MYSQL_LIB_DEBUG}")
endif()
if (NOT MYSQL_DLL_DEBUG)
set(MYSQL_DLL_DEBUG "${MYSQL_DLL}")
endif()
if (NOT MYSQL_DLL)
set(MYSQL_DLL "${MYSQL_DLL_DEBUG}")
endif()
endif()
#
# Define import target for the client library (currently only static)
#
add_library(MySQL::client-static STATIC IMPORTED GLOBAL)
set_target_properties(MySQL::client-static PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${MYSQL_INCLUDE_DIR}"
IMPORTED_LOCATION "${MYSQL_LIB}"
IMPORTED_LOCATION_DEBUG "${MYSQL_LIB_DEBUG}"
)
add_library(MySQL::client-shared SHARED IMPORTED GLOBAL)
set_target_properties(MySQL::client-shared PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${MYSQL_INCLUDE_DIR}"
IMPORTED_LOCATION "${MYSQL_DLL}"
IMPORTED_LOCATION_DEBUG "${MYSQL_DLL_DEBUG}"
)
if (WIN32)
if(MYSQL_DLL_IMP)
set_target_properties(MySQL::client-shared PROPERTIES
IMPORTED_IMPLIB "${MYSQL_DLL_IMP}")
endif()
if(MYSQL_DLL_IMP_DEBUG)
set_target_properties(MySQL::client-shared PROPERTIES
IMPORTED_IMPLIB_DEBUG "${MYSQL_DLL_IMP_DEBUG}")
endif()
endif()
# Define alias MySQL::client pointing to -static or -shared library,
# depending on MYSQL_LIB_STATIC setting.
#
# Note: In older cmake versions it is not possible to make an alias
# to imported target. For that reason we create alias to interface target
# that depends on the final imported library.
add_library(mysql-client-if INTERFACE)
set_target_properties(mysql-client-if PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${MYSQL_INCLUDE_DIR}"
)
if(MYSQL_LIB_STATIC)
target_link_libraries(mysql-client-if INTERFACE MySQL::client-static)
else()
target_link_libraries(mysql-client-if INTERFACE MySQL::client-shared)
endif()
add_library(MySQL::client ALIAS mysql-client-if)
#
# Determine library version
#
get_version()
if(NOT MYSQL_VERSION)
message(FATAL_ERROR
"Could not determine the MySQL client library version."
)
endif()
set_property(TARGET MySQL::client-static
PROPERTY VERSION ${MYSQL_VERSION}
)
set_property(TARGET MySQL::client-shared
PROPERTY VERSION ${MYSQL_VERSION}
)
#
# Detect shared libraries on which MySQL client lib depends (if possible).
# Stores result in MYSQL_EXTERNAL_DEPENDENCIES.
#
get_dependencies()
message(" version: ${MYSQL_VERSION}")
get_target_property(dummy MySQL::client-shared INTERFACE_INCLUDE_DIRECTORIES)
message(" include path: ${dummy}")
get_target_property(dummy MySQL::client-shared IMPORTED_LOCATION)
message(" library location: ${dummy}")
# Using INTERFACE_LINK_LIBRARIES we ensure that -L option will appear
# in the link line of the consumer of this library. Adding this -L option
# is needed to resolve dependencies, such as -lssl, to the libraries that
# are bundled with the server.
#
# Note: This must be done before populating INTERFACE_LINK_LIBRARIES with
# the dependencies themselves.
if(NOT MSVC)
set(searchpath "")
list(APPEND searchpath "-L${MYSQL_LIB_DIR}"
"-L${MYSQL_LIB_DIR}/private")
if(MYSQL_EXTERNAL_SEARCHPATH)
foreach(search ${MYSQL_EXTERNAL_SEARCHPATH})
list(APPEND searchpath "-L${search}")
endforeach()
endif()
string(REPLACE ";" " " searchpath "${searchpath}")
message(" dependencies search path: ${searchpath}")
set_property(TARGET MySQL::client-static
PROPERTY INTERFACE_LINK_LIBRARIES
"${searchpath}"
)
set_property(TARGET MySQL::client-shared
PROPERTY INTERFACE_LINK_LIBRARIES
"${searchpath}"
)
endif()
if(MYSQL_EXTERNAL_DEPENDENCIES)
string(REPLACE ";" " " deps "${MYSQL_EXTERNAL_DEPENDENCIES}")
message(" dependencies: ${deps}")
#
# If external dependencies were found, add them to the static target
# as any code that links to static library should also link with the
# external dependencies.
#
target_link_libraries(MySQL::client-static INTERFACE ${MYSQL_EXTERNAL_DEPENDENCIES})
endif()
endfunction(main)
##################################################################
function(get_version)
# MYSQL_VERSION could have been already determined in use_mysql_config()
if(NOT MYSQL_VERSION)
#
# If mysql_config could not be used, we compile small program that takes
# version information from the client library headers.
#
set(GETMYSQLVERSION_SOURCEFILE
"${CMAKE_CURRENT_BINARY_DIR}/getmysqlversion.c"
)
file(WRITE "${GETMYSQLVERSION_SOURCEFILE}"
"#include <mysql.h>\n"
"#include <stdio.h>\n"
"int main() {\n"
" printf(\"%s\", MYSQL_SERVER_VERSION);\n"
"}\n"
)
# Compile and run the created executable, store output in MYSQL_VERSION
try_run(_run_result _compile_result
"${CMAKE_BINARY_DIR}"
"${GETMYSQLVERSION_SOURCEFILE}"
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${MYSQL_INCLUDE_DIR}"
RUN_OUTPUT_VARIABLE MYSQL_VERSION
COMPILE_OUTPUT_VARIABLE _compile_out
)
#message("DBG: Running \"getmysqlversion\": (compile: ${_compile_result}) (run: ${_run_result})")
#if (NOT _compile_result)
# message(FATAL_ERROR "compilation failed:\n\n${_compile_out}")
#endif()
endif()
# Clean up so only numeric, in case of "-alpha" or similar. Compute
# MYSQL_VERSION_ID and MYSQL_NUM_VERSION
string(REGEX MATCHALL "([0-9]+.[0-9]+.[0-9]+)" MYSQL_VERSION "${MYSQL_VERSION}")
# To create a fully numeric version, first normalize so N.NN.NN
string(REGEX REPLACE "[.]([0-9])[.]" ".0\\1." MYSQL_VERSION_ID "${MYSQL_VERSION}")
string(REGEX REPLACE "[.]([0-9])$" ".0\\1" MYSQL_VERSION_ID "${MYSQL_VERSION_ID}")
# Finally remove the dot
string(REGEX REPLACE "[.]" "" MYSQL_VERSION_ID "${MYSQL_VERSION_ID}")
set(MYSQL_VERSION ${MYSQL_VERSION} CACHE INTERNAL "MySQL client library version")
set(MYSQL_VERSION_ID ${MYSQL_VERSION_ID} CACHE INTERNAL "MySQL client library version")
set(MYSQL_NUM_VERSION ${MYSQL_VERSION_ID} CACHE INTERNAL "MySQL client library version")
endfunction(get_version)
##################################################################
function(get_dependencies)
# Currently the only way of determining dependencies is
# via mysql_config, which should happen in use_mysql_config()
#
# TODO: Find a way of extracting MYSQL_EXTERNAL_DEPENDENCIES also
# on Windows
set(MYSQL_EXTERNAL_DEPENDENCIES "${MYSQL_EXTERNAL_DEPENDENCIES}"
CACHE INTERNAL
"List of external libraries on which MySQL client library depends."
)
set(MYSQL_EXTERNAL_SEARCHPATH "${MYSQL_EXTERNAL_SEARCHPATH}"
CACHE INTERNAL
"List of locations of external libraries on which MySQL client library depends as reported by mysql_config."
)
endfunction(get_dependencies)
##################################################################
function(use_mysql_config)
if(NOT EXISTS "${MYSQL_CONFIG_EXECUTABLE}")
#message("-- mysql_config not fount")
return()
endif()
# Install location
_mysql_conf(MYSQL_INCLUDE_DIR --variable=pkgincludedir)
_mysql_conf(MYSQL_LIB_DIR --variable=pkglibdir)
file(TO_CMAKE_PATH "${MYSQL_INCLUDE_DIR}" MYSQL_INCLUDE_DIR)
file(TO_CMAKE_PATH "${MYSQL_LIB_DIR}" MYSQL_LIB_DIR)
set(MYSQL_INCLUDE_DIR "${MYSQL_INCLUDE_DIR}" PARENT_SCOPE)
set(MYSQL_LIB_DIR "${MYSQL_LIB_DIR}" PARENT_SCOPE)
if(NOT MYSQL_PLUGIN_DIR)
_mysql_conf(MYSQL_PLUGIN_DIR --variable=plugindir)
file(TO_CMAKE_PATH "${MYSQL_PLUGIN_DIR}" MYSQL_PLUGIN_DIR)
set(MYSQL_PLUGIN_DIR "${MYSQL_PLUGIN_DIR}" PARENT_SCOPE)
endif()
# client library version (note: it will be cleaned up in get_version())
_mysql_conf(MYSQL_VERSION --version)
set(MYSQL_VERSION "${MYSQL_VERSION}" PARENT_SCOPE)
# Find external dependencies
set(MYSQL_EXTERNAL_DEPENDENCIES "")
_mysql_conf(config_libs_paths --libs)
string(REGEX MATCHALL " -l[^ ]+" config_libs ${config_libs_paths})
# message("-- libs: ${config_libs}")
foreach(lib ${config_libs})
string(REGEX REPLACE " -l([^ ]+)" "\\1" lib ${lib})
#message("-- checking lib: ${lib}")
# Libraries that are known to be internal compiler ones are not set as
# explicit dependencies.
# Openssl dependency is treated differently, respecting users WITH_SSL
# option.
if(NOT lib MATCHES
"(mysqlclient|libmysql|^stdc|^gcc|^CrunG3|^c$|^statomic)"
#|^ssl|^crypto)"
)
list(APPEND MYSQL_EXTERNAL_DEPENDENCIES ${lib})
else()
#message("-- skipping it")
endif()
endforeach()
set(MYSQL_EXTERNAL_DEPENDENCIES "${MYSQL_EXTERNAL_DEPENDENCIES}" PARENT_SCOPE)
# check if --libs have libs search path
set(MYSQL_EXTERNAL_SEARCHPATH "")
string(REGEX MATCHALL " -L[^ ]+" config_lib_search_path ${config_libs_paths})
message("-- libs search path: ${config_lib_search_path}")
foreach(search ${config_lib_search_path})
string(REGEX REPLACE " -L([^ ]+)" "\\1" search ${search})
message("-- checking search path: ${search}")
list(APPEND MYSQL_EXTERNAL_SEARCHPATH ${search})
endforeach()
set(MYSQL_EXTERNAL_SEARCHPATH "${MYSQL_EXTERNAL_SEARCHPATH}" PARENT_SCOPE)
endfunction(use_mysql_config)
##################################################################
# mysql_config helpers
# ----------------------------------------------------------------------
#
# Macro that runs "mysql_config ${_opt}" and return the line after
# trimming away ending space/newline.
#
# _mysql_conf(
# _var - output variable name, will contain a ';' separated list
# _opt - the flag to give to mysql_config
#
# ----------------------------------------------------------------------
macro(_mysql_conf _var _opt)
execute_process(
COMMAND ${MYSQL_CONFIG_EXECUTABLE} ${_opt}
OUTPUT_VARIABLE ${_var}
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endmacro()
# ----------------------------------------------------------------------
#
# Macro that runs "mysql_config ${_opt}", selects output args using a
# regex, and clean it up a bit removing space/tab/newline before
# setting it to a variable.
#
# _mysql_config(
# _var - output variable name, will contain a ';' separated list
# _regex - regular expression matching the prefix of args to select
# _opt - the flag to give to mysql_config
#
# ----------------------------------------------------------------------
macro(_mysql_config _var _regex _opt)
_mysql_conf(_mysql_config_output ${_opt})
string(REGEX MATCHALL "${_regex}([^ ]+)" _mysql_config_output "${_mysql_config_output}")
string(REGEX REPLACE "^[ \t]+" "" _mysql_config_output "${_mysql_config_output}")
IF(CMAKE_SYSTEM_NAME MATCHES "SunOS")
string(REGEX REPLACE " -latomic" "" _mysql_config_output "${_mysql_config_output}")
ENDIF()
string(REGEX REPLACE "${_regex}" "" _mysql_config_output "${_mysql_config_output}")
separate_arguments(_mysql_config_output)
set(${_var} ${_mysql_config_output})
endmacro()
######################################################################
main()
return()