1

I'd like to set c++ header file path automatically from .vimrc. So I tried to write .vimrc file as shown below:

let g:gcpp_headers_path=system("g++ --version | grep g++ | awk '{print \"/usr/include/c++/\"$NF}'")

"if isdirectory(gcpp_headers_path)
  set path+=g:gcpp_headers_path
"endif

from the vimrc above I found the vim variable path set as shown below:

:set path?
path=.,/usr/include,,,g:gcpp_headers_path

The wanted output is as shown below:

:set path?
path=.,/usr/include,/usr/include/c++/7.5.0

I'd like to get this reviewed. Could someone advise me?

F.Y.I. The command in system() is shown below:

~$ g++ --version | grep g++ | awk '{print "/usr/include/c++/"$NF}'
/usr/include/c++/7.5.0
1

3 Answers 3

2

Here is the full implementation taken from my own config. Basically, run preprocessor, parse the output and cache the result. Then set path by ftplugin as needed.

~/.vim/autoload/misc.vim

" misc#gcc_include([{gcc} [, {force} [, {ft}]]])
" get GCC include dirs
function! misc#gcc_include(gcc = b:current_compiler, force = v:false, ft = &ft) abort
    let l:var = printf('%s_include_%s', fnamemodify(a:gcc, ':t:gs?[-.]?_?'), a:ft)
    if a:force || !has_key(s:, l:var)
        " $INCLUDE
        let s:[l:var] = split($INCLUDE, has('win32') ? ';' : ':')
        " builtin dirs
        let l:cmd = printf('%s -x%s -v -E -', a:gcc, a:ft is# 'cpp' ? 'c++' : a:ft)
        silent let l:include = map(systemlist(l:cmd, []), 'trim(v:val)')
        let l:ix1 = match(l:include, '#include <\.\.\.>') + 1
        let l:ix2 = match(l:include, '\.$', l:ix1) - 1
        if l:ix1 <= l:ix2
            let s:[l:var] += map(l:include[l:ix1 : l:ix2], 'simplify(v:val)')
        endif
    endif
    return copy(s:[l:var])
endfunction

~/.vim/after/ftplugin/c.vim

compiler gcc
let &l:path = misc#gcc_include()->insert('.')->add(',')->join(',')
2
  • Thank you for the answer, it's not that easy to understand though..
    – Jumogehn
    Commented Feb 27, 2022 at 8:09
  • 1
    @Jumogehn Actually, this is more or less the same thing that LucHermitte had already explained. But this is complete and working implementation. See also stackoverflow.com/questions/4980819/…
    – Matt
    Commented Feb 27, 2022 at 8:31
1

I remember system() cannot be used from .vimrc because 'shellredir' isn't set yet (see :h starting). This is odd you're able to make it work.

Because of that issue I had to ask for compiler system includes on VimEnter event -- in order to configure coc+ccls.

BTW I obtain the exact list of system includes with g++ -E -xc++ - -Wp,-v < /dev/null. The version number obtained through --version doesn't necessarily match the include directory, while this command give me the correct pathnames. For instance, my 7.5.0 g++ uses /usr/include/c++/7 and not 7.5.0. Same issue with g++-8, 11, and so on.

IOW, IMO you'll want something like (untested code)

augroup SetSystemPaths
  au!
  au VimEnter * exe set path+=systemlist('g++ -E -xc++ - -Wp,v </dev/null')->filter({_,v -> =~ '^ '})->map({_,v -> substitute(v, '^ *', '', '')})->join(',')
augroup END

You may not want to keep every path. You can select them thanks to filter()

1
  • 1
    Thank you for the answer! But the filter() function is remained in a question. I select my own answer because it works. I wonder if there is any security issue with my answer. Anyway thank you for the answer!
    – Jumogehn
    Commented Feb 27, 2022 at 2:19
1

This works!

let g:gcpp_headers_path = system("g++ --version | grep g++ | awk '{print \"/usr/include/c++/\"$NF}'")

execute 'set path+=' . g:gcpp_headers_path

This answer was given from stackoverflow user romainl

References: here there

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.