2015-01-07 89 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 
    }