1

Unix スタイルの Makefile で CMake を使用し、youcompleteme プラグインで vim を使用して Mac (Xcode 6 を使用する Yosemite) で C++ プロジェクトをセットアップしようとして問題が発生しました (私は Linux のベテランであり、Mac の初心者なので、このセットアップを好むXcode)。コードはビルドされて実行されますが、youcompleteme はいくつかの偽のエラーをスローします。

Linuxでも試してみましたが、同じ問題がありました。

Cake によって生成された compile_commands.json を使用するように .ycm_extra_conf.py を構成しました。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 を直接の親として含むディレクトリへの明示的な参照はないようです。

コマンドラインでc ++を実行しているときに動作するように見えるディレクトリを暗黙的に見つけることができるような方法で、libclangで作業を行うようにyoucompletemeを取得できる方法はありますか? または、適切なシステム ヘッダー パスを配線せずに cmake に追加させる最善の方法は何ですか? CMakeLists.txt を移植可能にし、ツールチェーンのアップグレードに対応できるようにしたいと考えています。

私の .ycm_extra_conf.py は、提供された例のほとんどのコピーであり、配置した compile_commands.json を見つけるために少し変更されています。

4

3 に答える 3

3

@ladislas が言ったように、libclang は通常のコンパイラ ドライバの呼び出し (つまり、コマンド ラインからの clang++) が使用するのと同じ暗黙的な場所を使用しないため、YCM は関連するすべてのインクルード ディレクトリを明示的に指す必要があります。

私が通常 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 コードを使用してその変数を別の方法で設定することができます。

于 2015-01-08T11:13:02.380 に答える
2

YCM がソース、ライブラリなどを探すために必要なすべてのパスを追加する必要があります。

再帰的には機能しないため、最初は少し面倒ですが、プロジェクトに設定したら変更しないでください。

例として、ここにArduinoプロジェクトの私のものがあります:

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

お役に立てれば!

編集 - 2015/01/08

@abigagli のソリューションは非常にエレガントです! 私もこのようなものを使用して、ディレクトリを解析し、パスを追加するファイルをlib探します。.hflags

役に立つかどうかはここにあります:) http://git.io/IiR1JA

于 2015-01-08T08:14:05.067 に答える
0

上記の回答からわかったように、YCM はコンパイラのシステムに、コンパイラを使用する他の方法では通常暗黙的なパスが含まれていることを伝える必要があります。GetSystemIncludePaths().ycm_extra_conf.py に関数を追加して、これらのパスをポータブルに検出してキャッシュしました。これは、フラグリストのコメントと無関係なコンテンツを切り取った完全なファイルです。オリジナルは Copyright (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
  }
于 2015-01-10T15:07:07.473 に答える