Skip to content

Commit bcbec21

Browse files
authored
Merge pull request #30 from linuxlizard/dpoole/fix-stdout-stderr-shellflags
Dpoole/fix stdout stderr shellflags
2 parents 9f05fd6 + 1024179 commit bcbec21

5 files changed

Lines changed: 68 additions & 34 deletions

File tree

pymake/functions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ def eval(self, symbol_table):
8484
if self.fmt:
8585
t = self.token_list[0]
8686
filename, linenumber = t.get_pos()
87-
print(self.fmt.format(filename, linenumber, msg), file=self.fh)
87+
print(self.fmt.format(filename, linenumber, msg), file=self.fh, flush=True)
8888
else:
89-
print("%s" % msg, file=self.fh)
89+
print("%s" % msg, file=self.fh, flush=True)
9090

9191
return ""
9292

pymake/pymake.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -532,14 +532,14 @@ def check_prefixes(s):
532532
s, ignore_failure, silent = check_prefixes(s)
533533

534534
if not silent and not args.silent:
535-
print(s)
535+
print(s,flush=True)
536536

537537
if args.dry_run:
538-
print(s)
538+
print(s, flush=True)
539539
continue
540540

541541
exit_code = 0
542-
ret = shell.execute(s, symtable)
542+
ret = shell.execute(s, symtable, capture=False)
543543

544544
#
545545
# !!! Run a Sub-Make !!!
@@ -565,10 +565,9 @@ def check_prefixes(s):
565565
ret.stdout = ""
566566

567567
exit_code = ret.exit_code
568-
print(ret.stdout,end="")
569568
if exit_code != 0:
570-
print("make:", ret.stderr, file=sys.stderr, end="")
571-
print("make: *** [%r: %s] Error %d %s" % (recipe.get_pos(), rule.target, exit_code, "(ignored)" if ignore_failure else ""), file=sys.stderr)
569+
print("make: *** [%r: %s] Error %d %s" % (recipe.get_pos(), rule.target,
570+
exit_code, "(ignored)" if ignore_failure else ""), file=sys.stderr)
572571

573572
if not ignore_failure:
574573
break

pymake/shell.py

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323

2424
class ShellReturn:
2525
def __init__(self):
26+
# note: stderr is never captured
2627
self.stdout = None
27-
self.stderr = None
2828
self.exit_code = None
2929
self.errmsg = None
3030
self.is_submake = False
3131

3232

33-
def execute(cmd_str, symbol_table, use_default_shell=True):
33+
def execute(cmd_str, symbol_table, use_default_shell=True, capture=True):
3434
"""execute a string with the shell, returning a bunch of useful info"""
3535

3636
# capture a timestamp so we can match shell debug messages
@@ -79,7 +79,7 @@ def execute(cmd_str, symbol_table, use_default_shell=True):
7979
if shell:
8080
cmd.extend(shell_list)
8181
if shellflags:
82-
cmd.append(shellflags)
82+
cmd.extend([f for f in shellflags.split()])
8383
cmd.append(cmd_str)
8484

8585
env = symbol_table.get_exports()
@@ -115,27 +115,35 @@ def execute(cmd_str, symbol_table, use_default_shell=True):
115115
# outfile.write(" ".join(cmd))
116116
# outfile.write("\n\n\n")
117117

