Skip to content

Commit 7deaf3e

Browse files
DEV: meson: allow specifying build directory and install prefix (scipy#15502)
- default "install-prefix" to `<build-dir>-install` so installs are not overwritten - reconfigure build if install directory is inconsistent with the build directory - ignore everything in the install directory [skip azp]
1 parent 725a4eb commit 7deaf3e

File tree

3 files changed

+61
-19
lines changed

3 files changed

+61
-19
lines changed

.github/workflows/linux_meson.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ on:
1616

1717
env:
1818
CCACHE_DIR: "${{ github.workspace }}/.ccache"
19-
INSTALLDIR: "installdir"
19+
INSTALLDIR: "build-install"
2020

2121
jobs:
2222
test_meson:

.github/workflows/macos_meson.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ on:
1111
- maintenance/**
1212

1313
env:
14-
INSTALLDIR: "installdir"
14+
INSTALLDIR: "build-install"
1515
CCACHE_DIR: "${{ github.workspace }}/.ccache"
1616

1717
jobs:

dev.py

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import time
7070
import datetime
7171
import importlib.util
72+
import json # noqa: E402
7273
from sysconfig import get_path
7374

7475
try:
@@ -77,8 +78,6 @@
7778
from imp import new_module
7879

7980
ROOT_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

8483
def 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

Comments
 (0)