diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py new file mode 100644 index 0000000..d9561e2 --- /dev/null +++ b/.ycm_extra_conf.py @@ -0,0 +1,194 @@ +# This file is NOT licensed under the GPLv3, which is the license for the rest +# of YouCompleteMe. +# +# Here's the license text for this file: +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# For more information, please refer to + +import itertools +import glob +import logging +import logging.handlers +import os +import ycm_core + +logger = logging.getLogger('ycm_extra_conf') + +# Uncomment to save debugging output if you are having issues with YCM completion. +# See https://github.com/Valloric/YouCompleteMe/issues/1560 +# LOG_FILENAME = '/tmp/tsnecuda_ycm_extra_conf.py.out' +# logger.setLevel(logging.DEBUG) +# handler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=1024 * 64, backupCount=1) +# logger.addHandler(handler) + + +def DirectoryOfThisScript(): + return os.path.dirname(os.path.abspath(__file__)) + + +# These are the compilation flags that will be used in case there's no +# compilation database set (by default, one is not set). +# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. +flags = [ + '-Wall', + '-Wextra', + '-Werror', + '-pedantic', + '-std=c++11', + '-Isrc', + '-Isrc/include', + '-Isrc/include/kernels', + '-Ithird_party/FIt-TSNE/src', + '-I/usr/include', + '-I/usr/local/include', +] + +# Set this to the absolute path to the folder (NOT the file!) containing the +# compile_commands.json file to use that instead of 'flags'. See here for +# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html +# +# You can get CMake to generate this file for you by adding: +# set(CMAKE_EXPORT_COMPILE_COMMANDS 1) +# to your CMakeLists.txt file. +# +# Most projects will NOT need to set this to anything; you can just change the +# 'flags' list of compilation flags. Notice that YCM itself uses that approach. +compilation_db_globs = [os.path.join(DirectoryOfThisScript(), p) for p in ( + "build/compile_commands.json", + "cmake/*/compile_commands.json") +] + +logger.debug("compilation_db_globs: %s" % compilation_db_globs) + +compilation_dbs = sorted( + itertools.chain.from_iterable(glob.glob(g) for g in compilation_db_globs), + key=lambda f: -os.path.getmtime(f) +) +logger.debug("compilation_dbs: %s" % compilation_dbs) + +if compilation_dbs: + logger.debug("loading compilation db: %s" % compilation_dbs[0]) + database = ycm_core.CompilationDatabase(os.path.dirname(compilation_dbs[0])) +else: + database = None + + +SOURCE_EXTENSIONS = ['.cu', '.cpp', '.cxx', '.cc', '.c', '.m', '.mm'] +HEADER_EXTENSIONS = ['.h', '.hxx', '.hpp', '.hh', ".fwd.hh"] + + +def MakeRelativePathsInFlagsAbsolute(flags, working_directory): + if not working_directory: + return list(flags) + new_flags = [] + make_next_absolute = False + path_flags = ['-isystem', '-I', '-iquote', '--sysroot='] + for flag in flags: + new_flag = flag + + if make_next_absolute: + make_next_absolute = False + if not flag.startswith('/'): + new_flag = os.path.join(working_directory, flag) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + + if flag.startswith(path_flag): + path = flag[len(path_flag):] + new_flag = path_flag + os.path.join(working_directory, path) + break + + if new_flag: + new_flags.append(new_flag) + return new_flags + + +def IsHeaderFile(filename): + return any(filename.endswith(ext) for ext in HEADER_EXTENSIONS) + + +def HeaderFileBase(filename): + for ext in HEADER_EXTENSIONS: + if filename.endswith(filename): + return filename[len(ext):] + return None + + +def GetCompilationInfoForFile(filename): + logger.debug("GetCompilationInfoForFile filename: %s" % filename) + # The compilation_commands.json file generated by CMake does not have entries + # for header files. So we do our best by asking the db for flags for a + # corresponding source file, if any. If one exists, the flags for that file + # should be good enough. + if IsHeaderFile(filename): + basename = HeaderFileBase(filename) + for extension in SOURCE_EXTENSIONS: + replacement_file = basename + extension + if os.path.exists(replacement_file): + logger.debug("GetCompilationInfoForFile resolved header equiv: %s" % replacement_file) + compilation_info = database.GetCompilationInfoForFile( + replacement_file) + if compilation_info.compiler_flags_: + return compilation_info + else: + logger.debug("GetCompilationInfoForFile header fallback: %s" % "src/core/pose/Pose.cc") + compilation_info = database.GetCompilationInfoForFile( + os.path.join(DirectoryOfThisScript(), "src/core/pose/Pose.cc")) + if compilation_info.compiler_flags_: + return compilation_info + return None + + return database.GetCompilationInfoForFile(filename) + + +def FlagsForFile(filename, **kwargs): + logger.debug("FlagsForFile: %s" % filename) + if database: + # Bear in mind that compilation_info.compiler_flags_ does NOT return a + # python list, but a "list-like" StringVec object + compilation_info = GetCompilationInfoForFile(filename) + compilation_info = { + "compiler_flags": list(compilation_info.compiler_flags_), + "compiler_working_dir": compilation_info.compiler_working_dir_ + } + logger.debug("compilation_info: %s" % compilation_info) + else: + compilation_info = None + + if compilation_info and compilation_info["compiler_flags"]: + final_flags = MakeRelativePathsInFlagsAbsolute( + compilation_info["compiler_flags"], + compilation_info["compiler_working_dir"] + ) + else: + relative_to = DirectoryOfThisScript() + final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to) + + logger.debug("final_flags: %s" % final_flags) + return {'flags': final_flags}