1 import os 2 import 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. 7 flags = [ 8 '-Wall', 9 '-Werror', 10 '-pendantic-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. 32 compilation_database_folder = '' 33 34 if os.path.exists( compilation_database_folder ): 35 database = ycm_core.CompilationDatabase( compilation_database_folder ) 36 else: 37 database = None 38 39 SOURCE_EXTENSIONS = [ '.cc' ] 40 41 def DirectoryOfThisScript(): 42 return os.path.dirname( os.path.abspath( __file__ ) ) 43 44 45 def 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 74 def IsHeaderFile( filename ): 75 extension = os.path.splitext( filename )[ 1 ] 76 return extension in [ '.h', '.hxx', '.hpp', '.hh' ] 77 78 79 def 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 97 def 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