Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add option g:clang_compiler_bin to make it easier to use #418

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/clang_complete.txt
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,13 @@ Default: 1
*g:clang_library_path*
If libclang.[dll/so/dylib] is not in your library search path, set this to the
absolute path where libclang is available.
Default: ""

*clang_complete-compiler_bin*
*g:clang_compiler_bin*
This option is used to get built-in include paths of the specified compiler.
If built-in include paths can be obtained,
options "-I[include path]" will be added to the parsing and completion engine of libclang.
Default: ""

*clang_complete-sort_algo*
Expand Down
6 changes: 5 additions & 1 deletion plugin/clang_complete.vim
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ function! s:ClangCompleteInit()
let g:clang_library_path = ''
endif

if !exists('g:clang_compiler_bin')
let g:clang_compiler_bin = ''
endif

if !exists('g:clang_complete_macros')
let g:clang_complete_macros = 0
endif
Expand Down Expand Up @@ -356,7 +360,7 @@ function! s:initClangCompletePython()
return 0
endif

py vim.command('let l:res = ' + str(initClangComplete(vim.eval('g:clang_complete_lib_flags'), vim.eval('g:clang_compilation_database'), vim.eval('g:clang_library_path'))))
py vim.command('let l:res = ' + str(initClangComplete()))
if l:res == 0
return 0
endif
Expand Down
121 changes: 50 additions & 71 deletions plugin/libclang.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,28 @@
import os
import shlex

# Check if libclang is able to find the builtin include files.
#
# libclang sometimes fails to correctly locate its builtin include files. This
# happens especially if libclang is not installed at a standard location. This
# function checks if the builtin includes are available.
def canFindBuiltinHeaders(index, args = []):
flags = 0
currentFile = ("test.c", '#include "stddef.h"')
try:
tu = index.parse("test.c", args, [currentFile], flags)
except TranslationUnitLoadError, e:
return 0
return len(tu.diagnostics) == 0

# Derive path to clang builtin headers.
#
# This function tries to derive a path to clang's builtin header files. We are
# just guessing, but the guess is very educated. In fact, we should be right
# for all manual installations (the ones where the builtin header path problem
# is very common) as well as a set of very common distributions.
def getBuiltinHeaderPath(library_path):
knownPaths = [
library_path + "/../lib/clang", # default value
library_path + "/../clang", # gentoo
library_path + "/clang", # opensuse
library_path + "/", # Google
"/usr/lib64/clang", # x86_64 (openSUSE, Fedora)
"/usr/lib/clang"
]

for path in knownPaths:
try:
files = os.listdir(path)
if len(files) >= 1:
files = sorted(files)
subDir = files[-1]
else:
subDir = '.'
path = path + "/" + subDir + "/include/"
arg = "-I" + path
if canFindBuiltinHeaders(index, [arg]):
return path
except:
pass

return None

def initClangComplete(clang_complete_flags, clang_compilation_database, \
library_path):
def initClangComplete():
global index
global includes

debug = int(vim.eval("g:clang_debug")) == 1
clang_complete_flags = vim.eval('g:clang_complete_lib_flags')
clang_compilation_database = vim.eval('g:clang_compilation_database')
library_path = vim.eval('g:clang_library_path')
compiler_bin = vim.eval('g:clang_compiler_bin')

if len(compiler_bin) != 0:
includes = get_include_paths(compiler_bin)
if len(includes) == 0:
print 'WARNING: Can not find the include paths for "%s"' % compiler_bin
print ' This will cause code completion not to work.'
print ' Try to add this line to your .vimrc:'
print ' g:clang_compiler_bin=your_compiler'
if debug:
for include in includes:
print 'built-in include path: %s' % include
else:
includes = []

if library_path:
Config.set_library_path(library_path)
Expand All @@ -81,16 +51,6 @@ def initClangComplete(clang_complete_flags, clang_compilation_database, \
''' % (suggestion, exception_msg)
return 0

global builtinHeaderPath
builtinHeaderPath = None
if not canFindBuiltinHeaders(index):
builtinHeaderPath = getBuiltinHeaderPath(library_path)

if not builtinHeaderPath:
print "WARNING: libclang can not find the builtin includes."
print " This will cause slow code completion."
print " Please report the problem."

global translationUnits
translationUnits = dict()
global complete_flags
Expand All @@ -104,6 +64,35 @@ def initClangComplete(clang_complete_flags, clang_compilation_database, \
libclangLock = threading.Lock()
return 1

def get_include_paths(compiler):
from subprocess import Popen, PIPE, STDOUT
import tempfile
cwd = os.getcwd()
new_cwd = os.path.dirname(compiler)
if new_cwd and len(new_cwd) != 0:
os.chdir(new_cwd)

TMP_FILE = tempfile.gettempdir() + '/dummy.cc'
TMP_OBJECT = tempfile.gettempdir() + '/dummy.o'
fp = open(TMP_FILE, 'w')
fp.close()
p = Popen('%s -c -v %s -o %s' % (compiler, TMP_FILE, TMP_OBJECT), \
shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT);
lines = p.stdout.read().split('\n')

included = False
include = []
for line in lines:
if not included:
if line.startswith('''#include <...> search starts here:'''):
included = True
else:
if line.startswith('''End of search list.'''):
break
include.append(line.lstrip().rstrip())
os.chdir(cwd)
return include

# Get a tuple (fileName, fileContent) for the file opened in the current
# vim buffer. The fileContent contains the unsafed buffer content.
def getCurrentFile():
Expand Down Expand Up @@ -297,12 +286,6 @@ def getCompilationDBParams(fileName):
if arg == '-o':
skip_next = 1;
continue
if arg.startswith('-I'):
includePath = arg[2:]
if not os.path.isabs(includePath):
includePath = os.path.normpath(os.path.join(cwd, includePath))
args.append('-I'+includePath)
continue
args.append(arg)
getCompilationDBParams.last_query = { 'args': args, 'cwd': cwd }

Expand All @@ -315,16 +298,12 @@ def getCompilationDBParams(fileName):
getCompilationDBParams.last_query = { 'args': [], 'cwd': None }

def getCompileParams(fileName):
global builtinHeaderPath
params = getCompilationDBParams(fileName)
args = params['args']
args += splitOptions(vim.eval("g:clang_user_options"))
args += splitOptions(vim.eval("b:clang_user_options"))
args += splitOptions(vim.eval("b:clang_parameters"))

if builtinHeaderPath:
args.append("-I" + builtinHeaderPath)

for include in includes:
args.append("-I" + include)
return { 'args' : args,
'cwd' : params['cwd'] }

Expand Down