forked from dhermes/bezier
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsetup_helpers_windows.py
143 lines (117 loc) · 4.84 KB
/
setup_helpers_windows.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helpers for ``setup.py`` specific to Windows."""
import os
import shutil
import sys
import setup_helpers
LIB_DIR = os.path.join("bezier", "lib")
DLL_DIR = os.path.join("bezier", "extra-dll")
DLL_NAME = "bezier.dll"
DEF_NAME = "bezier.def"
LIB_NAME = "bezier.lib"
# See: https://docs.python.org/3/library/platform.html#cross-platform
if sys.maxsize == 2 ** 63 - 1:
MACHINE_TYPE = "/machine:x64"
elif sys.maxsize == 2 ** 31 - 1:
MACHINE_TYPE = "/machine:x86"
else: # pragma: NO COVER
raise ImportError("Unexpected maxsize", sys.maxsize)
def _ensure_exists(*dir_names):
for dir_name in dir_names:
if not os.path.exists(dir_name):
os.makedirs(dir_name)
def make_static_lib(build_ext_cmd, obj_files):
f90_compiler = build_ext_cmd.F90_COMPILER
c_compiler = f90_compiler.c_compiler
gfortran_exe = f90_compiler.compiler_f90[0]
static_lib_dir = os.path.join(build_ext_cmd.build_lib, LIB_DIR)
extra_dll_dir = os.path.join(build_ext_cmd.build_lib, DLL_DIR)
_ensure_exists(static_lib_dir, extra_dll_dir, build_ext_cmd.build_temp)
# Add build lib dir to extensions (for linking).
for extension in build_ext_cmd.extensions:
library_dirs = extension.library_dirs
if static_lib_dir not in library_dirs:
library_dirs.append(static_lib_dir)
# NOTE: Would prefer to use a `tuple` but command must be
# mutable on Windows.
temp_dll_filename = os.path.join(build_ext_cmd.build_temp, DLL_NAME)
cmd = [gfortran_exe, "-static", "-shared", "-o", temp_dll_filename]
cmd.extend(obj_files)
def_filename = os.path.join(build_ext_cmd.build_temp, DEF_NAME)
cmd.append("-Wl,--output-def," + def_filename)
f90_compiler.spawn(cmd)
# NOTE: This assumes, but does not check that ``c_compiler.initialized``
# is True.
temp_lib_filename = os.path.join(build_ext_cmd.build_temp, LIB_NAME)
cmd = [
c_compiler.lib,
"/def:" + def_filename,
"/out:" + temp_lib_filename,
MACHINE_TYPE,
]
f90_compiler.spawn(cmd)
# Move files for distribution from build temp. dir to build lib dir.
dll_filename = os.path.join(extra_dll_dir, DLL_NAME)
shutil.move(temp_dll_filename, dll_filename)
lib_filename = os.path.join(static_lib_dir, LIB_NAME)
shutil.move(temp_lib_filename, lib_filename)
def run_cleanup(build_ext_cmd):
"""Cleanup after ``BuildFortranThenExt.run``.
For in-place builds, moves the built shared library into the source
directory.
"""
if not build_ext_cmd.inplace:
return
bezier_dir = os.path.join("src", "python", "bezier")
shutil.move(os.path.join(build_ext_cmd.build_lib, LIB_DIR), bezier_dir)
shutil.move(os.path.join(build_ext_cmd.build_lib, DLL_DIR), bezier_dir)
def _remove_fpic(compiler_flags):
"""Remove ``-fPIC`` from a given set of compiler flags.
Args:
compiler_flags (List[str]): Existing flags associated with a compiler.
Returns:
List[str]: The modified list.
"""
return [value for value in compiler_flags if value != setup_helpers.FPIC]
def patch_f90_compiler(f90_compiler):
"""Patch up ``f90_compiler.library_dirs``.
Updates flags in ``gfortran`` and ignores other compilers. The only
modification is the removal of ``-fPIC`` since it is not used on Windows
and the build flags turn warnings into errors.
Args:
f90_compiler (numpy.distutils.fcompiler.FCompiler): A Fortran compiler
instance.
"""
# NOTE: NumPy may not be installed, but we don't want **this** module to
# cause an import failure.
from numpy.distutils.fcompiler import gnu
# Only Windows.
if os.name != "nt":
return
# Only ``gfortran``.
if not isinstance(f90_compiler, gnu.Gnu95FCompiler):
return
f90_compiler.compiler_f77[:] = _remove_fpic(f90_compiler.compiler_f77)
f90_compiler.compiler_f90[:] = _remove_fpic(f90_compiler.compiler_f90)
c_compiler = f90_compiler.c_compiler
if c_compiler.compiler_type != "msvc":
raise NotImplementedError(
"MSVC is the only supported C compiler on Windows."
)
def patch_cmd(cmd_class):
# Only Windows.
if os.name != "nt":
return
cmd_class.CUSTOM_STATIC_LIB = make_static_lib
cmd_class.USE_SHARED_LIBRARY = True
cmd_class.CLEANUP = run_cleanup