diff options
-rw-r--r-- | mesonbuild/backend/backends.py | 41 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 17 | ||||
-rw-r--r-- | mesonbuild/mesonmain.py | 5 | ||||
-rw-r--r-- | mesonbuild/scripts/meson_exe.py | 74 |
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:])) |