I am trying to configure the vim Plugin "YouCompleteMe". My C++ project consists of many header files, which are spread all over the directory tree. In order to add header directories I have to add them in the ".ycm_extra_conf.py".
Excerpt:
'-I',
'./src/base/utils',
'-I',
'./src/base/modules',
But something like this does not work:
'-I',
'./src/base/*',
Is there a way to tell YCM to recursively search for header files?
Thank you.
I have added a new syntax -ISUB to include all sub-directories.
e.g.
"-ISUB./Pods/Headers/Public"
full .ycm_extra_conf.py here
import os
import ycm_core
flags = [
#custom definition, include subfolders
'-ISUB./Pods/Headers/Public',
'-I./Pod/Classes',
]
def Subdirectories(directory):
res = []
for path, subdirs, files in os.walk(directory):
for name in subdirs:
item = os.path.join(path, name)
res.append(item)
return res
def IncludeFlagsOfSubdirectory( flags, working_directory ):
if not working_directory:
return list( flags )
new_flags = []
make_next_include_subdir = False
path_flags = [ '-ISUB']
for flag in flags:
# include the directory of flag as well
new_flag = [flag.replace('-ISUB', '-I')]
if make_next_include_subdir:
make_next_include_subdir = False
for subdir in Subdirectories(os.path.join(working_directory, flag)):
new_flag.append('-I')
new_flag.append(subdir)
for path_flag in path_flags:
if flag == path_flag:
make_next_include_subdir = True
break
if flag.startswith( path_flag ):
path = flag[ len( path_flag ): ]
for subdir in Subdirectories(os.path.join(working_directory, path)):
new_flag.append('-I' + subdir)
break
new_flags =new_flags + new_flag
return new_flags
I had the same problem so I created a function that do it.
add the following to your ".ycm_extra_conf.py" right after the flags list:
import glob
flagsRec=['/opt/e17/include/*']
def AddDirsRecursively( flagsRec ):
global flags
new_flags = []
for flag in flagsRec:
for d in glob.glob(flag) :
if os.path.isdir(d):
new_flags.append('-I')
new_flags.append(d)
flags += new_flags
AddDirsRecursively( flagsRec )
where "flagsRec" is the list of dirs(regular expressions) you want to traverse and add to "flags"
Related
I'm trying to amend this code so that the UID and GID of the files inserted into the tarball belong to root.
import tarball
sources = [ 'test-directory', 'another-directory/file1' ]
with tarfile.open("/tmp/test.tar","w") as tarball:
for source in sources:
tarball.add(source)
sources is mixed list of directory and filenames. With the above code, all the files are there, but with my user UID and GID. If I were doing this on the command line, I'd prefix a call to tar with fakeroot.
In Python (3), if I try just looking at one directory:
import tarfile
import glob
with tarfile.open("/tmp/test.tar","w") as tarball:
for filename in glob.iglob('test-directory/**', recursive=True):
info = tarball.gettarinfo(filename)
info.uid = 0
info.gid = 0
info.uname = 'root'
info.gname = 'root'
tarball.addfile(info)
That gets me proper ownership but it's missing files in the test-directory tree because I can't get the glob to working satisfactorily.
How can I do this?
Reading the source (tarfile.py)
I added this function based on inspecting the add() method from the above.
def add_tarinfo(tarball, tarinfo, name, arcname, fakeroot):
if fakeroot:
tarinfo.uid = 0
tarinfo.gid = 0
tarinfo.uname = 'root'
tarinfo.gname = 'root'
if tarinfo.isreg():
with open(name, "rb") as f:
tarball.addfile(tarinfo, f)
elif tarinfo.isdir():
tarball.addfile(tarinfo)
for f in os.listdir(name):
nname = os.path.join(name, f)
narcname = os.path.join(arcname, f)
ntarinfo = tarball.gettarinfo(nname, narcname)
add_tarinfo(tarfile, ntarinfo, nname, narcname, fakeroot)
else:
tarball.addfile(tarinfo)
So the original code becomes:
with tarfile.open("/tmp/test.tar","w") as tarball:
for arcname in self.sources:
name = os.path.join(self.source_path, arcname)
tarinfo = tarball.gettarinfo(name=name, arcname=arcname)
add_tarinfo(tarball, tarinfo, name, arcname, True)
I achieved this using the filter parameter (available since Python 3.2) of TarFile.add() method (docs.python.org):
def fakeroot_filter(tarinfo):
tarinfo.gid = 0
tarinfo.uid = 0
tarinfo.gname = 'root'
tarinfo.uname = 'root'
return tarinfo
with tarfile.open('data.tgz', 'w:gz', format=tarfile.GNU_FORMAT) as arc:
arc.add(f'{path}/data', arcname='data', filter=fakeroot_filter)
Some additional info about this feature can be found in the related issue on bugs.python.org
I´ve got a folder/sub-directories structure as follow:
-main_folder
-sub_1
322.txt
024.ops
-sub_2
977.txt
004.txt
-sub_3
396.xml
059.ops
I´m trying to iterate with os.walk through the folder and its sub-directories and collect the names inside these folders. When a name gets found by a regex rule, I want to either store the path in list or directly move that file into a new folder (mkdir).
I´ve already got the regex done to find the document I want.
For example:
find_000_099 = r'\b(0\d{2}.\w{1,4})'
find_300_399 = r'\b(3\d{2}.\w{1,4})'
find_900_999 = r'\b(9\d{2}.\w{1,4})'
I wish my expected result to be like:
-main_folder
-sub_from_000_099
024.ops
004.txt
059.ops
-sub_from_300_399
322.txt
396.xml
-sub_from_900_999
977.txt
You can use the below-given code, which moves the file from its initial directory to the desired directory.
import os
import re
import shutil
find_000_099 = r'\b(0\d{2}.\w{1,4})'
find_300_399 = r'\b(3\d{2}.\w{1,4})'
find_900_999 = r'\b(9\d{2}.\w{1,4})'
count = 0
for roots,dirs,files in os.walk('Directory Path'):
#print(roots, len(dirs), len(files))
if count == 0:
parent_dir = roots
os.mkdir ( parent_dir + "/sub_from_000_099" )
os.mkdir ( parent_dir + "/sub_from_300_399" )
os.mkdir ( parent_dir + "/sub_from_900_999" )
count += 1
else:
print(count)
for file in files:
print(file)
if re.match(find_000_099, file):
shutil.move ( roots + "/" + file, parent_dir + "/sub_from_000_099/" + file)
elif re.match ( find_300_399, file ):
shutil.move ( roots + "/" + file, parent_dir + "/sub_from_300_399/" + file )
elif re.match ( find_900_999, file ):
shutil.move ( roots + "/" + file, parent_dir + "/sub_from_900_999/" + file )
It's a skeleton code, which fulfills your requirements.
You can add checks on creating directories, by first checking whether the directory exists or not, and other checks as per your needs.
Here is a simpler way, using pathlib and shutil
import re
import shutil
from pathlib import Path
new_path = Path("new_folder")
if not new_path.exists(): new_path.mkdir()
# Getting all files in the main directory
files = Path("main_folder").rglob("*.*")
regs = {
r'\b(0\d{2}.\w{1,4})': "sub_1", # find_000_099
r'\b(3\d{2}.\w{1,4})': "sub_2", # find_300_399
r'\b(9\d{2}.\w{1,4})': "sub_3" # find_900_999
}
for f in files:
for reg in regs:
if re.search(reg, f.name):
temp_path = new_path / regs[reg]
if not temp_path.exists(): temp_path.mkdir()
# Change the following method to 'move' after testing it
shutil.copy(f, temp_path / f.name)
break
Here is my code with reads the input from a config file and moving files to another directory based on a condition and logs the information to a log file
import shutil
import configparser
import logging.handlers
import os
#Reading the input configuration
config = configparser.ConfigParser()
config.read("config_input.ini")
src_filepath = (config.get("Configuration Inputs","src_filepath"))
dst_filepath = (config.get("Configuration Inputs","dst_filepath"))
log_file_name = (config.get("Configuration Inputs","log_file_name"))
file_limit = int((config.get("Configuration Inputs","file_limit")))
if not os.path.exists (dst_filepath):
os.makedirs(dst_filepath)
onlyfiles_in_dst = next ( os.walk ( dst_filepath ) ) [ 2 ]
file_count_indst = len ( onlyfiles_in_dst )
onlyfiles_in_src = next ( os.walk ( src_filepath ) ) [ 2 ]
file_count_insrc = len ( onlyfiles_in_src )
def sorted_ls(src_filepath):
mtime = lambda f: os.stat(os.path.join(src_filepath, f)).st_mtime
return list(sorted(os.listdir(src_filepath), key=mtime))
move_list = sorted_ls(src_filepath)
#print (move_list)
if file_count_indst < file_limit:
for mfile in move_list:
shutil.move(src_filepath + '\\' + mfile, dst_filepath)
**#Logging everything**
logger = logging.getLogger()
logging.basicConfig(filename=log_file_name, format='%(asctime)s %(message)s', filemode='a')
logger.setLevel(logging.INFO)
logger.info('Number of files moved from source ' + str(len(move_list)))
But the problem is I want to move only the 1000 files from source to destination.
Something like
"ls -lrt| head ls -lrt | head -n 1000"
which I can not do iy as I am running this script on Windows platform.
Please suggest a proper way to do it.
Also please suggest how can I put it under a user defined class and may be can use in some other program.
Can't a simple counter be the solution?
if file_count_indst < file_limit:
count=0;
for mfile in move_list:
shutil.move(src_filepath + '\\' + mfile, dst_filepath)
count = count +1
if count==1000:
break
I've encountered a problem trying to set up a C++ project on my Mac (Yosemite with Xcode 6) using CMake with Unix style Makefiles and vim with the youcompleteme plugin (I'm a Linux veteran and Mac newbie so I prefer this setup to Xcode). The code builds and runs but youcompleteme throws some bogus errors which I think boil down to it not being able to find the <cstdint> header.
I've just tried it on Linux too, and had the same problem.
I've configured .ycm_extra_conf.py to use a compile_commands.json generated by cake. The "command" lines in compile_commands.json use these flags:
"command": "/usr/bin/c++ -std=c++11 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -F/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/System/Library/Frameworks -I/usr/local/include -I/Users/tony/Dev/cow/jni -I/Users/tony/Library/Frameworks/SDL2.framework/Headers -Wall -Wextra -Wunused -F/Users/tony/Library/Frameworks -o ...
There doesn't seem to be an explicit reference there to any directory containing stdint as a direct parent.
Is there a way I can get youcompleteme to do its stuff with libclang in such a way that it can find the directory implicitly, which seems to work when running c++ on the command line? Or what's the best way to get cmake to add an appropriate system header path without hardwiring it? I want my CMakeLists.txt to be portable and to be able to cope with toolchain upgrades.
My .ycm_extra_conf.py was pretty much a copy of the supplied example modified slightly to find compile_commands.json where I put it.
As #ladislas said, YCM needs to be explicitly pointed to all relevant include directories as libclang won't use the same implicit location a normal compiler driver invocation (i.e. clang++ from the command line) would use.
What I usually do, on OSX, is to let YCM know about Xcode's libc++ headers with something like (in .ycm_extra_conf.py):
import os
import ycm_core
import subprocess
xcode_cpp11headers = subprocess.Popen("xcode-select -p", stdout = subprocess.PIPE, shell=True).communicate()[0].rstrip('\n') + '/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1'
.
.
flags = [
.
.
'-isystem',
xcode_cpp11headers,
.
.
]
The "xcode_cpp11headers" variable is populated with the proper path depending on the location of your current Xcode's installation, and you can change it accordingly if you want to use say the commandline-tools version of libc++ (i.e. the includes are in /Library/Developer/CommandLineTools/usr/include/c++/v1) or a source distribution of libc++ if you have compiled your own.
Of course this is platform dependant and either you provide a platform specific .ycm_extra_conf.py alongside your project, or you can populate that variable differently with some extra python code accordingly to the current platform.
You must add all the paths where YCM needs to look for your sources, libraries, and so on.
It does not work recursively, so it's a little bit cumbersome at first but is should not change once set for your project.
As an example, here is mine for an Arduino project :
https://github.com/ladislas/Bare-Arduino-Project/blob/master/.ycm_extra_conf.py#L21
Hope this helps!
EDIT - 2015/01/08
The solution of #abigagli is very elegant! I too use something like this to parse my lib directory and look for .h files to add their path to flags.
Here it is if it can be useful :) http://git.io/IiR1JA
As I found out from the above answers, YCM needs to be told the compiler's system include paths which are usually implicit in other ways of using the compiler. I added a function GetSystemIncludePaths() to .ycm_extra_conf.py to discover and cache these paths portably. Here's the full file with comments and irrelevant content of flags list snipped. The original is Copyright (C) 2014 Google Inc with a GPL2+ licence:
import subprocess, os
import ycm_core
flags = []
def DirectoryOfThisScript():
return os.path.dirname( os.path.abspath( __file__ ) )
compilation_database_folder = os.path.abspath(
os.path.join(DirectoryOfThisScript(), 'build-make'))
if os.path.exists( compilation_database_folder ):
database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
database = None
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
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 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 ):
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 GetSystemIncludePaths():
cache = os.path.join(DirectoryOfThisScript(), ".ycm_sys_incs")
if os.path.exists(cache):
fp = open(cache, 'r')
flags = fp.readlines()
fp.close()
flags = [s.strip() for s in flags]
else:
devnull = open(os.devnull, 'r')
child = subprocess.Popen(["/usr/bin/cpp", "-xc++", "-v"],
stdin = devnull, stderr = subprocess.PIPE)
output = child.communicate()[1].split('\n')
devnull.close()
flags = []
status = 0
for l in output:
l = l.strip()
if l == '#include "..." search starts here:':
status = 1
elif l == '#include <...> search starts here:':
status = 2
elif status:
if l == 'End of search list.':
break
elif l.endswith('(framework directory)'):
continue
elif status == 1:
flags.append('-I')
elif status == 2:
flags.append('-isystem')
flags.append(os.path.normpath(l))
fp = open(cache, 'w')
fp.write('\n'.join(flags))
fp.close()
return flags
def FlagsForFile( filename, **kwargs ):
if database:
compilation_info = GetCompilationInfoForFile( filename )
if not compilation_info:
return None
final_flags = MakeRelativePathsInFlagsAbsolute(
compilation_info.compiler_flags_,
compilation_info.compiler_working_dir_ )
sys_incs = GetSystemIncludePaths()
if sys_incs:
final_flags += sys_incs
else:
relative_to = DirectoryOfThisScript()
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
return {
'flags': final_flags,
'do_cache': True
}
Let's say I want to strip all the debug symbols in the shared libraries that I build whiling keeping the original file name.
I tried to add an command in the method:
def mySharedLibrary(self, *args, **kwargs):
# do some common work for every shared library like add a soname or append some lib files to LIBS parameter
target = SharedLibary(*args, **kwargs)
target = env.Command(target,target, "objcopy --strip-debug ${SOURCE}")
return target
I get this error: two different method was given to the same target,
I guess it's because the two targets returned by env.Command and SharedLibrary are exactly the same name.
Any ideas to do this?
Thanks in advance!
I had the same problem and got the same error. What I had to do was to create an intermediate target/library. The intermediate and final targets each had their own library name, so SCons doesnt get confused.
You could probably do something like the following:
env.SharedLibrary(target = 'namePreStrip', source = 'yourSource')
env.Command(target = 'name', source = 'namePreStrip', 'objcopy...')
I used objcopy to build a library out of several libraries. Here's the actual source code I implemented:
#
# Build an object file out of several other source files, objects, and libraries
# Optionally execute objcopy on the resulting library, depending if objcopyFlags
# has been populated
#
# env - SCons Environment used to build, Mandatory arg
# target - resulting library name, without LIBPREFIX and LIBSUFFIX, ej 'nsp2p',
# Mandatory arg
# sourceFiles - list of '.cc' files that will be compiled and included in the
# resulting lib, Optional arg
# objects - list of already compiled object files to be included in resulting lib,
# Optional arg
# libraries - list of libraries to be included in resulting lib, Optional arg
# objcopyFlags - list of flags to pass to objcopy command. objcopy will only
# be executed if this list is populated, Optional arg
#
# One of [sourceFiles, objects, or libraries] must be specified, else nothing
# will be performed
#
# Not using a custom builder because I dont like the way SCons prints the
# entire command each time its called, even if its not going to actually
# build anything AND I need more method args than provided by custom builders
#
def buildWholeArchive(self, env, target, sourceFiles, objects, libraries, objcopyFlags):
if len(sourceFiles) == 0 and len(objects) == 0 and len(libraries) == 0:
print "Incorrect use of buildWholeArchive, at least one of [sourceFiles | objects | librarires] must be specified, no build action will be performed"
return None
# Compile each source file
objNodes = []
if len(sourceFiles) > 0:
objNodes = env.Object(source = sourceFiles)
cmdList = []
cmdList.append(env['CXX'])
cmdList.append('-nostdlib -r -o $TARGET -Wl,--whole-archive')
for obj in objNodes:
cmdList.append(env.File(obj).abspath)
for obj in objects:
cmdList.append(env.File(obj).abspath)
for lib in libraries:
cmdList.append(lib)
cmdList.append('-Wl,--no-whole-archive')
cmd = ' '.join(cmdList)
libTarget = '%s%s%s' % (env['LIBPREFIX'], target, env['LIBSUFFIX'])
if len(objcopyFlags) > 0:
# First create the library, then run objcopy on it
objTarget = '%s%s_preObjcopy%s' % (env['LIBPREFIX'], target, env['LIBSUFFIX'])
preObjcopyTarget = env.Command(target = objTarget, source = [], action = cmd)
env.Depends(preObjcopyTarget, [objNodes, sourceFiles, objects, libraries])
objCmdList = [env['OBJCOPY']]
objCmdList.extend(objcopyFlags)
objCmdList.append('$SOURCE $TARGET')
objcopyCmd = ' '.join(objCmdList)
archiveTarget = env.Command(target = libTarget, source = preObjcopyTarget, action = objcopyCmd)
else:
# Just create the library
archiveTarget = env.Command(target = libTarget, source = [], action = cmd)
env.Depends(archiveTarget, [objNodes, sourceFiles, objects, libraries])
return archiveTarget
And here is how I called it:
sourceFiles = ['file1.cc', 'file2.cc']
libSource = []
if 'OcteonArchitecture' in env:
libSource.append(lib1)
libSource.append(lib2)
libSource.append(lib3)
objcopy = []
if 'OcteonArchitecture' in env:
objcopy.extend([
'--redefine-sym calloc=ns_calloc',
'--redefine-sym free=ns_free',
'--redefine-sym malloc=ns_malloc',
'--redefine-sym realloc=ns_realloc'])
archiveTarget = clonedEnv.buildWholeArchive(target = libName,
sourceFiles = sourceFiles,
objects = [],
libraries = libSource,
objcopyFlags = objcopy)
env.Alias('libMyLib', archiveTarget)