33"""
44
55import os
6+ from copy import copy
67from pathlib import Path
78from typing import Any , Dict , List , Optional , Union
89
910from cmdstanpy .utils import get_logger
1011
1112STANC_OPTS = [
1213 'O' ,
13- 'allow_undefined ' ,
14+ 'allow-undefined ' ,
1415 'use-opencl' ,
1516 'warn-uninitialized' ,
16- 'include_paths ' ,
17+ 'include-paths ' ,
1718 'name' ,
1819 'warn-pedantic' ,
1920]
2021
22+ STANC_DEPRECATED_OPTS = {
23+ 'allow_undefined' : 'allow-undefined' ,
24+ 'include_paths' : 'include-paths' ,
25+ }
26+
2127STANC_IGNORE_OPTS = [
2228 'debug-lex' ,
2329 'debug-parse' ,
@@ -121,19 +127,37 @@ def validate_stanc_opts(self) -> None:
121127 return
122128 ignore = []
123129 paths = None
130+ for deprecated , replacement in STANC_DEPRECATED_OPTS .items ():
131+ if deprecated in self ._stanc_options :
132+ if replacement :
133+ get_logger ().warning (
134+ 'compiler option "%s" is deprecated, use "%s" instead' ,
135+ deprecated ,
136+ replacement ,
137+ )
138+ self ._stanc_options [replacement ] = copy (
139+ self ._stanc_options [deprecated ]
140+ )
141+ del self ._stanc_options [deprecated ]
142+ else :
143+ get_logger ().warning (
144+ 'compiler option "%s" is deprecated and '
145+ 'should not be used' ,
146+ deprecated ,
147+ )
124148 for key , val in self ._stanc_options .items ():
125149 if key in STANC_IGNORE_OPTS :
126150 get_logger ().info ('ignoring compiler option: %s' , key )
127151 ignore .append (key )
128152 elif key not in STANC_OPTS :
129153 raise ValueError (f'unknown stanc compiler option: { key } ' )
130- elif key == 'include_paths ' :
154+ elif key == 'include-paths ' :
131155 paths = val
132156 if isinstance (val , str ):
133157 paths = val .split (',' )
134158 elif not isinstance (val , list ):
135159 raise ValueError (
136- 'Invalid include_paths , expecting list or '
160+ 'Invalid include-paths , expecting list or '
137161 f'string, found type: { type (val )} .'
138162 )
139163 elif key == 'use-opencl' :
@@ -145,17 +169,16 @@ def validate_stanc_opts(self) -> None:
145169 for opt in ignore :
146170 del self ._stanc_options [opt ]
147171 if paths is not None :
148- self ._stanc_options ['include_paths' ] = paths
149- bad_paths = [
150- dir
151- for dir in self ._stanc_options ['include_paths' ]
152- if not os .path .exists (dir )
153- ]
172+ bad_paths = [dir for dir in paths if not os .path .exists (dir )]
154173 if any (bad_paths ):
155174 raise ValueError (
156175 'invalid include paths: {}' .format (', ' .join (bad_paths ))
157176 )
158177
178+ self ._stanc_options ['include-paths' ] = [
179+ os .path .abspath (os .path .expanduser (path )) for path in paths
180+ ]
181+
159182 def validate_cpp_opts (self ) -> None :
160183 """
161184 Check cpp compiler args.
@@ -190,8 +213,8 @@ def validate_user_header(self) -> None:
190213 raise ValueError (
191214 f"Header file must end in .hpp, got { self ._user_header } "
192215 )
193- if "allow_undefined " not in self ._stanc_options :
194- self ._stanc_options ["allow_undefined " ] = True
216+ if "allow-undefined " not in self ._stanc_options :
217+ self ._stanc_options ["allow-undefined " ] = True
195218 # set full path
196219 self ._user_header = os .path .abspath (self ._user_header )
197220
@@ -218,7 +241,7 @@ def add(self, new_opts: "CompilerOptions") -> None: # noqa: disable=Q000
218241 self ._stanc_options = new_opts .stanc_options
219242 else :
220243 for key , val in new_opts .stanc_options .items ():
221- if key == 'include_paths ' :
244+ if key == 'include-paths ' :
222245 self .add_include_path (str (val ))
223246 else :
224247 self ._stanc_options [key ] = val
@@ -230,30 +253,35 @@ def add(self, new_opts: "CompilerOptions") -> None: # noqa: disable=Q000
230253
231254 def add_include_path (self , path : str ) -> None :
232255 """Adds include path to existing set of compiler options."""
233- if 'include_paths' not in self ._stanc_options :
234- self ._stanc_options ['include_paths' ] = [path ]
235- elif path not in self ._stanc_options ['include_paths' ]:
236- self ._stanc_options ['include_paths' ].append (path )
256+ path = os .path .abspath (os .path .expanduser (path ))
257+ if 'include-paths' not in self ._stanc_options :
258+ self ._stanc_options ['include-paths' ] = [path ]
259+ elif path not in self ._stanc_options ['include-paths' ]:
260+ self ._stanc_options ['include-paths' ].append (path )
237261
238- def compose (self ) -> List [str ]:
239- """Format makefile options as list of strings."""
262+ def compose_stanc (self ) -> List [str ]:
240263 opts = []
241264 if self ._stanc_options is not None and len (self ._stanc_options ) > 0 :
242265 for key , val in self ._stanc_options .items ():
243- if key == 'include_paths ' :
266+ if key == 'include-paths ' :
244267 opts .append (
245- 'STANCFLAGS+=--include_paths ='
268+ '--include-paths ='
246269 + ',' .join (
247270 (
248271 Path (p ).as_posix ()
249- for p in self ._stanc_options ['include_paths ' ]
272+ for p in self ._stanc_options ['include-paths ' ]
250273 )
251274 )
252275 )
253276 elif key == 'name' :
254- opts .append (f'STANCFLAGS+= --name={ val } ' )
277+ opts .append (f'--name={ val } ' )
255278 else :
256- opts .append (f'STANCFLAGS+=--{ key } ' )
279+ opts .append (f'--{ key } ' )
280+ return opts
281+
282+ def compose (self ) -> List [str ]:
283+ """Format makefile options as list of strings."""
284+ opts = ['STANCFLAGS+=' + flag for flag in self .compose_stanc ()]
257285 if self ._cpp_options is not None and len (self ._cpp_options ) > 0 :
258286 for key , val in self ._cpp_options .items ():
259287 opts .append (f'{ key } ={ val } ' )
0 commit comments