]>
Commit | Line | Data |
---|---|---|
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 | |
14 | from __future__ import print_function\r | |
15 | import argparse\r | |
16 | import threading\r | |
17 | import time\r | |
18 | import os\r | |
19 | import subprocess\r | |
20 | import multiprocessing\r | |
21 | import copy\r | |
22 | import 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 | |
28 | cpu_count = multiprocessing.cpu_count()\r | |
29 | output_lock = threading.Lock()\r | |
30 | def 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 | |
1c27ec42 | 41 | message = stdout.decode(encoding='utf-8', 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 | |
48 | print(message)\r | |
49 | output_lock.release()\r | |
50 | \r | |
51 | return p.returncode, stdout\r | |
52 | \r | |
53 | class TaskUnit(object):\r | |
54 | def __init__(self, func, args, kwargs):\r | |
55 | self.func = func\r | |
56 | self.args = args\r | |
57 | self.kwargs = kwargs\r | |
58 | \r | |
59 | def __eq__(self, other):\r | |
60 | return id(self).__eq__(id(other))\r | |
61 | \r | |
62 | def run(self):\r | |
63 | return self.func(*self.args, **self.kwargs)\r | |
64 | \r | |
65 | def __str__(self):\r | |
66 | para = list(self.args)\r | |
67 | para.extend("{0}={1}".format(k, v)for k, v in self.kwargs.items())\r | |
68 | \r | |
69 | return "{0}({1})".format(self.func.__name__, ",".join(para))\r | |
70 | \r | |
71 | class ThreadControl(object):\r | |
72 | \r | |
73 | def __init__(self, maxthread):\r | |
74 | self._processNum = maxthread\r | |
75 | self.pending = []\r | |
76 | self.running = []\r | |
77 | self.pendingLock = threading.Lock()\r | |
78 | self.runningLock = threading.Lock()\r | |
79 | self.error = False\r | |
80 | self.errorLock = threading.Lock()\r | |
81 | self.errorMsg = "errorMsg"\r | |
82 | \r | |
83 | def addTask(self, func, *args, **kwargs):\r | |
84 | self.pending.append(TaskUnit(func, args, kwargs))\r | |
85 | \r | |
86 | def waitComplete(self):\r | |
87 | self._schedule.join()\r | |
88 | \r | |
89 | def startSchedule(self):\r | |
90 | self._schedule = threading.Thread(target=self.Schedule)\r | |
91 | self._schedule.start()\r | |
92 | \r | |
93 | def Schedule(self):\r | |
94 | for i in range(self._processNum):\r | |
95 | task = threading.Thread(target=self.startTask)\r | |
96 | task.daemon = False\r | |
97 | self.running.append(task)\r | |
98 | \r | |
99 | self.runningLock.acquire(True)\r | |
100 | for thread in self.running:\r | |
101 | thread.start()\r | |
102 | self.runningLock.release()\r | |
103 | \r | |
104 | while len(self.running) > 0:\r | |
105 | time.sleep(0.1)\r | |
106 | if self.error:\r | |
2d53d54a | 107 | print("subprocess not exit successfully")\r |
4c0d19e5 DG |
108 | print(self.errorMsg)\r |
109 | \r | |
110 | def startTask(self):\r | |
111 | while True:\r | |
112 | if self.error:\r | |
113 | break\r | |
114 | self.pendingLock.acquire(True)\r | |
115 | if len(self.pending) == 0:\r | |
116 | self.pendingLock.release()\r | |
117 | break\r | |
118 | task = self.pending.pop(0)\r | |
119 | self.pendingLock.release()\r | |
120 | try:\r | |
121 | task.run()\r | |
122 | except RuntimeError as e:\r | |
123 | if self.error: break\r | |
124 | self.errorLock.acquire(True)\r | |
125 | self.error = True\r | |
126 | self.errorMsg = str(e)\r | |
127 | time.sleep(0.1)\r | |
128 | self.errorLock.release()\r | |
129 | break\r | |
130 | \r | |
131 | self.runningLock.acquire(True)\r | |
132 | self.running.remove(threading.currentThread())\r | |
133 | self.runningLock.release()\r | |
134 | \r | |
135 | def Run():\r | |
136 | curdir = os.path.abspath(os.curdir)\r | |
137 | if len(args.subdirs) == 1:\r | |
138 | args.jobs = 1\r | |
139 | if args.jobs == 1:\r | |
140 | try:\r | |
141 | for dir in args.subdirs:\r | |
142 | RunCommand(os.path.join(curdir, dir), "nmake", args.target, stdout=sys.stdout, stderr=subprocess.STDOUT)\r | |
143 | except RuntimeError:\r | |
144 | exit(1)\r | |
145 | else:\r | |
146 | controller = ThreadControl(args.jobs)\r | |
147 | for dir in args.subdirs:\r | |
148 | controller.addTask(RunCommand, os.path.join(curdir, dir), "nmake", args.target)\r | |
149 | controller.startSchedule()\r | |
150 | controller.waitComplete()\r | |
151 | if controller.error:\r | |
152 | exit(1)\r | |
153 | \r | |
154 | if __name__ == "__main__":\r | |
155 | parser = argparse.ArgumentParser(prog=__prog__, description=__description__ + __copyright__, conflict_handler='resolve')\r | |
156 | \r | |
157 | parser.add_argument("target", help="the target for nmake")\r | |
158 | parser.add_argument("subdirs", nargs="+", help="the relative dir path of makefile")\r | |
159 | parser.add_argument("--jobs", type=int, dest="jobs", default=cpu_count, help="thread number")\r | |
160 | parser.add_argument('--version', action='version', version=__version__)\r | |
161 | args = parser.parse_args()\r | |
162 | Run()\r | |
163 | \r |