Skip to content

Commit

Permalink
Update link job for flang on windows
Browse files Browse the repository at this point in the history
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 <markus.muetzel@gmx.de>
  • Loading branch information
rovka and mmuetzel committed Jun 20, 2022
1 parent 7050d5b commit 26041e1
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 37 deletions.
26 changes: 21 additions & 5 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -739,23 +739,39 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
return true;
}

void tools::addFortranRuntimeLibs(llvm::opt::ArgStringList &CmdArgs) {
CmdArgs.push_back("-lFortran_main");
CmdArgs.push_back("-lFortranRuntime");
CmdArgs.push_back("-lFortranDecimal");
void tools::addFortranRuntimeLibs(const ToolChain &TC,
llvm::opt::ArgStringList &CmdArgs) {
if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
CmdArgs.push_back("Fortran_main.lib");
CmdArgs.push_back("FortranRuntime.lib");
CmdArgs.push_back("FortranDecimal.lib");
} else {
CmdArgs.push_back("-lFortran_main");
CmdArgs.push_back("-lFortranRuntime");
CmdArgs.push_back("-lFortranDecimal");
}
}

void tools::addFortranRuntimeLibraryPath(const ToolChain &TC,
const llvm::opt::ArgList &Args,
ArgStringList &CmdArgs) {
// NOTE: Generating executables by Flang is considered an "experimental"
// feature and hence this is guarded with a command line option.
// TODO: Make this work unconditionally once Flang is mature enough.
if (!Args.hasArg(options::OPT_flang_experimental_exec))
return;

// Default to the <driver-path>/../lib directory. This works fine on the
// platforms that we have tested so far. We will probably have to re-fine
// this in the future. In particular, on some platforms, we may need to use
// lib64 instead of lib.
SmallString<256> DefaultLibPath =
llvm::sys::path::parent_path(TC.getDriver().Dir);
llvm::sys::path::append(DefaultLibPath, "lib");
CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath));
if (TC.getTriple().isKnownWindowsMSVCEnvironment())
CmdArgs.push_back(Args.MakeArgString("-libpath:" + DefaultLibPath));
else
CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath));
}

static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Driver/ToolChains/CommonArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC,
bool IsOffloadingHost = false, bool GompNeedsRT = false);

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

/// Adds the path for the Fortran runtime libraries to \p CmdArgs.
void addFortranRuntimeLibraryPath(const ToolChain &TC,
Expand Down
9 changes: 2 additions & 7 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,14 +637,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,

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

if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
Expand Down
8 changes: 2 additions & 6 deletions clang/lib/Driver/ToolChains/Gnu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -596,13 +596,9 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// to generate executables. As Fortran runtime depends on the C runtime,
// these dependencies need to be listed before the C runtime below (i.e.
// AddRuntTimeLibs).
//
// NOTE: Generating executables by Flang is considered an "experimental"
// feature and hence this is guarded with a command line option.
// TODO: Make this work unconditionally once Flang is mature enough.
if (D.IsFlangMode() && Args.hasArg(options::OPT_flang_experimental_exec)) {
if (D.IsFlangMode()) {
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
addFortranRuntimeLibs(CmdArgs);
addFortranRuntimeLibs(ToolChain, CmdArgs);
CmdArgs.push_back("-lm");
}

Expand Down
12 changes: 11 additions & 1 deletion clang/lib/Driver/ToolChains/MSVC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(std::string("-out:") + Output.getFilename()));

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

if (C.getDriver().IsFlangMode()) {
addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
addFortranRuntimeLibs(TC, CmdArgs);

// Inform the MSVC linker that we're generating a console application, i.e.
// one with `main` as the "user-defined" entry point. The `main` function is
// defined in flang's runtime libraries.
CmdArgs.push_back("/subsystem:console");
}

// Add the compiler-rt library directories to libpath if they exist to help
// the linker find the various sanitizer, builtin, and profiling runtimes.
for (const auto &LibPath : TC.getLibraryPaths()) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Driver/ToolChains/MinGW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,

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

if (C.getDriver().IsFlangMode()) {
addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
addFortranRuntimeLibs(TC, CmdArgs);
}

// TODO: Add profile stuff here

if (TC.ShouldLinkCXXStdlib(Args)) {
Expand Down
54 changes: 37 additions & 17 deletions flang/test/Driver/linker-flags.f90
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
! invocation. These libraries are added on top of other standard runtime
! libraries that the Clang driver will include.

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

!------------
! RUN COMMAND
!------------
! Use `--ld-path` so that the linker location (used in the LABEL below) is deterministic.
! RUN: %flang -### -flang-experimental-exec --ld-path=/usr/bin/ld %S/Inputs/hello.f90 2>&1 | FileCheck %s
! NOTE: Clang's driver library, clangDriver, usually adds 'libcmt' and
! 'oldnames' on Windows, but they are not needed when compiling
! Fortran code and they might bring in additional dependencies.
! Make sure they're not added.
! 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

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

! Linker invocation to generate the executable
! CHECK-LABEL: "/usr/bin/ld"
! CHECK-SAME: "[[object_file]]"
! CHECK-SAME: -lFortran_main
! CHECK-SAME: -lFortranRuntime
! CHECK-SAME: -lFortranDecimal
! CHECK-SAME: -lm
! GNU-LABEL: "{{.*}}ld"
! GNU-SAME: "[[object_file]]"
! GNU-SAME: -lFortran_main
! GNU-SAME: -lFortranRuntime
! GNU-SAME: -lFortranDecimal
! GNU-SAME: -lm

! DARWIN-LABEL: "{{.*}}ld"
! DARWIN-SAME: "[[object_file]]"
! DARWIN-SAME: -lFortran_main
! DARWIN-SAME: -lFortranRuntime
! DARWIN-SAME: -lFortranDecimal

! MINGW-LABEL: "{{.*}}ld"
! MINGW-SAME: "[[object_file]]"
! MINGW-SAME: -lFortran_main
! MINGW-SAME: -lFortranRuntime
! MINGW-SAME: -lFortranDecimal

! NOTE: This check should also match if the default linker is lld-link.exe
! MSVC-LABEL: link.exe
! MSVC-SAME: Fortran_main.lib
! MSVC-SAME: FortranRuntime.lib
! MSVC-SAME: FortranDecimal.lib
! MSVC-SAME: /subsystem:console
! MSVC-SAME: "[[object_file]]"

0 comments on commit 26041e1

Please sign in to comment.