vim youcompleteme无法找到cstdint

时间:2015-01-07 21:29:35

标签: vim cmake libclang

我尝试在我的Mac上设置C ++项目(Yosemite with Xcode 6)时遇到问题,使用CMake和Unix风格的Makefile和vim与youcompleteme插件(我是Linux老手和Mac新手)所以我更喜欢这种设置Xcode)。代码构建并运行但是youcompleteme会抛出一些虚假的错误,我认为归结为它无法找到< cstdint>报头中。

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

我已将.ycm_extra_conf.py配置为使用cake生成的compile_commands.json。 "命令" compile_commands.json中的行使用以下标志:

  "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作为直接父级的任何目录,似乎没有明确的引用。

有没有办法可以让你使用libclang来完成它的内容,以便它可以隐式找到目录,这在命令行上运行c ++时似乎有效?或者,什么是让cmake添加适当的系统头路径而不需要硬连接的最佳方法?我希望我的CMakeLists.txt可以移植,并且能够应对工具链升级。

我的.ycm_extra_conf.py几乎是所提供的示例的副本,稍微修改了一下我在其中找到了compile_commands.json。

3 个答案:

答案 0 :(得分:3)

正如@ladislas所说,YCM需要明确指向所有相关的include目录,因为libclang不会使用普通编译器驱动程序调用(即命令行中的clang ++)使用的相同隐式位置。

我通常在OSX上做的是让YCM知道Xcode的libc ++标题,例如(在.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安装的位置,如果要使用libc ++的命令行工具版本(即包含在/中),您可以相应地更改它Library / Developer / CommandLineTools / usr / include / c ++ / v1)或libc ++的源代码发布,如果你已经编译了自己的。

当然这是依赖于平台的,要么在项目旁边提供特定于平台的.ycm_extra_conf.py,要么可以使用一些额外的python代码以不同的方式填充该变量到当前平台。

答案 1 :(得分:2)

您必须添加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

答案 2 :(得分:0)

正如我从上面的答案中发现的那样,YCM需要被告知编译器的系统包含通常在使用编译器的其他方式中隐含的路径。我向.ycm_extra_conf.py添加了一个函数GetSystemIncludePaths(),以便可移植地发现和缓存这些路径。这是包含标记列表的注释和不相关内容的完整文件。原件是版权所有(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
  }