aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/backends.py41
-rw-r--r--mesonbuild/backend/ninjabackend.py17
-rw-r--r--mesonbuild/mesonmain.py5
-rw-r--r--mesonbuild/scripts/meson_exe.py74
4 files changed, 135 insertions, 2 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index ceb466b..08e3d2d 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -34,6 +34,18 @@ class InstallData():
self.install_scripts = []
self.install_subdirs = []
+class ExecutableSerialisation():
+ def __init__(self, name, fname, cmd_args, env, is_cross, exe_wrapper,
+ workdir, extra_paths):
+ self.name = name
+ self.fname = fname
+ self.cmd_args = cmd_args
+ self.env = env
+ self.is_cross = is_cross
+ self.exe_runner = exe_wrapper
+ self.workdir = workdir
+ self.extra_paths = extra_paths
+
class TestSerialisation:
def __init__(self, name, suite, fname, is_cross, exe_wrapper, is_parallel, cmd_args, env,
should_fail, valgrind_args, timeout, workdir, extra_paths):
@@ -154,6 +166,35 @@ class Backend():
raise MesonException('Unknown data type in object list.')
return obj_list
+ def serialise_executable(self, exe, cmd_args, workdir, env={}):
+ import uuid
+ # Can't just use exe.name here; it will likely be run more than once
+ scratch_file = 'meson_exe_{0}_{1}.dat'.format(exe.name,
+ str(uuid.uuid4())[:8])
+ exe_data = os.path.join(self.environment.get_scratch_dir(), scratch_file)
+ with open(exe_data, 'wb') as f:
+ if isinstance(exe, dependencies.ExternalProgram):
+ exe_fullpath = exe.fullpath
+ else:
+ exe_fullpath = [os.path.join(self.environment.get_build_dir(),
+ self.get_target_filename(exe))]
+ is_cross = self.environment.is_cross_build() and \
+ self.environment.cross_info.need_cross_compiler() and \
+ self.environment.cross_info.need_exe_wrapper()
+ if is_cross:
+ exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None)
+ else:
+ exe_wrapper = None
+ if mesonlib.is_windows():
+ extra_paths = self.determine_windows_extra_paths(exe)
+ else:
+ extra_paths = []
+ es = ExecutableSerialisation(exe.name, exe_fullpath, cmd_args, env,
+ is_cross, exe_wrapper, workdir,
+ extra_paths)
+ pickle.dump(es, f)
+ return exe_data
+
def serialise_tests(self):
test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat')
datafile = open(test_data, 'wb')
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 201b2d1..9964322 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -341,6 +341,7 @@ int dummy;
def generate_custom_target(self, target, outfile):
(srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
deps = []
+ desc = 'Generating {0} with a {1} command.'
for i in target.get_dependencies():
# FIXME, should not grab element at zero but rather expand all.
if isinstance(i, list):
@@ -364,9 +365,23 @@ int dummy;
tmp = [tmp]
for fname in tmp:
elem.add_dep(os.path.join(self.get_target_dir(d), fname))
+ # Windows doesn't have -rpath, so for EXEs that need DLLs built within
+ # the project, we need to set PATH so the DLLs are found. We use
+ # a serialized executable wrapper for that and check if the
+ # CustomTarget command needs extra paths first.
+ if mesonlib.is_windows() and \
+ self.determine_windows_extra_paths(target.command[0]):
+ exe_data = self.serialise_executable(target.command[0], cmd[1:],
+ # All targets are built from the build dir
+ self.environment.get_build_dir())
+ cmd = [sys.executable, self.environment.get_build_command(),
+ '--internal', 'exe', exe_data]
+ cmd_type = 'meson_exe.py custom'
+ else:
+ cmd_type = 'custom'
elem.add_item('COMMAND', cmd)
- elem.add_item('description', 'Generating %s with a custom command.' % target.name)
+ elem.add_item('description', desc.format(target.name, cmd_type))
elem.write(outfile)
self.processed_targets[target.name + target.type_suffix()] = True
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 3b05afb..052c178 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -163,7 +163,10 @@ itself as required.'''
def run_script_command(args):
cmdname = args[0]
cmdargs = args[1:]
- if cmdname == 'test':
+ if cmdname == 'exe':
+ import mesonbuild.scripts.meson_exe as abc
+ cmdfunc = abc.run
+ elif cmdname == 'test':
import mesonbuild.scripts.meson_test as abc
cmdfunc = abc.run
elif cmdname == 'benchmark':
diff --git a/mesonbuild/scripts/meson_exe.py b/mesonbuild/scripts/meson_exe.py
new file mode 100644
index 0000000..2b91de8
--- /dev/null
+++ b/mesonbuild/scripts/meson_exe.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+
+# Copyright 2013-2016 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+import argparse
+import pickle
+import platform
+import subprocess
+
+import mesonbuild
+
+options = None
+
+parser = argparse.ArgumentParser()
+parser.add_argument('args', nargs='+')
+
+def is_windows():
+ platname = platform.system().lower()
+ return platname == 'windows' or 'mingw' in platname
+
+def run_with_mono(fname):
+ if fname.endswith('.exe') and not is_windows():
+ return True
+ return False
+
+def run_exe(exe):
+ if exe.fname[0].endswith('.jar'):
+ cmd = ['java', '-jar'] + exe.fname
+ elif not exe.is_cross and run_with_mono(exe.fname[0]):
+ cmd = ['mono'] + exe.fname
+ else:
+ if exe.is_cross:
+ if exe.exe_runner is None:
+ raise Exception('BUG: Trying to run cross-compiled exes with no wrapper')
+ else:
+ cmd = [exe.exe_runner] + exe.fname
+ else:
+ cmd = exe.fname
+ child_env = os.environ.copy()
+ child_env.update(exe.env)
+ if len(exe.extra_paths) > 0:
+ child_env['PATH'] = child_env['PATH'] + ';'.join([''] + exe.extra_paths)
+ p = subprocess.Popen(cmd + exe.cmd_args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=child_env,
+ cwd=exe.workdir)
+
+def run(args):
+ global options
+ options = parser.parse_args(args)
+ if len(options.args) != 1:
+ print('Test runner for Meson. Do not run on your own, mmm\'kay?')
+ print(sys.argv[0] + ' [data file]')
+ exe_data_file = options.args[0]
+ exe = pickle.load(open(exe_data_file, 'rb'))
+ run_exe(exe)
+
+if __name__ == '__main__':
+ sys.exit(run(sys.argv[1:]))