]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/Makefiles/NmakeSubdirs.py
BaseTools/VolInfo: Update copyright information
[mirror_edk2.git] / BaseTools / Source / C / Makefiles / NmakeSubdirs.py
CommitLineData
4c0d19e5
DG
1# @file NmakeSubdirs.py\r
2# This script support parallel build for nmake in windows environment.\r
3# It supports Python2.x and Python3.x both.\r
4#\r
5# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r
6#\r
2e351cbe 7# SPDX-License-Identifier: BSD-2-Clause-Patent\r
4c0d19e5
DG
8#\r
9\r
10#\r
11# Import Modules\r
12#\r
13\r
14from __future__ import print_function\r
15import argparse\r
16import threading\r
17import time\r
18import os\r
19import subprocess\r
20import multiprocessing\r
21import copy\r
22import sys\r
23__prog__ = 'NmakeSubdirs'\r
24__version__ = '%s Version %s' % (__prog__, '0.10 ')\r
25__copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.'\r
26__description__ = 'Replace for NmakeSubdirs.bat in windows ,support parallel build for nmake.\n'\r
27\r
28cpu_count = multiprocessing.cpu_count()\r
29output_lock = threading.Lock()\r
30def RunCommand(WorkDir=None, *Args, **kwargs):\r
31 if WorkDir is None:\r
32 WorkDir = os.curdir\r
33 if "stderr" not in kwargs:\r
34 kwargs["stderr"] = subprocess.STDOUT\r
35 if "stdout" not in kwargs:\r
36 kwargs["stdout"] = subprocess.PIPE\r
37 p = subprocess.Popen(Args, cwd=WorkDir, stderr=kwargs["stderr"], stdout=kwargs["stdout"])\r
38 stdout, stderr = p.communicate()\r
39 message = ""\r
40 if stdout is not None:\r
caa91749 41 message = stdout.decode(errors='ignore') #for compatibility in python 2 and 3\r
4c0d19e5
DG
42\r
43 if p.returncode != 0:\r
44 raise RuntimeError("Error while execute command \'{0}\' in direcotry {1}\n{2}".format(" ".join(Args), WorkDir, message))\r
45\r
46 output_lock.acquire(True)\r
47 print("execute command \"{0}\" in directory {1}".format(" ".join(Args), WorkDir))\r
dc0dae2d 48 try:\r
49 print(message)\r
50 except:\r
51 pass\r
4c0d19e5
DG
52 output_lock.release()\r
53\r
54 return p.returncode, stdout\r
55\r
56class TaskUnit(object):\r
57 def __init__(self, func, args, kwargs):\r
58 self.func = func\r
59 self.args = args\r
60 self.kwargs = kwargs\r
61\r
62 def __eq__(self, other):\r
63 return id(self).__eq__(id(other))\r
64\r
65 def run(self):\r
66 return self.func(*self.args, **self.kwargs)\r
67\r
68 def __str__(self):\r
69 para = list(self.args)\r
70 para.extend("{0}={1}".format(k, v)for k, v in self.kwargs.items())\r
71\r
72 return "{0}({1})".format(self.func.__name__, ",".join(para))\r
73\r
74class ThreadControl(object):\r
75\r
76 def __init__(self, maxthread):\r
77 self._processNum = maxthread\r
78 self.pending = []\r
79 self.running = []\r
80 self.pendingLock = threading.Lock()\r
81 self.runningLock = threading.Lock()\r
82 self.error = False\r
83 self.errorLock = threading.Lock()\r
84 self.errorMsg = "errorMsg"\r
85\r
86 def addTask(self, func, *args, **kwargs):\r
87 self.pending.append(TaskUnit(func, args, kwargs))\r
88\r
89 def waitComplete(self):\r
90 self._schedule.join()\r
91\r
92 def startSchedule(self):\r
93 self._schedule = threading.Thread(target=self.Schedule)\r
94 self._schedule.start()\r
95\r
96 def Schedule(self):\r
97 for i in range(self._processNum):\r
98 task = threading.Thread(target=self.startTask)\r
99 task.daemon = False\r
100 self.running.append(task)\r
101\r
102 self.runningLock.acquire(True)\r
103 for thread in self.running:\r
104 thread.start()\r
105 self.runningLock.release()\r
106\r
107 while len(self.running) > 0:\r
108 time.sleep(0.1)\r
109 if self.error:\r
2d53d54a 110 print("subprocess not exit successfully")\r
4c0d19e5
DG
111 print(self.errorMsg)\r
112\r
113 def startTask(self):\r
114 while True:\r
115 if self.error:\r
116 break\r
117 self.pendingLock.acquire(True)\r
118 if len(self.pending) == 0:\r
119 self.pendingLock.release()\r
120 break\r
121 task = self.pending.pop(0)\r
122 self.pendingLock.release()\r
123 try:\r
124 task.run()\r
125 except RuntimeError as e:\r
126 if self.error: break\r
127 self.errorLock.acquire(True)\r
128 self.error = True\r
129 self.errorMsg = str(e)\r
130 time.sleep(0.1)\r
131 self.errorLock.release()\r
132 break\r
133\r
134 self.runningLock.acquire(True)\r
135 self.running.remove(threading.currentThread())\r
136 self.runningLock.release()\r
137\r
138def Run():\r
139 curdir = os.path.abspath(os.curdir)\r
140 if len(args.subdirs) == 1:\r
141 args.jobs = 1\r
142 if args.jobs == 1:\r
143 try:\r
144 for dir in args.subdirs:\r
145 RunCommand(os.path.join(curdir, dir), "nmake", args.target, stdout=sys.stdout, stderr=subprocess.STDOUT)\r
146 except RuntimeError:\r
147 exit(1)\r
148 else:\r
149 controller = ThreadControl(args.jobs)\r
150 for dir in args.subdirs:\r
151 controller.addTask(RunCommand, os.path.join(curdir, dir), "nmake", args.target)\r
152 controller.startSchedule()\r
153 controller.waitComplete()\r
154 if controller.error:\r
155 exit(1)\r
156\r
157if __name__ == "__main__":\r
158 parser = argparse.ArgumentParser(prog=__prog__, description=__description__ + __copyright__, conflict_handler='resolve')\r
159\r
160 parser.add_argument("target", help="the target for nmake")\r
161 parser.add_argument("subdirs", nargs="+", help="the relative dir path of makefile")\r
162 parser.add_argument("--jobs", type=int, dest="jobs", default=cpu_count, help="thread number")\r
163 parser.add_argument('--version', action='version', version=__version__)\r
164 args = parser.parse_args()\r
165 Run()\r
166\r