Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use pkg-config instead of mysql_config #586

Merged
merged 4 commits into from
May 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ $ pip install mysqlclient

### Customize build (POSIX)

mysqlclient uses `mysql_config` or `mariadb_config` by default for finding
mysqlclient uses `pkg-config --clfags --ldflags mysqlclient` by default for finding
compiler/linker flags.

You can use `MYSQLCLIENT_CFLAGS` and `MYSQLCLIENT_LDFLAGS` environment
Expand Down
5 changes: 3 additions & 2 deletions metadata.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[metadata]
version: 2.1.1
version_info: (2,1,1,'final',0)
name: mysqlclient
version: 2.1.2
version_info: (2,1,2,'dev',0)
description: Python interface to MySQL
author: Inada Naoki
author_email: songofacandy@gmail.com
Expand Down
4 changes: 2 additions & 2 deletions setup_common.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from configparser import ConfigParser as SafeConfigParser
from configparser import ConfigParser


def get_metadata_and_options():
config = SafeConfigParser()
config = ConfigParser()
config.read(["metadata.cfg", "site.cfg"])

metadata = dict(config.items("metadata"))
Expand Down
178 changes: 52 additions & 126 deletions setup_posix.py
Original file line number Diff line number Diff line change
@@ -1,168 +1,94 @@
import os
import sys
import subprocess

# This dequote() business is required for some older versions
# of mysql_config


def dequote(s):
if not s:
raise Exception(
"Wrong MySQL configuration: maybe https://bugs.mysql.com/bug.php?id=86971 ?"
)
if s[0] in "\"'" and s[0] == s[-1]:
s = s[1:-1]
return s


_mysql_config_path = "mysql_config"


def mysql_config(what):
cmd = "{} --{}".format(_mysql_config_path, what)
print(cmd)
f = os.popen(cmd)
data = f.read().strip().split()
ret = f.close()
if ret:
if ret / 256:
data = []
if ret / 256 > 1:
raise OSError("{} not found".format(_mysql_config_path))
print(data)
return data
def find_package_name():
"""Get available pkg-config package name"""
packages = ["mysqlclient", "mariadb"]
for pkg in packages:
try:
cmd = f"pkg-config --exists {pkg}"
print(f"Trying {cmd}")
subprocess.check_call(cmd, shell=True)
except subprocess.CalledProcessError as err:
print(err)
else:
return pkg
raise Exception("Can not find valid pkg-config")


def get_config():
from setup_common import get_metadata_and_options, enabled, create_release_file

global _mysql_config_path

metadata, options = get_metadata_and_options()

if "mysql_config" in options:
_mysql_config_path = options["mysql_config"]
else:
try:
mysql_config("version")
except OSError:
# try mariadb_config
_mysql_config_path = "mariadb_config"
try:
mysql_config("version")
except OSError:
_mysql_config_path = "mysql_config"

extra_objects = []
static = enabled(options, "static")

# allow a command-line option to override the base config file to permit
# a static build to be created via requirements.txt
#
if "--static" in sys.argv:
static = True
sys.argv.remove("--static")

libs = os.environ.get("MYSQLCLIENT_LDFLAGS")
if libs:
libs = libs.strip().split()
else:
libs = mysql_config("libs")
library_dirs = [dequote(i[2:]) for i in libs if i.startswith("-L")]
libraries = [dequote(i[2:]) for i in libs if i.startswith("-l")]
extra_link_args = [x for x in libs if not x.startswith(("-l", "-L"))]

ldflags = os.environ.get("MYSQLCLIENT_LDFLAGS")
cflags = os.environ.get("MYSQLCLIENT_CFLAGS")
if cflags:
use_mysqlconfig_cflags = False
cflags = cflags.strip().split()
else:
use_mysqlconfig_cflags = True
cflags = mysql_config("cflags")

include_dirs = []
extra_compile_args = ["-std=c99"]

for a in cflags:
if a.startswith("-I"):
include_dirs.append(dequote(a[2:]))
elif a.startswith(("-L", "-l")): # This should be LIBS.
pass
else:
extra_compile_args.append(a.replace("%", "%%"))

