Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"Finds solvers, sets gpkit settings, and builds gpkit"
2import os
3import sys
4import shutil
5import subprocess
7LOGSTR = ""
8settings = {}
11def log(*args):
12 "Print a line and append it to the log string."
13 global LOGSTR # pylint: disable=global-statement
14 print(*args)
15 LOGSTR += " ".join(args) + "\n"
18def pathjoin(*args):
19 "Join paths, collating multiple arguments."
20 return os.sep.join(args)
23def isfile(path):
24 "Returns true if there's a file at $path. Logs."
25 if os.path.isfile(path):
26 log("# Found %s" % path)
27 return True
28 log("# Could not find %s" % path)
29 return False
32def replacedir(path):
33 "Replaces directory at $path. Logs."
34 log("# Replacing directory", path)
35 if os.path.isdir(path):
36 shutil.rmtree(path)
37 os.makedirs(path)
38 return path
41def call(cmd):
42 "Calls subprocess. Logs."
43 log("# Calling '%s'" % cmd)
44 log("##")
45 log("### CALL BEGINS")
46 retcode = subprocess.call(cmd, shell=True)
47 log("### CALL ENDS")
48 log("##")
49 return retcode
52def diff(filename, diff_dict):
53 "Applies a simple diff to a file. Logs."
54 with open(filename, "r") as a:
55 with open(filename+".new", "w") as b:
56 for line_number, line in enumerate(a):
57 if line[:-1].strip() in diff_dict:
58 newline = diff_dict[line[:-1].strip()]+"\n"
59 log("#\n# Change in %s"
60 "on line %i" % (filename, line_number + 1))
61 log("# --", line[:-1][:70])
62 log("# ++", newline[:70])
63 b.write(newline)
64 else:
65 b.write(line)
66 shutil.move(filename+".new", filename)
69class SolverBackend:
70 "Inheritable class for finding solvers. Logs."
71 name = look = None
73 def __init__(self):
74 log("\n# Looking for `%s`" % self.name)
75 found_in = self.look() # pylint: disable=not-callable
76 if found_in:
77 log("\nFound %s %s" % (self.name, found_in))
78 self.installed = True
79 else:
80 log("# Did not find\n#", self.name)
81 self.installed = False
84class MosekCLI(SolverBackend):
85 "MOSEK command line interface finder."
86 name = "mosek_cli"
88 def look(self): # pylint: disable=too-many-return-statements
89 "Looks in default install locations for a mosek before version 9."
90 log("# (A \"success\" is if mskexpopt complains that")
91 log("# we haven't specified a file for it to open.)")
92 already_in_path = self.run()
93 if already_in_path:
94 return already_in_path
96 log("# Looks like `mskexpopt` was not found in the default PATH,")
97 log("# so let's try locating that binary ourselves.")
99 if sys.platform[:3] == "win":
100 rootdir = "C:\\Program Files\\Mosek"
101 mosek_platform = "win64x86"
102 elif sys.platform[:6] == "darwin":
103 rootdir = pathjoin(os.path.expanduser("~"), "mosek")
104 mosek_platform = "osx64x86"
105 elif sys.platform[:5] == "linux":
106 rootdir = pathjoin(os.path.expanduser("~"), "mosek")
107 mosek_platform = "linux64x86"
108 else:
109 return log("# Platform unsupported: %s" % sys.platform)
111 if "MSKHOME" in os.environ: # allow specification of root dir
112 rootdir = os.environ["MSKHOME"]
113 log("# Using MSKHOME environment variable (value %s) instead of"
114 " OS-default MOSEK home directory" % rootdir)
115 if not os.path.isdir(rootdir):
116 return log("# expected MOSEK directory not found: %s" % rootdir)
118 possible_versions = [f for f in os.listdir(rootdir)
119 if len(f) == 1 and f < "9"]
120 if not possible_versions:
121 return log("# no version folders (e.g. '7', '8') found"
122 " in mosek directory \"%s\"" % rootdir)
123 version = sorted(possible_versions)[-1]
124 tools_dir = pathjoin(rootdir, version, "tools")
125 lib_dir = pathjoin(tools_dir, "platform", mosek_platform)
126 bin_dir = pathjoin(lib_dir, "bin")
127 settings["mosek_bin_dir"] = bin_dir
128 os.environ['PATH'] = os.environ['PATH'] + os.pathsep + bin_dir
129 log("# Adding %s to the PATH" % bin_dir)
131 return self.run("in " + bin_dir)
133 def run(self, where="in the default PATH"):
134 "Attempts to run mskexpopt."
135 try:
136 if call("mskexpopt") in (1052, 28): # 28 for MacOSX
137 return where
138 except: # pylint: disable=bare-except
139 pass # exception type varies by operating system
140 return None
143class CVXopt(SolverBackend):
144 "CVXopt finder."
145 name = "cvxopt"
147 def look(self):
148 "Attempts to import cvxopt."
149 try:
150 log("# Trying to import cvxopt...")
151 import cvxopt # pylint: disable=unused-import
152 return "in the default PYTHONPATH"
153 except ImportError:
154 pass
157class MosekConif(SolverBackend):
158 "MOSEK exponential cone solver finder."
159 name = "mosek_conif"
161 def look(self):
162 "Attempts to import a mosek supporting exponential cones."
163 try:
164 log("# Trying to import mosek...")
165 import mosek
166 if hasattr(mosek.conetype, "pexp"):
167 return "in the default PYTHONPATH"
168 return None
169 except ImportError:
170 pass
172def build():
173 "Builds GPkit"
174 import gpkit
175 log("# Building GPkit version %s" % gpkit.__version__)
176 log("# Moving to the directory from which GPkit was imported.")
177 start_dir = os.getcwd()
178 os.chdir(gpkit.__path__[0])
180 log("\nAttempting to find and build solvers:")
181 solvers = [MosekCLI(), MosekConif(), CVXopt()]
182 installed_solvers = [solver.name for solver in solvers if solver.installed]
183 if not installed_solvers:
184 log("Can't find any solvers!\n")
185 if "GPKITSOLVERS" in os.environ:
186 log("Replaced found solvers (%s) with environment var GPKITSOLVERS"
187 " (%s)" % (installed_solvers, os.environ["GPKITSOLVERS"]))
188 settings["installed_solvers"] = os.environ["GPKITSOLVERS"]
189 else:
190 settings["installed_solvers"] = ", ".join(installed_solvers)
191 log("\nFound the following solvers: " + settings["installed_solvers"])
193 # Write settings
194 envpath = "env"
195 replacedir(envpath)
196 with open(pathjoin(envpath, "settings"), "w") as f:
197 for setting, value in sorted(settings.items()):
198 f.write("%s : %s\n" % (setting, value))
199 with open(pathjoin(envpath, "build.log"), "w") as f:
200 f.write(LOGSTR)
202 os.chdir(start_dir)
204if __name__ == "__main__":
205 build()