1111import glob
1212import os
1313import re
14+ import shutil
1415import sys
1516import warnings
17+ from pathlib import Path
1618
1719from setuptools import Extension , setup
20+ from setuptools .command .build_ext import build_ext
1821
1922# Use this version when git data are not available, like in git zip archive.
2023# Update when tagging a new release.
2124FALLBACK_VERSION = "1.4.3"
2225
23- MYDIR = os . path . dirname ( os . path . abspath ( __file__ ))
26+ MYDIR = str ( Path ( __file__ ). parent . resolve ( ))
2427
2528# Helper functions -----------------------------------------------------------
2629
2730
2831def get_compiler_type ():
29- """find compiler used for building extensions."""
32+ """Find compiler used for building extensions."""
3033 cc_arg = [a for a in sys .argv if a .startswith ("--compiler=" )]
3134 if cc_arg :
32- compiler_type = cc_arg [- 1 ].split ("=" , 1 )[1 ]
33- else :
34- from distutils .ccompiler import new_compiler
35+ return cc_arg [- 1 ].split ("=" , 1 )[1 ]
36+ from distutils .ccompiler import new_compiler
3537
36- compiler_type = new_compiler ().compiler_type
37- return compiler_type
38+ return new_compiler ().compiler_type
3839
3940
4041def get_gsl_config ():
4142 """Return dictionary with paths to GSL library."""
42- gslcfgpaths = [os . path . join ( p , "gsl-config" ) for p in ([MYDIR ] + os .environ ["PATH" ].split (os .pathsep ))]
43- gslcfgpaths = [p for p in gslcfgpaths if os . path . isfile ( p )]
43+ gslcfgpaths = [Path ( p ) / "gsl-config" for p in ([MYDIR ] + os .environ ["PATH" ].split (os .pathsep ))]
44+ gslcfgpaths = [p for p in gslcfgpaths if p . is_file ( )]
4445 rv = {"include_dirs" : [], "library_dirs" : []}
4546 if not gslcfgpaths :
46- wmsg = "Cannot find gsl-config in {!r} nor in system PATH."
47- warnings .warn (wmsg .format (MYDIR ))
47+ warnings .warn (f"Cannot find gsl-config in { MYDIR } nor in system PATH." )
4848 return rv
4949 gslcfg = gslcfgpaths [0 ]
50- with open (gslcfg ) as fp :
51- txt = fp .read ()
52- mprefix = re .search ("(?m)^prefix=(.+)" , txt )
50+ txt = gslcfg .read_text ()
51+ mprefix = re .search (r"(?m)^prefix=(.+)" , txt )
5352 minclude = re .search (r"(?m)^[^#]*\s-I(\S+)" , txt )
5453 mlibpath = re .search (r"(?m)^[^#]*\s-L(\S+)" , txt )
5554 if not mprefix :
56- emsg = "Cannot find 'prefix=' line in {}."
57- raise RuntimeError (emsg .format (gslcfg ))
58- p = mprefix .group (1 )
59- inc = minclude .group (1 ) if minclude else (p + "/include" )
60- lib = mlibpath .group (1 ) if mlibpath else (p + "/lib" )
61- rv ["include_dirs" ] += [inc ]
62- rv ["library_dirs" ] += [lib ]
55+ raise RuntimeError (f"Cannot find 'prefix=' line in { gslcfg } ." )
56+ p = Path (mprefix .group (1 ))
57+ rv ["include_dirs" ].append (str (minclude .group (1 ) if minclude else p / "include" ))
58+ rv ["library_dirs" ].append (str (mlibpath .group (1 ) if mlibpath else p / "lib" ))
6359 return rv
6460
6561
6662def get_gsl_config_win ():
6763 """Return dictionary with paths to GSL library on Windows."""
68- gsl_path = os .environ .get ("GSL_PATH" )
64+ gsl_path = os .environ .get ("GSL_PATH" , "" )
6965 if gsl_path :
70- inc = os . path . join (gsl_path , "include" )
71- lib = os . path . join (gsl_path , "lib" )
66+ inc = Path (gsl_path ) / "include"
67+ lib = Path (gsl_path ) / "lib"
7268 else :
7369 conda_prefix = os .environ .get ("CONDA_PREFIX" )
7470 if conda_prefix :
75- inc = os . path . join (conda_prefix , "Library" , "include" )
76- lib = os . path . join (conda_prefix , "Library" , "lib" )
71+ inc = Path (conda_prefix ) / "Library" / "include"
72+ lib = Path (conda_prefix ) / "Library" / "lib"
7773 else :
7874 raise EnvironmentError (
7975 "Neither GSL_PATH nor CONDA_PREFIX environment variables are set. "
8076 "Please ensure GSL is installed and GSL_PATH is correctly set."
8177 )
78+ return {"include_dirs" : [str (inc )], "library_dirs" : [str (lib )]}
79+
80+
81+ class CustomBuildExt (build_ext ):
82+ def run (self ):
83+ super ().run ()
84+ gsl_path = (
85+ Path (os .environ .get ("GSL_PATH" ))
86+ if os .environ .get ("GSL_PATH" )
87+ else Path (os .environ .get ("CONDA_PREFIX" , "" )) / "Library"
88+ )
89+ bin_path = gsl_path / "bin"
90+ dest_path = Path (self .build_lib ) / "diffpy" / "pdffit2"
91+ dest_path .mkdir (parents = True , exist_ok = True )
8292
83- return {"include_dirs" : [inc ], "library_dirs" : [lib ]}
93+ for dll_file in bin_path .glob ("gsl*.dll" ):
94+ shutil .copy (str (dll_file ), str (dest_path ))
8495
8596
8697# ----------------------------------------------------------------------------
8798
88- # compile and link options
89- define_macros = []
99+ # Compile and link options
90100os_name = os .name
91101if os_name == "nt" :
92102 gcfg = get_gsl_config_win ()
93103else :
94104 gcfg = get_gsl_config ()
95- include_dirs = [MYDIR ] + gcfg ["include_dirs" ]
96- library_dirs = []
105+
97106if sys .platform == "darwin" :
98107 libraries = []
99108else :
100109 libraries = ["gsl" ]
110+
111+ include_dirs = [MYDIR ] + gcfg ["include_dirs" ]
112+ library_dirs = []
113+ define_macros = []
101114extra_objects = []
102115extra_compile_args = []
103116extra_link_args = []
104117
118+
105119compiler_type = get_compiler_type ()
106120if compiler_type in ("unix" , "cygwin" , "mingw32" ):
107121 extra_compile_args = ["-std=c++11" , "-Wall" , "-Wno-write-strings" , "-O3" , "-funroll-loops" , "-ffast-math" ]
@@ -114,7 +128,7 @@ def get_gsl_config_win():
114128 library_dirs += gcfg ["library_dirs" ]
115129# add optimization flags for other compilers if needed
116130
117- # define extension arguments here
131+ # Define extension arguments
118132ext_kws = {
119133 "include_dirs" : include_dirs ,
120134 "libraries" : libraries ,
@@ -126,14 +140,15 @@ def get_gsl_config_win():
126140}
127141
128142
129- # define extension here
143+ # Define extensions
130144def create_extensions ():
131145 ext = Extension ("diffpy.pdffit2.pdffit2" , glob .glob ("src/extensions/**/*.cc" ), ** ext_kws )
132146 return [ext ]
133147
134148
135149setup_args = dict (
136150 ext_modules = [],
151+ cmdclass = {"build_ext" : CustomBuildExt },
137152)
138153
139154if __name__ == "__main__" :
0 commit comments