diff --git a/README.chromium b/README.chromium index 6b84c0dbd..e703b5eb6 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 1440 +Version: 1441 License: BSD License File: LICENSE diff --git a/include/libyuv/version.h b/include/libyuv/version.h index 355e415c7..b78a44bae 100644 --- a/include/libyuv/version.h +++ b/include/libyuv/version.h @@ -11,6 +11,6 @@ #ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT #define INCLUDE_LIBYUV_VERSION_H_ -#define LIBYUV_VERSION 1440 +#define LIBYUV_VERSION 1441 #endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT diff --git a/source/convert.cc b/source/convert.cc index a38b93676..22a8fa81e 100644 --- a/source/convert.cc +++ b/source/convert.cc @@ -817,22 +817,20 @@ int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24, src_stride_rgb24 = -src_stride_rgb24; } +// Neon version does direct RGB24 to YUV. #if defined(HAS_RGB24TOYROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { + RGB24ToUVRow = RGB24ToUVRow_Any_NEON; RGB24ToYRow = RGB24ToYRow_Any_NEON; if (IS_ALIGNED(width, 8)) { RGB24ToYRow = RGB24ToYRow_NEON; + if (IS_ALIGNED(width, 16)) { + RGB24ToUVRow = RGB24ToUVRow_NEON; + } } } -#endif -#if defined(HAS_RGB24TOUVROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - RGB24ToUVRow = RGB24ToUVRow_Any_NEON; - if (IS_ALIGNED(width, 16)) { - RGB24ToUVRow = RGB24ToUVRow_NEON; - } - } -#endif +// Other platforms do intermediate conversion from RGB24 to ARGB. +#else #if defined(HAS_RGB24TOARGBROW_SSSE3) if (TestCpuFlag(kCpuHasSSSE3)) { RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; @@ -861,7 +859,6 @@ int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24, } } #endif -#if !defined(HAS_RGB24TOYROW_NEON) { // Allocate 2 rows of ARGB. const int kRowSize = (width * 4 + 31) & ~31; @@ -934,22 +931,20 @@ int RAWToI420(const uint8* src_raw, int src_stride_raw, src_stride_raw = -src_stride_raw; } +// Neon version does direct RAW to YUV. #if defined(HAS_RAWTOYROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { + RAWToUVRow = RAWToUVRow_Any_NEON; RAWToYRow = RAWToYRow_Any_NEON; if (IS_ALIGNED(width, 8)) { RAWToYRow = RAWToYRow_NEON; + if (IS_ALIGNED(width, 16)) { + RAWToUVRow = RAWToUVRow_NEON; + } } } -#endif -#if defined(HAS_RAWTOUVROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - RAWToUVRow = RAWToUVRow_Any_NEON; - if (IS_ALIGNED(width, 16)) { - RAWToUVRow = RAWToUVRow_NEON; - } - } -#endif +// Other platforms do intermediate conversion from RAW to ARGB. +#else #if defined(HAS_RAWTOARGBROW_SSSE3) if (TestCpuFlag(kCpuHasSSSE3)) { RAWToARGBRow = RAWToARGBRow_Any_SSSE3; @@ -978,7 +973,6 @@ int RAWToI420(const uint8* src_raw, int src_stride_raw, } } #endif -#if !defined(HAS_RAWTOYROW_NEON) { // Allocate 2 rows of ARGB. const int kRowSize = (width * 4 + 31) & ~31; @@ -1051,18 +1045,20 @@ int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565, src_stride_rgb565 = -src_stride_rgb565; } +// Neon version does direct RGB565 to YUV. #if defined(HAS_RGB565TOYROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { + RGB565ToUVRow = RGB565ToUVRow_Any_NEON; RGB565ToYRow = RGB565ToYRow_Any_NEON; if (IS_ALIGNED(width, 8)) { RGB565ToYRow = RGB565ToYRow_NEON; - } - RGB565ToUVRow = RGB565ToUVRow_Any_NEON; - if (IS_ALIGNED(width, 16)) { - RGB565ToUVRow = RGB565ToUVRow_NEON; + if (IS_ALIGNED(width, 16)) { + RGB565ToUVRow = RGB565ToUVRow_NEON; + } } } -#endif +// Other platforms do intermediate conversion from RGB565 to ARGB. +#else #if defined(HAS_RGB565TOARGBROW_SSE2) if (TestCpuFlag(kCpuHasSSE2)) { RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; @@ -1099,7 +1095,6 @@ int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565, } } #endif -#if !defined(HAS_RGB565TOYROW_NEON) { // Allocate 2 rows of ARGB. const int kRowSize = (width * 4 + 31) & ~31; @@ -1172,19 +1167,20 @@ int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555, src_stride_argb1555 = -src_stride_argb1555; } +// Neon version does direct ARGB1555 to YUV. #if defined(HAS_ARGB1555TOYROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { + ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON; ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON; if (IS_ALIGNED(width, 8)) { ARGB1555ToYRow = ARGB1555ToYRow_NEON; - } - ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON; - if (IS_ALIGNED(width, 16)) { - ARGB1555ToUVRow = ARGB1555ToUVRow_NEON; + if (IS_ALIGNED(width, 16)) { + ARGB1555ToUVRow = ARGB1555ToUVRow_NEON; + } } } -#endif - +// Other platforms do intermediate conversion from ARGB1555 to ARGB. +#else #if defined(HAS_ARGB1555TOARGBROW_SSE2) if (TestCpuFlag(kCpuHasSSE2)) { ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; @@ -1221,12 +1217,12 @@ int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555, } } #endif -#if !defined(HAS_ARGB1555TOYROW_NEON) { // Allocate 2 rows of ARGB. const int kRowSize = (width * 4 + 31) & ~31; align_buffer_64(row, kRowSize * 2); #endif + for (y = 0; y < height - 1; y += 2) { #if defined(HAS_ARGB1555TOYROW_NEON) ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width); @@ -1236,6 +1232,7 @@ int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555, #else ARGB1555ToARGBRow(src_argb1555, row, width); ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize, + width); ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); ARGBToYRow(row, dst_y, width); @@ -1295,19 +1292,20 @@ int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444, src_stride_argb4444 = -src_stride_argb4444; } +// Neon version does direct ARGB4444 to YUV. #if defined(HAS_ARGB4444TOYROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { + ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON; ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON; if (IS_ALIGNED(width, 8)) { ARGB4444ToYRow = ARGB4444ToYRow_NEON; - } - ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON; - if (IS_ALIGNED(width, 16)) { - ARGB4444ToUVRow = ARGB4444ToUVRow_NEON; + if (IS_ALIGNED(width, 16)) { + ARGB4444ToUVRow = ARGB4444ToUVRow_NEON; + } } } -#endif - +// Other platforms do intermediate conversion from ARGB4444 to ARGB. +#else #if defined(HAS_ARGB4444TOARGBROW_SSE2) if (TestCpuFlag(kCpuHasSSE2)) { ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; @@ -1344,8 +1342,6 @@ int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444, } } #endif - -#if !defined(HAS_ARGB4444TOYROW_NEON) { // Allocate 2 rows of ARGB. const int kRowSize = (width * 4 + 31) & ~31; diff --git a/tools/protoc_wrapper/protoc_wrapper.py b/tools/protoc_wrapper/protoc_wrapper.py new file mode 100644 index 000000000..e6ddf9518 --- /dev/null +++ b/tools/protoc_wrapper/protoc_wrapper.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +A simple wrapper for protoc. + +- Adds includes in generated headers. +- Handles building with system protobuf as an option. +""" + +import fnmatch +import optparse +import os.path +import shutil +import subprocess +import sys +import tempfile + +PROTOC_INCLUDE_POINT = '// @@protoc_insertion_point(includes)\n' + +def ModifyHeader(header_file, extra_header): + """Adds |extra_header| to |header_file|. Returns 0 on success. + + |extra_header| is the name of the header file to include. + |header_file| is a generated protobuf cpp header. + """ + include_point_found = False + header_contents = [] + with open(header_file) as f: + for line in f: + header_contents.append(line) + if line == PROTOC_INCLUDE_POINT: + extra_header_msg = '#include "%s"\n' % extra_header + header_contents.append(extra_header_msg) + include_point_found = True; + if not include_point_found: + return 1 + + with open(header_file, 'wb') as f: + f.write(''.join(header_contents)) + return 0 + +def ScanForBadFiles(scan_root): + """Scan for bad file names, see http://crbug.com/386125 for details. + Returns True if any filenames are bad. Outputs errors to stderr. + + |scan_root| is the path to the directory to be recursively scanned. + """ + badname = False + real_scan_root = os.path.realpath(scan_root) + for dirpath, dirnames, filenames in os.walk(real_scan_root): + matches = fnmatch.filter(filenames, '*-*.proto') + if len(matches) > 0: + if not badname: + badname = True + sys.stderr.write('proto files must not have hyphens in their names (' + 'see http://crbug.com/386125 for more information):\n') + for filename in matches: + sys.stderr.write(' ' + os.path.join(real_scan_root, + dirpath, filename) + '\n') + return badname + + +def RewriteProtoFilesForSystemProtobuf(path): + wrapper_dir = tempfile.mkdtemp() + try: + for filename in os.listdir(path): + if not filename.endswith('.proto'): + continue + with open(os.path.join(path, filename), 'r') as src_file: + with open(os.path.join(wrapper_dir, filename), 'w') as dst_file: + for line in src_file: + # Remove lines that break build with system protobuf. + # We cannot optimize for lite runtime, because system lite runtime + # does not have a Chromium-specific hack to retain unknown fields. + # Similarly, it does not understand corresponding option to control + # the usage of that hack. + if 'LITE_RUNTIME' in line or 'retain_unknown_fields' in line: + continue + dst_file.write(line) + + return wrapper_dir + except: + shutil.rmtree(wrapper_dir) + raise + + +def main(argv): + parser = optparse.OptionParser() + parser.add_option('--include', dest='extra_header', + help='The extra header to include. This must be specified ' + 'along with --protobuf.') + parser.add_option('--protobuf', dest='generated_header', + help='The c++ protobuf header to add the extra header to. ' + 'This must be specified along with --include.') + parser.add_option('--proto-in-dir', + help='The directory containing .proto files.') + parser.add_option('--proto-in-file', help='Input file to compile.') + parser.add_option('--use-system-protobuf', type=int, default=0, + help='Option to use system-installed protobuf ' + 'instead of bundled one.') + (options, args) = parser.parse_args(sys.argv) + if len(args) < 2: + return 1 + + if ScanForBadFiles(options.proto_in_dir): + return 1 + + proto_path = options.proto_in_dir + if options.use_system_protobuf == 1: + proto_path = RewriteProtoFilesForSystemProtobuf(proto_path) + try: + # Run what is hopefully protoc. + protoc_args = args[1:] + protoc_args += ['--proto_path=%s' % proto_path, + os.path.join(proto_path, options.proto_in_file)] + ret = subprocess.call(protoc_args) + if ret != 0: + return ret + finally: + if options.use_system_protobuf == 1: + # Remove temporary directory holding re-written files. + shutil.rmtree(proto_path) + + # protoc succeeded, check to see if the generated cpp header needs editing. + if not options.extra_header or not options.generated_header: + return 0 + return ModifyHeader(options.generated_header, options.extra_header) + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/tools/swarming_client b/tools/swarming_client new file mode 160000 index 000000000..b39a448d8 --- /dev/null +++ b/tools/swarming_client @@ -0,0 +1 @@ +Subproject commit b39a448d8522392389b28f6997126a6ab04bfe87 diff --git a/tools/vim/chromium.ycm_extra_conf.py b/tools/vim/chromium.ycm_extra_conf.py new file mode 100644 index 000000000..5715e294d --- /dev/null +++ b/tools/vim/chromium.ycm_extra_conf.py @@ -0,0 +1,407 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Autocompletion config for YouCompleteMe in Chromium. +# +# USAGE: +# +# 1. Install YCM [https://github.com/Valloric/YouCompleteMe] +# (Googlers should check out [go/ycm]) +# +# 2. Create a symbolic link to this file called .ycm_extra_conf.py in the +# directory above your Chromium checkout (i.e. next to your .gclient file). +# +# cd src +# ln -rs tools/vim/chromium.ycm_extra_conf.py ../.ycm_extra_conf.py +# +# 3. (optional) Whitelist the .ycm_extra_conf.py from step #2 by adding the +# following to your .vimrc: +# +# let g:ycm_extra_conf_globlist=[''] +# +# You can also add other .ycm_extra_conf.py files you want to use to this +# list to prevent excessive prompting each time you visit a directory +# covered by a config file. +# +# 4. Profit +# +# +# Usage notes: +# +# * You must use ninja & clang to build Chromium. +# +# * You must have run gyp_chromium and built Chromium recently. +# +# +# Hacking notes: +# +# * The purpose of this script is to construct an accurate enough command line +# for YCM to pass to clang so it can build and extract the symbols. +# +# * Right now, we only pull the -I and -D flags. That seems to be sufficient +# for everything I've used it for. +# +# * That whole ninja & clang thing? We could support other configs if someone +# were willing to write the correct commands and a parser. +# +# * This has only been tested on gPrecise. + + +import os +import os.path +import re +import shlex +import subprocess +import sys + +# A dictionary mapping Clang binary path to a list of Clang command line +# arguments that specify the system include paths. It is used as a cache of the +# system include options since these options aren't expected to change per +# source file for the same clang binary. SystemIncludeDirectoryFlags() updates +# this map each time it runs a Clang binary to determine system include paths. +# +# Entries look like: +# '/home/username/my-llvm/bin/clang++': ['-isystem', +# '/home/username/my-llvm/include', '-isystem', '/usr/include'] +_clang_system_include_map = {} + + +# Flags from YCM's default config. +_default_flags = [ + '-DUSE_CLANG_COMPLETER', + '-std=c++11', + '-x', + 'c++', +] + + +def FallbackSystemIncludeDirectoryFlags(): + """Returns a best guess list of system include directory flags for Clang. + + If Ninja doesn't give us a build step that specifies a Clang invocation or if + something goes wrong while determining the system include paths, then this + function can be used to determine some set of values that's better than + nothing. + + Returns: + (List of Strings) Compiler flags that specify the system include paths. + """ + if _clang_system_include_map: + return _clang_system_include_map.itervalues().next() + return [] + + +def SystemIncludeDirectoryFlags(clang_binary, clang_flags): + """Determines compile flags for specifying system include directories. + + Use as a workaround for https://github.com/Valloric/YouCompleteMe/issues/303 + + Caches the results of determining the system include directories in + _clang_system_include_map. Subsequent calls to SystemIncludeDirectoryFlags() + uses the cached results for the same binary even if |clang_flags| differ. + + Args: + clang_binary: (String) Path to clang binary. + clang_flags: (List of Strings) List of additional flags to clang. It may + affect the choice of system include directories if -stdlib= is specified. + _default_flags are always included in the list of flags passed to clang. + + Returns: + (List of Strings) Compile flags to append. + """ + + if clang_binary in _clang_system_include_map: + return _clang_system_include_map[clang_binary] + + all_clang_flags = [] + _default_flags + all_clang_flags += [flag for flag in clang_flags + if flag.startswith('-std=') or flag.startswith('-stdlib=')] + all_clang_flags += ['-v', '-E', '-'] + try: + with open(os.devnull, 'rb') as DEVNULL: + output = subprocess.check_output([clang_binary] + all_clang_flags, + stdin=DEVNULL, stderr=subprocess.STDOUT) + except: + # Even though we couldn't figure out the flags for the given binary, if we + # have results from another one, we'll use that. This logic assumes that the + # list of default system directories for one binary can be used with + # another. + return FallbackSystemIncludeDirectoryFlags() + includes_regex = r'#include <\.\.\.> search starts here:\s*' \ + r'(.*?)End of search list\.' + includes = re.search(includes_regex, output.decode(), re.DOTALL).group(1) + system_include_flags = [] + for path in includes.splitlines(): + path = path.strip() + if os.path.isdir(path): + system_include_flags.append('-isystem') + system_include_flags.append(path) + if system_include_flags: + _clang_system_include_map[clang_binary] = system_include_flags + return system_include_flags + + +def PathExists(*args): + return os.path.exists(os.path.join(*args)) + + +def FindChromeSrcFromFilename(filename): + """Searches for the root of the Chromium checkout. + + Simply checks parent directories until it finds .gclient and src/. + + Args: + filename: (String) Path to source file being edited. + + Returns: + (String) Path of 'src/', or None if unable to find. + """ + curdir = os.path.normpath(os.path.dirname(filename)) + while not (os.path.basename(os.path.realpath(curdir)) == 'src' + and PathExists(curdir, 'DEPS') + and (PathExists(curdir, '..', '.gclient') + or PathExists(curdir, '.git'))): + nextdir = os.path.normpath(os.path.join(curdir, '..')) + if nextdir == curdir: + return None + curdir = nextdir + return curdir + + +def GetDefaultCppFile(chrome_root, filename): + """Returns the default target file to use for |filename|. + + The default target is some source file that is known to exist and loosely + related to |filename|. Compile flags used to build the default target is + assumed to be a close-enough approximation for building |filename|. + + Args: + chrome_root: (String) Absolute path to the root of Chromium checkout. + filename: (String) Absolute path to the target source file. + + Returns: + (String) Absolute path to substitute target file. + """ + blink_root = os.path.join(chrome_root, 'third_party', 'WebKit') + if filename.startswith(blink_root): + return os.path.join(blink_root, 'Source', 'core', 'Init.cpp') + else: + return os.path.join(chrome_root, 'base', 'logging.cc') + + +def GetBuildTargetForSourceFile(chrome_root, filename): + """Returns a build target corresponding to |filename|. + + Args: + chrome_root: (String) Absolute path to the root of Chromium checkout. + filename: (String) Absolute path to the target source file. + + Returns: + (String) Absolute path to build target. + """ + if filename.endswith('.h'): + # Header files can't be built. Instead, try to match a header file to its + # corresponding source file. + alternates = ['.cc', '.cpp', '.c'] + for alt_extension in alternates: + alt_name = filename[:-2] + alt_extension + if os.path.exists(alt_name): + return alt_name + + # Failing that, build a default file instead and assume that the resulting + # commandline options are valid for the .h file. + return GetDefaultCppFile(chrome_root, filename) + + return filename + + +def GetClangCommandLineFromNinjaForFilename(out_dir, filename): + """Returns the Clang command line for building |filename| + + Asks ninja for the list of commands used to build |filename| and returns the + final Clang invocation. + + Args: + out_dir: (String) Absolute path to ninja build output directory. + filename: (String) Absolute path to source file. + + Returns: + (String) Clang command line or None if command line couldn't be determined. + """ + # Ninja needs the path to the source file relative to the output build + # directory. + rel_filename = os.path.relpath(os.path.realpath(filename), out_dir) + + # Ask ninja how it would build our source file. + p = subprocess.Popen(['ninja', '-v', '-C', out_dir, '-t', + 'commands', rel_filename + '^'], + stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + if p.returncode: + return None + + # Ninja might execute several commands to build something. We want the last + # clang command. + for line in reversed(stdout.split('\n')): + if 'clang' in line: + return line + return None + + +def GetNormalizedClangCommand(command, out_dir): + """Gets the normalized Clang binary path if |command| is a Clang command. + + Args: + command: (String) Clang command. + out_dir: (String) Absolute path the ninja build directory. + + Returns: + (String or None) + None : if command is not a clang command. + Absolute path to clang binary : if |command| is an absolute or relative + path to clang. If relative, it is assumed to be relative to |out_dir|. + |command|: if command is a name of a binary. + """ + if command.endswith('clang++') or command.endswith('clang'): + if os.path.basename(command) == command: + return command + return os.path.normpath(os.path.join(out_dir, command)) + return None + + +def GetClangOptionsFromCommandLine(clang_commandline, out_dir, + additional_flags): + """Extracts relevant command line options from |clang_commandline| + + Args: + clang_commandline: (String) Full Clang invocation. + out_dir: (String) Absolute path to ninja build directory. Relative paths in + the command line are relative to |out_dir|. + additional_flags: (List of String) Additional flags to return. + + Returns: + ((List of Strings), (List of Strings)) The first item in the tuple is a list + of command line flags for this source file. The second item in the tuple is + a list of command line flags that define the system include paths. Either or + both can be empty. + """ + chrome_flags = [] + additional_flags + system_include_flags = [] + + # Parse flags that are important for YCM's purposes. + clang_tokens = shlex.split(clang_commandline) + for flag in clang_tokens: + if flag.startswith('-I'): + # Relative paths need to be resolved, because they're relative to the + # output dir, not the source. + if flag[2] == '/': + chrome_flags.append(flag) + else: + abs_path = os.path.normpath(os.path.join(out_dir, flag[2:])) + chrome_flags.append('-I' + abs_path) + elif flag.startswith('-std'): + chrome_flags.append(flag) + elif flag.startswith('-') and flag[1] in 'DWFfmO': + if flag == '-Wno-deprecated-register' or flag == '-Wno-header-guard': + # These flags causes libclang (3.3) to crash. Remove it until things + # are fixed. + continue + chrome_flags.append(flag) + + # Assume that the command for invoking clang++ looks like one of the + # following: + # 1) /path/to/clang/clang++ arguments + # 2) /some/wrapper /path/to/clang++ arguments + # + # We'll look at the first two tokens on the command line to see if they look + # like Clang commands, and if so use it to determine the system include + # directory flags. + for command in clang_tokens[0:2]: + normalized_command = GetNormalizedClangCommand(command, out_dir) + if normalized_command: + system_include_flags += SystemIncludeDirectoryFlags(normalized_command, + chrome_flags) + break + + return (chrome_flags, system_include_flags) + + +def GetClangOptionsFromNinjaForFilename(chrome_root, filename): + """Returns the Clang command line options needed for building |filename|. + + Command line options are based on the command used by ninja for building + |filename|. If |filename| is a .h file, uses its companion .cc or .cpp file. + If a suitable companion file can't be located or if ninja doesn't know about + |filename|, then uses default source files in Blink and Chromium for + determining the commandline. + + Args: + chrome_root: (String) Path to src/. + filename: (String) Absolute path to source file being edited. + + Returns: + ((List of Strings), (List of Strings)) The first item in the tuple is a list + of command line flags for this source file. The second item in the tuple is + a list of command line flags that define the system include paths. Either or + both can be empty. + """ + if not chrome_root: + return ([],[]) + + # Generally, everyone benefits from including Chromium's src/, because all of + # Chromium's includes are relative to that. + additional_flags = ['-I' + os.path.join(chrome_root)] + + # Version of Clang used to compile Chromium can be newer then version of + # libclang that YCM uses for completion. So it's possible that YCM's libclang + # doesn't know about some used warning options, which causes compilation + # warnings (and errors, because of '-Werror'); + additional_flags.append('-Wno-unknown-warning-option') + + sys.path.append(os.path.join(chrome_root, 'tools', 'vim')) + from ninja_output import GetNinjaOutputDirectory + out_dir = os.path.realpath(GetNinjaOutputDirectory(chrome_root)) + + clang_line = GetClangCommandLineFromNinjaForFilename( + out_dir, GetBuildTargetForSourceFile(chrome_root, filename)) + if not clang_line: + # If ninja didn't know about filename or it's companion files, then try a + # default build target. It is possible that the file is new, or build.ninja + # is stale. + clang_line = GetClangCommandLineFromNinjaForFilename( + out_dir, GetDefaultCppFile(chrome_root, filename)) + + return GetClangOptionsFromCommandLine(clang_line, out_dir, additional_flags) + + +def FlagsForFile(filename): + """This is the main entry point for YCM. Its interface is fixed. + + Args: + filename: (String) Path to source file being edited. + + Returns: + (Dictionary) + 'flags': (List of Strings) Command line flags. + 'do_cache': (Boolean) True if the result should be cached. + """ + abs_filename = os.path.abspath(filename) + chrome_root = FindChromeSrcFromFilename(abs_filename) + (chrome_flags, system_include_flags) = GetClangOptionsFromNinjaForFilename( + chrome_root, abs_filename) + + # If either chrome_flags or system_include_flags could not be determined, then + # assume that was due to a transient failure. Preventing YCM from caching the + # flags allows us to try to determine the flags again. + should_cache_flags_for_file = \ + bool(chrome_flags) and bool(system_include_flags) + + if not system_include_flags: + system_include_flags = FallbackSystemIncludeDirectoryFlags() + final_flags = _default_flags + chrome_flags + system_include_flags + + return { + 'flags': final_flags, + 'do_cache': should_cache_flags_for_file + } diff --git a/tools/vim/clang-format.vim b/tools/vim/clang-format.vim new file mode 100644 index 000000000..982b8d2ed --- /dev/null +++ b/tools/vim/clang-format.vim @@ -0,0 +1,19 @@ +" Copyright (c) 2014 The Chromium Authors. All rights reserved. +" Use of this source code is governed by a BSD-style license that can be +" found in the LICENSE file. + +" Binds cmd-shift-i (on Mac) or ctrl-shift-i (elsewhere) to invoking +" clang-format.py. +" It will format the current selection (and if there's no selection, the +" current line.) + +let s:script = expand(':p:h') . + \'/../../buildtools/clang_format/script/clang-format.py' + +if has('mac') + execute "map :pyf " . s:script . "" + execute "imap :pyf " . s:script . "i" +else + execute "map :pyf " . s:script . "" + execute "imap :pyf " . s:script . "i" +endif diff --git a/tools/vim/filetypes.vim b/tools/vim/filetypes.vim new file mode 100644 index 000000000..3e7c8f9ea --- /dev/null +++ b/tools/vim/filetypes.vim @@ -0,0 +1,9 @@ +" To get syntax highlighting and tab settings for gyp(i) and DEPS files, +" add the following to your .vimrc file: +" so /path/to/src/tools/vim/filetypes.vim + +augroup filetype + au! BufRead,BufNewFile *.gyp set filetype=python expandtab tabstop=2 shiftwidth=2 + au! BufRead,BufNewFile *.gypi set filetype=python expandtab tabstop=2 shiftwidth=2 + au! BufRead,BufNewFile DEPS set filetype=python expandtab tabstop=2 shiftwidth=2 +augroup END diff --git a/tools/vim/mojom/ftdetect/mojomfiletype.vim b/tools/vim/mojom/ftdetect/mojomfiletype.vim new file mode 100644 index 000000000..cff7ce6d1 --- /dev/null +++ b/tools/vim/mojom/ftdetect/mojomfiletype.vim @@ -0,0 +1,28 @@ +" Copyright 2015 The Chromium Authors. All rights reserved. +" Use of this source code is governed by a BSD-style license that can be +" found in the LICENSE file. + +" We take care to preserve the user's fileencodings and fileformats, +" because those settings are global (not buffer local), yet we want +" to override them for loading mojom files, which should be UTF-8. + +let s:current_fileformats = '' +let s:current_fileencodings = '' + +" define fileencodings to open as utf-8 encoding even if it's ascii. +function! s:mojomfiletype_pre() + let s:current_fileformats = &g:fileformats + let s:current_fileencodings = &g:fileencodings + set fileencodings=utf-8 fileformats=unix + setlocal filetype=mojom +endfunction + +" restore fileencodings as others +function! s:mojomfiletype_post() + let &g:fileformats = s:current_fileformats + let &g:fileencodings = s:current_fileencodings +endfunction + +au BufNewFile *.mojom setlocal filetype=mojom fileencoding=utf-8 fileformat=unix +au BufRead *.mojom call s:mojomfiletype_pre() +au BufReadPost *.mojom call s:mojomfiletype_post() diff --git a/tools/vim/mojom/syntax/mojom.vim b/tools/vim/mojom/syntax/mojom.vim new file mode 100644 index 000000000..cdd3f7e72 --- /dev/null +++ b/tools/vim/mojom/syntax/mojom.vim @@ -0,0 +1,48 @@ +" Copyright 2015 The Chromium Authors. All rights reserved. +" Use of this source code is governed by a BSD-style license that can be +" found in the LICENSE file. + +" Vim syntax file " Language: Mojom +" To get syntax highlighting for .mojom files, add the following to your .vimrc +" file: +" set runtimepath^=/path/to/src/tools/vim/mojom + +syn case match + +syntax region mojomFold start="{" end="}" transparent fold + +" keyword definitions +syntax keyword mojomType bool int8 int16 int32 int64 uint8 uint16 uint32 uint64 float double array +syntax match mojomImport "^\(import\)\s" +syntax keyword mojomKeyword const module interface enum struct union +syntax match mojomOperator /=>/ +syntax match mojomOperator /?/ + +" Comments +syntax keyword mojomTodo contained TODO FIXME XXX +syntax region mojomComment start="/\*" end="\*/" contains=mojomTodo,mojomDocLink,@Spell +syntax match mojomLineComment "//.*" contains=mojomTodo,@Spell +syntax match mojomLineDocComment "///.*" contains=mojomTodo,mojomDocLink,@Spell +syntax region mojomDocLink contained start=+\[+ end=+\]+ + +" Strings +syn region mojomString start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell +hi def link mojomString String + +" The default highlighting. +highlight default link mojomTodo Todo +highlight default link mojomComment Comment +highlight default link mojomLineComment Comment +highlight default link mojomLineDocComment Comment +highlight default link mojomDocLink SpecialComment +highlight default link mojomType Type +highlight default link mojomImport Include +highlight default link mojomKeyword Keyword +highlight default link mojomOperator Operator + +let b:current_syntax = "mojom" +let b:spell_options = "contained" + +syn sync minlines=500 + +let b:current_syntax = "mojom" diff --git a/tools/vim/ninja-build.vim b/tools/vim/ninja-build.vim new file mode 100644 index 000000000..70e5a83cf --- /dev/null +++ b/tools/vim/ninja-build.vim @@ -0,0 +1,119 @@ +" Copyright (c) 2012 The Chromium Authors. All rights reserved. +" Use of this source code is governed by a BSD-style license that can be +" found in the LICENSE file. +" +" Adds a "Compile this file" function, using ninja. On Mac, binds Cmd-k to +" this command. On Windows, Ctrl-F7 (which is the same as the VS default). +" On Linux, o, which is \o by default ("o"=creates .o files) +" +" Adds a "Build this target" function, using ninja. This is not bound +" to any key by default, but can be used via the :CrBuild command. +" It builds 'chrome' by default, but :CrBuild target1 target2 etc works as well. +" +" Requires that gyp has already generated build.ninja files, and that ninja is +" in your path (which it is automatically if depot_tools is in your path). +" +" Add the following to your .vimrc file: +" so /path/to/src/tools/vim/ninja-build.vim + +python << endpython +import os +import vim + + +def path_to_current_buffer(): + """Returns the absolute path of the current buffer.""" + return vim.current.buffer.name + + +def path_to_source_root(): + """Returns the absolute path to the chromium source root.""" + candidate = os.path.dirname(path_to_current_buffer()) + # This is a list of files that need to identify the src directory. The shorter + # it is, the more likely it's wrong (checking for just "build/common.gypi" + # would find "src/v8" for files below "src/v8", as "src/v8/build/common.gypi" + # exists). The longer it is, the more likely it is to break when we rename + # directories. + fingerprints = ['chrome', 'net', 'v8', 'build', 'skia'] + while candidate and not all( + [os.path.isdir(os.path.join(candidate, fp)) for fp in fingerprints]): + candidate = os.path.dirname(candidate) + return candidate + + +def path_to_build_dir(configuration): + """Returns //(Release|Debug).""" + + chrome_root = path_to_source_root() + sys.path.append(os.path.join(chrome_root, 'tools', 'vim')) + from ninja_output import GetNinjaOutputDirectory + return GetNinjaOutputDirectory(chrome_root, configuration) + +def compute_ninja_command_for_current_buffer(configuration=None): + """Returns the shell command to compile the file in the current buffer.""" + build_dir = path_to_build_dir(configuration) + + # ninja needs filepaths for the ^ syntax to be relative to the + # build directory. + file_to_build = path_to_current_buffer() + file_to_build = os.path.relpath(file_to_build, build_dir) + + build_cmd = ' '.join(['ninja', '-C', build_dir, file_to_build + '^']) + if sys.platform == 'win32': + # Escape \ for Vim, and ^ for both Vim and shell. + build_cmd = build_cmd.replace('\\', '\\\\').replace('^', '^^^^') + vim.command('return "%s"' % build_cmd) + + +def compute_ninja_command_for_targets(targets='', configuration=None): + build_cmd = ' '.join(['ninja', '-C', path_to_build_dir(configuration), + targets]) + vim.command('return "%s"' % build_cmd) +endpython + +fun! s:MakeWithCustomCommand(build_cmd) + let l:oldmakepgr = &makeprg + let &makeprg=a:build_cmd + if exists(':Make') == 2 + Make + else + silent make | cwindow + endif + if !has('gui_running') + redraw! + endif + let &makeprg = l:oldmakepgr +endfun + +fun! s:NinjaCommandForCurrentBuffer() + python compute_ninja_command_for_current_buffer() +endfun + +fun! s:NinjaCommandForTargets(targets) + python compute_ninja_command_for_targets(vim.eval('a:targets')) +endfun + +fun! CrCompileFile() + call s:MakeWithCustomCommand(s:NinjaCommandForCurrentBuffer()) +endfun + +fun! CrBuild(...) + let l:targets = a:0 > 0 ? join(a:000, ' ') : '' + if (l:targets !~ '\i') + let l:targets = 'chrome' + endif + call s:MakeWithCustomCommand(s:NinjaCommandForTargets(l:targets)) +endfun + +command! CrCompileFile call CrCompileFile() +command! -nargs=* CrBuild call CrBuild() + +if has('mac') + map :CrCompileFile + imap :CrCompileFile +elseif has('win32') + map :CrCompileFile + imap :CrCompileFile +elseif has('unix') + map o :CrCompileFile +endif diff --git a/tools/vim/ninja_output.py b/tools/vim/ninja_output.py new file mode 100644 index 000000000..e343c5b7f --- /dev/null +++ b/tools/vim/ninja_output.py @@ -0,0 +1,57 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + +import os +import os.path +import re + + +def GetNinjaOutputDirectory(chrome_root, configuration=None): + """Returns //(Release|Debug). + + The output_dir is detected in the following ways, in order of precedence: + 1. CHROMIUM_OUT_DIR environment variable. + 2. GYP_GENERATOR_FLAGS environment variable output_dir property. + 3. Symlink target, if src/out is a symlink. + 4. Most recently modified (e.g. built) directory called out or out_*. + + The configuration chosen is the one most recently generated/built, but can be + overriden via the parameter.""" + + output_dirs = [] + if ('CHROMIUM_OUT_DIR' in os.environ and + os.path.isdir(os.path.join(chrome_root, os.environ['CHROMIUM_OUT_DIR']))): + output_dirs = [os.environ['CHROMIUM_OUT_DIR']] + if not output_dirs: + generator_flags = os.getenv('GYP_GENERATOR_FLAGS', '').split(' ') + for flag in generator_flags: + name_value = flag.split('=', 1) + if (len(name_value) == 2 and name_value[0] == 'output_dir' and + os.path.isdir(os.path.join(chrome_root, name_value[1]))): + output_dirs = [name_value[1]] + if not output_dirs: + out = os.path.join(chrome_root, 'out') + if os.path.islink(out): + out_target = os.path.join(os.path.dirname(out), os.readlink(out)) + if os.path.exists(out_target): + output_dirs = [out_target] + if not output_dirs: + for f in os.listdir(chrome_root): + if (re.match('out(?:$|_)', f) and + os.path.isdir(os.path.join(chrome_root, f))): + output_dirs.append(f) + + configs = [configuration] if configuration else ['Debug', 'Release'] + output_paths = [os.path.join(chrome_root, out_dir, config) + for out_dir in output_dirs for config in configs] + + def approx_directory_mtime(path): + if not os.path.exists(path): + return -1 + # This is a heuristic; don't recurse into subdirectories. + paths = [path] + [os.path.join(path, f) for f in os.listdir(path)] + return max(os.path.getmtime(p) for p in paths) + + return max(output_paths, key=approx_directory_mtime)