-
-
Save ajford/f551b2b6fd4d6b6e1ef2 to your computer and use it in GitHub Desktop.
""" | |
YouCompleteMe extra configuration for Platformio based | |
projects. | |
Based on the `.ycm_extra_conf.py` by @ladislas in his Bare-Arduino-Project. | |
Anthony Ford <github.com/ajford> | |
""" | |
import os | |
import ycm_core | |
import logging | |
# Logger for additional logging. | |
# To enable debug logging, add `let g:ycm_server_log_level = 'debug'` to | |
# your .vimrc file. | |
logger = logging.getLogger('ycm-extra-conf') | |
# Platformio Autogen libs. | |
## Platformio automatically copies over the libs you use after your first run. | |
## Be warned that you will not receive autocompletion on libraries until after | |
## your first `platformio run`. | |
PlatformioAutogen = ".pioenvs/" | |
# All Platformio Arduin Libs | |
## This will link directly to the Platformio Libs for Arduino. | |
## Be warned that this can polute your namespace (in #include) | |
## and slightly increase startup time (while crawling the lib | |
## dir for header files). This will however allow you to | |
## complete for header files you haven't included yet. | |
PlatformioArduinoLibs = "~/.platformio/packages/framework-arduinoavr/libraries/" | |
# Platformio Arduino Core | |
## This links to the Platformio Arduino Cores. This provides | |
## the core libs, such as Arduino.h and HardwareSerial.h | |
PlatformioArduinoCore = "~/.platformio/packages/framework-arduinoavr/cores/arduino/" | |
# Platformio Arduino Std Libs | |
## Arduino Std libs from .platformio packages. Provides stdlib.h and such. | |
PlatformioArduinoSTD = '~/.platformio/packages/toolchain-atmelavr/avr/include' | |
# This is the list of all directories to search for header files. | |
# Dirs in this list can be paths relative to this file, absolute | |
# paths, or paths relative to the user (using ~/path/to/file). | |
libDirs = [ | |
"lib" | |
,PlatformioAutogen | |
,PlatformioArduinoCore | |
,PlatformioArduinoLibs | |
,PlatformioArduinoSTD | |
] | |
flags = [ | |
# General flags | |
'-Wall' | |
,'-x' | |
,'c++' | |
,'-ansi' | |
# Customize microcontroler and Arduino version | |
,'-mmcu=atmega328p' | |
,'-DF_CPU=16000000L' | |
,'-DARDUINO_ARCH_AVR' | |
,'-DARDUINO_AVR_DUEMILANOVE' | |
,'-DARDUINO=106000' | |
# ,'-MMD -DUSB_VID=null' | |
# ,'-DUSB_PID=null' | |
] | |
compilation_database_folder = '' | |
if os.path.exists( compilation_database_folder ): | |
database = ycm_core.CompilationDatabase( compilation_database_folder ) | |
else: | |
database = None | |
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.ino', '.m', '.mm' ] | |
def DirectoryOfThisScript(): | |
return os.path.dirname( os.path.abspath( __file__ ) ) | |
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 libDir in libDirs: | |
# dir is relative to $HOME | |
if libDir.startswith('~'): | |
libDir = os.path.expanduser(libDir) | |
# dir is relative to `working_directory` | |
if not libDir.startswith('/'): | |
libDir = os.path.join(working_directory,libDir) | |
# Else, assume dir is absolute | |
for path, dirs, files in os.walk(libDir): | |
# Add to flags if dir contains a header file and is not | |
# one of the metadata dirs (examples and extras). | |
if any(IsHeaderFile(x) for x in files) and\ | |
path.find("examples") is -1 and path.find("extras") is -1: | |
logger.debug("Directory contains header files - %s"%path) | |
flags.append('-I'+path) | |
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 ): | |
# The compilation_commands.json file generated by CMake does not have entries | |
# for header files. So we do our best by asking the db for flags for a | |
# corresponding source file, if any. If one exists, the flags for that file | |
# should be good enough. | |
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 FlagsForFile( filename, **kwargs ): | |
if database: | |
# Bear in mind that compilation_info.compiler_flags_ does NOT return a | |
# python list, but a "list-like" StringVec object | |
compilation_info = GetCompilationInfoForFile( filename ) | |
if not compilation_info: | |
return None | |
final_flags = MakeRelativePathsInFlagsAbsolute( | |
compilation_info.compiler_flags_, | |
compilation_info.compiler_working_dir_ ) | |
# NOTE: This is just for YouCompleteMe. it's highly likely that your project | |
# does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR | |
# ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT. | |
#try: | |
# final_flags.remove( '-stdlib=libc++' ) | |
#except ValueError: | |
# pass | |
else: | |
relative_to = DirectoryOfThisScript() | |
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) | |
return { | |
'flags': final_flags, | |
'do_cache': True | |
} |
PlatformioAutogen
, PlatformioArduinoLibs
, and PlatformioArduinoCore
are overlapping, and as such, you can drop the latter two in favor of PlatformioAutogen
.
Autogen
provides the pins_arduino.h
file in a clean and simple way for all variants (i.e. mega/micro/leonardo/etc.). It also provides the same files as PlatformioArduinoCore
, but will only do so after your first platformio run
.
I've added -ansi
as a flag, as AVR-C is based on ANSI C, and this gets Syntastic to stop complaining about some things that are deprecated in later standards.
clang does not seem to accept
-mmcu=atmega328p
out of the box, i dont think it has support for avr? is there a compiled version of clang that does this? or will i have to recompile it from source?
Sorry for the stupid question but where do I put this?
Update: Put it in your project directory or put it in your dotfiles and modify g:ycm_global_ycm_extra_conf
accordingly.
@ajford all the files in my .pioenvs folder are .o files. Header, .h, files for non-built-in libraries are saved in .piolibdeps
Thanks for the example.
@ajford Thanks for this example, my arduino code can go the function declaration, but can't go to function definition, would you give some idea?
@ajford very nice! Glad the Bare Arduino Project was helpful ;) I'm now considering moving to platformio instead of Arduino Makefile, it looks a lot simpler and powerful
For custom libraries and my dependencies I need to add them manually:
libDirs = [
"~/.platformio/lib/Drive"
,".piolibdeps/Ultrasonic_ID1507/src"
,"lib"
,PlatformioAutogen
[...]
Any idea how to improve this? I can't just add .piolibdeps
and ~/.platformio/lib
, it basically needs to traverse those folders. Same for lib
.
Have tried to use YouCompleteMe with platformio and vim many times but I always fail.
This time YouCompleteMe does not recognise Serial altought I have included Arduino.h
Also YcmDiags give me this errors:
/home/neophytos/.platformio/packages/toolchain-atmelavr/avr/include/avr/io.h|625 col 6 warning| "device type not defined" /home/neophytos/.platformio/packages/framework-arduinoavr/cores/arduino/Arduino.h|163 col 23 warning| unknown attribute '__progmem__' ignored /home/neophytos/.platformio/packages/framework-arduinoavr/cores/arduino/Arduino.h|164 col 23 warning| unknown attribute '__progmem__' ignored /home/neophytos/.platformio/packages/framework-arduinoavr/cores/arduino/Arduino.h|165 col 23 warning| unknown attribute '__progmem__' ignored /home/neophytos/.platformio/packages/framework-arduinoavr/cores/arduino/Arduino.h|167 col 22 warning| unknown attribute '__progmem__' ignored /home/neophytos/.platformio/packages/framework-arduinoavr/cores/arduino/Arduino.h|169 col 22 warning| unknown attribute '__progmem__' ignored /home/neophytos/.platformio/packages/framework-arduinoavr/cores/arduino/Arduino.h|170 col 22 warning| unknown attribute '__progmem__' ignored /home/neophytos/.platformio/packages/toolchain-atmelavr/avr/include/avr/eeprom.h|41 col 3 warning| "Device does not have EEPROM available." /home/neophytos/.platformio/packages/toolchain-atmelavr/avr/include/util/delay_basic.h|108 col 5 error| invalid output constraint '=w' in asm /home/neophytos/.platformio/packages/toolchain-atmelavr/avr/include/util/delay.h|112 col 3 warning| "Compiler optimizations disabled; functions from <util /delay.h> won't work as designed" /home/neophytos/.platformio/packages/framework-arduinoavr/cores/arduino/Arduino.h|257 col 10 error| 'pins_arduino.h' file not found src/main.cpp|6 col 5 error| use of undeclared identifier 'Serial'
Any help will be highly appreciated
Inspiration from @ladislas and his Bare-Arduino-Project