Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
PlatformIO/YouCompleteMe Integration
"""
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
}
@ajford

This comment has been minimized.

Copy link
Owner Author

ajford commented Mar 9, 2015

Inspiration from @ladislas and his Bare-Arduino-Project

@ajford

This comment has been minimized.

Copy link
Owner Author

ajford commented Mar 9, 2015

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.

@ajford

This comment has been minimized.

Copy link
Owner Author

ajford commented Mar 12, 2015

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.

@HeLiBloks

This comment has been minimized.

Copy link

HeLiBloks commented Dec 11, 2016

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?

@Iambecomeroot

This comment has been minimized.

Copy link

Iambecomeroot commented Jul 28, 2017

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.

@teejK

This comment has been minimized.

Copy link

teejK commented Aug 6, 2017

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

@smslit

This comment has been minimized.

Copy link

smslit commented Aug 16, 2017

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

@ladislas

This comment has been minimized.

Copy link

ladislas commented Oct 22, 2017

@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

@hashworks

This comment has been minimized.

Copy link

hashworks commented May 13, 2018

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.

@neophytos-theodorou

This comment has been minimized.

Copy link

neophytos-theodorou commented Jun 26, 2018

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.