From d119a1ae5c42d6641bef790bbf53e8c1ec2f666f Mon Sep 17 00:00:00 2001 From: Ingo Heimbach Date: Tue, 15 Mar 2016 08:52:20 +0100 Subject: [PATCH 01/20] On OSX Makefiles generated by qmake are patched to remove absolute compiler and linker paths. --- config_gen.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/config_gen.py b/config_gen.py index e535a3b..c60c35b 100755 --- a/config_gen.py +++ b/config_gen.py @@ -202,6 +202,25 @@ def run(cmd, *args, **kwargs): print("$ " + " ".join(cmd)) subprocess.call(cmd, *args, **kwargs) + # helper function to set CC and CXX variables correctly on OSX with qmake + def patch_qmake_makefile(makefile_path): + compilers = { + "CC": "clang", + "CXX": "clang++", + "LINK": "clang++" + } + patched_makefile_lines = [] + with open(makefile_path, "r") as f: + for line in f: + line = line.rstrip() + for variable_name, compiler in compilers.items(): + if re.match("\s*{}\s*=".format(variable_name), line): + line = re.sub("=.*", "= {}".format(compiler), line) + break + patched_makefile_lines.append(line) + with open(makefile_path, "w") as f: + f.write("\n".join(patched_makefile_lines)) + # execute the build system if(os.path.exists(os.path.join(project_dir, "CMakeLists.txt"))): # cmake @@ -286,6 +305,8 @@ def run(cmd, *args, **kwargs): print("Running qmake in '{}' with Qt {}...".format(build_dir, qt_version)) run(["qmake"] + configure_opts + [pro_files[0]], env=env_config, **proc_opts) + if os.uname()[0] == "Darwin": + patch_qmake_makefile(os.path.join(build_dir, "Makefile")) print("\nRunning make...") run(make_args, env=env, **proc_opts) From 082ad91057b5316322f2274e7ec4267d18a9d0d3 Mon Sep 17 00:00:00 2001 From: Ingo Heimbach Date: Wed, 16 Mar 2016 11:25:43 +0100 Subject: [PATCH 02/20] Altered qmake patch function: - PEP8 style doc string - Simplified patching (uses only re.sub) - Notification is printed when the patching function is invoked --- config_gen.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/config_gen.py b/config_gen.py index c60c35b..361084f 100755 --- a/config_gen.py +++ b/config_gen.py @@ -202,24 +202,31 @@ def run(cmd, *args, **kwargs): print("$ " + " ".join(cmd)) subprocess.call(cmd, *args, **kwargs) - # helper function to set CC and CXX variables correctly on OSX with qmake def patch_qmake_makefile(makefile_path): - compilers = { + '''Function that patches Makefiles generated by qmake to set CC, CXX and LINK variables correctly on Mac OSX + + makefile_path: path to the qmake generated Makefile; patched result is written to the same file + ''' + + variables = { "CC": "clang", "CXX": "clang++", "LINK": "clang++" } - patched_makefile_lines = [] + + def sub_func(match_obj): + variable = match_obj.group(1).strip() + if variable in variables: + new_value = variables[variable] + return "{}= {}".format(match_obj.group(1), new_value) + else: + return match_obj.group(0) + with open(makefile_path, "r") as f: - for line in f: - line = line.rstrip() - for variable_name, compiler in compilers.items(): - if re.match("\s*{}\s*=".format(variable_name), line): - line = re.sub("=.*", "= {}".format(compiler), line) - break - patched_makefile_lines.append(line) + makefile_input = f.read() + makefile_output = re.sub(r"(\s*\w+\s*)=.*", sub_func, makefile_input) with open(makefile_path, "w") as f: - f.write("\n".join(patched_makefile_lines)) + f.write(makefile_output) # execute the build system if(os.path.exists(os.path.join(project_dir, "CMakeLists.txt"))): @@ -306,6 +313,7 @@ def patch_qmake_makefile(makefile_path): run(["qmake"] + configure_opts + [pro_files[0]], env=env_config, **proc_opts) if os.uname()[0] == "Darwin": + print("Patching generated makefile...") patch_qmake_makefile(os.path.join(build_dir, "Makefile")) print("\nRunning make...") From 4fee21327a09411a587ae16e88aef830125dfcae Mon Sep 17 00:00:00 2001 From: totalkrill Date: Mon, 29 Aug 2016 10:24:40 +0200 Subject: [PATCH 03/20] added avr and arm compilers to faketoolchain --- fake-toolchain/Unix/arm-none-eabi-g++ | 1 + fake-toolchain/Unix/arm-none-eabi-gcc | 1 + fake-toolchain/Unix/avr-g++ | 1 + fake-toolchain/Unix/avr-gcc | 1 + 4 files changed, 4 insertions(+) create mode 120000 fake-toolchain/Unix/arm-none-eabi-g++ create mode 120000 fake-toolchain/Unix/arm-none-eabi-gcc create mode 120000 fake-toolchain/Unix/avr-g++ create mode 120000 fake-toolchain/Unix/avr-gcc diff --git a/fake-toolchain/Unix/arm-none-eabi-g++ b/fake-toolchain/Unix/arm-none-eabi-g++ new file mode 120000 index 0000000..34836c6 --- /dev/null +++ b/fake-toolchain/Unix/arm-none-eabi-g++ @@ -0,0 +1 @@ +cxx \ No newline at end of file diff --git a/fake-toolchain/Unix/arm-none-eabi-gcc b/fake-toolchain/Unix/arm-none-eabi-gcc new file mode 120000 index 0000000..2652f5f --- /dev/null +++ b/fake-toolchain/Unix/arm-none-eabi-gcc @@ -0,0 +1 @@ +cc \ No newline at end of file diff --git a/fake-toolchain/Unix/avr-g++ b/fake-toolchain/Unix/avr-g++ new file mode 120000 index 0000000..34836c6 --- /dev/null +++ b/fake-toolchain/Unix/avr-g++ @@ -0,0 +1 @@ +cxx \ No newline at end of file diff --git a/fake-toolchain/Unix/avr-gcc b/fake-toolchain/Unix/avr-gcc new file mode 120000 index 0000000..2652f5f --- /dev/null +++ b/fake-toolchain/Unix/avr-gcc @@ -0,0 +1 @@ +cc \ No newline at end of file From 9cf43ce6daea8c8ef7604538cdfb1615ca9bb285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A1udio=20Pereira?= Date: Thu, 1 Sep 2016 12:52:13 +0100 Subject: [PATCH 04/20] Fixed AUR URL. AUR4 was temporary. It no longer exists, regular AUR has already been upgraded --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c45a787..febe1ee 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Add ```NeoBundle 'rdnetto/YCM-Generator'``` to your vimrc (or the equivalent for For [vim-plug](https://github.com/junegunn/vim-plug) users, add ```Plug 'rdnetto/YCM-Generator', { 'branch': 'stable'}``` to your vimrc. -Alternatively, Arch Linux users can install YCM-Generator using the (unofficial) [AUR package](https://aur4.archlinux.org/packages/ycm-generator-git/). +Alternatively, Arch Linux users can install YCM-Generator using the (unofficial) [AUR package](https://aur.archlinux.org/packages/ycm-generator-git/). ## Usage Run ```./config_gen.py PROJECT_DIRECTORY```, where ```PROJECT_DIRECTORY``` is the root directory of your project's build system (i.e. the one containing the root Makefile, etc.) From 396942a4cb25b249d90b6e9c10a66e2321d0019b Mon Sep 17 00:00:00 2001 From: Reuben D'Netto Date: Mon, 10 Oct 2016 20:55:26 +1100 Subject: [PATCH 05/20] OS X 10.12 doesn't have python2. Closes #85. --- config_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config_gen.py b/config_gen.py index 69130df..413594b 100755 --- a/config_gen.py +++ b/config_gen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python2.7 import sys import os From 5b1594e5dc611d03bfcbe35c1db893b405b9b75d Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Mon, 17 Oct 2016 03:48:17 +0200 Subject: [PATCH 06/20] Python2 and python3 compatible - initial version --- config_gen.py | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/config_gen.py b/config_gen.py index 54e89f9..b1f8feb 100755 --- a/config_gen.py +++ b/config_gen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import sys import os @@ -102,8 +102,8 @@ def main(): }[output_format] # temporary files to hold build logs - with tempfile.NamedTemporaryFile(mode="rw") as c_build_log: - with tempfile.NamedTemporaryFile(mode="rw") as cxx_build_log: + with tempfile.NamedTemporaryFile(mode="r") as c_build_log: + with tempfile.NamedTemporaryFile(mode="r") as cxx_build_log: # perform the actual compilation of flags fake_build(project_dir, c_build_log.name, cxx_build_log.name, **args) (c_count, c_skip, c_flags) = parse_flags(c_build_log) @@ -175,7 +175,10 @@ def fake_build(project_dir, c_build_log_path, cxx_build_log_path, verbose, make_ else: # Preserve HOME, since Cmake needs it to find some packages and it's # normally there anyway. See #26. - env = dict(map(lambda x: (x, os.environ[x]), ["HOME"])) + if sys.version_info[0] == 2: + env = dict(map(lambda x: (x, os.environ[x]), ["HOME"])) + if sys.version_info[0] == 3: + env = dict([(x, os.environ[x]) for x in ["HOME"]]) env["PATH"] = "{}:{}".format(fake_path, os.environ["PATH"]) env["CC"] = "clang" @@ -401,7 +404,10 @@ def parse_flags(build_log): # Only specify one word size (the largest) # (Different sizes are used for different files in the linux kernel.) mRegex = re.compile("^-m[0-9]+$") - word_flags = list([f for f in flags if isinstance(f, basestring) and mRegex.match(f)]) + if sys.version_info[0] == 2: + word_flags = list([f for f in flags if isinstance(f, basestring) and mRegex.match(f)]) + elif sys.version_info[0] == 3: + word_flags = list([f for f in flags if isinstance(f, str) and mRegex.match(f)]) if(len(word_flags) > 1): for flag in word_flags: @@ -428,11 +434,18 @@ def generate_cc_conf(flags, config_file): with open(config_file, "w") as output: for flag in flags: - if(isinstance(flag, basestring)): - output.write(flag + "\n") - else: # is tuple - for f in flag: - output.write(f + "\n") + if sys.version_info[0] == 2: + if(isinstance(flag, basestring)): + output.write(flag + "\n") + else: # is tuple + for f in flag: + output.write(f + "\n") + elif sys.version_info[0] == 3: + if(isinstance(flag, str)): + output.write(flag + "\n") + else: # is tuple + for f in flag: + output.write(f + "\n") def generate_ycm_conf(flags, config_file): @@ -451,8 +464,12 @@ def generate_ycm_conf(flags, config_file): if(line == " # INSERT FLAGS HERE\n"): # insert generated code for flag in flags: - if(isinstance(flag, basestring)): - output.write(" '{}',\n".format(flag)) + if sys.version_info[0] == 2: + if(isinstance(flag, basestring)): + output.write(" '{}',\n".format(flag)) + elif sys.version_info[0] == 3: + if(isinstance(flag, str)): + output.write(" '{}',\n".format(flag)) else: # is tuple output.write(" '{}', '{}',\n".format(*flag)) From 69ec295aadf56405bb4dccbe7c28201bb7fb6e34 Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Mon, 17 Oct 2016 11:59:38 +0200 Subject: [PATCH 07/20] Fix else block indentation --- config_gen.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config_gen.py b/config_gen.py index b1f8feb..a1ec51d 100755 --- a/config_gen.py +++ b/config_gen.py @@ -467,11 +467,13 @@ def generate_ycm_conf(flags, config_file): if sys.version_info[0] == 2: if(isinstance(flag, basestring)): output.write(" '{}',\n".format(flag)) + else: # is tuple + output.write(" '{}', '{}',\n".format(*flag)) elif sys.version_info[0] == 3: if(isinstance(flag, str)): output.write(" '{}',\n".format(flag)) - else: # is tuple - output.write(" '{}', '{}',\n".format(*flag)) + else: # is tuple + output.write(" '{}', '{}',\n".format(*flag)) else: # copy template From 2dcf823c22f52adde694dd5140e69e02933fe1a8 Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Mon, 17 Oct 2016 12:22:57 +0200 Subject: [PATCH 08/20] iteritems() is python2 only construct --- config_gen.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/config_gen.py b/config_gen.py index a1ec51d..cbb963a 100755 --- a/config_gen.py +++ b/config_gen.py @@ -416,12 +416,20 @@ def parse_flags(build_log): flags.add(max(word_flags)) # Resolve duplicate macro definitions (always choose the last value for consistency) - for name, values in define_flags.iteritems(): - if(len(values) > 1): - print("WARNING: {} distinct definitions of macro {} found".format(len(values), name)) - values.sort() + if sys.version_info[0] == 2: + for name, values in define_flags.iteritems(): + if(len(values) > 1): + print("WARNING: {} distinct definitions of macro {} found".format(len(values), name)) + values.sort() + + flags.add("-D{}={}".format(name, values[0])) + elif sys.version_info[0] == 3: + for name, values in list(define_flags.items()): + if(len(values) > 1): + print("WARNING: {} distinct definitions of macro {} found".format(len(values), name)) + values.sort() - flags.add("-D{}={}".format(name, values[0])) + flags.add("-D{}={}".format(name, values[0])) return (line_count, skip_count, sorted(flags)) From e657d4acd631c7a2fa4f24316f2d7e8c343a75bc Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Mon, 17 Oct 2016 12:27:13 +0200 Subject: [PATCH 09/20] Remove superfluous list() --- config_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config_gen.py b/config_gen.py index cbb963a..2390ca5 100755 --- a/config_gen.py +++ b/config_gen.py @@ -424,7 +424,7 @@ def parse_flags(build_log): flags.add("-D{}={}".format(name, values[0])) elif sys.version_info[0] == 3: - for name, values in list(define_flags.items()): + for name, values in define_flags.items(): if(len(values) > 1): print("WARNING: {} distinct definitions of macro {} found".format(len(values), name)) values.sort() From 3435764fc127c776ca459c7e1732a6fbd2b001c9 Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Mon, 17 Oct 2016 22:06:40 +0200 Subject: [PATCH 10/20] Open the files readable and writeable, as they used to be --- config_gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config_gen.py b/config_gen.py index 2390ca5..26b22dc 100755 --- a/config_gen.py +++ b/config_gen.py @@ -102,8 +102,8 @@ def main(): }[output_format] # temporary files to hold build logs - with tempfile.NamedTemporaryFile(mode="r") as c_build_log: - with tempfile.NamedTemporaryFile(mode="r") as cxx_build_log: + with tempfile.NamedTemporaryFile(mode="r+") as c_build_log: + with tempfile.NamedTemporaryFile(mode="r+") as cxx_build_log: # perform the actual compilation of flags fake_build(project_dir, c_build_log.name, cxx_build_log.name, **args) (c_count, c_skip, c_flags) = parse_flags(c_build_log) From 911a95e0d4c038a34a295c0aa282f73a9b3fadbf Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Wed, 19 Oct 2016 16:38:05 +0200 Subject: [PATCH 11/20] Refactor to make the code more readable --- config_gen.py | 66 +++++++++++++++++---------------------------------- 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/config_gen.py b/config_gen.py index 26b22dc..e571e69 100755 --- a/config_gen.py +++ b/config_gen.py @@ -25,6 +25,12 @@ # be able to find the plugin directory. ycm_generator_dir = os.path.dirname(os.path.realpath(__file__)) +def isString(string): + if sys.version_info[0] == 2: + return isinstance(string, basestring) + elif sys.version_info[0] == 3: + return isinstance(string, str) + def main(): # parse command-line args @@ -175,10 +181,7 @@ def fake_build(project_dir, c_build_log_path, cxx_build_log_path, verbose, make_ else: # Preserve HOME, since Cmake needs it to find some packages and it's # normally there anyway. See #26. - if sys.version_info[0] == 2: - env = dict(map(lambda x: (x, os.environ[x]), ["HOME"])) - if sys.version_info[0] == 3: - env = dict([(x, os.environ[x]) for x in ["HOME"]]) + env = { x: os.environ[x] for x in ["HOME"] } env["PATH"] = "{}:{}".format(fake_path, os.environ["PATH"]) env["CC"] = "clang" @@ -404,10 +407,7 @@ def parse_flags(build_log): # Only specify one word size (the largest) # (Different sizes are used for different files in the linux kernel.) mRegex = re.compile("^-m[0-9]+$") - if sys.version_info[0] == 2: - word_flags = list([f for f in flags if isinstance(f, basestring) and mRegex.match(f)]) - elif sys.version_info[0] == 3: - word_flags = list([f for f in flags if isinstance(f, str) and mRegex.match(f)]) + word_flags = list([f for f in flags if isString(f) and mRegex.match(f)]) if(len(word_flags) > 1): for flag in word_flags: @@ -416,20 +416,12 @@ def parse_flags(build_log): flags.add(max(word_flags)) # Resolve duplicate macro definitions (always choose the last value for consistency) - if sys.version_info[0] == 2: - for name, values in define_flags.iteritems(): - if(len(values) > 1): - print("WARNING: {} distinct definitions of macro {} found".format(len(values), name)) - values.sort() - - flags.add("-D{}={}".format(name, values[0])) - elif sys.version_info[0] == 3: - for name, values in define_flags.items(): - if(len(values) > 1): - print("WARNING: {} distinct definitions of macro {} found".format(len(values), name)) - values.sort() + for name, values in define_flags.items(): + if(len(values) > 1): + print("WARNING: {} distinct definitions of macro {} found".format(len(values), name)) + values.sort() - flags.add("-D{}={}".format(name, values[0])) + flags.add("-D{}={}".format(name, values[0])) return (line_count, skip_count, sorted(flags)) @@ -442,19 +434,11 @@ def generate_cc_conf(flags, config_file): with open(config_file, "w") as output: for flag in flags: - if sys.version_info[0] == 2: - if(isinstance(flag, basestring)): - output.write(flag + "\n") - else: # is tuple - for f in flag: - output.write(f + "\n") - elif sys.version_info[0] == 3: - if(isinstance(flag, str)): - output.write(flag + "\n") - else: # is tuple - for f in flag: - output.write(f + "\n") - + if(isString(flag)): + output.write(flag + "\n") + else: # is tuple + for f in flag: + output.write(f + "\n") def generate_ycm_conf(flags, config_file): '''Generates the .ycm_extra_conf.py. @@ -472,16 +456,10 @@ def generate_ycm_conf(flags, config_file): if(line == " # INSERT FLAGS HERE\n"): # insert generated code for flag in flags: - if sys.version_info[0] == 2: - if(isinstance(flag, basestring)): - output.write(" '{}',\n".format(flag)) - else: # is tuple - output.write(" '{}', '{}',\n".format(*flag)) - elif sys.version_info[0] == 3: - if(isinstance(flag, str)): - output.write(" '{}',\n".format(flag)) - else: # is tuple - output.write(" '{}', '{}',\n".format(*flag)) + if(isString(flag)): + output.write(" '{}',\n".format(flag)) + else: # is tuple + output.write(" '{}', '{}',\n".format(*flag)) else: # copy template From daf3781aa2aa358fb6150db6dc25f796cf6e1fce Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Wed, 19 Oct 2016 16:41:21 +0200 Subject: [PATCH 12/20] Remove double empty line --- config_gen.py | 1 - 1 file changed, 1 deletion(-) diff --git a/config_gen.py b/config_gen.py index e571e69..ceb5948 100755 --- a/config_gen.py +++ b/config_gen.py @@ -31,7 +31,6 @@ def isString(string): elif sys.version_info[0] == 3: return isinstance(string, str) - def main(): # parse command-line args parser = argparse.ArgumentParser(description="Automatically generates config files for YouCompleteMe") From 6f044a695ee1eb35f5ed0aa1b13a68fc8e24dd42 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Sun, 23 Oct 2016 13:24:06 -0400 Subject: [PATCH 13/20] Add the workaround from https://gist.github.com/cpradog/aad88d51001ea83ecfc6 In the FAQ of https://github.com/Valloric/YouCompleteMe, there was an issue of C++ standard library headers not found (Valloric/YouCompleteMe#303) that has been resolved with a workaround, and @cpradog has kindly implemented it. However, this workaround has not yet been incorporated into template.py in https://github.com/rdnetto/YCM-Generator, so adding this becomes the main purpose of this fork. --- template.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/template.py b/template.py index 2985a70..d9cb772 100644 --- a/template.py +++ b/template.py @@ -30,12 +30,28 @@ import os import ycm_core +import re +import subprocess + flags = [ # INSERT FLAGS HERE ] +def LoadSystemIncludes(): + regex = re.compile(ur'(?:\#include \<...\> search starts here\:)(?P.*?)(?:End of search list)', re.DOTALL); + process = subprocess.Popen(['clang', '-v', '-E', '-x', 'c++', '-'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE); + process_out, process_err = process.communicate(''); + output = process_out + process_err; + includes = []; + for p in re.search(regex, output).group('list').split('\n'): + p = p.strip(); + if len(p) > 0 and p.find('(framework directory)') < 0: + includes.append('-isystem'); + includes.append(p); + return includes; + # Set this to the absolute path to the folder (NOT the file!) containing the # compile_commands.json file to use that instead of 'flags'. See here for # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html @@ -54,6 +70,8 @@ database = None SOURCE_EXTENSIONS = [ '.C', '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] +systemIncludes = LoadSystemIncludes(); +flags = flags + systemIncludes; def DirectoryOfThisScript(): return os.path.dirname( os.path.abspath( __file__ ) ) @@ -121,7 +139,7 @@ def FlagsForFile( filename, **kwargs ): final_flags = MakeRelativePathsInFlagsAbsolute( compilation_info.compiler_flags_, - compilation_info.compiler_working_dir_ ) + compilation_info.compiler_working_dir_ ) + systemIncludes else: relative_to = DirectoryOfThisScript() From 945f9e146e613e8d5b4fa0655dd3ee08d77d1ff8 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Sun, 23 Oct 2016 13:52:14 -0400 Subject: [PATCH 14/20] change the "python2" string in header of config_gen.py to "python" --- config_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config_gen.py b/config_gen.py index 54e89f9..72dfc0a 100755 --- a/config_gen.py +++ b/config_gen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import sys import os From 910380c8ff83bc13fb514a92206444feca763dda Mon Sep 17 00:00:00 2001 From: ssfdust Date: Sun, 13 Nov 2016 22:01:58 +0800 Subject: [PATCH 15/20] fix sorted problem --- config_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config_gen.py b/config_gen.py index de6d9bc..c94b5c5 100755 --- a/config_gen.py +++ b/config_gen.py @@ -452,7 +452,7 @@ def parse_flags(build_log): flags.add("-D{}={}".format(name, values[0])) - return (line_count, skip_count, sorted(flags)) + return (line_count, skip_count, sorted(flags, key=lambda x:x[0] if isinstance(x, tuple) else x)) def generate_cc_conf(flags, config_file): From 507ca72988d87c1c34d7ce0572dc5aaccc00a103 Mon Sep 17 00:00:00 2001 From: Vyas Giridharan Date: Thu, 25 May 2017 23:49:07 +0530 Subject: [PATCH 16/20] Added meson + ninja support --- config_gen.py | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/config_gen.py b/config_gen.py index 54e89f9..92f8de5 100755 --- a/config_gen.py +++ b/config_gen.py @@ -18,6 +18,9 @@ # Default flags for make default_make_flags = ["-i", "-j" + str(multiprocessing.cpu_count())] +# Default flags for ninja +default_ninja_flags = ["-j" + str(multiprocessing.cpu_count())] + # Set YCM-Generator directory # Always obtain the real path to the directory where 'config_gen.py' lives as, # in some cases, it will be a symlink placed in '/usr/bin' (as is the case @@ -32,11 +35,12 @@ def main(): parser.add_argument("-v", "--verbose", action="store_true", help="Show output from build process") parser.add_argument("-f", "--force", action="store_true", help="Overwrite the file if it exists.") parser.add_argument("-m", "--make", default="make", help="Use the specified executable for make.") - parser.add_argument("-b", "--build-system", choices=["cmake", "autotools", "qmake", "make"], help="Force use of the specified build system rather than trying to autodetect.") + parser.add_argument("-b", "--build-system", choices=["meson", "cmake", "autotools", "qmake", "make"], help="Force use of the specified build system rather than trying to autodetect.") parser.add_argument("-c", "--compiler", help="Use the specified executable for clang. It should be the same version as the libclang used by YCM. The executable for clang++ will be inferred from this.") parser.add_argument("-C", "--configure_opts", default="", help="Additional flags to pass to configure/cmake/etc. e.g. --configure_opts=\"--enable-FEATURE\"") parser.add_argument("-F", "--format", choices=["ycm", "cc"], default="ycm", help="Format of output file (YouCompleteMe or color_coded). Default: ycm") parser.add_argument("-M", "--make-flags", help="Flags to pass to make when fake-building. Default: -M=\"{}\"".format(" ".join(default_make_flags))) + parser.add_argument("-N", "--ninja-flags", help="Flags to pass to ninja when fake-building. Default: -N=\"{}\"".format(" ".join (default_ninja_flags))) parser.add_argument("-o", "--output", help="Save the config file as OUTPUT. Default: .ycm_extra_conf.py, or .color_coded if --format=cc.") parser.add_argument("-x", "--language", choices=["c", "c++"], help="Only output flags for the given language. This defaults to whichever language has its compiler invoked the most.") parser.add_argument("--out-of-tree", action="store_true", help="Build autotools projects out-of-tree. This is a no-op for other project types.") @@ -87,8 +91,10 @@ def main(): # command-line args to pass to fake_build() using kwargs args["make_cmd"] = args.pop("make") + args["ninja_cmd"] = "ninja" args["configure_opts"] = shlex.split(args["configure_opts"]) args["make_flags"] = default_make_flags if args["make_flags"] is None else shlex.split(args["make_flags"]) + args["ninja_flags"] = default_ninja_flags if args["ninja_flags"] is None else shlex.split(args["ninja_flags"]) force_lang = args.pop("language") output_format = args.pop("format") del args["compiler"] @@ -140,7 +146,7 @@ def main(): print("Created {} config file with {} {} flags".format(output_format.upper(), len(flags), lang.upper())) -def fake_build(project_dir, c_build_log_path, cxx_build_log_path, verbose, make_cmd, build_system, cc, cxx, out_of_tree, configure_opts, make_flags, preserve_environment, qt_version): +def fake_build(project_dir, c_build_log_path, cxx_build_log_path, verbose, make_cmd, ninja_cmd, build_system, cc, cxx, out_of_tree, configure_opts, make_flags, ninja_flags, preserve_environment, qt_version): '''Builds the project using the fake toolchain, to collect the compiler flags. project_dir: the directory containing the source files @@ -154,6 +160,7 @@ def fake_build(project_dir, c_build_log_path, cxx_build_log_path, verbose, make_ make_flags: additional flags for make preserve_environment: pass environment variables to build processes qt_version: The Qt version to use when building with qmake. + ninja_cmd: The ninja command to use. ''' # TODO: add Windows support @@ -192,6 +199,8 @@ def fake_build(project_dir, c_build_log_path, cxx_build_log_path, verbose, make_ # depend upon the existence of various output files make_args = [make_cmd] + make_flags + ninja_args = [ninja_cmd] + ninja_flags + # Used for the qmake build system below pro_files = glob.glob(os.path.join(project_dir, "*.pro")) @@ -210,6 +219,8 @@ def run(cmd, *args, **kwargs): build_system = "autotools" elif pro_files: build_system = "qmake" + elif os.path.exists(os.path.join(project_dir, "meson.build")): + build_system = "meson" elif any([os.path.exists(os.path.join(project_dir, x)) for x in ["GNUmakefile", "makefile", "Makefile"]]): build_system = "make" @@ -304,6 +315,23 @@ def run(cmd, *args, **kwargs): print("\nCleaning up...") print("") shutil.rmtree(build_dir) + + elif build_system == "meson": + # meson build system + build_dir = tempfile.mkdtemp() + proc_opts["cwd"] = build_dir + print("Configuring meson in '{}'...".format(build_dir)) + + print("\nRunning meson...",project_dir) + run(["meson", project_dir], env=env_config, **proc_opts) + + print("\nRunning ninja...") + print(project_dir) + run(ninja_args, env=env, **proc_opts) + + print("\nCleaning up...") + print("") + shutil.rmtree(build_dir) elif build_system == "make": # make From c1ac189e4534148c6e4953fbc3471b53b14cbfc9 Mon Sep 17 00:00:00 2001 From: Reuben D'Netto Date: Tue, 30 May 2017 10:04:26 +1000 Subject: [PATCH 17/20] Added files for running CI --- .travis.yml | 15 +++++++++++++++ mocks/ycm_core.py | 6 ++++++ 2 files changed, 21 insertions(+) create mode 100644 .travis.yml create mode 100644 mocks/ycm_core.py diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9a4e73c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: python +python: + - "2.7" + - "3.6" + +addons: + apt: + packages: + - clang + +script: + - python --version + - python config_gen.py --help + - env PYTHONPATH=mocks python template.py + diff --git a/mocks/ycm_core.py b/mocks/ycm_core.py new file mode 100644 index 0000000..fcc5cbb --- /dev/null +++ b/mocks/ycm_core.py @@ -0,0 +1,6 @@ +# This file defines a mock of the ycm_core module so we can test template.py by +# running it. + +def CompilationDatabase(x): + pass + From 7551995a34cefda2f6086fef9b4322c450ca6b12 Mon Sep 17 00:00:00 2001 From: Vyas Giridharan Date: Tue, 30 May 2017 23:56:23 +0530 Subject: [PATCH 18/20] Updated README to reflect meson support This patch updates the README to reflect the support for the meson (Ninja) build system. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c45a787..c5a6429 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ You can also invoke it from within Vim using the ```:YcmGenerateConfig``` or ``` + cmake + qmake + autotools + + meson (Ninja) Your build system should support specifying the compiler through the ```CC```/```CXX``` environment variables, or not use an absolute path to the compiler. @@ -63,6 +64,7 @@ The following projects are used for testing: | [Clementine](https://github.com/clementine-player/Clementine.git) | Cmake | | | [ExtPlane](https://github.com/vranki/ExtPlane.git) | Qmake | Should be tested with both versions of Qt. | | [OpenFOAM](https://github.com/OpenFOAM/OpenFOAM-3.0.x.git) | wmake | | +| [Nautilus](https://git.gnome.org/browse/nautilus | meson (Ninja) | | ## License YCM-Generator is published under the GNU GPLv3. From 46f4c0d94912b83497ff477d014e9a455d6c5ef9 Mon Sep 17 00:00:00 2001 From: Reuben D'Netto Date: Tue, 30 May 2017 19:09:22 +1000 Subject: [PATCH 19/20] Fixed template.py to be compatible with both versions of Python Also removed spurious semicolons --- template.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/template.py b/template.py index d9cb772..7f52bb4 100644 --- a/template.py +++ b/template.py @@ -28,6 +28,9 @@ # # For more information, please refer to +# Needed because ur"" syntax is no longer supported +from __future__ import unicode_literals + import os import ycm_core import re @@ -40,17 +43,18 @@ def LoadSystemIncludes(): - regex = re.compile(ur'(?:\#include \<...\> search starts here\:)(?P.*?)(?:End of search list)', re.DOTALL); - process = subprocess.Popen(['clang', '-v', '-E', '-x', 'c++', '-'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE); - process_out, process_err = process.communicate(''); - output = process_out + process_err; - includes = []; + regex = re.compile(r'(?:\#include \<...\> search starts here\:)(?P.*?)(?:End of search list)', re.DOTALL) + process = subprocess.Popen(['clang', '-v', '-E', '-x', 'c++', '-'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process_out, process_err = process.communicate('') + output = (process_out + process_err).decode("utf8") + + includes = [] for p in re.search(regex, output).group('list').split('\n'): - p = p.strip(); + p = p.strip() if len(p) > 0 and p.find('(framework directory)') < 0: - includes.append('-isystem'); - includes.append(p); - return includes; + includes.append('-isystem') + includes.append(p) + return includes # Set this to the absolute path to the folder (NOT the file!) containing the # compile_commands.json file to use that instead of 'flags'. See here for @@ -70,8 +74,8 @@ def LoadSystemIncludes(): database = None SOURCE_EXTENSIONS = [ '.C', '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] -systemIncludes = LoadSystemIncludes(); -flags = flags + systemIncludes; +systemIncludes = LoadSystemIncludes() +flags = flags + systemIncludes def DirectoryOfThisScript(): return os.path.dirname( os.path.abspath( __file__ ) ) @@ -139,7 +143,7 @@ def FlagsForFile( filename, **kwargs ): final_flags = MakeRelativePathsInFlagsAbsolute( compilation_info.compiler_flags_, - compilation_info.compiler_working_dir_ ) + systemIncludes + compilation_info.compiler_working_dir_ ) + systemIncludes else: relative_to = DirectoryOfThisScript() From cba79ec36fb77942f39ec9626b3c0e471a6e43cf Mon Sep 17 00:00:00 2001 From: Reuben D'Netto Date: Tue, 30 May 2017 19:11:30 +1000 Subject: [PATCH 20/20] Added CI badge to README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index febe1ee..69e99b2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,11 @@ # YCM-Generator +| | | +| -------------------------------------------------------------------------------------------------------------------------------- | ------------------ | +| [![Build Status](https://travis-ci.org/rdnetto/YCM-Generator.svg?branch=stable)](https://travis-ci.org/rdnetto/YCM-Generator) | Stable branch | +| [![Build Status](https://travis-ci.org/rdnetto/YCM-Generator.svg?branch=develop)](https://travis-ci.org/rdnetto/YCM-Generator) | Development branch | + +## Introduction + This is a script which generates a list of compiler flags from a project with an arbitrary build system. It can be used to: * generate a ```.ycm_extra_conf.py``` file for use with [YouCompleteMe](https://github.com/Valloric/YouCompleteMe)