Fix makegen creating Makefile if no config exist

This commit is contained in:
Thraix
2019-01-29 22:41:52 +01:00
parent 4e2785bb26
commit 048e3d050d
6 changed files with 250 additions and 259 deletions
Executable → Regular
+95 -128
View File
@@ -1,86 +1,72 @@
# Generated by YCM Generator at 2019-01-29 22:35:09.802732
# This file is NOT licensed under the GPLv3, which is the license for the rest
# of YouCompleteMe.
#
# Here's the license text for this file:
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to <http://unlicense.org/>
import os import os
import os.path
import fnmatch
import logging
import ycm_core import ycm_core
import re
BASE_FLAGS = [ flags = [
'-Wall', '-x',
'-Wuninitialized', 'c++',
'-Wextra', '-D_DEBUG',
'-Wno-long-long',
'-Wno-variadic-macros',
'-fexceptions',
'-ferror-limit=10000',
'-DNDEBUG',
'-std=c++17', '-std=c++17',
'-xc++', ]
'-I/usr/lib/',
'-I/usr/include/',
]
SOURCE_EXTENSIONS = [
'.cpp',
]
SOURCE_DIRECTORIES = [ # Set this to the absolute path to the folder (NOT the file!) containing the
'src' # compile_commands.json file to use that instead of 'flags'. See here for
] # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
#
# You can get CMake to generate this file for you by adding:
# set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
# to your CMakeLists.txt file.
#
# Most projects will NOT need to set this to anything; you can just change the
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
compilation_database_folder = ''
HEADER_EXTENSIONS = [ if os.path.exists( compilation_database_folder ):
'.h', database = ycm_core.CompilationDatabase( compilation_database_folder )
] else:
database = None
HEADER_DIRECTORIES = [ SOURCE_EXTENSIONS = [ '.C', '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
]
def IsHeaderFile(filename): def DirectoryOfThisScript():
extension = os.path.splitext(filename)[1] return os.path.dirname( os.path.abspath( __file__ ) )
return extension in HEADER_EXTENSIONS
def GetCompilationInfoForFile(database, filename):
if IsHeaderFile(filename):
basename = os.path.splitext(filename)[0]
for extension in SOURCE_EXTENSIONS:
# Get info from the source files by replacing the extension.
replacement_file = basename + extension
if os.path.exists(replacement_file):
compilation_info = database.GetCompilationInfoForFile(replacement_file)
if compilation_info.compiler_flags_:
return compilation_info
# If that wasn't successful, try replacing possible header directory with possible source directories.
for header_dir in HEADER_DIRECTORIES:
for source_dir in SOURCE_DIRECTORIES:
src_file = replacement_file.replace(header_dir, source_dir)
if os.path.exists(src_file):
compilation_info = database.GetCompilationInfoForFile(src_file)
if compilation_info.compiler_flags_:
return compilation_info
return None
return database.GetCompilationInfoForFile(filename)
def FindNearest(path, target, build_folder): def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
candidate = os.path.join(path, target)
if(os.path.isfile(candidate) or os.path.isdir(candidate)):
logging.info("Found nearest " + target + " at " + candidate)
return candidate;
parent = os.path.dirname(os.path.abspath(path));
if(parent == path):
raise RuntimeError("Could not find " + target);
if(build_folder):
candidate = os.path.join(parent, build_folder, target)
if(os.path.isfile(candidate) or os.path.isdir(candidate)):
logging.info("Found nearest " + target + " in build folder at " + candidate)
return candidate;
return FindNearest(parent, target, build_folder)
def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
if not working_directory: if not working_directory:
return list(flags) return list( flags )
new_flags = [] new_flags = []
make_next_absolute = False make_next_absolute = False
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
@@ -89,84 +75,65 @@ def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
if make_next_absolute: if make_next_absolute:
make_next_absolute = False make_next_absolute = False
if not flag.startswith('/'): if not flag.startswith( '/' ):
new_flag = os.path.join(working_directory, flag) new_flag = os.path.join( working_directory, flag )
for path_flag in path_flags: for path_flag in path_flags:
if flag == path_flag: if flag == path_flag:
make_next_absolute = True make_next_absolute = True
break break
if flag.startswith(path_flag): if flag.startswith( path_flag ):
path = flag[ len(path_flag): ] path = flag[ len( path_flag ): ]
new_flag = path_flag + os.path.join(working_directory, path) new_flag = path_flag + os.path.join( working_directory, path )
break break
if new_flag: if new_flag:
new_flags.append(new_flag) new_flags.append( new_flag )
return new_flags return new_flags
def FlagsForClangComplete(root): def IsHeaderFile( filename ):
try: extension = os.path.splitext( filename )[ 1 ]
clang_complete_path = FindNearest(root, '.clang_complete') return extension in [ '.H', '.h', '.hxx', '.hpp', '.hh' ]
clang_complete_flags = open(clang_complete_path, 'r').read().splitlines()
return clang_complete_flags
except:
return None
def FlagsForInclude(root):
try:
include_path = FindNearest(root, 'include')
flags = []
for dirroot, dirnames, filenames in os.walk(include_path):
for dir_path in dirnames:
real_path = os.path.join(dirroot, dir_path)
flags = flags + ["-I" + real_path]
return flags
except:
return None
def FlagsForCompilationDatabase(root, filename): def GetCompilationInfoForFile( filename ):
try: # The compilation_commands.json file generated by CMake does not have entries
# Last argument of next function is the name of the build folder for # for header files. So we do our best by asking the db for flags for a
# out of source projects # corresponding source file, if any. If one exists, the flags for that file
compilation_db_path = FindNearest(root, 'compile_commands.json', 'build') # should be good enough.
compilation_db_dir = os.path.dirname(compilation_db_path) if IsHeaderFile( filename ):
logging.info("Set compilation database directory to " + compilation_db_dir) basename = os.path.splitext( filename )[ 0 ]
compilation_db = ycm_core.CompilationDatabase(compilation_db_dir) for extension in SOURCE_EXTENSIONS:
if not compilation_db: replacement_file = basename + extension
logging.info("Compilation database file found but unable to load") if os.path.exists( replacement_file ):
compilation_info = database.GetCompilationInfoForFile(
replacement_file )
if compilation_info.compiler_flags_:
return compilation_info
return None return None
compilation_info = GetCompilationInfoForFile(compilation_db, filename) 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: if not compilation_info:
logging.info("No compilation info for " + filename + " in compilation database")
return None return None
return MakeRelativePathsInFlagsAbsolute(
final_flags = MakeRelativePathsInFlagsAbsolute(
compilation_info.compiler_flags_, compilation_info.compiler_flags_,
compilation_info.compiler_working_dir_) compilation_info.compiler_working_dir_ )
except:
return None
def FlagsForFile(filename):
root = os.path.realpath(filename);
compilation_db_flags = FlagsForCompilationDatabase(root, filename)
confPath = os.path.dirname(os.path.abspath(__file__))
for dir in HEADER_DIRECTORIES:
BASE_FLAGS.append('-I'+confPath+'/'+dir)
if compilation_db_flags:
final_flags = compilation_db_flags
else: else:
final_flags = BASE_FLAGS relative_to = DirectoryOfThisScript()
clang_flags = FlagsForClangComplete(root) final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
if clang_flags:
final_flags = final_flags + clang_flags
include_flags = FlagsForInclude(root)
if include_flags:
final_flags = final_flags + include_flags
return { return {
'flags': final_flags, 'flags': final_flags,
'do_cache': True 'do_cache': True
} }
+1 -1
View File
@@ -1,4 +1,4 @@
# This Makefile was generated using MakeGen v1.0.8 made by Tim Håkansson # This Makefile was generated using MakeGen v1.0.9 made by Tim Håkansson
# and is licensed under MIT. Full source of the project can be found at # and is licensed under MIT. Full source of the project can be found at
# https://github.com/Thraix/MakeGen # https://github.com/Thraix/MakeGen
CC=@g++ CC=@g++
+1 -1
View File
@@ -12,7 +12,7 @@
// Release , should be backwards compatible with any minor version // Release , should be backwards compatible with any minor version
#define MAKEGEN_VERSION_RELEASE 0 #define MAKEGEN_VERSION_RELEASE 0
// Minor changes, should be compatible with any other minor version with same major and release. // Minor changes, should be compatible with any other minor version with same major and release.
#define MAKEGEN_VERSION_MINOR 8 #define MAKEGEN_VERSION_MINOR 9
#define MAKEGEN_VERSION ("v" STR(MAKEGEN_VERSION_MAJOR) "." STR(MAKEGEN_VERSION_RELEASE) "." STR(MAKEGEN_VERSION_MINOR)) #define MAKEGEN_VERSION ("v" STR(MAKEGEN_VERSION_MAJOR) "." STR(MAKEGEN_VERSION_RELEASE) "." STR(MAKEGEN_VERSION_MINOR))
const static unsigned int FLAG_HELP = BIT(0); const static unsigned int FLAG_HELP = BIT(0);
+5 -2
View File
@@ -13,7 +13,7 @@ ConfigFile::ConfigFile()
} }
ConfigFile ConfigFile::Load() ConfigFile ConfigFile::Load(const std::string& filename)
{ {
ConfigFile conf; ConfigFile conf;
unsigned int loadFlag = 0; unsigned int loadFlag = 0;
@@ -22,9 +22,11 @@ ConfigFile ConfigFile::Load()
std::string* s; std::string* s;
bool* b; bool* b;
std::ifstream file("makegen.conf"); std::ifstream file(filename);
std::string line; std::string line;
if(file.is_open())
{
while(std::getline(file,line)) while(std::getline(file,line))
{ {
if(line[0]=='#') if(line[0]=='#')
@@ -110,6 +112,7 @@ ConfigFile ConfigFile::Load()
} }
} }
return conf; return conf;
}
} }
void ConfigFile::InputMultiple(const std::string& inputText, std::vector<std::string>& vec, bool needEnding) void ConfigFile::InputMultiple(const std::string& inputText, std::vector<std::string>& vec, bool needEnding)
+1 -1
View File
@@ -21,7 +21,7 @@ class ConfigFile
ConfigFile(); ConfigFile();
void Save() const; void Save() const;
static ConfigFile Gen(); static ConfigFile Gen();
static ConfigFile Load(); static ConfigFile Load(const std::string& filename);
private: private:
static void InputMultiple(const std::string& inputText, std::vector<std::string>& vec, bool needEnding); static void InputMultiple(const std::string& inputText, std::vector<std::string>& vec, bool needEnding);
}; };
+33 -12
View File
@@ -11,10 +11,38 @@
#include "Makefile.h" #include "Makefile.h"
#include "Timer.h" #include "Timer.h"
void GenMakefile() void PrintHelp()
{ {
ConfigFile conf = ConfigFile::Load(); LOG_INFO("Usage: makegen [options]");
LOG_INFO(" Options:");
LOG_INFO(" --help\tDisplays this information");
LOG_INFO(" --conf\tGenerate a config file for the project");
LOG_INFO(" --version\tDisplays the version of this program");
LOG_INFO(" install\tGenerates a Makefile and runs make install");
LOG_INFO(" clean\t\tGenerates a Makefile and runs make clean");
LOG_INFO(" rebuild\tGenerates a Makefile and runs make rebuild");
LOG_INFO(" If no option is given it will run default make");
}
bool GenMakefile()
{
std::ifstream f("makegen.conf");
if(f.good())
{
ConfigFile conf = ConfigFile::Load("makegen.conf");
Makefile::Save(conf); Makefile::Save(conf);
return true;
}
f.close();
f = std::ifstream("Makefile");
if(!f.good())
{
LOG_ERROR("No makegen.conf or Makefile found.");
PrintHelp();
return false;
}
return true;
} }
unsigned int ReadFlags(int argc, char** argv) unsigned int ReadFlags(int argc, char** argv)
@@ -50,15 +78,7 @@ int main(int argc, char** argv)
unsigned int flags = ReadFlags(argc,argv); unsigned int flags = ReadFlags(argc,argv);
if(flags & FLAG_HELP) if(flags & FLAG_HELP)
{ {
LOG_INFO("Usage: makegen [options]"); PrintHelp();
LOG_INFO(" Options:");
LOG_INFO(" --help\tDisplays this information");
LOG_INFO(" --conf\tGenerate a config file for the project");
LOG_INFO(" --version\tDisplays the version of this program");
LOG_INFO(" install\tGenerates a Makefile and runs make install");
LOG_INFO(" clean\t\tGenerates a Makefile and runs make clean");
LOG_INFO(" rebuild\tGenerates a Makefile and runs make rebuild");
LOG_INFO(" If no option is given it will generate a Makefile and run default make");
return 0; return 0;
} }
if(flags & FLAG_VERSION) if(flags & FLAG_VERSION)
@@ -73,7 +93,8 @@ int main(int argc, char** argv)
} }
LOG_INFO("Generating Makefile..."); LOG_INFO("Generating Makefile...");
Timer timer; Timer timer;
GenMakefile(); if(!GenMakefile())
return 1;
LOG_INFO("Took ", round(timer.Elapsed()*1000.0)/1000.0,"s"); LOG_INFO("Took ", round(timer.Elapsed()*1000.0)/1000.0,"s");
LOG_INFO("Running Makefile..."); LOG_INFO("Running Makefile...");
for(int i = 1;i<argc;i++) for(int i = 1;i<argc;i++)