6969import time
7070import datetime
7171import importlib .util
72+ import json # noqa: E402
7273from sysconfig import get_path
7374
7475try :
7778 from imp import new_module
7879
7980ROOT_DIR = os .path .abspath (os .path .join (os .path .dirname (__file__ )))
80- PATH_INSTALLED = os .path .join (os .path .abspath (os .path .dirname (__file__ )),
81- 'installdir' )
8281
8382
8483def import_module_from_path (mod_name , mod_path ):
@@ -166,8 +165,24 @@ def main(argv):
166165 "Note: this argument may be removed in the future "
167166 "once a `site.cfg`-like mechanism to select BLAS/LAPACK "
168167 "libraries is implemented for Meson" )
168+ parser .add_argument ("--build-dir" , default = "build" ,
169+ help = "Relative path to the build directory. "
170+ "Default is 'build'" )
171+ parser .add_argument ("--install-prefix" , default = None ,
172+ help = "Relative path to the install directory. "
173+ "Default is <build-dir>-install." )
169174 args = parser .parse_args (argv )
170175
176+ global PATH_INSTALLED
177+ build_dir = Path (args .build_dir )
178+ install_dir = args .install_prefix
179+ if not install_dir :
180+ install_dir = build_dir .parent / (build_dir .stem + "-install" )
181+ PATH_INSTALLED = os .path .join (
182+ os .path .abspath (os .path .dirname (__file__ )),
183+ install_dir
184+ )
185+
171186 if args .win_cp_openblas and platform .system () != 'Windows' :
172187 raise RuntimeError ('--win-cp-openblas only has effect on Windows' )
173188
@@ -250,7 +265,7 @@ def main(argv):
250265 sys .exit (0 )
251266
252267 if args .coverage :
253- dst_dir = os .path .join (ROOT_DIR , 'build' , 'coverage' )
268+ dst_dir = os .path .join (ROOT_DIR , args . build_dir , 'coverage' )
254269 fn = os .path .join (dst_dir , 'coverage_html.js' )
255270 if os .path .isdir (dst_dir ) and os .path .isfile (fn ):
256271 shutil .rmtree (dst_dir )
@@ -358,7 +373,7 @@ def main(argv):
358373 if not args .no_build :
359374 test_dir = site_dir
360375 else :
361- test_dir = os .path .join (ROOT_DIR , 'build' , 'test' )
376+ test_dir = os .path .join (ROOT_DIR , args . build_dir , 'test' )
362377 if not os .path .isdir (test_dir ):
363378 os .makedirs (test_dir )
364379
@@ -392,11 +407,32 @@ def setup_build(args, env):
392407 """
393408 Setting up meson-build
394409 """
395- cmd = ["meson" , "setup" , "build" , "--prefix" , PATH_INSTALLED ]
410+ cmd = ["meson" , "setup" , args .build_dir , "--prefix" , PATH_INSTALLED ]
411+ build_dir = Path (args .build_dir )
412+ run_dir = os .getcwd ()
413+ if build_dir .exists () and not (build_dir / 'meson-info' ).exists ():
414+ if list (build_dir .iterdir ()):
415+ raise RuntimeError ("Can't build into non-empty directory "
416+ f"'{ build_dir .absolute ()} '" )
417+ if os .path .exists (build_dir ):
418+ build_options_file = (build_dir / "meson-info"
419+ / "intro-buildoptions.json" )
420+ with open (build_options_file ) as f :
421+ build_options = json .load (f )
422+ installdir = None
423+ for option in build_options :
424+ if option ["name" ] == "prefix" :
425+ installdir = option ["value" ]
426+ break
427+ if installdir != PATH_INSTALLED :
428+ run_dir = os .path .join (run_dir , build_dir )
429+ cmd = ["meson" , "--reconfigure" , "--prefix" , PATH_INSTALLED ]
430+ else :
431+ return
396432 if args .werror :
397433 cmd += ["--werror" ]
398434 # Setting up meson build
399- ret = subprocess .call (cmd , env = env , cwd = ROOT_DIR )
435+ ret = subprocess .call (cmd , env = env , cwd = run_dir )
400436 if ret == 0 :
401437 print ("Meson build setup OK" )
402438 else :
@@ -405,14 +441,20 @@ def setup_build(args, env):
405441 return
406442
407443
408- def install_project (show_build_log ):
444+ def install_project (args ):
409445 """
410446 Installs the project after building.
411447 """
412- cmd = ["meson" , "install" , "-C" , "build" ]
448+ if os .path .exists (PATH_INSTALLED ):
449+ installdir = get_site_packages ()
450+ non_empty = len (os .listdir (PATH_INSTALLED ))
451+ if non_empty and not os .path .exists (installdir ):
452+ raise RuntimeError ("Can't install in non-empty directory: "
453+ f"'{ PATH_INSTALLED } '" )
454+ cmd = ["meson" , "install" , "-C" , args .build_dir ]
413455 log_filename = os .path .join (ROOT_DIR , 'meson-install.log' )
414456 start_time = datetime .datetime .now ()
415- if show_build_log :
457+ if args . show_build_log :
416458 ret = subprocess .call (cmd , cwd = ROOT_DIR )
417459 else :
418460 print ("Installing, see meson-install.log..." )
@@ -445,12 +487,16 @@ def install_project(show_build_log):
445487 elapsed = datetime .datetime .now () - start_time
446488
447489 if ret != 0 :
448- if not show_build_log :
490+ if not args . show_build_log :
449491 with open (log_filename , 'r' ) as f :
450492 print (f .read ())
451493 print ("Installation failed! ({0} elapsed)" .format (elapsed ))
452494 sys .exit (1 )
453495
496+ # ignore everything in the install directory.
497+ with open (Path (PATH_INSTALLED ) / ".gitignore" , "w" ) as f :
498+ f .write ("*" )
499+
454500 print ("Installation OK" )
455501 return
456502
@@ -537,15 +583,11 @@ def build_project(args):
537583 env ['LDFLAGS' ] = " " .join (cvars ['LDSHARED' ].split ()[1 :]) + \
538584 ' --coverage'
539585
540- build_dir = os .path .join (ROOT_DIR , 'build' )
541-
542- # Check if meson is already setup
543- if not os .path .exists (os .path .join (build_dir , 'build.ninja' )):
544- setup_build (args , env )
586+ setup_build (args , env )
545587
546588 site_dir = get_site_packages ()
547589
548- cmd = ["ninja" , "-C" , "build" ]
590+ cmd = ["ninja" , "-C" , args . build_dir ]
549591 if args .parallel > 1 :
550592 cmd += ["-j" , str (args .parallel )]
551593
@@ -558,7 +600,7 @@ def build_project(args):
558600 print ("Build failed!" )
559601 sys .exit (1 )
560602
561- install_project (args . show_build_log )
603+ install_project (args )
562604
563605 if args .win_cp_openblas and platform .system () == 'Windows' :
564606 if copy_openblas () == 0 :
0 commit comments