|
#!/usr/bin/env python3 |
|
|
|
# from https://gist.github.com/RichardsonAlex/3de8adaebec0d488c13911edd2e0fe63 |
|
# Edited by Arnaud 'Bluexin' Sole to work on windows |
|
|
|
import os |
|
import shutil |
|
import re |
|
import sys |
|
import subprocess |
|
# ---------------------- Configuration section ------------------------------ |
|
|
|
TRACING = False |
|
REAL_CMAKE = shutil.which('cmake').replace("\\", "/") |
|
if not os.path.isfile(REAL_CMAKE): |
|
sys.exit('Could not find cmake!') |
|
NINJA_PATH = shutil.which('ninja').replace("\\", "/") |
|
if not os.path.isfile(NINJA_PATH): |
|
sys.exit('Could not find ninja!') |
|
if TRACING: |
|
TEE_PATH = shutil.which('ninja').replace("\\", "/") |
|
if not os.path.isFile(NINJA_PATH): |
|
TEE_PATH = os.path.abspath(os.path.join(os.path.dirname(shutil.which('git')), "../usr/bin/tee.exe")).replace("\\", "/") |
|
if not os.path.isfile(TEE_PATH): |
|
sys.exit('Could not find tee! Tried ' + TEE_PATH) |
|
|
|
dir_path = os.path.dirname(os.path.realpath(__file__)) |
|
|
|
# --------------------------- Code section ---------------------------------- |
|
|
|
|
|
def trace(message, argv = []): |
|
if not TRACING: |
|
return |
|
|
|
with open(os.path.join(dir_path, "cmake_wrapper.log"), 'a') as log: |
|
if not argv == []: |
|
log.write("\n\n") |
|
|
|
if isinstance(message, bytes): |
|
message = message.decode() |
|
log.write(message) |
|
|
|
if not argv == []: |
|
argv = '"%s"' % ('" "'.join(argv)) |
|
log.write("\n\n\t%s\n\tat: %s\n" % (argv, os.getcwd())) |
|
|
|
|
|
def tracerr(message, argv = []): |
|
if not TRACING: |
|
return |
|
|
|
with open(os.path.join(dir_path, "cmake_wrapper_err.log"), 'a') as log: |
|
if not argv == []: |
|
log.write("\n\n") |
|
|
|
if isinstance(message, bytes): |
|
message = message.decode() |
|
log.write(message) |
|
|
|
if not argv == []: |
|
argv = '"%s"' % ('" "'.join(argv)) |
|
log.write("\n\n\t%s\n\tat: %s\n" % (argv, os.getcwd())) |
|
|
|
def call_cmake(passing_args): |
|
"""Call real cmake as a subprocess passing it's output both to stdout and trace file.""" |
|
passing_args = [REAL_CMAKE] + passing_args |
|
trace("Calling real cmake:", passing_args) |
|
|
|
|
|
if TRACING: |
|
proc = subprocess.Popen(passing_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0) |
|
tee = subprocess.Popen([TEE_PATH, os.path.join(dir_path, 'cmake_wrapper-sub.log')], stdin=proc.stdout) |
|
tee2 = subprocess.Popen([TEE_PATH, os.path.join(dir_path, 'cmake_wrapper-sub_err.log')], stdin=proc.stderr) |
|
tee.communicate() |
|
tee2.communicate() |
|
else : |
|
proc = subprocess.Popen(passing_args, stdout=sys.stdout, stderr=sys.stderr, bufsize=0) |
|
|
|
return proc.wait() |
|
|
|
|
|
def is_real_project(): |
|
return "cmake-build" in os.getcwd() |
|
|
|
class CMakeCache(object): |
|
"""CMake cache management utility""" |
|
def __init__(self, path): |
|
super(CMakeCache, self).__init__() |
|
self.path = path |
|
|
|
def alter(self, variable, value): |
|
""" |
|
Change a variable value in CMake cache. |
|
TODO: Add variable if it doesn't already exist |
|
""" |
|
if not os.path.isfile(self.path): |
|
return |
|
|
|
with open(self.path, 'r') as cache_file: |
|
cache_data = cache_file.read() |
|
|
|
pattern = '%s=.*' % re.escape(variable) |
|
replacement = '%s=%s' % (variable, value) |
|
cache_data = re.sub(pattern, replacement, cache_data) |
|
|
|
with open(self.path, 'w') as cache_file: |
|
cache_file.write(cache_data) |
|
cache_file.flush() |
|
|
|
def ninjafy(self): |
|
self.alter('CMAKE_GENERATOR:INTERNAL', 'Ninja') |
|
self.alter('CMAKE_MAKE_PROGRAM:FILEPATH', NINJA_PATH) |
|
|
|
def makefy(self): |
|
self.alter('CMAKE_GENERATOR:INTERNAL', 'MinGW Makefiles') |
|
self.alter('CMAKE_MAKE_PROGRAM:FILEPATH', REAL_CMAKE) |
|
|
|
|
|
def ninjafy_argv(original): |
|
"""Replace Unix Makefiles generator with Ninja""" |
|
processed = [] |
|
next_g = False |
|
for a in original: |
|
if a == '-G': |
|
next_g = True |
|
elif next_g and 'MinGW Makefiles' in a: |
|
a = a.replace('MinGW Makefiles', 'Ninja') |
|
|
|
processed.append(a) |
|
|
|
return processed |
|
|
|
trace('Originally called:', sys.argv) |
|
|
|
# Enable wrapping logic only when called inside clion private directory. |
|
if not is_real_project(): |
|
sys.exit(call_cmake(sys.argv[1:])) |
|
|
|
# Check if generator argument was specified |
|
if "-G" in sys.argv: |
|
#Generate Makefile artifacts required by CLion |
|
exit_code = call_cmake(sys.argv[1:]) |
|
trace("cmake exit code: " + str(exit_code) + '\n') |
|
sys.stdout.write("cmake exit code: " + str(exit_code) + '\n') |
|
cache = CMakeCache('CMakeCache.txt') |
|
cache.makefy() |
|
if exit_code != 0: |
|
sys.exit(exit_code) |
|
|
|
# Generate Ninja artifacts for actual build |
|
passing_args = ninjafy_argv(sys.argv[1:]) |
|
cache.ninjafy() |
|
|
|
sys.exit(call_cmake(passing_args)) |
|
else: |
|
sys.exit(call_cmake(sys.argv[1:])) |