diff options
author | John Ericson <git@JohnEricson.me> | 2020-08-03 11:48:27 -0400 |
---|---|---|
committer | John Ericson <git@JohnEricson.me> | 2020-08-03 11:48:27 -0400 |
commit | eaf6343c065842b9719793066e765b2e5f1c2f3b (patch) | |
tree | 1bfeac5297ba489721e704e63c28f33d0fb98990 /mesonbuild/scripts | |
parent | 87aa98c1787d800145853a8e84654e4c54ee1078 (diff) | |
parent | 70edf82c6c77902cd64f44848302bbac92d611d8 (diff) | |
download | meson-lang-enum.tar.gz |
Merge remote-tracking branch 'upstream/master' into lang-enumlang-enum
Diffstat (limited to 'mesonbuild/scripts')
-rwxr-xr-x | mesonbuild/scripts/cmake_run_ctgt.py | 100 | ||||
-rw-r--r-- | mesonbuild/scripts/coverage.py | 46 | ||||
-rw-r--r-- | mesonbuild/scripts/depfixer.py | 32 | ||||
-rw-r--r-- | mesonbuild/scripts/gtkdochelper.py | 8 | ||||
-rw-r--r-- | mesonbuild/scripts/symbolextractor.py | 35 |
5 files changed, 197 insertions, 24 deletions
diff --git a/mesonbuild/scripts/cmake_run_ctgt.py b/mesonbuild/scripts/cmake_run_ctgt.py new file mode 100755 index 000000000..5c0b31f6f --- /dev/null +++ b/mesonbuild/scripts/cmake_run_ctgt.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 + +import argparse +import subprocess +import shutil +import os +import sys +from pathlib import Path + +def run(argsv): + commands = [[]] + SEPARATOR = ';;;' + + # Generate CMD parameters + parser = argparse.ArgumentParser(description='Wrapper for add_custom_command') + parser.add_argument('-d', '--directory', type=str, metavar='D', required=True, help='Working directory to cwd to') + parser.add_argument('-o', '--outputs', nargs='+', metavar='O', required=True, help='Expected output files') + parser.add_argument('-O', '--original-outputs', nargs='*', metavar='O', default=[], help='Output files expected by CMake') + parser.add_argument('commands', nargs=argparse.REMAINDER, help='A "{}" seperated list of commands'.format(SEPARATOR)) + + # Parse + args = parser.parse_args(argsv) + + dummy_target = None + if len(args.outputs) == 1 and len(args.original_outputs) == 0: + dummy_target = args.outputs[0] + elif len(args.outputs) != len(args.original_outputs): + print('Length of output list and original output list differ') + sys.exit(1) + + for i in args.commands: + if i == SEPARATOR: + commands += [[]] + continue + + i = i.replace('"', '') # Remove lefover quotes + commands[-1] += [i] + + # Execute + for i in commands: + # Skip empty lists + if not i: + continue + + cmd = [] + stdout = None + stderr = None + capture_file = '' + + for j in i: + if j in ['>', '>>']: + stdout = subprocess.PIPE + continue + elif j in ['&>', '&>>']: + stdout = subprocess.PIPE + stderr = subprocess.STDOUT + continue + + if stdout is not None or stderr is not None: + capture_file += j + else: + cmd += [j] + + try: + os.makedirs(args.directory, exist_ok=True) + + res = subprocess.run(cmd, stdout=stdout, stderr=stderr, cwd=args.directory, check=True) + if capture_file: + out_file = Path(args.directory) / capture_file + out_file.write_bytes(res.stdout) + except subprocess.CalledProcessError: + sys.exit(1) + + if dummy_target: + with open(dummy_target, 'a'): + os.utime(dummy_target, None) + sys.exit(0) + + # Copy outputs + zipped_outputs = zip(args.outputs, args.original_outputs) + for expected, generated in zipped_outputs: + do_copy = False + if not os.path.exists(expected): + if not os.path.exists(generated): + print('Unable to find generated file. This can cause the build to fail:') + print(generated) + do_copy = False + else: + do_copy = True + elif os.path.exists(generated): + if os.path.getmtime(generated) > os.path.getmtime(expected): + do_copy = True + + if do_copy: + if os.path.exists(expected): + os.remove(expected) + shutil.copyfile(generated, expected) + +if __name__ == '__main__': + sys.run(sys.argv[1:]) diff --git a/mesonbuild/scripts/coverage.py b/mesonbuild/scripts/coverage.py index 4bd41fe91..72319724d 100644 --- a/mesonbuild/scripts/coverage.py +++ b/mesonbuild/scripts/coverage.py @@ -12,15 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -from mesonbuild import environment +from mesonbuild import environment, mesonlib -import argparse, sys, os, subprocess, pathlib +import argparse, sys, os, subprocess, pathlib, stat -def coverage(outputs, source_root, subproject_root, build_root, log_dir): +def coverage(outputs, source_root, subproject_root, build_root, log_dir, use_llvm_cov): outfiles = [] exitcode = 0 - (gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe) = environment.find_coverage_tools() + (gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe, llvm_cov_exe) = environment.find_coverage_tools() # gcovr >= 4.2 requires a different syntax for out of source builds if gcovr_new_rootdir: @@ -28,13 +28,18 @@ def coverage(outputs, source_root, subproject_root, build_root, log_dir): else: gcovr_base_cmd = [gcovr_exe, '-r', build_root] + if use_llvm_cov: + gcov_exe_args = ['--gcov-executable', llvm_cov_exe + ' gcov'] + else: + gcov_exe_args = [] + if not outputs or 'xml' in outputs: if gcovr_exe: subprocess.check_call(gcovr_base_cmd + ['-x', '-e', subproject_root, - '-o', os.path.join(log_dir, 'coverage.xml'), - ]) + '-o', os.path.join(log_dir, 'coverage.xml') + ] + gcov_exe_args) outfiles.append(('Xml', pathlib.Path(log_dir, 'coverage.xml'))) elif outputs: print('gcovr >= 3.3 needed to generate Xml coverage report') @@ -44,8 +49,8 @@ def coverage(outputs, source_root, subproject_root, build_root, log_dir): if gcovr_exe: subprocess.check_call(gcovr_base_cmd + ['-e', subproject_root, - '-o', os.path.join(log_dir, 'coverage.txt'), - ]) + '-o', os.path.join(log_dir, 'coverage.txt') + ] + gcov_exe_args) outfiles.append(('Text', pathlib.Path(log_dir, 'coverage.txt'))) elif outputs: print('gcovr >= 3.3 needed to generate text coverage report') @@ -58,19 +63,34 @@ def coverage(outputs, source_root, subproject_root, build_root, log_dir): initial_tracefile = covinfo + '.initial' run_tracefile = covinfo + '.run' raw_tracefile = covinfo + '.raw' + if use_llvm_cov: + # Create a shim to allow using llvm-cov as a gcov tool. + if mesonlib.is_windows(): + llvm_cov_shim_path = os.path.join(log_dir, 'llvm-cov.bat') + with open(llvm_cov_shim_path, 'w') as llvm_cov_bat: + llvm_cov_bat.write('@"{}" gcov %*'.format(llvm_cov_exe)) + else: + llvm_cov_shim_path = os.path.join(log_dir, 'llvm-cov.sh') + with open(llvm_cov_shim_path, 'w') as llvm_cov_sh: + llvm_cov_sh.write('#!/usr/bin/env sh\nexec "{}" gcov $@'.format(llvm_cov_exe)) + os.chmod(llvm_cov_shim_path, os.stat(llvm_cov_shim_path).st_mode | stat.S_IEXEC) + gcov_tool_args = ['--gcov-tool', llvm_cov_shim_path] + else: + gcov_tool_args = [] subprocess.check_call([lcov_exe, '--directory', build_root, '--capture', '--initial', '--output-file', - initial_tracefile]) + initial_tracefile] + + gcov_tool_args) subprocess.check_call([lcov_exe, '--directory', build_root, '--capture', '--output-file', run_tracefile, '--no-checksum', - '--rc', 'lcov_branch_coverage=1', - ]) + '--rc', 'lcov_branch_coverage=1'] + + gcov_tool_args) # Join initial and test results. subprocess.check_call([lcov_exe, '-a', initial_tracefile, @@ -137,6 +157,8 @@ def run(args): const='xml', help='generate Xml report') parser.add_argument('--html', dest='outputs', action='append_const', const='html', help='generate Html report') + parser.add_argument('--use_llvm_cov', action='store_true', + help='use llvm-cov') parser.add_argument('source_root') parser.add_argument('subproject_root') parser.add_argument('build_root') @@ -144,7 +166,7 @@ def run(args): options = parser.parse_args(args) return coverage(options.outputs, options.source_root, options.subproject_root, options.build_root, - options.log_dir) + options.log_dir, options.use_llvm_cov) if __name__ == '__main__': sys.exit(run(sys.argv[1:])) diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py index 5ba3a9728..a3a3eff05 100644 --- a/mesonbuild/scripts/depfixer.py +++ b/mesonbuild/scripts/depfixer.py @@ -290,13 +290,13 @@ class Elf(DataSizes): self.bf.seek(offset) self.bf.write(newname) - def fix_rpath(self, new_rpath): + def fix_rpath(self, rpath_dirs_to_remove, new_rpath): # The path to search for can be either rpath or runpath. # Fix both of them to be sure. - self.fix_rpathtype_entry(new_rpath, DT_RPATH) - self.fix_rpathtype_entry(new_rpath, DT_RUNPATH) + self.fix_rpathtype_entry(rpath_dirs_to_remove, new_rpath, DT_RPATH) + self.fix_rpathtype_entry(rpath_dirs_to_remove, new_rpath, DT_RUNPATH) - def fix_rpathtype_entry(self, new_rpath, entrynum): + def fix_rpathtype_entry(self, rpath_dirs_to_remove, new_rpath, entrynum): if isinstance(new_rpath, str): new_rpath = new_rpath.encode('utf8') rp_off = self.get_entry_offset(entrynum) @@ -305,7 +305,23 @@ class Elf(DataSizes): print('File does not have rpath. It should be a fully static executable.') return self.bf.seek(rp_off) + old_rpath = self.read_str() + new_rpaths = [] + if new_rpath: + new_rpaths.append(new_rpath) + if old_rpath: + # Filter out build-only rpath entries + # added by get_link_dep_subdirs() or + # specified by user with build_rpath. + for dir in old_rpath.split(b':'): + if not (dir in rpath_dirs_to_remove or + dir == (b'X' * len(dir))): + new_rpaths.append(dir) + + # Prepend user-specified new entries while preserving the ones that came from pkgconfig etc. + new_rpath = b':'.join(new_rpaths) + if len(old_rpath) < len(new_rpath): sys.exit("New rpath must not be longer than the old one.") # The linker does read-only string deduplication. If there is a @@ -343,13 +359,13 @@ class Elf(DataSizes): entry.write(self.bf) return None -def fix_elf(fname, new_rpath, verbose=True): +def fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose=True): with Elf(fname, verbose) as e: if new_rpath is None: e.print_rpath() e.print_runpath() else: - e.fix_rpath(new_rpath) + e.fix_rpath(rpath_dirs_to_remove, new_rpath) def get_darwin_rpaths_to_remove(fname): out = subprocess.check_output(['otool', '-l', fname], @@ -430,7 +446,7 @@ def fix_jar(fname): f.truncate() subprocess.check_call(['jar', 'ufm', fname, 'META-INF/MANIFEST.MF']) -def fix_rpath(fname, new_rpath, final_path, install_name_mappings, verbose=True): +def fix_rpath(fname, rpath_dirs_to_remove, new_rpath, final_path, install_name_mappings, verbose=True): global INSTALL_NAME_TOOL # Static libraries, import libraries, debug information, headers, etc # never have rpaths @@ -441,7 +457,7 @@ def fix_rpath(fname, new_rpath, final_path, install_name_mappings, verbose=True) if fname.endswith('.jar'): fix_jar(fname) return - fix_elf(fname, new_rpath, verbose) + fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose) return except SystemExit as e: if isinstance(e.code, int) and e.code == 0: diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py index 6b174a6c4..812604af5 100644 --- a/mesonbuild/scripts/gtkdochelper.py +++ b/mesonbuild/scripts/gtkdochelper.py @@ -16,7 +16,7 @@ import sys, os import subprocess import shutil import argparse -from ..mesonlib import MesonException, Popen_safe, is_windows, split_args +from ..mesonlib import MesonException, Popen_safe, is_windows, is_cygwin, split_args from . import destdir_join parser = argparse.ArgumentParser() @@ -55,16 +55,18 @@ def gtkdoc_run_check(cmd, cwd, library_paths=None): library_paths = [] env = dict(os.environ) - if is_windows(): + if is_windows() or is_cygwin(): if 'PATH' in env: library_paths.extend(env['PATH'].split(os.pathsep)) env['PATH'] = os.pathsep.join(library_paths) - cmd.insert(0, sys.executable) else: if 'LD_LIBRARY_PATH' in env: library_paths.extend(env['LD_LIBRARY_PATH'].split(os.pathsep)) env['LD_LIBRARY_PATH'] = os.pathsep.join(library_paths) + if is_windows(): + cmd.insert(0, sys.executable) + # Put stderr into stdout since we want to print it out anyway. # This preserves the order of messages. p, out = Popen_safe(cmd, cwd=cwd, env=env, stderr=subprocess.STDOUT)[0:2] diff --git a/mesonbuild/scripts/symbolextractor.py b/mesonbuild/scripts/symbolextractor.py index d393f933e..f4084bea8 100644 --- a/mesonbuild/scripts/symbolextractor.py +++ b/mesonbuild/scripts/symbolextractor.py @@ -113,11 +113,23 @@ def gnu_syms(libfilename: str, outfilename: str): continue line_split = line.split() entry = line_split[0:2] - if len(line_split) >= 4: + # Store the size of symbols pointing to data objects so we relink + # when those change, which is needed because of copy relocations + # https://github.com/mesonbuild/meson/pull/7132#issuecomment-628353702 + if line_split[1].upper() in ('B', 'G', 'D') and len(line_split) >= 4: entry += [line_split[3]] result += [' '.join(entry)] write_if_changed('\n'.join(result) + '\n', outfilename) +def solaris_syms(libfilename: str, outfilename: str): + # gnu_syms() works with GNU nm & readelf, not Solaris nm & elfdump + origpath = os.environ['PATH'] + try: + os.environ['PATH'] = '/usr/gnu/bin:' + origpath + gnu_syms(libfilename, outfilename) + finally: + os.environ['PATH'] = origpath + def osx_syms(libfilename: str, outfilename: str): # Get the name of the library output = call_tool('otool', ['-l', libfilename]) @@ -139,6 +151,23 @@ def osx_syms(libfilename: str, outfilename: str): result += [' '.join(x.split()[0:2]) for x in output.split('\n')] write_if_changed('\n'.join(result) + '\n', outfilename) +def openbsd_syms(libfilename: str, outfilename: str): + # Get the name of the library + output = call_tool('readelf', ['-d', libfilename]) + if not output: + dummy_syms(outfilename) + return + result = [x for x in output.split('\n') if 'SONAME' in x] + assert(len(result) <= 1) + # Get a list of all symbols exported + output = call_tool('nm', ['-D', '-P', '-g', libfilename]) + if not output: + dummy_syms(outfilename) + return + # U = undefined (cope with the lack of --defined-only option) + result += [' '.join(x.split()[0:2]) for x in output.split('\n') if x and not x.endswith('U ')] + write_if_changed('\n'.join(result) + '\n', outfilename) + def cygwin_syms(impfilename: str, outfilename: str): # Get the name of the library output = call_tool('dlltool', ['-I', impfilename]) @@ -234,6 +263,8 @@ def gen_symbols(libfilename: str, impfilename: str, outfilename: str, cross_host gnu_syms(libfilename, outfilename) elif mesonlib.is_osx(): osx_syms(libfilename, outfilename) + elif mesonlib.is_openbsd(): + openbsd_syms(libfilename, outfilename) elif mesonlib.is_windows(): if os.path.isfile(impfilename): windows_syms(impfilename, outfilename) @@ -248,6 +279,8 @@ def gen_symbols(libfilename: str, impfilename: str, outfilename: str, cross_host # No import library. Not sure how the DLL is being used, so just # rebuild everything that links to it every time. dummy_syms(outfilename) + elif mesonlib.is_sunos(): + solaris_syms(libfilename, outfilename) else: if not os.path.exists(TOOL_WARNING_FILE): mlog.warning('Symbol extracting has not been implemented for this ' |