# Copy the arch flags for linking as well
try:
i = extra_compile_args.index("-arch")
if "-arch" not in extra_link_args:
extra_link_args += ["-arch", extra_compile_args[i + 1]]
except ValueError:
pass
pkg_name = None
static_opt = " --static" if static else ""
if not (cflags and ldflags):
pkg_name = find_package_name()
if not cflags:
cflags = subprocess.check_output(
f"pkg-config{static_opt} --cflags {pkg_name}", encoding="utf-8", shell=True
)
if not ldflags:
ldflags = subprocess.check_output(
f"pkg-config{static_opt} --libs {pkg_name}", encoding="utf-8", shell=True
)

if static:
# properly handle mysql client libraries that are not called libmysqlclient
client = None
CLIENT_LIST = [
"mysqlclient",
"mysqlclient_r",
"mysqld",
"mariadb",
"mariadbclient",
"perconaserverclient",
"perconaserverclient_r",
]
for c in CLIENT_LIST:
if c in libraries:
client = c
break

if client == "mariadb":
client = "mariadbclient"
if client is None:
raise ValueError("Couldn't identify mysql client library")

extra_objects.append(os.path.join(library_dirs[0], "lib%s.a" % client))
if client in libraries:
libraries.remove(client)
cflags = cflags.split()
for f in cflags:
if f.startswith("-std="):
break
else:
if use_mysqlconfig_cflags:
# mysql_config may have "-lmysqlclient -lz -lssl -lcrypto", but zlib and
# ssl is not used by _mysql. They are needed only for static build.
for L in ("crypto", "ssl", "z", "zstd"):
if L in libraries:
libraries.remove(L)
cflags += ["-std=c99"]

name = "mysqlclient"
metadata["name"] = name
ldflags = ldflags.split()

define_macros = [
("version_info", metadata["version_info"]),
("__version__", metadata["version"]),
]
create_release_file(metadata)
del metadata["version_info"]

# print(f"{cflags = }")
# print(f"{ldflags = }")
# print(f"{define_macros = }")

ext_options = dict(
library_dirs=library_dirs,
libraries=libraries,
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
include_dirs=include_dirs,
extra_objects=extra_objects,
extra_compile_args=cflags,
extra_link_args=ldflags,
define_macros=define_macros,
)

# newer versions of gcc require libstdc++ if doing a static build
if static:
ext_options["language"] = "c++"

print("ext_options:")
print("Options for building extention module:")
for k, v in ext_options.items():
print(" {}: {}".format(k, v))
print(f" {k}: {v}")

create_release_file(metadata)
del metadata["version_info"]

return metadata, ext_options


if __name__ == "__main__":
sys.stderr.write(
"""You shouldn't be running this directly; it is used by setup.py."""
)
from pprint import pprint

metadata, config = get_config()
print("# Metadata")
pprint(metadata, sort_dicts=False, compact=True)
print("\n# Extention options")
pprint(config, sort_dicts=False, compact=True)
14 changes: 7 additions & 7 deletions setup_windows.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import os
import sys


def get_config():
Expand Down Expand Up @@ -38,9 +37,6 @@ def get_config():

extra_link_args = ["/MANIFEST"]

name = "mysqlclient"
metadata["name"] = name

define_macros = [
("version_info", metadata["version_info"]),
("__version__", metadata["version"]),
Expand All @@ -59,6 +55,10 @@ def get_config():


if __name__ == "__main__":
sys.stderr.write(
"""You shouldn't be running this directly; it is used by setup.py."""
)
from pprint import pprint

metadata, config = get_config()
print("# Metadata")
pprint(metadata)
print("\n# Extention options")
pprint(config)
5 changes: 0 additions & 5 deletions site.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@
# static: link against a static library
static = False

# The path to mysql_config.
# Only use this if mysql_config is not on your PATH, or you have some weird
# setup that requires it.
#mysql_config = /usr/local/bin/mysql_config

# http://stackoverflow.com/questions/1972259/mysql-python-install-problem-using-virtualenv-windows-pip
# Windows connector libs for MySQL. You need a 32-bit connector for your 32-bit Python build.
connector =