1import os 2import ycm_core 3 4# These are the compilation flags that will be used in case there's no 5# compilation database set (by default, one is not set). 6# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. 7flags = [ 8'-Wall', 9'-Werror', 10'-pedantic-errors', 11'-std=c++0x', 12'-fno-strict-aliasing', 13'-O3', 14'-DNDEBUG', 15# ...and the same thing goes for the magic -x option which specifies the 16# language that the files to be compiled are written in. This is mostly 17# relevant for c++ headers. 18# For a C project, you would set this to 'c' instead of 'c++'. 19'-x', 'c++', 20'-I', 'include', 21'-isystem', '/usr/include', 22'-isystem', '/usr/local/include', 23] 24 25 26# Set this to the absolute path to the folder (NOT the file!) containing the 27# compile_commands.json file to use that instead of 'flags'. See here for 28# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 29# 30# Most projects will NOT need to set this to anything; you can just change the 31# 'flags' list of compilation flags. Notice that YCM itself uses that approach. 32compilation_database_folder = '' 33 34if os.path.exists( compilation_database_folder ): 35 database = ycm_core.CompilationDatabase( compilation_database_folder ) 36else: 37 database = None 38 39SOURCE_EXTENSIONS = [ '.cc' ] 40 41def DirectoryOfThisScript(): 42 return os.path.dirname( os.path.abspath( __file__ ) ) 43 44 45def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): 46 if not working_directory: 47 return list( flags ) 48 new_flags = [] 49 make_next_absolute = False 50 path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] 51 for flag in flags: 52 new_flag = flag 53 54 if make_next_absolute: 55 make_next_absolute = False 56 if not flag.startswith( '/' ): 57 new_flag = os.path.join( working_directory, flag ) 58 59 for path_flag in path_flags: 60 if flag == path_flag: 61 make_next_absolute = True 62 break 63 64 if flag.startswith( path_flag ): 65 path = flag[ len( path_flag ): ] 66 new_flag = path_flag + os.path.join( working_directory, path ) 67 break 68 69 if new_flag: 70 new_flags.append( new_flag ) 71 return new_flags 72 73 74def IsHeaderFile( filename ): 75 extension = os.path.splitext( filename )[ 1 ] 76 return extension in [ '.h', '.hxx', '.hpp', '.hh' ] 77 78 79def GetCompilationInfoForFile( filename ): 80 # The compilation_commands.json file generated by CMake does not have entries 81 # for header files. So we do our best by asking the db for flags for a 82 # corresponding source file, if any. If one exists, the flags for that file 83 # should be good enough. 84 if IsHeaderFile( filename ): 85 basename = os.path.splitext( filename )[ 0 ] 86 for extension in SOURCE_EXTENSIONS: 87 replacement_file = basename + extension 88 if os.path.exists( replacement_file ): 89 compilation_info = database.GetCompilationInfoForFile( 90 replacement_file ) 91 if compilation_info.compiler_flags_: 92 return compilation_info 93 return None 94 return database.GetCompilationInfoForFile( filename ) 95 96 97def FlagsForFile( filename, **kwargs ): 98 if database: 99 # Bear in mind that compilation_info.compiler_flags_ does NOT return a 100 # python list, but a "list-like" StringVec object 101 compilation_info = GetCompilationInfoForFile( filename ) 102 if not compilation_info: 103 return None 104 105 final_flags = MakeRelativePathsInFlagsAbsolute( 106 compilation_info.compiler_flags_, 107 compilation_info.compiler_working_dir_ ) 108 else: 109 relative_to = DirectoryOfThisScript() 110 final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) 111 112 return { 113 'flags': final_flags, 114 'do_cache': True 115 } 116