【问题标题】:vim youcompleteme can't find cstdintvim youcompleteme 找不到 cstdint
【发布时间】:2015-03-05 21:49:05
【问题描述】:

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

我也刚刚在 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 作为直接父级的目录。

有没有一种方法可以让 youcompleteme 使用 libclang 完成它的工作,使其可以隐式找到目录,这在命令行上运行 c++ 时似乎可以工作?或者,让 cmake 添加适当的系统头文件路径而不进行硬连线的最佳方法是什么?我希望我的 CMakeLists.txt 具有可移植性,并且能够应对工具链升级。

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

【问题讨论】:

  • 您能否向我们提供您的.ycm_extra_conf.py 文件并告诉我们更多有关您如何组织项目的信息。
  • 我已将 .ycm_extra_conf 添加到我原来的问题中,因为单独评论太长了。它与插件提供的示例几乎相同,我只是更改了它找到compilation_database_folder的位(并在粘贴之前删除了cmets)。我认为它可以找到数据库文件,因为有一次我将 final_flags 转储到一个文件中,并发现它包含 compile_commands.json 中存在的内容,但该脚本中的硬连线标志中没有。
  • 我的项目布局有两个与此问题相关的主要子目录。一个叫 jni(期待移植到 Android),其中包含我所有的源文件,另一个叫 build-make,它是 cmake 的工作目录。

标签: vim cmake libclang


【解决方案1】:

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

【讨论】:

    【解决方案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

    【讨论】:

      【解决方案3】:

      正如@ladislas 所说,YCM 需要明确指向所有相关的包含目录,因为 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 代码以不同方式填充该变量。

      【讨论】:

      • 谢谢两位。为了可移植性,我将尝试敲出一些我可以从 cmake 运行的东西来解析 this other question 建议的命令之一的输出。
      • 非常优雅!我也使用类似的东西来解析我的lib 目录并查找.h 文件以将它们的路径添加到flags。如果它有用的话就在这里:) git.io/IiR1JA
      • 我放弃了尝试让 cmake 运行带有项目特定编译器标志的额外脚本,并在 .ycm_extra_conf.py 中添加了 GetSystemIncludePaths() 函数来使用缓存运行 cpp。发布在上面。
      猜你喜欢
      • 1970-01-01
      • 2015-12-09
      • 1970-01-01
      • 2015-12-10
      • 1970-01-01
      • 1970-01-01
      • 2018-01-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多