2015-01-07 86 views
1

我遇到了一个问题,试图在我的Mac(Yosemite与Xcode 6)上使用CMake与Unix风格Makefiles和vim与youcompleteme插件建立一个C++项目(我是Linux老兵和Mac新手,所以我更喜欢这个设置到Xcode)。该代码的构建和运行,但你完成我抛出一些虚假的错误,我认为它不能找到<cstdint>标题。vim 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放在哪里。

+0

您可以向我们提供您'.ycm_extra_conf.py'文件,并告诉我们一些关于你如何组织你的项目。 – ladislas

+0

我已经将.ycm_extra_conf添加到了我原来的问题中,因为它太长了,无法进行单独的评论。这与插件提供的示例非常相似,我只是更改了它找到compilation_database_folder的位(并在此处粘贴之前删除了注释)。我认为这是找到数据库文件确定,因为有一次我将final_flags转储到一个文件中,发现它包含了compile_commands.json中的东西,但不包含此脚本中的硬连线标志。 – realh

+0

我的项目布置了两个与此问题相关的主要子目录。一个叫做jni(预期移植到Android)包含我所有的源文件,另一个叫做build-make,它是cmake的工作目录。 – realh

回答

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++的commandline-tools版本(即包含在/ Library/Developer/CommandLineTools/usr/include/C++/v1中)或者如果你编译了自己的libC++的源码分发。

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

+0

谢谢。为了便于携带,我将尝试打开一些可以从cmake运行的东西来解析[this other question]中建议的命令之一的输出(http://stackoverflow.com/questions/11946294/dump-include-paths-从-G)。 – realh

+0

很优雅!我也使用这样的东西来解析我的'lib'目录并寻找'.h'文件来将它们的路径添加到'flags'。在这里它是如果它可以是有用的:) http://git.io/IiR1JA – ladislas

+0

我放弃了试图让cmake运行带有项目特定编译器标志的额外脚本,并向.ycm_extra_conf添加了GetSystemIncludePaths()函数。 py运行cpp,使用缓存。在上面发布。 – realh

2

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

它不会递归地工作,所以它起初有点麻烦,但不应该为您的项目设置一次。

作为一个例子,这里是我的一个Arduino项目:

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

希望这有助于!

编辑 - 2015年1月8日

@abigagli的解决方案是很优雅!我也使用这样的东西来解析我的lib目录,并寻找.h文件将其路径添加到flags

这如果能够http://git.io/IiR1JA

0

正如我从上面的答案中发现的,YCM需要被告知编译器的系统包含通常在使用编译器的其他方式中隐含的路径。我为.ycm_extra_conf.py添加了一个函数GetSystemIncludePaths()以便便携地发现并缓存这些路径。这里是完整的文件,其中包含评论和无关标志清单的内容。原来是版权所有(C)听英语谷歌公司与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 
    }