Skip to content

Commit 26041e1

Browse files
rovkammuetzel
andcommitted
Update link job for flang on windows
When linking a Fortran program, we need to add the runtime libraries to the command line. This is exactly what we do for Linux/Darwin, but the MSVC interface is slightly different (e.g. -libpath instead of -L). We also remove oldnames and libcmt, since they're not needed at the moment and they bring in more dependencies. We also pass `/subsystem:console` to the linker so it can figure out the right entry point. This is only needed for MSVC's `link.exe`. For LLD it is redundant but doesn't hurt. Differential Revision: https://reviews.llvm.org/D126291 Co-authored-by: Markus Mützel <[email protected]>
1 parent 7050d5b commit 26041e1

File tree

7 files changed

+80
-37
lines changed

7 files changed

+80
-37
lines changed

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -739,23 +739,39 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
739739
return true;
740740
}
741741

742-
void tools::addFortranRuntimeLibs(llvm::opt::ArgStringList &CmdArgs) {
743-
CmdArgs.push_back("-lFortran_main");
744-
CmdArgs.push_back("-lFortranRuntime");
745-
CmdArgs.push_back("-lFortranDecimal");
742+
void tools::addFortranRuntimeLibs(const ToolChain &TC,
743+
llvm::opt::ArgStringList &CmdArgs) {
744+
if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
745+
CmdArgs.push_back("Fortran_main.lib");
746+
CmdArgs.push_back("FortranRuntime.lib");
747+
CmdArgs.push_back("FortranDecimal.lib");
748+
} else {
749+
CmdArgs.push_back("-lFortran_main");
750+
CmdArgs.push_back("-lFortranRuntime");
751+
CmdArgs.push_back("-lFortranDecimal");
752+
}
746753
}
747754

748755
void tools::addFortranRuntimeLibraryPath(const ToolChain &TC,
749756
const llvm::opt::ArgList &Args,
750757
ArgStringList &CmdArgs) {
758+
// NOTE: Generating executables by Flang is considered an "experimental"
759+
// feature and hence this is guarded with a command line option.
760+
// TODO: Make this work unconditionally once Flang is mature enough.
761+
if (!Args.hasArg(options::OPT_flang_experimental_exec))
762+
return;
763+
751764
// Default to the <driver-path>/../lib directory. This works fine on the
752765
// platforms that we have tested so far. We will probably have to re-fine
753766
// this in the future. In particular, on some platforms, we may need to use
754767
// lib64 instead of lib.
755768
SmallString<256> DefaultLibPath =
756769
llvm::sys::path::parent_path(TC.getDriver().Dir);
757770
llvm::sys::path::append(DefaultLibPath, "lib");
758-
CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath));
771+
if (TC.getTriple().isKnownWindowsMSVCEnvironment())
772+
CmdArgs.push_back(Args.MakeArgString("-libpath:" + DefaultLibPath));
773+
else
774+
CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath));
759775
}
760776

761777
static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,

clang/lib/Driver/ToolChains/CommonArgs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC,
121121
bool IsOffloadingHost = false, bool GompNeedsRT = false);
122122

123123
/// Adds Fortran runtime libraries to \p CmdArgs.
124-
void addFortranRuntimeLibs(llvm::opt::ArgStringList &CmdArgs);
124+
void addFortranRuntimeLibs(const ToolChain &TC,
125+
llvm::opt::ArgStringList &CmdArgs);
125126

126127
/// Adds the path for the Fortran runtime libraries to \p CmdArgs.
127128
void addFortranRuntimeLibraryPath(const ToolChain &TC,

clang/lib/Driver/ToolChains/Darwin.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -637,14 +637,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
637637

638638
// Additional linker set-up and flags for Fortran. This is required in order
639639
// to generate executables.
640-
//
641-
// NOTE: Generating executables by Flang is considered an "experimental"
642-
// feature and hence this is guarded with a command line option.
643-
// TODO: Make this work unconditionally once Flang is mature enough.
644-
if (getToolChain().getDriver().IsFlangMode() &&
645-
Args.hasArg(options::OPT_flang_experimental_exec)) {
640+
if (getToolChain().getDriver().IsFlangMode()) {
646641
addFortranRuntimeLibraryPath(getToolChain(), Args, CmdArgs);
647-
addFortranRuntimeLibs(CmdArgs);
642+
addFortranRuntimeLibs(getToolChain(), CmdArgs);
648643
}
649644

650645
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))

clang/lib/Driver/ToolChains/Gnu.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -596,13 +596,9 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
596596
// to generate executables. As Fortran runtime depends on the C runtime,
597597
// these dependencies need to be listed before the C runtime below (i.e.
598598
// AddRuntTimeLibs).
599-
//
600-
// NOTE: Generating executables by Flang is considered an "experimental"
601-
// feature and hence this is guarded with a command line option.
602-
// TODO: Make this work unconditionally once Flang is mature enough.
603-
if (D.IsFlangMode() && Args.hasArg(options::OPT_flang_experimental_exec)) {
599+
if (D.IsFlangMode()) {
604600
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
605-
addFortranRuntimeLibs(CmdArgs);
601+
addFortranRuntimeLibs(ToolChain, CmdArgs);
606602
CmdArgs.push_back("-lm");
607603
}
608604

clang/lib/Driver/ToolChains/MSVC.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
8181
Args.MakeArgString(std::string("-out:") + Output.getFilename()));
8282

