[clang] [flang] [flang][driver] Remove Fortain_main static library from linking stages (PR #75816)

Michael Klemm via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 19 06:17:16 PST 2023


https://github.com/mjklemm updated https://github.com/llvm/llvm-project/pull/75816

>From 511f3a4537267284554bf6b33470a01d747b8a94 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Sat, 16 Dec 2023 20:15:17 +0100
Subject: [PATCH 1/4] Remove -lFortran_main from the link line when -shared is
 present

---
 clang/lib/Driver/ToolChains/CommonArgs.cpp | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 45901ee7157f77..5d525d3794ad1d 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1133,6 +1133,17 @@ static bool isWholeArchivePresent(const ArgList &Args) {
   return WholeArchiveActive;
 }
 
+static bool isSharedLinkage(const ArgList &Args) {
+  bool FoundSharedFlag = false;
+  for (auto *Arg : Args.filtered(options::OPT_shared)) {
+    if (Arg) {
+      FoundSharedFlag = true;
+    }
+  }
+
+  return FoundSharedFlag;
+}
+
 /// Add Fortran runtime libs for MSVC
 static void addFortranRuntimeLibsMSVC(const ArgList &Args,
                                       llvm::opt::ArgStringList &CmdArgs) {
@@ -1164,6 +1175,17 @@ static void addFortranRuntimeLibsMSVC(const ArgList &Args,
 // Add FortranMain runtime lib
 static void addFortranMain(const ToolChain &TC, const ArgList &Args,
                            llvm::opt::ArgStringList &CmdArgs) {
+  // 0. Shared-library linkage
+  // If we are attempting to link a shared library, we should not add
+  // -lFortran_main.a to the link line, as the `main` symbol is not
+  // required for a shared library and should also be provided by one
+  // of the translation units of the code that this shared library
+  // will be linked against eventually.
+  if (isSharedLinkage(Args)) {
+    printf("MK: --> shared linkage, do not add -lFortranMain\n");
+    return;
+  }
+
   // 1. MSVC
   if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
     addFortranRuntimeLibsMSVC(Args, CmdArgs);

>From 930f2c447daa625d9e6019cd38d82b5750942f5d Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Mon, 18 Dec 2023 11:27:59 +0100
Subject: [PATCH 2/4] Update dynamic_linker.f90 test and clean up a bit

---
 clang/lib/Driver/ToolChains/CommonArgs.cpp | 22 ++++++++++------------
 flang/test/Driver/dynamic-linker.f90       |  8 ++++++--
 2 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 5d525d3794ad1d..05ebd42829c95d 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1133,15 +1133,14 @@ static bool isWholeArchivePresent(const ArgList &Args) {
   return WholeArchiveActive;
 }
 
+/// Determine if driver is invoked to create a shared object library (-static)
 static bool isSharedLinkage(const ArgList &Args) {
-  bool FoundSharedFlag = false;
-  for (auto *Arg : Args.filtered(options::OPT_shared)) {
-    if (Arg) {
-      FoundSharedFlag = true;
-    }
-  }
+  return Args.hasArg(options::OPT_shared);
+}
 
-  return FoundSharedFlag;
+/// Determine if driver is invoked to create a static object library (-shared)
+static bool isStaticLinkage(const ArgList &Args) {
+  return Args.hasArg(options::OPT_static);
 }
 
 /// Add Fortran runtime libs for MSVC
@@ -1176,13 +1175,12 @@ static void addFortranRuntimeLibsMSVC(const ArgList &Args,
 static void addFortranMain(const ToolChain &TC, const ArgList &Args,
                            llvm::opt::ArgStringList &CmdArgs) {
   // 0. Shared-library linkage
-  // If we are attempting to link a shared library, we should not add
+  // If we are attempting to link a library, we should not add
   // -lFortran_main.a to the link line, as the `main` symbol is not
-  // required for a shared library and should also be provided by one
-  // of the translation units of the code that this shared library
+  // required for a library and should also be provided by one of
+  // the translation units of the code that this shared library
   // will be linked against eventually.
-  if (isSharedLinkage(Args)) {
-    printf("MK: --> shared linkage, do not add -lFortranMain\n");
+  if (isSharedLinkage(Args) || isStaticLinkage(Args)) {
     return;
   }
 
diff --git a/flang/test/Driver/dynamic-linker.f90 b/flang/test/Driver/dynamic-linker.f90
index df119c22a2ea51..af07e2483f93fa 100644
--- a/flang/test/Driver/dynamic-linker.f90
+++ b/flang/test/Driver/dynamic-linker.f90
@@ -3,18 +3,22 @@
 
 ! RUN: %flang -### --target=x86_64-linux-gnu -rpath /path/to/dir -shared \
 ! RUN:     -static %s 2>&1 | FileCheck \
-! RUN:     --check-prefixes=GNU-LINKER-OPTIONS %s
+! RUN:     --check-prefixes=GNU-LINKER-OPTIONS \
+! RUN:     --implicit-check-not=GNU-LINKER-OPTIONS-NOT %s
 ! RUN: %flang -### --target=x86_64-windows-msvc -rpath /path/to/dir -shared \
 ! RUN:     -static %s 2>&1 | FileCheck \
-! RUN:     --check-prefixes=MSVC-LINKER-OPTIONS %s
+! RUN:     --check-prefixes=MSVC-LINKER-OPTIONS \
+! RUN:     --implicit-check-not=MSVC-LINKER-OPTIONS-NOT %s
 
 ! TODO: Could the linker have an extension or a suffix?
 ! GNU-LINKER-OPTIONS: "{{.*}}ld{{(.exe)?}}"
 ! GNU-LINKER-OPTIONS-SAME: "-shared"
 ! GNU-LINKER-OPTIONS-SAME: "-static"
 ! GNU-LINKER-OPTIONS-SAME: "-rpath" "/path/to/dir"
+! GNU-LINKER-OPTIONS-NOT: "-lFortran_main.a"
 
 ! For MSVC, adding -static does not add any additional linker options.
 ! MSVC-LINKER-OPTIONS: "{{.*}}link{{(.exe)?}}"
 ! MSVC-LINKER-OPTIONS-SAME: "-dll"
 ! MSVC-LINKER-OPTIONS-SAME: "-rpath" "/path/to/dir"
+! MSVC-LINKER-OPTIONS-NOT: "/WHOLEARCHIVE:Fortran_main"

>From c60a3a7dbd038d9e1cac63cda00674462828c5c6 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Tue, 19 Dec 2023 15:07:14 +0100
Subject: [PATCH 3/4] Write up for Flang creates the link line and the thoughts
 behind that

---
 flang/docs/FlangDriver.md | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/flang/docs/FlangDriver.md b/flang/docs/FlangDriver.md
index 5231e78335f6ad..bdb3c46455601c 100644
--- a/flang/docs/FlangDriver.md
+++ b/flang/docs/FlangDriver.md
@@ -163,6 +163,40 @@ forward compiler options to the frontend driver, `flang-new -fc1`.
 You can read more on the design of `clangDriver` in Clang's [Driver Design &
 Internals](https://clang.llvm.org/docs/DriverInternals.html).
 
+## Linker Driver
+When used as a linker, Flang's frontend driver assembles the command line for an
+external linker command (e.g., LLVM's `lld`) and invokes it to create the final
+executable by linking static and shared libraries together with all the
+translation units supplied as object files.
+
+By default, the Flang linker driver adds several libraries to the linker
+invocation to make sure that all entrypoints for program start
+(Fortran's program unit) and runtime routines can be resolved by the linker.
+The libraries are:
+
+* `Fortran_main`: Provides the main entry point `main` that then invokes
+  `_QQmain` with the Fortran program unit.  This library has a dependency to
+  the `FortranRuntime` library.
+* `FortranRuntime`: Provides most of the Flang runtime library.
+* `FortranDecimal`: Provides operations for decimal numbers.
+
+The default is that, when using Flang as the linker, one of the Fortran
+translation units provides the program unit and therefore it is assumed that
+Fortran is the main code part (calling into C/C++ routines via `BIND
+(C)` interfaces).  When composing the linker commandline, Flang uses
+`--whole-archive` and `--no-whole-archive` (Windows: `/WHOLEARCHIVE:`,
+Darwin: *not implemented yet*) to make sure that all for `Fortran_main` is
+processed by the linker.  This is done to issue a proper error message when
+multiple definitions of `main` occur.  This happens, for instance, when linking
+a code that has a Fortran program unit with a C/C++ code that also defines a
+`main` function.
+
+If the code is C/C++ based and invokes Fortran routines, either use Clang as the
+linker driver (supplying `FortranRuntime` and/or `FortranDecimal` to the linker
+driver) or use Flang with the `-fno-fortran-main` flag.  This flag removes
+`Fortran_main` from the linker stage and hence requires one of the C/C++
+translation units to provide a definition of the `main` function.
+
 ## Frontend Driver
 Flang's frontend driver is the main interface between compiler developers and
 the Flang frontend. The high-level design is similar to Clang's frontend

>From 266687414fd78d8a474d7851cae1009185b68881 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Tue, 19 Dec 2023 15:16:54 +0100
Subject: [PATCH 4/4] Make small addition about static and shared libraries

---
 flang/docs/FlangDriver.md | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/flang/docs/FlangDriver.md b/flang/docs/FlangDriver.md
index bdb3c46455601c..0f9a571f8e0d61 100644
--- a/flang/docs/FlangDriver.md
+++ b/flang/docs/FlangDriver.md
@@ -197,6 +197,12 @@ driver) or use Flang with the `-fno-fortran-main` flag.  This flag removes
 `Fortran_main` from the linker stage and hence requires one of the C/C++
 translation units to provide a definition of the `main` function.
 
+When creating shared or static libraries, `Fortran_main` is automatically
+removed from the linker stage.  It is assumed that when creating a static or
+shared library, the generated library does not need a `main` function, as a
+final link stage will occur that will provide the `Fortran_main` library when
+creating the final executable.
+
 ## Frontend Driver
 Flang's frontend driver is the main interface between compiler developers and
 the Flang frontend. The high-level design is similar to Clang's frontend



More information about the cfe-commits mailing list