Skip to content

Commit 0e304e2

Browse files
committed
Don't use temp file for responsefile
1 parent ee0e670 commit 0e304e2

File tree

1 file changed

+38
-39
lines changed

1 file changed

+38
-39
lines changed

ports/zephyr-cp/cptools/cpbuild.py

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import re
99
import tempfile
1010
import time
11+
from typing import Optional
1112

1213
logger = logging.getLogger(__name__)
1314

@@ -109,7 +110,14 @@ def _create_semaphore():
109110
max_track = 0
110111

111112

112-
async def run_command(command, working_directory, description=None, check_hash=[], extradeps=[]):
113+
async def run_command(
114+
command,
115+
working_directory,
116+
description=None,
117+
check_hash=[],
118+
extradeps=[],
119+
responsefile: Optional[pathlib.Path] = None,
120+
):
113121
"""
114122
Runs a command asynchronously. The command should ideally be a list of strings
115123
and pathlib.Path objects. If all of the paths haven't been modified since the last
@@ -122,7 +130,11 @@ async def run_command(command, working_directory, description=None, check_hash=[
122130
123131
Paths in check_hash are hashed before and after the command. If the hash is
124132
the same, then the old mtimes are reset. This is helpful if a command may produce
125-
the same result and you don't want the rest of the build impacted.
133+
the same result and you don't want the rest of the build impacted
134+
135+
responsefile is used to store the command line arguments if they are too long for the OS.
136+
The arguments will be replaced with @<responsefile> and tried again.
137+
If None, commands that are too long will fail.
126138
"""
127139
paths = []
128140
if isinstance(command, list):
@@ -133,9 +145,16 @@ async def run_command(command, working_directory, description=None, check_hash=[
133145
# if isinstance(part, list):
134146

135147
command[i] = str(part)
136-
command = " ".join(command)
148+
command_string = " ".join(command)
137149

138-
command_hash = hashlib.sha3_256(command.encode("utf-8"))
150+
# When on windows, use a responsefile if the command string is >= 8192
151+
if os.name == "nt" and len(command_string) >= 8192:
152+
responsefile.write_text("\n".join(command[1:]))
153+
command_string = f"{command[0]}@{responsefile.name}"
154+
else:
155+
command_string = command
156+
157+
command_hash = hashlib.sha3_256(command_string.encode("utf-8"))
139158
command_hash.update(str(working_directory).encode("utf-8"))
140159
command_hash = command_hash.hexdigest()
141160

@@ -187,21 +206,14 @@ async def run_command(command, working_directory, description=None, check_hash=[
187206

188207
cancellation = None
189208
async with shared_semaphore:
190-
for i, part in enumerate(command.split()):
191-
if isinstance(part, str) and part.startswith("@"):
192-
print(part)
193-
with open(part[1:], "r") as f:
194-
print("Contents of file:", part[1:])
195-
content = f.read()
196-
print(content)
197209
global max_track
198210
if not tracks:
199211
max_track += 1
200212
tracks.append(max_track)
201213
track = tracks.pop()
202214
start_time = time.perf_counter_ns() // 1000
203215
process = await asyncio.create_subprocess_shell(
204-
command,
216+
command_string,
205217
stdout=asyncio.subprocess.PIPE,
206218
stderr=asyncio.subprocess.PIPE,
207219
cwd=working_directory,
@@ -247,22 +259,23 @@ async def run_command(command, working_directory, description=None, check_hash=[
247259
raise cancellation
248260
if description:
249261
logger.info(f"{description} ({run_reason})")
250-
logger.debug(command)
262+
logger.debug(command_string)
251263
else:
252-
logger.info(f"{command} ({run_reason})")
264+
logger.info(f"{command_string} ({run_reason})")
253265
if old_newest_file == newest_file:
254266
logger.error("No files were modified by the command.")
255267
raise RuntimeError()
256268
else:
257269
if command_hash in LAST_BUILD_TIMES:
258270
del LAST_BUILD_TIMES[command_hash]
271+
logger.error(command_string)
272+
logger.error(f"Return code: {process.returncode}")
259273
if stdout:
260274
logger.info(stdout.decode("utf-8").strip())
261275
if stderr:
262276
logger.warning(stderr.decode("utf-8").strip())
263277
if not stdout and not stderr:
264278
logger.warning("No output")
265-
logger.error(command)
266279
if cancellation:
267280
raise cancellation
268281
raise RuntimeError()
@@ -332,21 +345,6 @@ def __init__(self, srcdir: pathlib.Path, builddir: pathlib.Path, cmake_args):
332345
self.ar = cmake_args["AR"]
333346
self.cflags = cmake_args.get("CFLAGS", "")
334347

335-
self._cflags_tempfile = tempfile.NamedTemporaryFile()
336-
337-
# Windows paths have / as separator but gcc wants them as escaped backslashes.
338-
if os.name == "nt":
339-
escaped_cflags = self.cflags.replace("/", "\\\\")
340-
escaped_cflags = escaped_cflags.replace(" ", "\n")
341-
else:
342-
escaped_cflags = self.cflags
343-
print("writing to:", self._cflags_tempfile.name)
344-
print(escaped_cflags)
345-
self._cflags_tempfile.write(escaped_cflags.encode())
346-
self._cflags_tempfile.flush()
347-
self.cflags_file = "@" + self._cflags_tempfile.name
348-
print("cflags_file:", self.cflags_file)
349-
350348
self.srcdir = srcdir
351349
self.builddir = builddir
352350

@@ -355,26 +353,24 @@ async def preprocess(
355353
):
356354
output_file.parent.mkdir(parents=True, exist_ok=True)
357355
depfile = output_file.parent / (output_file.name + ".d")
358-
if depfile.exists():
359-
pass
356+
responsefile = output_file.parent / (output_file.name + ".rsp")
357+
360358
await run_command(
361359
[
362360
self.c_compiler,
363361
"-E",
364362
"-MMD",
365-
"-MF",
366-
depfile,
367-
"-v",
363+
f"-MF {depfile}",
368364
"-c",
369365
source_file,
370-
self.cflags_file,
366+
self.cflags,
371367
*flags,
372-
"-o",
373-
output_file,
368+
f"-o {output_file}",
374369
],
375370
description=f"Preprocess {source_file.relative_to(self.srcdir)} -> {output_file.relative_to(self.builddir)}",
376371
working_directory=self.srcdir,
377372
check_hash=[output_file],
373+
responsefile=responsefile,
378374
)
379375

380376
async def compile(
@@ -386,6 +382,7 @@ async def compile(
386382
output_file = self.builddir / output_file
387383
output_file.parent.mkdir(parents=True, exist_ok=True)
388384
depfile = output_file.with_suffix(".d")
385+
responsefile = output_file.with_suffix(".rsp")
389386
extradeps = []
390387
if depfile.exists():
391388
depfile_contents = depfile.read_text().split()
@@ -396,10 +393,11 @@ async def compile(
396393
extradeps.append(pathlib.Path(dep))
397394
else:
398395
extradeps.append(self.srcdir / dep)
396+
399397
await run_command(
400398
[
401399
self.c_compiler,
402-
self.cflags_file,
400+
self.cflags,
403401
"-MMD",
404402
"-c",
405403
source_file,
@@ -410,6 +408,7 @@ async def compile(
410408
description=f"Compile {source_file.relative_to(self.srcdir)} -> {output_file.relative_to(self.builddir)}",
411409
working_directory=self.srcdir,
412410
extradeps=extradeps,
411+
responsefile=responsefile,
413412
)
414413

415414
async def archive(self, objects: list[pathlib.Path], output_file: pathlib.Path):

0 commit comments

Comments
 (0)