3131from typing import Callable , Dict , Optional
3232
3333from cmdstanpy import _DOT_CMDSTAN , _DOT_CMDSTANPY
34- from cmdstanpy .utils import get_logger , pushd , validate_dir , wrap_progress_hook
35-
34+ from cmdstanpy .utils import (
35+ cmdstan_path ,
36+ get_logger ,
37+ pushd ,
38+ validate_dir ,
39+ wrap_progress_hook ,
40+ )
41+
42+ MAKE = os .getenv (
43+ 'MAKE' , 'make' if platform .system () != 'Windows' else 'mingw32-make'
44+ )
3645EXTENSION = '.exe' if platform .system () == 'Windows' else ''
3746
3847
@@ -63,6 +72,135 @@ def usage() -> None:
6372 print (msg )
6473
6574
75+ def clean_all (verbose : bool = False ) -> None :
76+ """
77+ Run `make clean-all` in the current directory (must be a cmdstan library).
78+
79+ :param verbose: when ``True``, print build msgs to stdout.
80+ """
81+ cmd = [MAKE , 'clean-all' ]
82+ proc = subprocess .Popen (
83+ cmd ,
84+ cwd = None ,
85+ stdin = subprocess .DEVNULL ,
86+ stdout = subprocess .PIPE ,
87+ stderr = subprocess .PIPE ,
88+ env = os .environ ,
89+ )
90+ while proc .poll () is None :
91+ if proc .stdout :
92+ output = proc .stdout .readline ().decode ('utf-8' ).strip ()
93+ if verbose and output :
94+ print (output , flush = True )
95+ _ , stderr = proc .communicate ()
96+ if proc .returncode :
97+ msgs = ['Command "make clean-all" failed' ]
98+ if stderr :
99+ msgs .append (stderr .decode ('utf-8' ).strip ())
100+ raise CmdStanInstallError ('\n ' .join (msgs ))
101+
102+
103+ def build (verbose : bool = False ) -> None :
104+ """
105+ Run `make build` in the current directory (must be a cmdstan library)
106+
107+ :param verbose: when ``True``, print build msgs to stdout.
108+ """
109+ cmd = [MAKE , 'build' ]
110+ proc = subprocess .Popen (
111+ cmd ,
112+ cwd = None ,
113+ stdin = subprocess .DEVNULL ,
114+ stdout = subprocess .PIPE ,
115+ stderr = subprocess .PIPE ,
116+ env = os .environ ,
117+ )
118+ while proc .poll () is None :
119+ if proc .stdout :
120+ output = proc .stdout .readline ().decode ('utf-8' ).strip ()
121+ if verbose and output :
122+ print (output , flush = True )
123+ _ , stderr = proc .communicate ()
124+ if proc .returncode :
125+ msgs = ['Command "make build" failed' ]
126+ if stderr :
127+ msgs .append (stderr .decode ('utf-8' ).strip ())
128+ raise CmdStanInstallError ('\n ' .join (msgs ))
129+ if not os .path .exists (os .path .join ('bin' , 'stansummary' + EXTENSION )):
130+ raise CmdStanInstallError (
131+ f'bin/stansummary{ EXTENSION } not found'
132+ ', please rebuild or report a bug!'
133+ )
134+ if not os .path .exists (os .path .join ('bin' , 'diagnose' + EXTENSION )):
135+ raise CmdStanInstallError (
136+ f'bin/stansummary{ EXTENSION } not found'
137+ ', please rebuild or report a bug!'
138+ )
139+ if platform .system () == 'Windows' :
140+ # Add tbb to the $PATH on Windows
141+ libtbb = os .path .join (
142+ os .getcwd (), 'stan' , 'lib' , 'stan_math' , 'lib' , 'tbb'
143+ )
144+ os .environ ['PATH' ] = ';' .join (
145+ list (
146+ OrderedDict .fromkeys (
147+ [libtbb ] + os .environ .get ('PATH' , '' ).split (';' )
148+ )
149+ )
150+ )
151+
152+
153+ def compile_example () -> None :
154+ """
155+ Compile the example model.
156+ The current directory must be a cmdstan library.
157+ """
158+ cmd = [
159+ MAKE ,
160+ Path (
161+ os .path .join ('examples' , 'bernoulli' , 'bernoulli' + EXTENSION )
162+ ).as_posix (),
163+ ]
164+ proc = subprocess .Popen (
165+ cmd ,
166+ cwd = None ,
167+ stdin = subprocess .DEVNULL ,
168+ stdout = subprocess .PIPE ,
169+ stderr = subprocess .PIPE ,
170+ env = os .environ ,
171+ )
172+ while proc .poll () is None :
173+ if proc .stdout :
174+ proc .stdout .readline ().decode ('utf-8' )
175+ _ , stderr = proc .communicate ()
176+ if proc .returncode :
177+ msgs = ['Failed to compile example model bernoulli.stan' ]
178+ if stderr :
179+ msgs .append (stderr .decode ('utf-8' ).strip ())
180+ raise CmdStanInstallError ('\n ' .join (msgs ))
181+
182+
183+ def rebuild_cmdstan (verbose : bool = True ) -> None :
184+ """
185+ Rebuilds the existing CmdStan installation.
186+ This assumes CmdStan has already been installed,
187+ though it need not be installed via CmdStanPy for
188+ this function to work.
189+
190+ :param verbose: Boolean value; when ``True``, output from CmdStan build
191+ processes will be streamed to the console. Default is ``False``.
192+ """
193+ try :
194+ with pushd (cmdstan_path ()):
195+ clean_all (verbose )
196+ build (verbose )
197+ compile_example ()
198+ except ValueError as e :
199+ raise CmdStanInstallError (
200+ "Failed to rebuild CmdStan. Are you sure it is installed?"
201+ ) from e
202+
203+
66204def install_version (
67205 cmdstan_version : str , overwrite : bool = False , verbose : bool = False
68206) -> None :
@@ -76,103 +214,17 @@ def install_version(
76214 :param verbose: when ``True``, print build msgs to stdout.
77215 """
78216 with pushd (cmdstan_version ):
79- make = os .getenv (
80- 'MAKE' , 'make' if platform .system () != 'Windows' else 'mingw32-make'
81- )
82217 print ('Building version {}' .format (cmdstan_version ))
83218 if overwrite :
84219 print (
85220 'Overwrite requested, remove existing build of version '
86221 '{}' .format (cmdstan_version )
87222 )
88- cmd = [make , 'clean-all' ]
89- proc = subprocess .Popen (
90- cmd ,
91- cwd = None ,
92- stdin = subprocess .DEVNULL ,
93- stdout = subprocess .PIPE ,
94- stderr = subprocess .PIPE ,
95- env = os .environ ,
96- )
97- while proc .poll () is None :
98- if proc .stdout :
99- output = proc .stdout .readline ().decode ('utf-8' ).strip ()
100- if verbose and output :
101- print (output , flush = True )
102- _ , stderr = proc .communicate ()
103- if proc .returncode :
104- msgs = ['Command "make clean-all" failed' ]
105- if stderr :
106- msgs .append (stderr .decode ('utf-8' ).strip ())
107- raise CmdStanInstallError ('\n ' .join (msgs ))
223+ clean_all (verbose )
108224 print ('Rebuilding version {}' .format (cmdstan_version ))
109- cmd = [make , 'build' ]
110- proc = subprocess .Popen (
111- cmd ,
112- cwd = None ,
113- stdin = subprocess .DEVNULL ,
114- stdout = subprocess .PIPE ,
115- stderr = subprocess .PIPE ,
116- env = os .environ ,
117- )
118- while proc .poll () is None :
119- if proc .stdout :
120-
121- output = proc .stdout .readline ().decode ('utf-8' ).strip ()
122- if verbose and output :
123- print (output , flush = True )
124- _ , stderr = proc .communicate ()
125- if proc .returncode :
126- msgs = ['Command "make build" failed' ]
127- if stderr :
128- msgs .append (stderr .decode ('utf-8' ).strip ())
129- raise CmdStanInstallError ('\n ' .join (msgs ))
130- if not os .path .exists (os .path .join ('bin' , 'stansummary' + EXTENSION )):
131- raise CmdStanInstallError (
132- f"bin/stansummary{ EXTENSION } not found"
133- ", please rebuild or report a bug!"
134- )
135- if not os .path .exists (os .path .join ('bin' , 'diagnose' + EXTENSION )):
136- raise CmdStanInstallError (
137- f"bin/stansummary{ EXTENSION } not found"
138- ", please rebuild or report a bug!"
139- )
225+ build (verbose )
140226 print ('Test model compilation' )
141- cmd = [
142- make ,
143- Path (
144- os .path .join ('examples' , 'bernoulli' , 'bernoulli' + EXTENSION )
145- ).as_posix (),
146- ]
147- if platform .system () == "Windows" :
148- # Add tbb to the $PATH on Windows
149- libtbb = os .path .join (
150- os .getcwd (), 'stan' , 'lib' , 'stan_math' , 'lib' , 'tbb'
151- )
152- os .environ ['PATH' ] = ';' .join (
153- list (
154- OrderedDict .fromkeys (
155- [libtbb ] + os .environ .get ('PATH' , '' ).split (';' )
156- )
157- )
158- )
159- proc = subprocess .Popen (
160- cmd ,
161- cwd = None ,
162- stdin = subprocess .DEVNULL ,
163- stdout = subprocess .PIPE ,
164- stderr = subprocess .PIPE ,
165- env = os .environ ,
166- )
167- while proc .poll () is None :
168- if proc .stdout :
169- proc .stdout .readline ().decode ('utf-8' )
170- _ , stderr = proc .communicate ()
171- if proc .returncode :
172- msgs = ['Failed to compile example model bernoulli.stan' ]
173- if stderr :
174- msgs .append (stderr .decode ('utf-8' ).strip ())
175- raise CmdStanInstallError ('\n ' .join (msgs ))
227+ compile_example ()
176228 print ('Installed {}' .format (cmdstan_version ))
177229
178230
0 commit comments