Skip to content

Commit 14538b2

Browse files
authored
Use pkg-config instead of mysql_config (#586)
MySQL breaks mysql_config often. Use pkg-config instead. Fixes #584
1 parent d065827 commit 14538b2

6 files changed

+65
-143
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ $ pip install mysqlclient
8383

8484
### Customize build (POSIX)
8585

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

8989
You can use `MYSQLCLIENT_CFLAGS` and `MYSQLCLIENT_LDFLAGS` environment

metadata.cfg

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[metadata]
2-
version: 2.1.1
3-
version_info: (2,1,1,'final',0)
2+
name: mysqlclient
3+
version: 2.1.2
4+
version_info: (2,1,2,'dev',0)
45
description: Python interface to MySQL
56
author: Inada Naoki
67
author_email: [email protected]

setup_common.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from configparser import ConfigParser as SafeConfigParser
1+
from configparser import ConfigParser
22

33

44
def get_metadata_and_options():
5-
config = SafeConfigParser()
5+
config = ConfigParser()
66
config.read(["metadata.cfg", "site.cfg"])
77

88
metadata = dict(config.items("metadata"))

setup_posix.py

+52-126
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,94 @@
11
import os
22
import sys
3+
import subprocess
34

4-
# This dequote() business is required for some older versions
5-
# of mysql_config
65

7-
8-
def dequote(s):
9-
if not s:
10-
raise Exception(
11-
"Wrong MySQL configuration: maybe https://bugs.mysql.com/bug.php?id=86971 ?"
12-
)
13-
if s[0] in "\"'" and s[0] == s[-1]:
14-
s = s[1:-1]
15-
return s
16-
17-
18-
_mysql_config_path = "mysql_config"
19-
20-
21-
def mysql_config(what):
22-
cmd = "{} --{}".format(_mysql_config_path, what)
23-
print(cmd)
24-
f = os.popen(cmd)
25-
data = f.read().strip().split()
26-
ret = f.close()
27-
if ret:
28-
if ret / 256:
29-
data = []
30-
if ret / 256 > 1:
31-
raise OSError("{} not found".format(_mysql_config_path))
32-
print(data)
33-
return data
6+
def find_package_name():
7+
"""Get available pkg-config package name"""
8+
packages = ["mysqlclient", "mariadb"]
9+
for pkg in packages:
10+
try:
11+
cmd = f"pkg-config --exists {pkg}"
12+
print(f"Trying {cmd}")
13+
subprocess.check_call(cmd, shell=True)
14+
except subprocess.CalledProcessError as err:
15+
print(err)
16+
else:
17+
return pkg
18+
raise Exception("Can not find valid pkg-config")
3419

3520

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

39-
global _mysql_config_path
40-
4124
metadata, options = get_metadata_and_options()
4225

43-
if "mysql_config" in options:
44-
_mysql_config_path = options["mysql_config"]
45-
else:
46-
try:
47-
mysql_config("version")
48-
except OSError:
49-
# try mariadb_config
50-
_mysql_config_path = "mariadb_config"
51-
try:
52-
mysql_config("version")
53-
except OSError:
54-
_mysql_config_path = "mysql_config"
55-
56-
extra_objects = []
5726
static = enabled(options, "static")
58-
5927
# allow a command-line option to override the base config file to permit
6028
# a static build to be created via requirements.txt
6129
#
6230
if "--static" in sys.argv:
6331
static = True
6432
sys.argv.remove("--static")
6533

66-
libs = os.environ.get("MYSQLCLIENT_LDFLAGS")
67-
if libs:
68-
libs = libs.strip().split()
69-
else:
70-
libs = mysql_config("libs")
71-
library_dirs = [dequote(i[2:]) for i in libs if i.startswith("-L")]
72-
libraries = [dequote(i[2:]) for i in libs if i.startswith("-l")]
73-
extra_link_args = [x for x in libs if not x.startswith(("-l", "-L"))]
74-
34+
ldflags = os.environ.get("MYSQLCLIENT_LDFLAGS")
7535
cflags = os.environ.get("MYSQLCLIENT_CFLAGS")
76-
if cflags:
77-
use_mysqlconfig_cflags = False
78-
cflags = cflags.strip().split()
79-
else:
80-
use_mysqlconfig_cflags = True
81-
cflags = mysql_config("cflags")
82-
83-
include_dirs = []
84-
extra_compile_args = ["-std=c99"]
8536

86-
for a in cflags:
87-
if a.startswith("-I"):
88-
include_dirs.append(dequote(a[2:]))
89-
elif a.startswith(("-L", "-l")): # This should be LIBS.
90-
pass
91-
else:
92-
extra_compile_args.append(a.replace("%", "%%"))
93-
94-
# Copy the arch flags for linking as well
95-
try:
96-
i = extra_compile_args.index("-arch")
97-
if "-arch" not in extra_link_args:
98-
extra_link_args += ["-arch", extra_compile_args[i + 1]]
99-
except ValueError:
100-
pass
37+
pkg_name = None
38+
static_opt = " --static" if static else ""
39+
if not (cflags and ldflags):
40+
pkg_name = find_package_name()
41+
if not cflags:
42+
cflags = subprocess.check_output(
43+
f"pkg-config{static_opt} --cflags {pkg_name}", encoding="utf-8", shell=True
44+
)
45+
if not ldflags:
46+
ldflags = subprocess.check_output(
47+
f"pkg-config{static_opt} --libs {pkg_name}", encoding="utf-8", shell=True
48+
)
10149

102-
if static:
103-
# properly handle mysql client libraries that are not called libmysqlclient
104-
client = None
105-
CLIENT_LIST = [
106-
"mysqlclient",
107-
"mysqlclient_r",
108-
"mysqld",
109-
"mariadb",
110-
"mariadbclient",
111-
"perconaserverclient",
112-
"perconaserverclient_r",
113-
]
114-
for c in CLIENT_LIST:
115-
if c in libraries:
116-
client = c
117-
break
118-
119-
if client == "mariadb":
120-
client = "mariadbclient"
121-
if client is None:
122-
raise ValueError("Couldn't identify mysql client library")
123-
124-
extra_objects.append(os.path.join(library_dirs[0], "lib%s.a" % client))
125-
if client in libraries:
126-
libraries.remove(client)
50+
cflags = cflags.split()
51+
for f in cflags:
52+
if f.startswith("-std="):
53+
break
12754
else:
128-
if use_mysqlconfig_cflags:
129-
# mysql_config may have "-lmysqlclient -lz -lssl -lcrypto", but zlib and
130-
# ssl is not used by _mysql. They are needed only for static build.
131-
for L in ("crypto", "ssl", "z", "zstd"):
132-
if L in libraries:
133-
libraries.remove(L)
55+
cflags += ["-std=c99"]
13456

135-
name = "mysqlclient"
136-
metadata["name"] = name
57+
ldflags = ldflags.split()
13758

13859
define_macros = [
13960
("version_info", metadata["version_info"]),
14061
("__version__", metadata["version"]),
14162
]
142-
create_release_file(metadata)
143-
del metadata["version_info"]
63+
64+
# print(f"{cflags = }")
65+
# print(f"{ldflags = }")
66+
# print(f"{define_macros = }")
67+
14468
ext_options = dict(
145-
library_dirs=library_dirs,
146-
libraries=libraries,
147-
extra_compile_args=extra_compile_args,
148-
extra_link_args=extra_link_args,
149-
include_dirs=include_dirs,
150-
extra_objects=extra_objects,
69+
extra_compile_args=cflags,
70+
extra_link_args=ldflags,
15171
define_macros=define_macros,
15272
)
153-
15473
# newer versions of gcc require libstdc++ if doing a static build
15574
if static:
15675
ext_options["language"] = "c++"
15776

158-
print("ext_options:")
77+
print("Options for building extention module:")
15978
for k, v in ext_options.items():
160-
print(" {}: {}".format(k, v))
79+
print(f" {k}: {v}")
80+
81+
create_release_file(metadata)
82+
del metadata["version_info"]
16183

16284
return metadata, ext_options
16385

16486

16587
if __name__ == "__main__":
166-
sys.stderr.write(
167-
"""You shouldn't be running this directly; it is used by setup.py."""
168-
)
88+
from pprint import pprint
89+
90+
metadata, config = get_config()
91+
print("# Metadata")
92+
pprint(metadata, sort_dicts=False, compact=True)
93+
print("\n# Extention options")
94+
pprint(config, sort_dicts=False, compact=True)

setup_windows.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import os
2-
import sys
32

43

54
def get_config():
@@ -38,9 +37,6 @@ def get_config():
3837

3938
extra_link_args = ["/MANIFEST"]
4039

41-
name = "mysqlclient"
42-
metadata["name"] = name
43-
4440
define_macros = [
4541
("version_info", metadata["version_info"]),
4642
("__version__", metadata["version"]),
@@ -59,6 +55,10 @@ def get_config():
5955

6056

6157
if __name__ == "__main__":
62-
sys.stderr.write(
63-
"""You shouldn't be running this directly; it is used by setup.py."""
64-
)
58+
from pprint import pprint
59+
60+
metadata, config = get_config()
61+
print("# Metadata")
62+
pprint(metadata)
63+
print("\n# Extention options")
64+
pprint(config)

site.cfg

-5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@
22
# static: link against a static library
33
static = False
44

5-
# The path to mysql_config.
6-
# Only use this if mysql_config is not on your PATH, or you have some weird
7-
# setup that requires it.
8-
#mysql_config = /usr/local/bin/mysql_config
9-
105
# http://stackoverflow.com/questions/1972259/mysql-python-install-problem-using-virtualenv-windows-pip
116
# Windows connector libs for MySQL. You need a 32-bit connector for your 32-bit Python build.
127
connector =

0 commit comments

Comments
 (0)