8383
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
84-
!C.getDriver().IsCLMode()) {
84+
!C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) {
8585
CmdArgs.push_back("-defaultlib:libcmt");
8686
CmdArgs.push_back("-defaultlib:oldnames");
8787
}
@@ -130,6 +130,16 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
130130
Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
131131
}
132132

133+
if (C.getDriver().IsFlangMode()) {
134+
addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
135+
addFortranRuntimeLibs(TC, CmdArgs);
136+
137+
// Inform the MSVC linker that we're generating a console application, i.e.
138+
// one with `main` as the "user-defined" entry point. The `main` function is
139+
// defined in flang's runtime libraries.
140+
CmdArgs.push_back("/subsystem:console");
141+
}
142+
133143
// Add the compiler-rt library directories to libpath if they exist to help
134144
// the linker find the various sanitizer, builtin, and profiling runtimes.
135145
for (const auto &LibPath : TC.getLibraryPaths()) {

clang/lib/Driver/ToolChains/MinGW.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
218218

219219
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
220220

221+
if (C.getDriver().IsFlangMode()) {
222+
addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
223+
addFortranRuntimeLibs(TC, CmdArgs);
224+
}
225+
221226
// TODO: Add profile stuff here
222227

223228
if (TC.ShouldLinkCXXStdlib(Args)) {

flang/test/Driver/linker-flags.f90

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22
! invocation. These libraries are added on top of other standard runtime
33
! libraries that the Clang driver will include.
44

5-
! NOTE: The additional linker flags tested here are currently only specified for
6-
! GNU and Darwin. The following line will make sure that this test is skipped on
7-
! Windows. If you are running this test on a yet another platform and it is
8-
! failing for you, please either update the following or (preferably) update the
9-
! linker invocation accordingly.
10-
! UNSUPPORTED: system-windows
5+
!-------------
6+
! RUN COMMANDS
7+
!-------------
8+
! RUN: %flang -### -flang-experimental-exec -target ppc64le-linux-gnu %S/Inputs/hello.f90 2>&1 | FileCheck %s --check-prefixes=CHECK,GNU
9+
! RUN: %flang -### -flang-experimental-exec -target aarch64-apple-darwin %S/Inputs/hello.f90 2>&1 | FileCheck %s --check-prefixes=CHECK,DARWIN
10+
! RUN: %flang -### -flang-experimental-exec -target x86_64-windows-gnu %S/Inputs/hello.f90 2>&1 | FileCheck %s --check-prefixes=CHECK,MINGW
1111

12-
!------------
13-
! RUN COMMAND
14-
!------------
15-
! Use `--ld-path` so that the linker location (used in the LABEL below) is deterministic.
16-
! RUN: %flang -### -flang-experimental-exec --ld-path=/usr/bin/ld %S/Inputs/hello.f90 2>&1 | FileCheck %s
12+
! NOTE: Clang's driver library, clangDriver, usually adds 'libcmt' and
13+
! 'oldnames' on Windows, but they are not needed when compiling
14+
! Fortran code and they might bring in additional dependencies.
15+
! Make sure they're not added.
16+
! RUN: %flang -### -flang-experimental-exec -target aarch64-windows-msvc %S/Inputs/hello.f90 2>&1 | FileCheck %s --check-prefixes=CHECK,MSVC --implicit-check-not libcmt --implicit-check-not oldnames
1717

1818
!----------------
1919
! EXPECTED OUTPUT
@@ -23,9 +23,29 @@
2323
! CHECK-SAME: "-o" "[[object_file:.*\.o]]" {{.*}}Inputs/hello.f90
2424

2525
! Linker invocation to generate the executable
26-
! CHECK-LABEL: "/usr/bin/ld"
27-
! CHECK-SAME: "[[object_file]]"
28-
! CHECK-SAME: -lFortran_main
29-
! CHECK-SAME: -lFortranRuntime
30-
! CHECK-SAME: -lFortranDecimal
31-
! CHECK-SAME: -lm
26+
! GNU-LABEL: "{{.*}}ld"
27+
! GNU-SAME: "[[object_file]]"
28+
! GNU-SAME: -lFortran_main
29+
! GNU-SAME: -lFortranRuntime
30+
! GNU-SAME: -lFortranDecimal
31+
! GNU-SAME: -lm
32+
33+
! DARWIN-LABEL: "{{.*}}ld"
34+
! DARWIN-SAME: "[[object_file]]"
35+
! DARWIN-SAME: -lFortran_main
36+
! DARWIN-SAME: -lFortranRuntime
37+
! DARWIN-SAME: -lFortranDecimal
38+
39+
! MINGW-LABEL: "{{.*}}ld"
40+
! MINGW-SAME: "[[object_file]]"
41+
! MINGW-SAME: -lFortran_main
42+
! MINGW-SAME: -lFortranRuntime
43+
! MINGW-SAME: -lFortranDecimal
44+
45+
! NOTE: This check should also match if the default linker is lld-link.exe
46+
! MSVC-LABEL: link.exe
47+
! MSVC-SAME: Fortran_main.lib
48+
! MSVC-SAME: FortranRuntime.lib
49+
! MSVC-SAME: FortranDecimal.lib
50+
! MSVC-SAME: /subsystem:console
51+
! MSVC-SAME: "[[object_file]]"

0 commit comments

Comments
 (0)