On windows system, when use command chcp displays the number of the active console code page, if the active console code is 936, run make cleanall in the BaseTools will hang. Issue reproduce step: chcp 936 edksetup.bat VS2015 cd BaseTools nmake cleanall Cc: Bob Feng <bob.c.feng@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Yuwei Chen <yuwei.chen@intel.com> Signed-off-by: Yunhua Feng <fengyunhua@byosoft.com.cn> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
167 lines
5.3 KiB
Python
167 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(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))
|
|
try:
|
|
print(message)
|
|
except:
|
|
pass
|
|
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()
|
|
|