29
29
from distutils .command .install_lib import install_lib
30
30
from distutils .errors import DistutilsExecError
31
31
from distutils .util import get_platform
32
- from distutils .dir_util import copy_tree
32
+ from distutils .version import LooseVersion
33
+ from distutils .dir_util import copy_tree , mkpath
34
+ from distutils .sysconfig import get_python_lib
33
35
from distutils import log
34
36
from glob import glob
35
37
import os
@@ -160,6 +162,8 @@ def parse_mysql_config_info(options, stdout):
160
162
161
163
info ['version' ] = tuple ([int (v ) for v in ver .split ('.' )[0 :3 ]])
162
164
libs = shlex .split (info ['libs' ])
165
+ if ',' in libs [1 ]:
166
+ libs .pop (1 )
163
167
info ['lib_dir' ] = libs [0 ].replace ('-L' , '' )
164
168
info ['libs' ] = [ lib .replace ('-l' , '' ) for lib in libs [1 :] ]
165
169
if platform .uname ()[0 ] == 'SunOS' :
@@ -169,9 +173,10 @@ def parse_mysql_config_info(options, stdout):
169
173
for lib in info ['libs' ]:
170
174
log .debug ("# {0}" .format (lib ))
171
175
libs = shlex .split (info ['libs_r' ])
176
+ if ',' in libs [1 ]:
177
+ libs .pop (1 )
172
178
info ['lib_r_dir' ] = libs [0 ].replace ('-L' , '' )
173
179
info ['libs_r' ] = [ lib .replace ('-l' , '' ) for lib in libs [1 :] ]
174
-
175
180
info ['include' ] = [x .strip () for x in info ['include' ].split ('-I' )[1 :]]
176
181
177
182
return info
@@ -290,6 +295,58 @@ def initialize_options(self):
290
295
self .extra_link_args = None
291
296
self .with_mysql_capi = None
292
297
298
+ def _get_posix_openssl_libs (self ):
299
+ openssl_libs = []
300
+ try :
301
+ openssl_libs_path = os .path .join (self .with_mysql_capi , "lib" )
302
+ openssl_libs .extend ([
303
+ os .path .basename (glob (
304
+ os .path .join (openssl_libs_path , "libssl.*.*.*" ))[0 ]),
305
+ os .path .basename (glob (
306
+ os .path .join (openssl_libs_path , "libcrypto.*.*.*" ))[0 ])
307
+ ])
308
+ except IndexError :
309
+ log .error ("Couldn't find OpenSSL libraries in libmysqlclient" )
310
+ return openssl_libs
311
+
312
+ def _copy_vendor_libraries (self ):
313
+ if not self .with_mysql_capi :
314
+ return
315
+
316
+ data_files = []
317
+
318
+ if os .name == "nt" :
319
+ openssl_libs = ["ssleay32.dll" , "libeay32.dll" ]
320
+ vendor_folder = ""
321
+ mysql_capi = os .path .join (self .with_mysql_capi , "bin" )
322
+ # Bundle libmysql.dll
323
+ src = os .path .join (self .with_mysql_capi , "lib" , "libmysql.dll" )
324
+ dst = os .getcwd ()
325
+ log .info ("copying {0} -> {1}" .format (src , dst ))
326
+ shutil .copy (src , dst )
327
+ data_files .append ("libmysql.dll" )
328
+ else :
329
+ openssl_libs = self ._get_posix_openssl_libs ()
330
+ vendor_folder = "mysql-vendor"
331
+ mysql_capi = os .path .join (self .with_mysql_capi , "lib" )
332
+
333
+ if vendor_folder :
334
+ mkpath (os .path .join (os .getcwd (), vendor_folder ))
335
+
336
+ # Copy OpenSSL libraries to 'mysql-vendor' folder
337
+ log .info ("Copying OpenSSL libraries" )
338
+ for filename in openssl_libs :
339
+ data_files .append (os .path .join (vendor_folder , filename ))
340
+ src = os .path .join (mysql_capi , filename )
341
+ dst = os .path .join (os .getcwd (), vendor_folder )
342
+ log .info ("copying {0} -> {1}" .format (src , dst ))
343
+ shutil .copy (src , dst )
344
+ # Add data_files to distribution
345
+ self .distribution .data_files = [(
346
+ os .path .join (get_python_lib (), vendor_folder ),
347
+ data_files
348
+ )]
349
+
293
350
def _finalize_connector_c (self , connc_loc ):
294
351
"""Finalize the --with-connector-c command line argument
295
352
"""
@@ -317,22 +374,21 @@ def _finalize_connector_c(self, connc_loc):
317
374
log .debug ("# connc_loc: {0}" .format (connc_loc ))
318
375
else :
319
376
# Probably using MS Windows
320
- myconfigh = os .path .join (connc_loc , 'include' , 'my_config.h' )
377
+ myversionh = os .path .join (connc_loc , 'include' ,
378
+ 'mysql_version.h' )
321
379
322
- if not os .path .exists (myconfigh ):
380
+ if not os .path .exists (myversionh ):
323
381
log .error ("MySQL C API installation invalid "
324
- "(my_config .h not found)" )
382
+ "(mysql_version .h not found)" )
325
383
sys .exit (1 )
326
384
else :
327
- with open (myconfigh , 'rb' ) as fp :
385
+ with open (myversionh , 'rb' ) as fp :
328
386
for line in fp .readlines ():
329
- if b'#define VERSION' in line :
330
- version = tuple ([
331
- int (v ) for v in
332
- line .split ()[2 ].replace (
333
- b'"' , b'' ).split (b'.' )
334
- ])
335
- if version < min_version :
387
+ if b'#define LIBMYSQL_VERSION' in line :
388
+ version = LooseVersion (
389
+ line .split ()[2 ].replace (b'"' , b'' ).decode ()
390
+ ).version
391
+ if tuple (version ) < min_version :
336
392
log .error (err_version );
337
393
sys .exit (1 )
338
394
break
@@ -414,6 +470,8 @@ def finalize_options(self):
414
470
('extra_link_args' , 'extra_link_args' ),
415
471
('with_mysql_capi' , 'with_mysql_capi' ))
416
472
473
+ self ._copy_vendor_libraries ()
474
+
417
475
build_ext .finalize_options (self )
418
476
419
477
print ("# Python architecture: {0}" .format (py_arch ))
@@ -423,13 +481,11 @@ def finalize_options(self):
423
481
self ._finalize_connector_c (self .with_mysql_capi )
424
482
425
483
def fix_compiler (self ):
426
- platform = get_platform ()
427
-
428
484
cc = self .compiler
429
485
if not cc :
430
486
return
431
487
432
- if 'macosx-10.9' in platform :
488
+ if 'macosx-10.9' in get_platform () :
433
489
for needle in ['-mno-fused-madd' ]:
434
490
try :
435
491
cc .compiler .remove (needle )
@@ -467,8 +523,11 @@ def fix_compiler(self):
467
523
if self .extra_compile_args :
468
524
ext .extra_compile_args .extend (self .extra_compile_args .split ())
469
525
# Add extra link args
470
- if self .extra_link_args :
471
- ext .extra_link_args .extend (self .extra_link_args .split ())
526
+ if self .extra_link_args and ext .name == "_mysql_connector" :
527
+ extra_link_args = self .extra_link_args .split ()
528
+ if platform .system () == "Linux" :
529
+ extra_link_args += ["-Wl,-rpath,$ORIGIN/mysql-vendor" ]
530
+ ext .extra_link_args .extend (extra_link_args )
472
531
# Add system headers
473
532
for sysheader in sysheaders :
474
533
if sysheader not in ext .extra_compile_args :
@@ -480,6 +539,8 @@ def fix_compiler(self):
480
539
481
540
def run (self ):
482
541
"""Run the command"""
542
+ if not self .with_mysql_capi :
543
+ return
483
544
if os .name == 'nt' :
484
545
for ext in self .extensions :
485
546
# Use the multithread, static version of the run-time library
@@ -498,6 +559,26 @@ def run(self):
498
559
self .fix_compiler ()
499
560
self .real_build_extensions ()
500
561
562
+ if platform .system () == "Darwin" :
563
+ libssl , libcrypto = self ._get_posix_openssl_libs ()
564
+ cmd_libssl = [
565
+ "install_name_tool" , "-change" , libssl ,
566
+ "@loader_path/mysql-vendor/{0}" .format (libssl ),
567
+ build_ext .get_ext_fullpath (self , "_mysql_connector" )
568
+ ]
569
+ log .info ("Executing: {0}" .format (" " .join (cmd_libssl )))
570
+ proc = Popen (cmd_libssl , stdout = PIPE , universal_newlines = True )
571
+ stdout , _ = proc .communicate ()
572
+
573
+ cmd_libcrypto = [
574
+ "install_name_tool" , "-change" , libcrypto ,
575
+ "@loader_path/mysql-vendor/{0}" .format (libcrypto ),
576
+ build_ext .get_ext_fullpath (self , "_mysql_connector" )
577
+ ]
578
+ log .info ("Executing: {0}" .format (" " .join (cmd_libcrypto )))
579
+ proc = Popen (cmd_libcrypto , stdout = PIPE , universal_newlines = True )
580
+ stdout , _ = proc .communicate ()
581
+
501
582
502
583
class BuildExtStatic (BuildExtDynamic ):
503
584
@@ -506,6 +587,8 @@ class BuildExtStatic(BuildExtDynamic):
506
587
user_options = build_ext .user_options + CEXT_OPTIONS
507
588
508
589
def finalize_options (self ):
590
+ self ._copy_vendor_libraries ()
591
+
509
592
install_obj = self .distribution .get_command_obj ('install' )
510
593
install_obj .with_mysql_capi = self .with_mysql_capi
511
594
install_obj .extra_compile_args = self .extra_compile_args
@@ -550,7 +633,10 @@ def _finalize_connector_c(self, connc_loc):
550
633
lib_file_path = os .path .join (self .connc_lib , lib_file )
551
634
if os .path .isfile (lib_file_path ) and not lib_file .endswith ('.a' ):
552
635
os .unlink (os .path .join (self .connc_lib , lib_file ))
553
-
636
+ elif os .name == 'nt' :
637
+ self .include_dirs .extend ([self .connc_include ])
638
+ self .libraries .extend (['libmysql' ])
639
+ self .library_dirs .extend ([self .connc_lib ])
554
640
555
641
def fix_compiler (self ):
556
642
BuildExtDynamic .fix_compiler (self )
@@ -601,16 +687,16 @@ def finalize_options(self):
601
687
602
688
def run (self ):
603
689
self .build ()
604
- outfiles = self .install ()
690
+ outfiles = [
691
+ filename for filename in self .install () if filename .endswith (".py" )
692
+ ]
605
693
606
694
# (Optionally) compile .py to .pyc
607
695
if outfiles is not None and self .distribution .has_pure_modules ():
608
696
self .byte_compile (outfiles )
609
697
610
698
if self .byte_code_only :
611
699
for source_file in outfiles :
612
- if os .path .join ('mysql' , '__init__.py' ) in source_file :
613
- continue
614
700
log .info ("Removing %s" , source_file )
615
701
os .remove (source_file )
616
702
0 commit comments