mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-30 12:43:41 +01:00
164 lines
5.3 KiB
Python
164 lines
5.3 KiB
Python
|
# @file NmakeSubdirs.py
|
||
|
# This script support parallel build for nmake in windows environment.
|
||
|
# It supports Python2.x and Python3.x both.
|
||
|
#
|
||
|
# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
|
||
|
#
|
||
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
#
|
||
|
|
||
|
#
|
||
|
# Import Modules
|
||
|
#
|
||
|
|
||
|
from __future__ import print_function
|
||
|
import argparse
|
||
|
import threading
|
||
|
import time
|
||
|
import os
|
||
|
import subprocess
|
||
|
import multiprocessing
|
||
|
import copy
|
||
|
import sys
|
||
|
__prog__ = 'NmakeSubdirs'
|
||
|
__version__ = '%s Version %s' % (__prog__, '0.10 ')
|
||
|
__copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.'
|
||
|
__description__ = 'Replace for NmakeSubdirs.bat in windows ,support parallel build for nmake.\n'
|
||
|
|
||
|
cpu_count = multiprocessing.cpu_count()
|
||
|
output_lock = threading.Lock()
|
||
|
def RunCommand(WorkDir=None, *Args, **kwargs):
|
||
|
if WorkDir is None:
|
||
|
WorkDir = os.curdir
|
||
|
if "stderr" not in kwargs:
|
||
|
kwargs["stderr"] = subprocess.STDOUT
|
||
|
if "stdout" not in kwargs:
|
||
|
kwargs["stdout"] = subprocess.PIPE
|
||
|
p = subprocess.Popen(Args, cwd=WorkDir, stderr=kwargs["stderr"], stdout=kwargs["stdout"])
|
||
|
stdout, stderr = p.communicate()
|
||
|
message = ""
|
||
|
if stdout is not None:
|
||
|
message = stdout.decode(encoding='utf-8', errors='ignore') #for compatibility in python 2 and 3
|
||
|
|
||
|
if p.returncode != 0:
|
||
|
raise RuntimeError("Error while execute command \'{0}\' in direcotry {1}\n{2}".format(" ".join(Args), WorkDir, message))
|
||
|
|
||
|
output_lock.acquire(True)
|
||
|
print("execute command \"{0}\" in directory {1}".format(" ".join(Args), WorkDir))
|
||
|
print(message)
|
||
|
output_lock.release()
|
||
|
|
||
|
return p.returncode, stdout
|
||
|
|
||
|
class TaskUnit(object):
|
||
|
def __init__(self, func, args, kwargs):
|
||
|
self.func = func
|
||
|
self.args = args
|
||
|
self.kwargs = kwargs
|
||
|
|
||
|
def __eq__(self, other):
|
||
|
return id(self).__eq__(id(other))
|
||
|
|
||
|
def run(self):
|
||
|
return self.func(*self.args, **self.kwargs)
|
||
|
|
||
|
def __str__(self):
|
||
|
para = list(self.args)
|
||
|
para.extend("{0}={1}".format(k, v)for k, v in self.kwargs.items())
|
||
|
|
||
|
return "{0}({1})".format(self.func.__name__, ",".join(para))
|
||
|
|
||
|
class ThreadControl(object):
|
||
|
|
||
|
def __init__(self, maxthread):
|
||
|
self._processNum = maxthread
|
||
|
self.pending = []
|
||
|
self.running = []
|
||
|
self.pendingLock = threading.Lock()
|
||
|
self.runningLock = threading.Lock()
|
||
|
self.error = False
|
||
|
self.errorLock = threading.Lock()
|
||
|
self.errorMsg = "errorMsg"
|
||
|
|
||
|
def addTask(self, func, *args, **kwargs):
|
||
|
self.pending.append(TaskUnit(func, args, kwargs))
|
||
|
|
||
|
def waitComplete(self):
|
||
|
self._schedule.join()
|
||
|
|
||
|
def startSchedule(self):
|
||
|
self._schedule = threading.Thread(target=self.Schedule)
|
||
|
self._schedule.start()
|
||
|
|
||
|
def Schedule(self):
|
||
|
for i in range(self._processNum):
|
||
|
task = threading.Thread(target=self.startTask)
|
||
|
task.daemon = False
|
||
|
self.running.append(task)
|
||
|
|
||
|
self.runningLock.acquire(True)
|
||
|
for thread in self.running:
|
||
|
thread.start()
|
||
|
self.runningLock.release()
|
||
|
|
||
|
while len(self.running) > 0:
|
||
|
time.sleep(0.1)
|
||
|
if self.error:
|
||
|
print("subprocess not exit successfully")
|
||
|
print(self.errorMsg)
|
||
|
|
||
|
def startTask(self):
|
||
|
while True:
|
||
|
if self.error:
|
||
|
break
|
||
|
self.pendingLock.acquire(True)
|
||
|
if len(self.pending) == 0:
|
||
|
self.pendingLock.release()
|
||
|
break
|
||
|
task = self.pending.pop(0)
|
||
|
self.pendingLock.release()
|
||
|
try:
|
||
|
task.run()
|
||
|
except RuntimeError as e:
|
||
|
if self.error: break
|
||
|
self.errorLock.acquire(True)
|
||
|
self.error = True
|
||
|
self.errorMsg = str(e)
|
||
|
time.sleep(0.1)
|
||
|
self.errorLock.release()
|
||
|
break
|
||
|
|
||
|
self.runningLock.acquire(True)
|
||
|
self.running.remove(threading.currentThread())
|
||
|
self.runningLock.release()
|
||
|
|
||
|
def Run():
|
||
|
curdir = os.path.abspath(os.curdir)
|
||
|
if len(args.subdirs) == 1:
|
||
|
args.jobs = 1
|
||
|
if args.jobs == 1:
|
||
|
try:
|
||
|
for dir in args.subdirs:
|
||
|
RunCommand(os.path.join(curdir, dir), "nmake", args.target, stdout=sys.stdout, stderr=subprocess.STDOUT)
|
||
|
except RuntimeError:
|
||
|
exit(1)
|
||
|
else:
|
||
|
controller = ThreadControl(args.jobs)
|
||
|
for dir in args.subdirs:
|
||
|
controller.addTask(RunCommand, os.path.join(curdir, dir), "nmake", args.target)
|
||
|
controller.startSchedule()
|
||
|
controller.waitComplete()
|
||
|
if controller.error:
|
||
|
exit(1)
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
parser = argparse.ArgumentParser(prog=__prog__, description=__description__ + __copyright__, conflict_handler='resolve')
|
||
|
|
||
|
parser.add_argument("target", help="the target for nmake")
|
||
|
parser.add_argument("subdirs", nargs="+", help="the relative dir path of makefile")
|
||
|
parser.add_argument("--jobs", type=int, dest="jobs", default=cpu_count, help="thread number")
|
||
|
parser.add_argument('--version', action='version', version=__version__)
|
||
|
args = parser.parse_args()
|
||
|
Run()
|
||
|
|