Bug#1149705: dh-fortran: FC_DEFAULT=gfortran resolves to hardcoded gfortran-16 instead of active default gfortran
Viktor Pashaiev
w.paszajew at gmail.com
Fri Oct 2 14:48:41 BST 2026
Package: src:dh-fortran
Version: 0.85
Severity: important
Tags: patch
User: ubuntu-devel at lists.ubuntu.com
Usertags: origin-ubuntu stonking ubuntu-patch
Dear Maintainer,
In dhfortran/compilers.py, default_compilers["gfortran"] is hardcoded to "gfortran-16":
default_compilers = {
"gfortran": "gfortran-16",
...
}
When debhelper packages or environment settings define FC_DEFAULT=gfortran (e.g. debian/rules or build harnesses), get_fc_default() calls canon("gfortran"):
def canon(f):
return default_compilers[f] if f in default_compilers else f
if "FC_DEFAULT" in os.environ:
return canon(os.environ["FC_DEFAULT"])
Because "gfortran-16" is not yet available and the system default is gfortran-15 (or whatever gfortran package is installed), get_fc_default() returns "gfortran-16". Subsequent calls fail because which("gfortran-16") returns None (for example in fortran-assert with "Compiler gfortran-16 not on PATH").
To fix this:
1. Dynamically detect the active default compiler from which("gfortran") and resolve symlinks (stripping multiarch / DEB_BUILD_GNU_TYPE prefixes so it matches the compiler dictionary key).
2. Fall back to gfortran-15 if available, else gfortran-16.
3. In canon(f), resolve symlinks when f is in default_compilers so canon("gfortran") maps to the target compiler flavor instead of an uninstalled version.
4. In get_f77(), check which("gfortran") before raising an error.
This issue is also tracked in Ubuntu at:
https://bugs.launchpad.net/ubuntu/+source/dh-fortran/+bug/2169224
The patch below resolves this behavior:
--- a/dhfortran/compilers.py
+++ b/dhfortran/compilers.py
@@ -20,9 +20,23 @@
check_output(["dpkg-architecture", "-qDEB_HOST_MULTIARCH"]).strip().decode("utf-8")
)
+def _detect_default_compiler(cmd: str, fallback: str) -> str:
+ p = which(cmd)
+ if p is not None:
+ name = Path(p).resolve().name
+ for m in (
+ multiarch,
+ check_output(["dpkg-architecture", "-qDEB_BUILD_GNU_TYPE"]).strip().decode("utf-8"),
+ ):
+ if name.startswith(m + "-"):
+ name = name[len(m) + 1 :]
+ return name
+ return fallback
+
+
# To be updated as gfortran, flang etc are updated for new versions
default_compilers = {
- "gfortran": "gfortran-16",
+ "gfortran": _detect_default_compiler("gfortran", "gfortran-15" if which("gfortran-15") is not None else "gfortran-16"),
"flang": "flang-22",
"flangext": "flang-to-external-fc-18",
}
@@ -441,7 +455,7 @@
f = f77 if f77 else "/etc/alternatives/f77"
fullpath = which(f)
if fullpath is None:
- fullpath = which(default_compilers['gfortran'])
+ fullpath = which("gfortran") or which(default_compilers['gfortran'])
if fullpath is None:
if f is None:
f='gfortran' # for better error message
@@ -454,7 +468,22 @@
"""Return the default Fortran compiler"""
def canon(f):
- return default_compilers[f] if f in default_compilers else f
+ if f in default_compilers:
+ p = which(f)
+ if p is not None:
+ p_name = Path(p).resolve().name
+ for m in (
+ multiarch,
+ check_output(["dpkg-architecture", "-qDEB_BUILD_GNU_TYPE"]).strip().decode("utf-8"),
+ ):
+ if p_name.startswith(m + "-"):
+ p_name = p_name[len(m) + 1 :]
+ for c in compilers:
+ if p_name in compilers[c]["exe"]:
+ return c
+ return p_name
+ return default_compilers[f]
+ return f
if "FC_DEFAULT" in os.environ:
return canon(os.environ["FC_DEFAULT"])
if fc is not None:
--- a/dhfortran/tests/compilers.py
+++ b/dhfortran/tests/compilers.py
@@ -26,6 +26,22 @@
1, "get_fc_flavor_arch('/bin/garbage') should fail"
+
+def test_get_fc_default_env():
+ import os
+ orig = os.environ.get("FC_DEFAULT")
+ try:
+ os.environ["FC_DEFAULT"] = "gfortran"
+ cp.get_fc_default.cache_clear()
+ assert cp.get_fc_default() == cp.default_compilers["gfortran"]
+ assert cp.which(cp.get_fc_default()) is not None
+ finally:
+ if orig is not None:
+ os.environ["FC_DEFAULT"] = orig
+ else:
+ os.environ.pop("FC_DEFAULT", None)
+ cp.get_fc_default.cache_clear()
+
def test_get_fc_default():
gf = cp.default_compilers["gfortran"]
assert cp.get_fc_default() == gf
More information about the debian-science-maintainers
mailing list