-
-
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