vim youcompleteme 找不到 cstdint

vim youcompleteme can't find cstdint

我在尝试使用带有 Unix 样式 Makefile 的 CMake 和 vim 使用 youcompleteme 插件(我是 Linux 老手和 Mac 新手,所以我更喜欢这个设置而不是 Xcode)。代码构建并运行,但 youcompleteme 抛出一些虚假错误,我认为归结为无法找到 header.

我也刚在 Linux 上试过,遇到了同样的问题。

我已经将 .ycm_extra_conf.py 配置为使用由 cake 生成的 compile_commands.json。 compile_commands.json 中的 "command" 行使用这些标志:

  "command": "/usr/bin/c++     -std=c++11 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -F/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/System/Library/Frameworks -I/usr/local/include -I/Users/tony/Dev/cow/jni -I/Users/tony/Library/Frameworks/SDL2.framework/Headers    -Wall -Wextra -Wunused -F/Users/tony/Library/Frameworks  -o ...

那里似乎没有明确引用任何包含 stdint 的目录作为直接 parent。

有没有一种方法可以让你用 libclang 完成它的工作,这样它就可以隐式地找到目录,这似乎在命令行上使用 运行 c++ 时有效?或者让 cmake 添加适当的系统 header 路径而无需硬接线的最佳方法是什么?我希望我的 CMakeLists.txt 具有便携性并能够应对工具链升级。

我的 .ycm_extra_conf.py 几乎是所提供示例的副本,稍作修改以找到我放置它的 compile_commands.json。

您必须添加 YCM 需要查找您的源、库等的所有路径。

它不能递归工作,所以一开始有点麻烦,但一旦为您的项目设置就不应更改。

例如,这是我的一个 Arduino 项目:

https://github.com/ladislas/Bare-Arduino-Project/blob/master/.ycm_extra_conf.py#L21

希望对您有所帮助!

编辑 - 2015/01/08

@abigagli的解决方案很优雅!我也使用类似的方法来解析我的 lib 目录并查找 .h 文件以将它们的路径添加到 flags.

如果有用就在这里:) http://git.io/IiR1JA

正如@ladislas 所说,YCM 需要明确指向所有相关的包含目录,因为 libclang 不会使用与普通编译器 driver 调用(即来自命令行的 clang++)相同的隐式位置.

我通常在 OSX 上做的是让 YCM 知道 Xcode 的 libc++ headers 类似 (in .ycm_extra_conf.py):

import os
import ycm_core
import subprocess
xcode_cpp11headers = subprocess.Popen("xcode-select -p", stdout = subprocess.PIPE, shell=True).communicate()[0].rstrip('\n') + '/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1'
.
.
flags = [
.
.
'-isystem',
xcode_cpp11headers,
.
.
]

"xcode_cpp11headers" 变量根据您当前 Xcode 的安装位置填充了正确的路径,如果您想使用 [=21],您可以相应地更改它=] 版本的 libc++(即包含在 /Library/Developer/CommandLineTools/usr/include/c++/v1 中)或 libc++ 的源代码分发,如果你自己编译的话。

当然这取决于平台,您可以在项目旁边提供特定于平台的 .ycm_extra_conf.py,或者您可以根据当前平台使用一些额外的 python 代码以不同方式填充该变量。

正如我从上述答案中发现的那样,YCM 需要被告知编译器的系统包含通常隐含在其他使用编译器的方式中的路径。我添加了一个函数 GetSystemIncludePaths() 到 .ycm_extra_conf.py 以可移植地发现和缓存这些路径。这是完整的文件,其中包含注释和旗帜列表的无关内容。原件版权所有 (C) 2014 Google Inc,拥有 GPL2+ 许可证:

import subprocess, os
import ycm_core

flags = []


def DirectoryOfThisScript():
  return os.path.dirname( os.path.abspath( __file__ ) )

compilation_database_folder = os.path.abspath(
        os.path.join(DirectoryOfThisScript(), 'build-make'))

if os.path.exists( compilation_database_folder ):
  database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
  database = None

SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]

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 ):
  extension = os.path.splitext( filename )[ 1 ]
  return extension in [ '.h', '.hxx', '.hpp', '.hh' ]


def GetCompilationInfoForFile( filename ):
  if IsHeaderFile( filename ):
    basename = os.path.splitext( filename )[ 0 ]
    for extension in SOURCE_EXTENSIONS:
      replacement_file = basename + extension
      if os.path.exists( replacement_file ):
        compilation_info = database.GetCompilationInfoForFile(
          replacement_file )
        if compilation_info.compiler_flags_:
          return compilation_info
    return None
  return database.GetCompilationInfoForFile( filename )


def GetSystemIncludePaths():
  cache = os.path.join(DirectoryOfThisScript(), ".ycm_sys_incs")
  if os.path.exists(cache):
    fp = open(cache, 'r')
    flags = fp.readlines()
    fp.close()
    flags = [s.strip() for s in flags]
  else:
    devnull = open(os.devnull, 'r')
    child = subprocess.Popen(["/usr/bin/cpp", "-xc++", "-v"],
        stdin = devnull, stderr = subprocess.PIPE)
    output = child.communicate()[1].split('\n')
    devnull.close()
    flags = []
    status = 0
    for l in output:
      l = l.strip()
      if l == '#include "..." search starts here:':
        status = 1
      elif l == '#include <...> search starts here:':
        status = 2
      elif status:
        if l == 'End of search list.':
          break
        elif l.endswith('(framework directory)'):
          continue
        elif status == 1:
          flags.append('-I')
        elif status == 2:
          flags.append('-isystem')
        flags.append(os.path.normpath(l))
    fp = open(cache, 'w')
    fp.write('\n'.join(flags))
    fp.close()
  return flags


def FlagsForFile( filename, **kwargs ):
  if database:
    compilation_info = GetCompilationInfoForFile( filename )
    if not compilation_info:
      return None

    final_flags = MakeRelativePathsInFlagsAbsolute(
      compilation_info.compiler_flags_,
      compilation_info.compiler_working_dir_ )
    sys_incs = GetSystemIncludePaths()
    if sys_incs:
        final_flags += sys_incs
  else:
    relative_to = DirectoryOfThisScript()
    final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )

  return {
    'flags': final_flags,
    'do_cache': True
  }