diff --git a/pkgs/build-support/cc-wrapper/add-clang-cc-cflags-before.sh b/pkgs/build-support/cc-wrapper/add-clang-cc-cflags-before.sh index 865e0d0548203..d5515604c0bcd 100644 --- a/pkgs/build-support/cc-wrapper/add-clang-cc-cflags-before.sh +++ b/pkgs/build-support/cc-wrapper/add-clang-cc-cflags-before.sh @@ -36,6 +36,6 @@ elif [[ $0 != *cpp ]]; then fi fi -if [[ "@darwinMinVersion@" ]]; then +if [[ "@darwinMinVersion@" ]] && [ "@isFlang@" != 1 ]; then extraBefore+=(-Werror=unguarded-availability) fi diff --git a/pkgs/build-support/cc-wrapper/cc-wrapper.sh b/pkgs/build-support/cc-wrapper/cc-wrapper.sh index 246c1b1f65f6e..3eefd9d876d2f 100644 --- a/pkgs/build-support/cc-wrapper/cc-wrapper.sh +++ b/pkgs/build-support/cc-wrapper/cc-wrapper.sh @@ -44,7 +44,7 @@ while (( "$n" < "$nParams" )); do case "$p" in -[cSEM] | -MM) dontLink=1 ;; - -cc1) cc1=1 ;; + -cc1 | -fc1 ) cc1=1 ;; -nostdinc) cInclude=0 cxxInclude=0 ;; -nostdinc++) cxxInclude=0 ;; -nostdlib) cxxLibrary=0 ;; @@ -218,6 +218,27 @@ if [[ -e @out@/nix-support/add-local-cc-cflags-before.sh ]]; then source @out@/nix-support/add-local-cc-cflags-before.sh fi +if [ "@isFlang@" = 1 ]; then + # Nix's reproducible-build hook injects -frandom-seed=..., but flang does + # not currently accept that option. Strip it here so the wrapper remains + # deterministic without surfacing a spurious flang driver failure. + kept=() + for p in ${extraBefore+"${extraBefore[@]}"}; do + if [[ "$p" != -frandom-seed=* ]]; then + kept+=("$p") + fi + done + extraBefore=(${kept+"${kept[@]}"}) + + kept=() + for p in ${extraAfter+"${extraAfter[@]}"}; do + if [[ "$p" != -frandom-seed=* ]]; then + kept+=("$p") + fi + done + extraAfter=(${kept+"${kept[@]}"}) +fi + # As a very special hack, if the arguments are just `-v', then don't # add anything. This is to prevent `gcc -v' (which normally prints # out the version number and returns exit code 0) from printing out diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix index 10175e91a0708..237476818bec2 100644 --- a/pkgs/build-support/cc-wrapper/default.nix +++ b/pkgs/build-support/cc-wrapper/default.nix @@ -26,6 +26,7 @@ nixSupport ? { }, isGNU ? false, isClang ? cc.isClang or false, + isFlang ? cc.isFlang or false, isZig ? cc.isZig or false, isArocc ? cc.isArocc or false, isCcache ? cc.isCcache or false, @@ -385,7 +386,9 @@ let # # TODO: Drop `mangle-NIX_STORE-in-__FILE__.patch` from GCC and make # this unconditional once the upstream bug is fixed. - useMacroPrefixMap = !isGNU; + useMacroPrefixMap = !isGNU && !isFlang; + systemIncludeFlag = if isFlang || isArocc then "-I" else "-idirafter"; + fortifyIncludeFlag = if isFlang then "-I" else "-isystem"; in assert includeFortifyHeaders' -> fortify-headers != null; @@ -573,10 +576,18 @@ stdenvNoCC.mkDerivation { '' + optionalString cc.langFortran or false '' - wrap ${targetPrefix}gfortran $wrapper $ccPath/${targetPrefix}gfortran - ln -sv ${targetPrefix}gfortran $out/bin/${targetPrefix}g77 - ln -sv ${targetPrefix}gfortran $out/bin/${targetPrefix}f77 - export named_fc=${targetPrefix}gfortran + if [ -e $ccPath/${targetPrefix}gfortran ]; then + wrap ${targetPrefix}gfortran $wrapper $ccPath/${targetPrefix}gfortran + ln -sv ${targetPrefix}gfortran $out/bin/${targetPrefix}g77 + ln -sv ${targetPrefix}gfortran $out/bin/${targetPrefix}f77 + export named_fc=${targetPrefix}gfortran + elif [ -e $ccPath/${targetPrefix}flang ]; then + wrap ${targetPrefix}flang $wrapper $ccPath/${targetPrefix}flang + export named_fc=${targetPrefix}flang + elif [ -e $ccPath/flang ]; then + wrap ${targetPrefix}flang $wrapper $ccPath/flang + export named_fc=${targetPrefix}flang + fi '' + optionalString cc.langGo or false '' @@ -712,9 +723,7 @@ stdenvNoCC.mkDerivation { echo "-B${libc_lib}${libc.libdir or "/lib/"}" >> $out/nix-support/libc-crt1-cflags '' + '' - include "-${ - if isArocc then "I" else "idirafter" - }" "${libc_dev}${libc.incdir or "/include"}" >> $out/nix-support/libc-cflags + include "${systemIncludeFlag}" "${libc_dev}${libc.incdir or "/include"}" >> $out/nix-support/libc-cflags '' + optionalString isGNU '' for dir in "${cc}"/lib/gcc/*/*/include-fixed; do @@ -722,9 +731,9 @@ stdenvNoCC.mkDerivation { done '' + optionalString (libc.w32api or null != null) '' - echo '-idirafter ${lib.getDev libc.w32api}${ + include "${systemIncludeFlag}" "${lib.getDev libc.w32api}${ libc.incdir or "/include/w32api" - }' >> $out/nix-support/libc-cflags + }" >> $out/nix-support/libc-cflags '' + '' @@ -739,7 +748,7 @@ stdenvNoCC.mkDerivation { # like option that forces the libc headers before all -idirafter, # hence -isystem here. + optionalString includeFortifyHeaders' '' - include -isystem "${fortify-headers}/include" >> $out/nix-support/libc-cflags + include "${fortifyIncludeFlag}" "${fortify-headers}/include" >> $out/nix-support/libc-cflags '' ) @@ -760,7 +769,7 @@ stdenvNoCC.mkDerivation { # already knows how to find its own libstdc++, and adding # additional -isystem flags will confuse gfortran (see # https://github.com/NixOS/nixpkgs/pull/209870#issuecomment-1500550903) - + optionalString (libcxx == null && isClang && (useGccForLibs && gccForLibs.langCC or false)) '' + + optionalString (libcxx == null && isClang && useGccForLibs && (cc.langCC or false)) '' for dir in ${gccForLibs}/include/c++/*; do include -cxx-isystem "$dir" >> $out/nix-support/libcxx-cxxflags done @@ -827,6 +836,7 @@ stdenvNoCC.mkDerivation { optionalString ( (cc.isClang or false) + && !isFlang && !(cc.isROCm or false) && !targetPlatform.isDarwin && !targetPlatform.isAndroid @@ -861,7 +871,8 @@ stdenvNoCC.mkDerivation { let enable_fp = !targetPlatform.isx86_32 && !targetPlatform.isS390; enable_leaf_fp = - enable_fp + !isFlang + && enable_fp && ( targetPlatform.isx86_64 || targetPlatform.isAarch64 @@ -927,7 +938,7 @@ stdenvNoCC.mkDerivation { # well with multi line flags, so make the flags single line again + '' for flags in "$out/nix-support"/*flags*; do - substituteInPlace "$flags" --replace $'\n' ' ' + substituteInPlace "$flags" --replace-quiet $'\n' ' ' done substituteAll ${./add-flags.sh} $out/nix-support/add-flags.sh @@ -973,6 +984,7 @@ stdenvNoCC.mkDerivation { env = { inherit isClang; + inherit isFlang; # for substitution in utils.bash # TODO(@sternenseemann): invent something cleaner than passing in "" in case of absence diff --git a/pkgs/development/compilers/llvm/21/flang/accept-and-ignore-some-gfortran-optimization-flags.patch b/pkgs/development/compilers/llvm/21/flang/accept-and-ignore-some-gfortran-optimization-flags.patch new file mode 100644 index 0000000000000..912be71696212 --- /dev/null +++ b/pkgs/development/compilers/llvm/21/flang/accept-and-ignore-some-gfortran-optimization-flags.patch @@ -0,0 +1,49 @@ +From da7174958be43d69b2ed6b581c8ac8a382b59180 Mon Sep 17 00:00:00 2001 +From: Tarun Prabhu +Date: Tue, 28 Oct 2025 19:35:27 -0600 +Subject: [PATCH] [flang][Driver] Accept (and ignore) some gfortran-specific + options + +Enable the clang_ignored_gcc_optimization_f_group in flang. These options are +accepted by clang, but ignored after emitting a warning message. flang's +behavior now mirrors clang. + +Fixes #158436 +--- + clang/include/clang/Driver/Options.td | 3 ++- + clang/lib/Driver/ToolChains/Flang.cpp | 8 ++++++++ + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td +index ef1c8758705f4..cac122d296624 100644 +--- a/include/clang/Driver/Options.td ++++ b/include/clang/Driver/Options.td +@@ -316,7 +316,8 @@ def mno_mpx : Flag<["-"], "mno-mpx">, Group; + + // Group that ignores all gcc optimizations that won't be implemented + def clang_ignored_gcc_optimization_f_Group : OptionGroup< +- "">, Group, Flags<[Ignored]>; ++ "">, ++ Group, Flags<[Ignored]>, Visibility<[ClangOption, FlangOption]>; + + class DiagnosticOpts + : KeyPathAndMacro<"DiagnosticOpts->", base, "DIAG_"> {} +diff --git a/lib/Driver/ToolChains/Flang.cpp b/lib/Driver/ToolChains/Flang.cpp +index 88bce181d40d2..2f5e93d139858 100644 +--- a/lib/Driver/ToolChains/Flang.cpp ++++ b/lib/Driver/ToolChains/Flang.cpp +@@ -858,6 +858,14 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, + if (const Arg *A = Args.getLastArg(Opt)) + D.Diag(diag::warn_drv_invalid_argument_for_flang) << A->getSpelling(); + ++ // Warn about options that are ignored by flang. These are options that are ++ // accepted by gfortran, but have no equivalent in flang. ++ for (const Arg *A : ++ Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) { ++ D.Diag(diag::warn_ignored_gcc_optimization) << A->getAsString(Args); ++ A->claim(); ++ } ++ + const InputInfo &Input = Inputs[0]; + types::ID InputType = Input.getType(); + diff --git a/pkgs/development/compilers/llvm/21/flang/use-xflang-in-diagnostics.patch b/pkgs/development/compilers/llvm/21/flang/use-xflang-in-diagnostics.patch new file mode 100644 index 0000000000000..29af46eba7989 --- /dev/null +++ b/pkgs/development/compilers/llvm/21/flang/use-xflang-in-diagnostics.patch @@ -0,0 +1,40 @@ +From 9ab9d33171ee35c948967a2a2d714b8059887607 Mon Sep 17 00:00:00 2001 +From: Tarun Prabhu +Date: Wed, 29 Oct 2025 09:13:17 -0600 +Subject: [PATCH] [flang][driver] Use -Xflang in diagnostics + +When an option that is only available in `flang -fc1` is provided to +`flang`, emit a diagnostic with a suggestion containing "did you mean +-Xflang '-foo'". + +Partially addresses #163550. +--- + clang/lib/Driver/Driver.cpp | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp +index 40ea513e85427..71c52807091ba 100644 +--- a/lib/Driver/Driver.cpp ++++ b/lib/Driver/Driver.cpp +@@ -365,9 +365,18 @@ + auto ArgString = A->getAsString(Args); + std::string Nearest; + if (getOpts().findNearest(ArgString, Nearest, VisibilityMask) > 1) { +- if (!IsCLMode() && +- getOpts().findExact(ArgString, Nearest, +- llvm::opt::Visibility(options::CC1Option))) { ++ if (IsFlangMode()) { ++ if (getOpts().findExact(ArgString, Nearest, ++ llvm::opt::Visibility(options::FC1Option))) { ++ DiagID = diag::err_drv_unknown_argument_with_suggestion; ++ Diags.Report(DiagID) << ArgString << "-Xflang " + Nearest; ++ } else { ++ DiagID = diag::err_drv_unknown_argument; ++ Diags.Report(DiagID) << ArgString; ++ } ++ } else if (!IsCLMode() && getOpts().findExact(ArgString, Nearest, ++ llvm::opt::Visibility( ++ options::CC1Option))) { + DiagID = diag::err_drv_unknown_argument_with_suggestion; + Diags.Report(DiagID) << ArgString << "-Xclang " + Nearest; + } else { diff --git a/pkgs/development/compilers/llvm/21/flang/warn-on-fbuiltin-and-fno-builtin.patch b/pkgs/development/compilers/llvm/21/flang/warn-on-fbuiltin-and-fno-builtin.patch new file mode 100644 index 0000000000000..ee2cb99b57a5c --- /dev/null +++ b/pkgs/development/compilers/llvm/21/flang/warn-on-fbuiltin-and-fno-builtin.patch @@ -0,0 +1,74 @@ +From 263377a175709c2d11f3ff63c2d2d2843afb91ea Mon Sep 17 00:00:00 2001 +From: Tarun Prabhu +Date: Thu, 23 Oct 2025 13:24:20 -0600 +Subject: [PATCH] [flang][Driver] Warn on -fbuiltin and -fno-builtin + +The options -fbuiltin and -fno-builtin are not valid for Fortran. However, +they are accepted by gfortran which emits a warning message but continues to +compile the code. Both -fbuiltin and -fno-builtin have been enabled for flang. +Specifying either will result in a warning message being shown but no other +effects. Compilation will proceed normally after these warnings are shown. This +brings flang's behavior in line with gfortran for these options. + +Fixes #164766 +--- + clang/include/clang/Basic/DiagnosticDriverKinds.td | 3 +++ + clang/include/clang/Driver/Options.td | 4 ++-- + clang/lib/Driver/ToolChains/Flang.cpp | 7 +++++++ + 3 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td +index 0581bf353d936..83980e3ac35b7 100644 +--- a/include/clang/Basic/DiagnosticDriverKinds.td ++++ b/include/clang/Basic/DiagnosticDriverKinds.td +@@ -131,6 +131,9 @@ def warn_drv_unsupported_option_for_offload_arch_req_feature : Warning< + def warn_drv_unsupported_option_for_target : Warning< + "ignoring '%0' option as it is not currently supported for target '%1'">, + InGroup; ++def warn_drv_invalid_argument_for_flang : Warning< ++ "'%0' is not valid for Fortran">, ++ InGroup; + def warn_drv_unsupported_option_for_flang : Warning< + "the argument '%0' is not supported for option '%1'. Mapping to '%1%2'">, + InGroup; +diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td +index ef1c8758705f4..bca8b26bc3d30 100644 +--- a/include/clang/Driver/Options.td ++++ b/include/clang/Driver/Options.td +@@ -1940,7 +1940,7 @@ defm borland_extensions : BoolFOption<"borland-extensions", + "Accept non-standard constructs supported by the Borland compiler">, + NegFlag>; + def fbuiltin : Flag<["-"], "fbuiltin">, Group, +- Visibility<[ClangOption, CLOption, DXCOption]>; ++ Visibility<[ClangOption, CLOption, DXCOption, FlangOption, FC1Option]>; + def fbuiltin_module_map : Flag <["-"], "fbuiltin-module-map">, Group, + Flags<[]>, HelpText<"Load the clang builtins module map file.">; + defm caret_diagnostics : BoolFOption<"caret-diagnostics", +@@ -3493,7 +3493,7 @@ def fno_assume_sane_operator_new : Flag<["-"], "fno-assume-sane-operator-new">, + HelpText<"Don't assume that C++'s global operator new can't alias any pointer">, + Visibility<[ClangOption, CC1Option]>, + MarshallingInfoNegativeFlag>; + def fno_builtin : Flag<["-"], "fno-builtin">, Group, +- Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, ++ Visibility<[ClangOption, CC1Option, CLOption, DXCOption, FlangOption, FC1Option]>, + HelpText<"Disable implicit builtin knowledge of functions">; + def fno_builtin_ : Joined<["-"], "fno-builtin-">, Group, + Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, +diff --git a/lib/Driver/ToolChains/Flang.cpp b/lib/Driver/ToolChains/Flang.cpp +index a56fa41c49d34..88bce181d40d2 100644 +--- a/lib/Driver/ToolChains/Flang.cpp ++++ b/lib/Driver/ToolChains/Flang.cpp +@@ -851,6 +851,13 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, + assert(false && "Unexpected action class for Flang tool."); + } + ++ // We support some options that are invalid for Fortran and have no effect. ++ // These are solely for compatibility with other compilers. Emit a warning if ++ // any such options are provided, then proceed normally. ++ for (options::ID Opt : {options::OPT_fbuiltin, options::OPT_fno_builtin}) ++ if (const Arg *A = Args.getLastArg(Opt)) ++ D.Diag(diag::warn_drv_invalid_argument_for_flang) << A->getSpelling(); ++ + const InputInfo &Input = Inputs[0]; + types::ID InputType = Input.getType(); + diff --git a/pkgs/development/compilers/llvm/common/clang/default.nix b/pkgs/development/compilers/llvm/common/clang/default.nix index e3ef79039539e..f3b8f52bcfa38 100644 --- a/pkgs/development/compilers/llvm/common/clang/default.nix +++ b/pkgs/development/compilers/llvm/common/clang/default.nix @@ -16,6 +16,7 @@ fixDarwinDylibNames, enableManpages ? false, enableClangToolsExtra ? true, + extraPatches ? [ ], devExtraCmakeFlags ? [ ], replaceVars, getVersionFile, @@ -73,7 +74,8 @@ stdenv.mkDerivation ( ]; stripLen = 1; hash = "sha256-1NKej08R9SPlbDY/5b0OKUsHjX07i9brR84yXiPwi7E="; - }); + }) + ++ extraPatches; nativeBuildInputs = [ cmake @@ -189,6 +191,8 @@ stdenv.mkDerivation ( passthru = { inherit libllvm; isClang = true; + langC = true; + langCC = true; hardeningUnsupportedFlagsByTargetPlatform = targetPlatform: [ "fortify3" ] diff --git a/pkgs/development/compilers/llvm/common/default.nix b/pkgs/development/compilers/llvm/common/default.nix index 2a88fecc0b6e0..bb0f0c66e7120 100644 --- a/pkgs/development/compilers/llvm/common/default.nix +++ b/pkgs/development/compilers/llvm/common/default.nix @@ -476,28 +476,83 @@ makeScopeWithSplicing' { // lib.optionalAttrs (lib.versionAtLeast metadata.release_version "19") { bolt = callPackage ./bolt { }; } - // lib.optionalAttrs (lib.versionAtLeast metadata.release_version "20") { - flang = callPackage ./flang { }; - - libc-overlay = callPackage ./libc { - isFullBuild = false; - # Use clang due to "gnu::naked" not working on aarch64. - # Issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77882 - stdenv = overrideCC stdenv buildLlvmPackages.clang; - }; - - libc-full = callPackage ./libc { - isFullBuild = true; - # Use clang due to "gnu::naked" not working on aarch64. - # Issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77882 - stdenv = overrideCC stdenv buildLlvmPackages.clangNoLibcNoRt; - # FIXME: This should almost certainly be `stdenv.hostPlatform`. - cmake = if stdenv.targetPlatform.libc == "llvm" then cmakeMinimal else cmake; - python3 = if stdenv.targetPlatform.libc == "llvm" then python3Minimal else python3; - }; - - libc = - # FIXME: This should almost certainly be `stdenv.hostPlatform`. - if stdenv.targetPlatform.libc == "llvm" then self.libc-full else self.libc-overlay; - }; + // lib.optionalAttrs (lib.versionAtLeast metadata.release_version "20") ( + let + # Standalone flang still resolves driver/option definitions via the + # installed libclang package, so keep flang-specific driver backports in + # a private libclang variant instead of patching the flang source tree. + flangDriverPatches = lib.optionals (lib.versions.major metadata.release_version == "21") [ + (metadata.getVersionFile "flang/warn-on-fbuiltin-and-fno-builtin.patch") + (metadata.getVersionFile "flang/use-xflang-in-diagnostics.patch") + (metadata.getVersionFile "flang/accept-and-ignore-some-gfortran-optimization-flags.patch") + ]; + flangLibclang = + if flangDriverPatches == [ ] then + self.libclang + else + self.libclang.override { + extraPatches = flangDriverPatches; + }; + flangUnwrapped = callPackage ./flang { + libclang = flangLibclang; + }; + flangRt = callPackage ./flang-rt { + buildFlang = buildLlvmPackages.flang-unwrapped; + }; + in + { + flang-unwrapped = flangUnwrapped; + flang-rt = flangRt; + flang = + let + wrapped = wrapCCWith rec { + cc = flangUnwrapped; + bintools = bintools'; + extraPackages = [ targetLlvmPackages.flang-rt ]; + extraBuildCommands = mkExtraBuildCommands0 cc + '' + # triplet however is not used in darwin + PLATFORM_DIR="${if stdenv.targetPlatform.isDarwin then "darwin" else stdenv.targetPlatform.config}" + RT_LIB_PATH="${targetLlvmPackages.flang-rt}/lib/clang/${clangVersion}/lib/$PLATFORM_DIR" + if [ -d "$RT_LIB_PATH" ]; then + ln -s "$RT_LIB_PATH" "$rsrc"/lib + echo "-L$rsrc/lib" >> $out/nix-support/cc-ldflags + else + ln -s "${targetLlvmPackages.flang-rt}/lib" "$rsrc"/lib + echo "-L$rsrc/lib" >> $out/nix-support/cc-ldflags + fi + ''; + }; + tests = callPackage ./flang/tests.nix { + flang = wrapped; + }; + in + wrapped + // { + passthru = (wrapped.passthru or { }) // { + inherit tests; + }; + }; + + libc-overlay = callPackage ./libc { + isFullBuild = false; + # Use clang due to "gnu::naked" not working on aarch64. + # Issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77882 + stdenv = overrideCC stdenv buildLlvmPackages.clang; + }; + + libc-full = callPackage ./libc { + isFullBuild = true; + # Use clang due to "gnu::naked" not working on aarch64. + # Issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77882 + stdenv = overrideCC stdenv buildLlvmPackages.clangNoLibcNoRt; + # FIXME: This should almost certainly be `stdenv.hostPlatform`. + cmake = if stdenv.targetPlatform.libc == "llvm" then cmakeMinimal else cmake; + python3 = if stdenv.targetPlatform.libc == "llvm" then python3Minimal else python3; + }; + + libc = + # FIXME: This should almost certainly be `stdenv.hostPlatform`. + if stdenv.targetPlatform.libc == "llvm" then self.libc-full else self.libc-overlay; + } + ); } diff --git a/pkgs/development/compilers/llvm/common/flang-rt/default.nix b/pkgs/development/compilers/llvm/common/flang-rt/default.nix new file mode 100644 index 0000000000000..01a1d6ca8584c --- /dev/null +++ b/pkgs/development/compilers/llvm/common/flang-rt/default.nix @@ -0,0 +1,81 @@ +{ + lib, + stdenv, + llvm_meta, + monorepoSrc, + runCommand, + cmake, + libllvm, + ninja, + python3, + buildFlang, + version, +}: +let + + minDarwinVersion = "10.12"; + effectiveDarwinVersion = + if stdenv.isDarwin && lib.versionOlder stdenv.hostPlatform.darwinMinVersion minDarwinVersion then + minDarwinVersion + else + stdenv.hostPlatform.darwinMinVersion; +in +stdenv.mkDerivation (finalAttrs: { + pname = "flang-rt"; + inherit version; + + src = + runCommand "${finalAttrs.pname}-src-${version}" + { + inherit (monorepoSrc) passthru; + } + '' + mkdir -p "$out" + cp -r ${monorepoSrc}/cmake "$out" + + mkdir -p "$out/llvm" + cp -r ${monorepoSrc}/llvm/cmake "$out/llvm" + cp -r ${monorepoSrc}/llvm/utils "$out/llvm" + cp -r ${monorepoSrc}/third-party "$out" + + cp -r ${monorepoSrc}/${finalAttrs.pname} "$out" + cp -r ${monorepoSrc}/flang "$out" + cp -r ${monorepoSrc}/runtimes "$out" + ''; + + sourceRoot = "${finalAttrs.src.name}/runtimes"; + + outputs = [ "out" ]; + + nativeBuildInputs = [ + buildFlang + cmake + ninja + python3 + ]; + buildInputs = [ + libllvm + ]; + + env = lib.optionalAttrs stdenv.isDarwin { + MACOSX_DEPLOYMENT_TARGET = effectiveDarwinVersion; + NIX_CFLAGS_COMPILE = "-mmacosx-version-min=${effectiveDarwinVersion}"; + }; + + cmakeFlags = [ + (lib.cmakeFeature "LLVM_DEFAULT_TARGET_TRIPLE" stdenv.hostPlatform.config) + (lib.cmakeFeature "CMAKE_Fortran_COMPILER" "${buildFlang}/bin/flang") + (lib.cmakeBool "CMAKE_Fortran_COMPILER_WORKS" true) + (lib.cmakeBool "CMAKE_Fortran_COMPILER_SUPPORTS_F90" true) + (lib.cmakeFeature "LLVM_DIR" "${libllvm.dev}/lib/cmake/llvm") + (lib.cmakeFeature "LLVM_ENABLE_RUNTIMES" "flang-rt") + ] + ++ lib.optionals stdenv.isDarwin [ + (lib.cmakeFeature "CMAKE_OSX_DEPLOYMENT_TARGET" effectiveDarwinVersion) + ]; + + meta = llvm_meta // { + homepage = "https://flang.llvm.org"; + description = "LLVM Fortran Runtime"; + }; +}) diff --git a/pkgs/development/compilers/llvm/common/flang/default.nix b/pkgs/development/compilers/llvm/common/flang/default.nix index 335633d7d19c9..5ddb77d74b2ef 100644 --- a/pkgs/development/compilers/llvm/common/flang/default.nix +++ b/pkgs/development/compilers/llvm/common/flang/default.nix @@ -23,21 +23,25 @@ stdenv.mkDerivation (finalAttrs: { pname = "flang"; inherit version; - src = runCommand "flang-src-${version}" { inherit (monorepoSrc) passthru; } '' - mkdir -p "$out" - cp -r ${monorepoSrc}/${finalAttrs.pname} "$out" - cp -r ${monorepoSrc}/cmake "$out" - cp -r ${monorepoSrc}/llvm "$out" - cp -r ${monorepoSrc}/clang "$out" - cp -r ${monorepoSrc}/mlir "$out" - cp -r ${monorepoSrc}/third-party "$out" - chmod -R +w $out/llvm - ''; + src = + runCommand "${finalAttrs.pname}-src-${finalAttrs.version}" + { + inherit (monorepoSrc) passthru; + } + '' + mkdir -p "$out" + cp -r ${monorepoSrc}/${finalAttrs.pname} "$out" + cp -r ${monorepoSrc}/cmake "$out" + cp -r ${monorepoSrc}/llvm "$out" + cp -r ${monorepoSrc}/clang "$out" + cp -r ${monorepoSrc}/mlir "$out" + cp -r ${monorepoSrc}/third-party "$out" + cp -r ${monorepoSrc}/flang-rt "$out" + chmod -R +w $out/llvm + ''; - patches = [ - ./dummy_target_19+.patch - ]; - patchFlags = [ "-p2" ]; + patches = [ ]; + patchFlags = [ "-p1" ]; sourceRoot = "${finalAttrs.src.name}/flang"; @@ -62,24 +66,35 @@ stdenv.mkDerivation (finalAttrs: { ls -l ${mlir.dev}/lib/cmake/mlir/MLIRConfig.cmake ''; cmakeFlags = [ - (lib.cmakeBool "CMAKE_VERBOSE_MAKEFILE" true) (lib.cmakeFeature "LLVM_DIR" "${libllvm.dev}/lib/cmake/llvm") - # TODO: Needs patches and the `lit` package like other LLVM builds? (lib.cmakeFeature "LLVM_TOOLS_BINARY_DIR" "${buildLlvmPackages.tblgen}/bin/") - (lib.cmakeFeature "LLVM_EXTERNAL_LIT" "${buildLlvmPackages.tblgen}/bin/llvm-lit") (lib.cmakeFeature "CLANG_DIR" "${libclang.dev}/lib/cmake/clang") (lib.cmakeFeature "MLIR_DIR" "${mlir.dev}/lib/cmake/mlir") (lib.cmakeFeature "MLIR_TABLEGEN_EXE" "${buildLlvmPackages.tblgen}/bin/mlir-tblgen") - (lib.cmakeFeature "MLIR_TABLEGEN_TARGET" "MLIR-TBLGen") - (lib.cmakeBool "LLVM_BUILD_EXAMPLES" false) + (lib.cmakeBool "MLIR_LINK_MLIR_DYLIB" (!stdenv.hostPlatform.isStatic)) + (lib.cmakeFeature "LLVM_LIT_ARGS" "-v") (lib.cmakeBool "LLVM_ENABLE_PLUGINS" false) (lib.cmakeBool "FLANG_STANDALONE_BUILD" true) (lib.cmakeBool "LLVM_INCLUDE_EXAMPLES" false) (lib.cmakeBool "FLANG_INCLUDE_TESTS" false) - ] ++ devExtraCmakeFlags; + passthru = { + # Used by cc-wrapper to determine whether or not the default setup hook is enabled. + langC = false; + langCC = false; + langFortran = true; + isClang = true; + isFlang = true; + + hardeningUnsupportedFlags = [ + "zerocallusedregs" + "stackprotector" + "stackclashprotection" + ]; + }; + postUnpack = '' chmod -R u+w -- $sourceRoot/.. ''; diff --git a/pkgs/development/compilers/llvm/common/flang/dummy_target_19+.patch b/pkgs/development/compilers/llvm/common/flang/dummy_target_19+.patch deleted file mode 100644 index ab09ef6504168..0000000000000 --- a/pkgs/development/compilers/llvm/common/flang/dummy_target_19+.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt -index 070c39eb6e9a..168c97524943 100644 ---- a/flang/CMakeLists.txt -+++ b/flang/CMakeLists.txt -@@ -1,6 +1,22 @@ - cmake_minimum_required(VERSION 3.20.0) - set(LLVM_SUBPROJECT_TITLE "Flang") - -+# Patch: define dummy mlir-tblgen target for TableGen.cmake -+if(DEFINED MLIR_TABLEGEN_EXE AND NOT TARGET mlir-tblgen) -+ add_executable(mlir-tblgen IMPORTED GLOBAL) -+ set_target_properties(mlir-tblgen PROPERTIES -+ IMPORTED_LOCATION "${MLIR_TABLEGEN_EXE}" -+ ) -+endif() -+ -+if(DEFINED MLIR_TABLEGEN_EXE AND NOT TARGET MLIR-TBLGen) -+ add_executable(MLIR-TBLGen IMPORTED GLOBAL) -+ set_target_properties(MLIR-TBLGen PROPERTIES -+ IMPORTED_LOCATION "${MLIR_TABLEGEN_EXE}" -+ ) -+endif() -+ -+ - if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS) - set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) - endif() diff --git a/pkgs/development/compilers/llvm/common/flang/tests.nix b/pkgs/development/compilers/llvm/common/flang/tests.nix new file mode 100644 index 0000000000000..87c933a1e0270 --- /dev/null +++ b/pkgs/development/compilers/llvm/common/flang/tests.nix @@ -0,0 +1,75 @@ +{ + runCommand, + flang, +}: +let + flangExe = "${flang}/bin/flang"; + writeHello = '' + cat > hello.f90 <<'EOF' + program hello + end program hello + EOF + ''; +in +{ + compile-smoke = runCommand "flang-compile-smoke" { } '' + set -euo pipefail + + ${writeHello} + + ${flangExe} -c hello.f90 -o compile.o + [ -f compile.o ] + + cat > args.rsp <<'EOF' + -c + hello.f90 + -o + response.o + EOF + + ${flangExe} @args.rsp + [ -f response.o ] + + touch $out + ''; + + driver-flags = runCommand "flang-driver-flags" { } '' + set -euo pipefail + + ${writeHello} + + ${flangExe} -### -c hello.f90 > no-seed.log 2>&1 + if grep -F -- "-frandom-seed=" no-seed.log; then + echo "wrapper unexpectedly injected -frandom-seed" >&2 + exit 1 + fi + + ${flangExe} -### -fbuiltin -fno-builtin hello.f90 > builtin.log 2>&1 + grep -F -- "warning: '-fbuiltin' is not valid for Fortran" builtin.log + grep -F -- "warning: '-fno-builtin' is not valid for Fortran" builtin.log + if grep -F -- "error: unknown argument" builtin.log; then + echo "builtin compatibility flags unexpectedly failed" >&2 + exit 1 + fi + + ${flangExe} -### -fexpensive-optimizations hello.f90 > ignored-flag.log 2>&1 + grep -F -- "optimization flag '-fexpensive-optimizations' is not supported" ignored-flag.log + if grep -F -- "error: unknown argument" ignored-flag.log; then + echo "ignored gfortran-style flag unexpectedly failed" >&2 + exit 1 + fi + + if ${flangExe} -### -complex-range=full hello.f90 > suggestion.log 2>&1; then + echo "expected -complex-range=full to fail at the driver layer" >&2 + exit 1 + fi + grep -F -- "error: unknown argument '-complex-range=full'" suggestion.log + grep -F -- "did you mean '-Xflang -complex-range=full'" suggestion.log + if grep -F -- "-Xclang -complex-range=full" suggestion.log; then + echo "driver suggested -Xclang instead of -Xflang" >&2 + exit 1 + fi + + touch $out + ''; +} diff --git a/pkgs/development/compilers/llvm/common/mlir/default.nix b/pkgs/development/compilers/llvm/common/mlir/default.nix index c68f6a9b0b68e..40bfddc38ee2f 100644 --- a/pkgs/development/compilers/llvm/common/mlir/default.nix +++ b/pkgs/development/compilers/llvm/common/mlir/default.nix @@ -39,6 +39,14 @@ stdenv.mkDerivation (finalAttrs: { patches = [ ./gnu-install-dirs.patch + # MLIRConfig.cmake unconditionally overwrites MLIR_TABLEGEN_EXE, breaking standalone + # builds that provide their own pre-built mlir-tblgen (e.g. in Nix sandboxed builds). + # The patch adds guards to respect caller-set values and auto-creates an imported + # mlir-tblgen target for downstream consumers. This replaces the previous dummy target + # workaround in flang's CMakeLists.txt. + + # Upstream issue: https://github.com/llvm/llvm-project/issues/150986 + ./mlir-tablegen-imported-target.patch ] ++ lib.optional (lib.versionOlder release_version "20") [ # Fix build with gcc15 diff --git a/pkgs/development/compilers/llvm/common/mlir/mlir-tablegen-imported-target.patch b/pkgs/development/compilers/llvm/common/mlir/mlir-tablegen-imported-target.patch new file mode 100644 index 0000000000000..a173341168d24 --- /dev/null +++ b/pkgs/development/compilers/llvm/common/mlir/mlir-tablegen-imported-target.patch @@ -0,0 +1,54 @@ +diff --git a/cmake/modules/MLIRConfig.cmake.in b/cmake/modules/MLIRConfig.cmake.in +index 71f3e028b1e8..b30b6cdc0de1 100644 +--- a/cmake/modules/MLIRConfig.cmake.in ++++ b/cmake/modules/MLIRConfig.cmake.in +@@ -9,9 +9,16 @@ find_package(LLVM ${LLVM_VERSION} EXACT REQUIRED CONFIG + set(MLIR_EXPORTED_TARGETS "@MLIR_EXPORTS@") + set(MLIR_CMAKE_DIR "@MLIR_CONFIG_CMAKE_DIR@") + set(MLIR_INCLUDE_DIRS "@MLIR_CONFIG_INCLUDE_DIRS@") +-set(MLIR_TABLEGEN_EXE "@MLIR_CONFIG_TABLEGEN_EXE@") +-set(MLIR_PDLL_TABLEGEN_EXE "@MLIR_CONFIG_PDLL_TABLEGEN_EXE@") +-set(MLIR_SRC_SHARDER_TABLEGEN_EXE "@MLIR_CONFIG_SRC_SHARDER_TABLEGEN_EXE@") ++# Allow users to override tablegen executables (e.g. for sandboxed builds). ++if(NOT MLIR_TABLEGEN_EXE) ++ set(MLIR_TABLEGEN_EXE "@MLIR_CONFIG_TABLEGEN_EXE@") ++endif() ++if(NOT MLIR_PDLL_TABLEGEN_EXE) ++ set(MLIR_PDLL_TABLEGEN_EXE "@MLIR_CONFIG_PDLL_TABLEGEN_EXE@") ++endif() ++if(NOT MLIR_SRC_SHARDER_TABLEGEN_EXE) ++ set(MLIR_SRC_SHARDER_TABLEGEN_EXE "@MLIR_CONFIG_SRC_SHARDER_TABLEGEN_EXE@") ++endif() + set(MLIR_IRDL_TO_CPP_EXE "@MLIR_CONFIG_IRDL_TO_CPP_EXE@") + set(MLIR_INSTALL_AGGREGATE_OBJECTS "@MLIR_INSTALL_AGGREGATE_OBJECTS@") + set(MLIR_ENABLE_BINDINGS_PYTHON "@MLIR_ENABLE_BINDINGS_PYTHON@") +@@ -32,6 +39,29 @@ if(NOT TARGET MLIRSupport) + @MLIR_CONFIG_INCLUDE_EXPORTS@ + endif() + ++# Ensure MLIR_TABLEGEN_EXE is a full path and has a corresponding imported ++# target. In install trees, MLIR_TABLEGEN_EXE may be a bare name ++# ("mlir-tblgen") rather than an absolute path. Resolve it so that ++# TableGen.cmake can use it as both a COMMAND and a DEPENDS entry. ++if(MLIR_TABLEGEN_EXE AND NOT IS_ABSOLUTE "${MLIR_TABLEGEN_EXE}" ++ AND NOT TARGET "${MLIR_TABLEGEN_EXE}") ++ find_program(_mlir_tblgen_exe "${MLIR_TABLEGEN_EXE}" ++ HINTS "${LLVM_TOOLS_BINARY_DIR}") ++ if(_mlir_tblgen_exe) ++ set(MLIR_TABLEGEN_EXE "${_mlir_tblgen_exe}") ++ endif() ++ unset(_mlir_tblgen_exe) ++endif() ++ ++if(NOT TARGET mlir-tblgen AND MLIR_TABLEGEN_EXE) ++ add_executable(mlir-tblgen IMPORTED GLOBAL) ++ set_target_properties(mlir-tblgen PROPERTIES ++ IMPORTED_LOCATION "${MLIR_TABLEGEN_EXE}") ++endif() ++if(NOT DEFINED MLIR_TABLEGEN_TARGET) ++ set(MLIR_TABLEGEN_TARGET mlir-tblgen) ++endif() ++ + # By creating these targets here, subprojects that depend on MLIR's + # tablegen-generated headers can always depend on these targets whether building + # in-tree with MLIR or not.