118+
# definitely need to capture stdout when we're running a sub-make because
119+
# that's how we determine the shell arguments to the actual sub-make
120+
if cmd_str.startswith(submake.getname()):
121+
capture = True
122+
123+
logger.debug("cmd=>>>%s<<<", cmd)
124+
125+
kwargs= {
126+
"shell":False,
127+
"universal_newlines":True,
128+
"check":False, # we'll check returncode ourselves
129+
"env":env
130+
}
131+
if capture:
132+
kwargs["stdout"] = subprocess.PIPE
133+
118134
try:
119-
p = subprocess.run(cmd,
120-
shell=False,
121-
stdout=subprocess.PIPE,
122-
stderr=subprocess.PIPE,
123-
universal_newlines=True,
124-
check=False, # we'll check returncode ourselves
125-
env=env
126-
)
135+
p = subprocess.run(cmd, **kwargs)
136+
#
127137
logger.debug("shell ts=%f exit status=%r", ts, p.returncode)
128138
# if p.returncode != 0:
129139
# breakpoint()
130140
return_status.exit_code = p.returncode
131141
return_status.stdout = p.stdout
132-
return_status.stderr = p.stderr
133142
except OSError as err:
134143
logger.error("shell ts=%f error=\"%s\"", ts, err)
144+
# match gnu make's output
135145
return_status.exit_code = 127
136146
return_status.stdout = ""
137-
# match gnu make's output
138-
return_status.stderr = err.strerror
139147

140148
if cmd_str.startswith(submake.getname()):
141149
return_status.is_submake = True
@@ -165,9 +173,9 @@ def execute_tokens(token_list, symbol_table):
165173
symbol_table.allow_recursion()
166174

167175
# GNU Make returns one whitespace separated string, no CR/LF
168-
# "all other newlines are replaced by spaces." gnu_make.pdf
176+
# "If the result of the execution ends in a newline, that one newline is
177+
# removed; all other newlines are replaced by spaces." GNU Make PDF
169178
exe_result.stdout = exe_result.stdout.strip().replace("\n", " ")
170-
exe_result.stderr = exe_result.stderr.strip().replace("\n", " ")
171179

172180
# save shell status
173181
pos = token_list[0].get_pos()
@@ -185,12 +193,8 @@ def execute_tokens(token_list, symbol_table):
185193
if exe_result.errmsg:
186194
error_message(pos, exe_result.errmsg)
187195
else:
188-
# otherwise report stderr (if any)
189-
if exe_result.stderr:
190-
logger.error("command at %r failed with exit_code=%d", pos, exe_result.exit_code)
191-
error_message(pos, exe_result.stderr)
192-
else:
193-
logger.error("command at %r failed with exit_code=%d (but stderr empty)", pos, exe_result.exit_code)
196+
# stderr already sent to the world
197+
logger.error("command at %r failed with exit_code=%d", pos, exe_result.exit_code)
194198

195199
return exe_result.stdout
196200

tests/test_export.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
# The subprocess.run_test() will raise error on non-zero exit.
1313

1414
def run_test(makefile, expect, extra_args=None, extra_env=None):
15-
output = run.pymake_string(makefile, extra_args, extra_env)
15+
output = run.gnumake_string(makefile, extra_args, extra_env)
1616
if _debug:
17-
print("pymake output=",output)
17+
print("gnumake output=>>>",output, "<<<")
1818
run.verify(output,expect)
19-
output = run.gnumake_string(makefile, extra_args, extra_env)
19+
output = run.pymake_string(makefile, extra_args, extra_env)
2020
if _debug:
21-
print("gnumake output=",output)
21+
print("pymake output=>>>",output, "<<<")
2222
run.verify(output,expect)
2323

2424
def test1():

tests/test_shellflags.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env python3
2+
# SPDX-License-Identifier: GPL-2.0
3+
4+
import run
5+
6+
def test_simple():
7+
makefile="""
8+
$(info .SHELLFLAGS=$(.SHELLFLAGS))
9+
@:;@:
10+
"""
11+
a = run.gnumake_string(makefile)
12+
13+
b = run.pymake_string(makefile)
14+
15+
assert a==b
16+
17+
# the -x flag will echo the command to stderr before executing it
18+
# (very useful when debugging)
19+
def test_x_flag():
20+
makefile="""
21+
.SHELLFLAGS+=-x
22+
$(info .SHELLFLAGS=$(.SHELLFLAGS))
23+
top:
24+
echo .SHELLFLAGS=$(.SHELLFLAGS)
25+
"""
26+
a = run.gnumake_string(makefile)
27+
28+
b = run.pymake_string(makefile)
29+
30+
assert a==b
31+

0 commit comments

Comments
 (0)