Skip to content

Commit 898b594

Browse files
Port f2c_fixes patch from upstream (#5)
Ports pyodide/pyodide#4822 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 5b3f4bb commit 898b594

File tree

2 files changed

+70
-10
lines changed

2 files changed

+70
-10
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
## [0.27.1] - 2024/06/28
11+
12+
## Changed
13+
14+
- ported f2c_fixes patch from https://github.com/pyodide/pyodide/pull/4822
15+
1016
## [0.27.0] - 2024/06/18
1117

1218
- pyodide-build is now developed under https://github.com/pyodide/pyodide-build.

pyodide_build/_f2c_fixes.py

+64-10
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ def fix_f2c_input(f2c_input_path: str) -> None:
5858
lines = f.readlines()
5959
new_lines = []
6060
lines = char1_args_to_int(lines)
61-
6261
for line in lines:
6362
line = fix_string_args(line)
6463

@@ -91,6 +90,27 @@ def fix_f2c_input(f2c_input_path: str) -> None:
9190

9291
new_lines.append(line)
9392

93+
# We assume one function per file, since this seems quite consistently true.
94+
# Figure out if it's supposed to be recursive. f2c can't handle the
95+
# recursive keyword so we need to remove it and add a comment so we can tell
96+
# it was supposed to be recursive. In fix_f2c_output, we'll remove the
97+
# static keywords from all the variables.
98+
is_recursive = False
99+
for idx, line in enumerate(new_lines):
100+
if "recursive" in line:
101+
is_recursive = True
102+
new_lines[idx] = new_lines[idx].replace("recursive", "")
103+
if line.strip() == "recursive":
104+
# If whole line was recursive, then the next line starts with an
105+
# asterisk to indicate line continuation. Fortran is very
106+
# persnickity so we have to remove the line continuation. Make
107+
# sure to replace the * with a space because the number of
108+
# pre-code characters is significant...
109+
new_lines[idx + 1] = new_lines[idx + 1].replace("*", " ")
110+
break
111+
if is_recursive:
112+
new_lines.insert(0, "C .. xxISRECURSIVExx ..\n")
113+
94114
with open(f2c_input_path, "w") as f:
95115
f.writelines(new_lines)
96116

@@ -194,9 +214,12 @@ def fix_f2c_output(f2c_output_path: str) -> str | None:
194214
90 and Fortran 95.
195215
"""
196216
f2c_output = Path(f2c_output_path)
197-
198217
with open(f2c_output) as f:
199218
lines = f.readlines()
219+
220+
is_recursive = any("xxISRECURSIVExx" in line for line in lines)
221+
222+
lines = list(regroup_lines(lines))
200223
if "id_dist" in f2c_output_path:
201224
# Fix implicit casts in id_dist.
202225
lines = fix_inconsistent_decls(lines)
@@ -270,16 +293,45 @@ def fix_line(line: str) -> str:
270293
if "eupd.c" in str(f2c_output):
271294
# put signature on a single line to make replacement more
272295
# straightforward
273-
regrouped_lines = regroup_lines(lines)
274296
lines = [
275-
re.sub(r",?\s*ftnlen\s*(howmny_len|bmat_len)", "", line)
276-
for line in regrouped_lines
297+
re.sub(r",?\s*ftnlen\s*(howmny_len|bmat_len)", "", line) for line in lines
277298
]
278299

279300
# Fix signature of c_abs to match the OpenBLAS one
280301
if "REVCOM.c" in str(f2c_output):
281302
lines = [line.replace("double c_abs(", "float c_abs(") for line in lines]
282303

304+
# Non recursive functions declare all their locals as static, ones marked
305+
# "recursive" need them to be proper local variables. For recursive
306+
# functions we'll replace them.
307+
def fix_static(line: str) -> str:
308+
static_prefix = " static"
309+
if not line.startswith(static_prefix):
310+
return line
311+
line = line.removeprefix(static_prefix).strip()
312+
# If line contains a { or " there's already an initializer and we'll get
313+
# confused. When there's an initializer there's also only one variable
314+
# so we don't need to do anything.
315+
if "{" in line or '"' in line:
316+
return line + "\n"
317+
# split off type
318+
type, rest = line.split(" ", 1)
319+
# Since there is no { or " each comma separates a variable name
320+
names = rest[:-1].split(",")
321+
init_names = []
322+
for name in names:
323+
if "=" in name:
324+
# There's already an initializer
325+
init_names.append(name)
326+
else:
327+
# = {0} initializes all types to all 0s.
328+
init_names.append(name + " = {0}")
329+
joined_names = ",".join(init_names)
330+
return f" {type} {joined_names};\n"
331+
332+
if is_recursive:
333+
lines = list(map(fix_static, lines))
334+
283335
with open(f2c_output, "w") as f:
284336
f.writelines(lines)
285337

@@ -333,15 +385,18 @@ def regroup_lines(lines: Iterable[str]) -> Iterator[str]:
333385
... static doublereal psum[52];
334386
... extern /* Subroutine */ int dqelg_(integer *, doublereal *, doublereal *,
335387
... doublereal *, doublereal *, integer *);
336-
... '''))))
388+
... '''))).strip())
337389
/* Subroutine */ int clanhfwrp_(real *ret, char *norm, char *transr, char * uplo, integer *n, complex *a, real *work, ftnlen norm_len, ftnlen transr_len, ftnlen uplo_len){
338390
static doublereal psum[52];
339391
extern /* Subroutine */ int dqelg_(integer *, doublereal *, doublereal *, doublereal *, doublereal *, integer *);
340-
341392
"""
342393
line_iter = iter(lines)
343394
for line in line_iter:
344-
if "/* Subroutine */" not in line:
395+
if "/* Subroutine */" not in line and "static" not in line:
396+
yield line
397+
continue
398+
399+
if '"' in line:
345400
yield line
346401
continue
347402

@@ -360,7 +415,7 @@ def regroup_lines(lines: Iterable[str]) -> Iterator[str]:
360415
if is_definition:
361416
yield joined_line
362417
else:
363-
yield from (x + ";" for x in joined_line.split(";")[:-1])
418+
yield from (x + ";\n" for x in joined_line.split(";")[:-1])
364419

365420

366421
def fix_inconsistent_decls(lines: list[str]) -> list[str]:
@@ -410,7 +465,6 @@ def fix_inconsistent_decls(lines: list[str]) -> list[str]:
410465
}
411466
"""
412467
func_types = {}
413-
lines = list(regroup_lines(lines))
414468
for line in lines:
415469
if not line.startswith("/* Subroutine */"):
416470
continue

0 commit comments

Comments
 (0)