Skip to content

Commit 682d8d9

Browse files
committed
Use a native coverage launcher instead of bash, to work on macos with no recursive shebang
1 parent 8edefcd commit 682d8d9

File tree

1 file changed

+38
-12
lines changed

1 file changed

+38
-12
lines changed

mx.graalpython/mx_graalpython.py

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,24 +1014,50 @@ def graalvm_vm_arg(java_arg):
10141014
agent_args = ' '.join(graalvm_vm_arg(arg) for arg in mx_gate.get_jacoco_agent_args() or [])
10151015

10161016
# We need to make sure the arguments get passed to subprocesses, so we create a temporary launcher
1017-
# with the arguments. We also disable compilation, it hardly helps for this use case
1017+
# with the arguments.
10181018
original_launcher = os.path.abspath(os.path.realpath(launcher))
10191019
if sys.platform != 'win32':
1020-
coverage_launcher = original_launcher + '.sh'
1021-
preamble = '#!/bin/sh'
1022-
pass_args = '"$@"'
1020+
coverage_launcher = original_launcher + "_cov"
1021+
c_launcher_source = coverage_launcher + ".c"
1022+
exe_arg = f"--python.Executable={coverage_launcher}"
1023+
agent_args_list = shlex.split(agent_args)
1024+
extra_args_c = []
1025+
for i, arg in enumerate(agent_args_list):
1026+
extra_args_c.append(f'new_args[{i + 3}] = "' + arg.replace("\"", r"\"") + '";')
1027+
extra_args_c = ' '.join(extra_args_c)
1028+
c_code = dedent(f"""\
1029+
#include <stdio.h>
1030+
#include <stdlib.h>
1031+
#include <unistd.h>
1032+
1033+
int main(int argc, char **argv) {{
1034+
char *new_args[argc + 3 + {len(agent_args_list)}];
1035+
new_args[0] = "{original_launcher}";
1036+
new_args[1] = "--jvm";
1037+
new_args[2] = "{exe_arg}";
1038+
{extra_args_c}
1039+
for (int i = 1; i < argc; i++) {{
1040+
new_args[i + 3 + {len(agent_args_list)}] = argv[i];
1041+
}}
1042+
new_args[argc + 3 + {len(agent_args_list)}] = NULL;
1043+
execvp("{original_launcher}", new_args);
1044+
perror("execvp failed");
1045+
return 1;
1046+
}}
1047+
""")
1048+
with open(c_launcher_source, "w") as f:
1049+
f.write(c_code)
1050+
compile_cmd = ["cc", c_launcher_source, "-o", coverage_launcher]
1051+
subprocess.check_call(compile_cmd)
1052+
os.chmod(coverage_launcher, 0o775)
10231053
else:
10241054
coverage_launcher = original_launcher.replace('.exe', '.cmd')
10251055
# Windows looks for libraries on PATH, we need to add the jvm bin dir there or it won't find the instrumentation dlls
10261056
jvm_bindir = os.path.join(os.path.dirname(os.path.dirname(original_launcher)), 'jvm', 'bin')
1027-
preamble = f'@echo off\nset PATH=%PATH%;{jvm_bindir}'
1028-
pass_args = '%*'
1029-
with open(coverage_launcher, "w") as f:
1030-
f.write(f'{preamble}\n')
1031-
exe_arg = quote(f"--python.Executable={coverage_launcher}")
1032-
f.write(f'{original_launcher} --jvm {exe_arg} {agent_args} {pass_args}\n')
1033-
if sys.platform != 'win32':
1034-
os.chmod(coverage_launcher, 0o775)
1057+
with open(coverage_launcher, "w") as f:
1058+
f.write(f'@echo off\nset PATH=%PATH%;{jvm_bindir}\n')
1059+
exe_arg = quote(f"--python.Executable={coverage_launcher}")
1060+
f.write(f'{original_launcher} --jvm {exe_arg} {agent_args} %*\n')
10351061
mx.log(f"Replaced {launcher} with {coverage_launcher} to collect coverage")
10361062
launcher = coverage_launcher
10371063
return launcher

0 commit comments

Comments
 (0)