forked from pybamm-team/PyBaMM
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CMakeBuild.py
152 lines (134 loc) · 5.75 KB
/
CMakeBuild.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
144
145
146
147
148
149
150
151
152
import os
import sys
import subprocess
from pathlib import Path
from platform import system
try:
from setuptools.command.build_ext import build_ext
except ImportError:
from distutils.command.build_ext import build_ext
default_lib_dir = (
"" if system() == "Windows" else os.path.join(os.getenv("HOME"), ".local")
)
def set_vcpkg_environment_variables():
if not os.getenv("VCPKG_ROOT_DIR"):
raise EnvironmentError("Environment variable 'VCPKG_ROOT_DIR' is undefined.")
if not os.getenv("VCPKG_DEFAULT_TRIPLET"):
raise EnvironmentError(
"Environment variable 'VCPKG_DEFAULT_TRIPLET' is undefined."
)
if not os.getenv("VCPKG_FEATURE_FLAGS"):
raise EnvironmentError(
"Environment variable 'VCPKG_FEATURE_FLAGS' is undefined."
)
return (
os.getenv("VCPKG_ROOT_DIR"),
os.getenv("VCPKG_DEFAULT_TRIPLET"),
os.getenv("VCPKG_FEATURE_FLAGS"),
)
class CMakeBuild(build_ext):
user_options = build_ext.user_options + [
("suitesparse-root=", None, "suitesparse source location"),
("sundials-root=", None, "sundials source location"),
]
def initialize_options(self):
build_ext.initialize_options(self)
self.suitesparse_root = None
self.sundials_root = None
def finalize_options(self):
build_ext.finalize_options(self)
# Determine the calling command to get the
# undefined options from.
# If build_ext was called directly then this
# doesn't matter.
try:
self.get_finalized_command("install", create=0)
calling_cmd = "install"
except AttributeError:
calling_cmd = "bdist_wheel"
self.set_undefined_options(
calling_cmd,
("suitesparse_root", "suitesparse_root"),
("sundials_root", "sundials_root"),
)
if not self.suitesparse_root:
self.suitesparse_root = os.path.join(default_lib_dir)
if not self.sundials_root:
self.sundials_root = os.path.join(default_lib_dir)
def get_build_directory(self):
# distutils outputs object files in directory self.build_temp
# (typically build/temp.*). This is our CMake build directory.
# On Windows, distutils is too smart and appends "Release" or
# "Debug" to self.build_temp. So in this case we want the
# build directory to be the parent directory.
if system() == "Windows":
return Path(self.build_temp).parents[0]
return self.build_temp
def run(self):
if not self.extensions:
return
cmake_args = ["-DPYTHON_EXECUTABLE={}".format(sys.executable)]
if self.suitesparse_root:
cmake_args.append(
"-DSuiteSparse_ROOT={}".format(os.path.abspath(self.suitesparse_root))
)
if self.sundials_root:
cmake_args.append(
"-DSUNDIALS_ROOT={}".format(os.path.abspath(self.sundials_root))
)
build_dir = self.get_build_directory()
if not os.path.exists(build_dir):
os.makedirs(build_dir)
# The CMakeError.log file is generated by cmake is the configure step
# encounters error. In the following the existence of this file is used
# to determine whether or not the cmake configure step went smoothly.
# So must make sure this file does not remain from a previous failed build.
if os.path.isfile(os.path.join(build_dir, "CMakeError.log")):
os.remove(os.path.join(build_dir, "CMakeError.log"))
build_env = os.environ
if os.getenv("PYBAMM_USE_VCPKG"):
(
vcpkg_root_dir,
vcpkg_default_triplet,
vcpkg_feature_flags,
) = set_vcpkg_environment_variables()
build_env["vcpkg_root_dir"] = vcpkg_root_dir
build_env["vcpkg_default_triplet"] = vcpkg_default_triplet
build_env["vcpkg_feature_flags"] = vcpkg_feature_flags
cmake_list_dir = os.path.abspath(os.path.dirname(__file__))
print("-" * 10, "Running CMake for idaklu solver", "-" * 40)
subprocess.run(
["cmake", cmake_list_dir] + cmake_args, cwd=build_dir, env=build_env
)
if os.path.isfile(os.path.join(build_dir, "CMakeError.log")):
msg = (
"cmake configuration steps encountered errors, and the idaklu module"
" could not be built. Make sure dependencies are correctly "
"installed. See "
"https://github.com/pybamm-team/PyBaMM/tree/develop"
"INSTALL-LINUX-MAC.md"
)
raise RuntimeError(msg)
else:
print("-" * 10, "Building idaklu module", "-" * 40)
subprocess.run(
["cmake", "--build", ".", "--config", "Release"],
cwd=build_dir,
env=build_env,
)
# Move from build temp to final position
for ext in self.extensions:
self.move_output(ext)
def move_output(self, ext):
# Copy built module to dist/ directory
build_temp = Path(self.build_temp).resolve()
# Get destination location
# self.get_ext_fullpath(ext.name) -->
# build/lib.linux-x86_64-3.5/idaklu.cpython-37m-x86_64-linux-gnu.so
# using resolve() with python < 3.6 will result in a FileNotFoundError
# since the location does not yet exists.
dest_path = Path(self.get_ext_fullpath(ext.name)).resolve()
source_path = build_temp / os.path.basename(self.get_ext_filename(ext.name))
dest_directory = dest_path.parents[0]
dest_directory.mkdir(parents=True, exist_ok=True)
self.copy_file(source_path, dest_path)