Skip to content

[flang][driver] Remove Fortain_main static library from linking stages #75816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 25, 2023

Conversation

mjklemm
Copy link
Contributor

@mjklemm mjklemm commented Dec 18, 2023

At present, when building static or shared libraries, Flang adds -lFortran_main.a (or /WHOLEARCHIVE:Fortran.*.lib pon Windows) to the link line. This leads to the problem that _QQmain and _QQEnvironmentDefaults (as of the time of this PR) are symbols marked as used, while main is being defined. This should not happen and this PR fixes this by detecting if -shared or -static is used on the Flang command line and removing the static Fortran_main library.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' flang:driver flang Flang issues not falling into any other category labels Dec 18, 2023
@mjklemm mjklemm self-assigned this Dec 18, 2023
@llvmbot
Copy link
Member

llvmbot commented Dec 18, 2023

@llvm/pr-subscribers-flang-driver
@llvm/pr-subscribers-clang-driver

@llvm/pr-subscribers-clang

Author: Michael Klemm (mjklemm)

Changes

At present, when building static or shared libraries, Flang adds -lFortran_main.a (or /WHOLEARCHIVE:Fortran.*.lib pon Windows) to the link line. This leads to the problem that _QQmain and _QQEnvironmentDefaults (as of the time of this PR) are symbols marked as used, while main is being defined. This should not happen and this PR fixes this by detecting if -shared or -static is used on the Flang command line and removing the static Fortran_main library.


Full diff: https://github.com/llvm/llvm-project/pull/75816.diff

2 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/CommonArgs.cpp (+20)
  • (modified) flang/test/Driver/dynamic-linker.f90 (+6-2)
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 45901ee7157f77..05ebd42829c95d 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1133,6 +1133,16 @@ 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) {
+  return Args.hasArg(options::OPT_shared);
+}
+
+/// 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
 static void addFortranRuntimeLibsMSVC(const ArgList &Args,
                                       llvm::opt::ArgStringList &CmdArgs) {
@@ -1164,6 +1174,16 @@ 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 library, we should not add
+  // -lFortran_main.a to the link line, as the `main` symbol is not
+  // 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) || isStaticLinkage(Args)) {
+    return;
+  }
+
   // 1. MSVC
   if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
     addFortranRuntimeLibsMSVC(Args, CmdArgs);
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"

@banach-space
Copy link
Contributor

Thanks! Mostly looks good, but I have a question:

This leads to the problem that _QQmain and _QQEnvironmentDefaults (as of the time of this PR) are symbols marked as used, while main is being defined.

Sorry for being pedantic, but not sure I follow. FortranMain defines main, which calls _QQmain. However, the latter wouldn't be available in a library, right?

Also, not sure what defines _QQEnvironmentDefaults and what exactly makes it problematic?

Btw, would you mind adding a note to the driver docs?

@mjklemm
Copy link
Contributor Author

mjklemm commented Dec 18, 2023

Thanks! Mostly looks good, but I have a question:

This leads to the problem that _QQmain and _QQEnvironmentDefaults (as of the time of this PR) are symbols marked as used, while main is being defined.

Sorry for being pedantic, but not sure I follow. FortranMain defines main, which calls _QQmain. However, the latter wouldn't be available in a library, right?

Yes, that's correct. The main symbol calls _QQmain, which happens to be the entry point for the Fortran program unit.

Also, not sure what defines _QQEnvironmentDefaults and what exactly makes it problematic?

The main entrypoint also calls _QQEnvironmentDefaults to treat argc, argv, etc. So, when main is included in the shared object, so will be those symbols are used symbols, which makes no sense.

Btw, would you mind adding a note to the driver docs?

Sure, I was planning to do this for the previous PR already but got distracted. Can you point me to the right place to add this? Thanks!

@mjklemm
Copy link
Contributor Author

mjklemm commented Dec 18, 2023

Also, not sure what defines _QQEnvironmentDefaults and what exactly makes it problematic?

The main entrypoint also calls _QQEnvironmentDefaults to treat argc, argv, etc. So, when main is included in the shared object, so will be those symbols are used symbols, which makes no sense.

I need to correct myself: _QQEnvironmentDefaults is not a function that is called, but rather an external file-scope variable that creates that symbol. The symbol used to initialize that is _FortranAProgramStart. Plus, there's _FortranAProgramEndStatement that also used by Fortran_main.a. So, lot's of symbols that should not be in a dynamic library for no reason. :-)

@banach-space
Copy link
Contributor

Sure, I was planning to do this for the previous PR already but got distracted. Can you point me to the right place to add this? Thanks!

Somewhere here:

I would probably create a section on building executables and just mention that 3 runtime libs will be linked auto-magically. Unless somebody uses -fno-fortran-main ;-) Make it as short or as long as you prefer - your contribution is greatly appreciated 🙏🏻 :)

@mjklemm
Copy link
Contributor Author

mjklemm commented Dec 19, 2023

I would probably create a section on building executables and just mention that 3 runtime libs will be linked auto-magically. Unless somebody uses -fno-fortran-main ;-) Make it as short or as long as you prefer - your contribution is greatly appreciated 🙏🏻 :)

I've have written up a first draft. Please have a look and let me know what you think.

@mjklemm
Copy link
Contributor Author

mjklemm commented Dec 19, 2023

@banach-space How did you draw the pictures in the MD file that I'm changing? If you have some sort of source file, I can try to add a nice chart to the explanation, I'm adding.

Copy link
Contributor

@banach-space banach-space left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense, thank you! I really appreciate you fixing this 🙏🏻

@kiranchandramohan - could you also take a look?

@kiranchandramohan
Copy link
Contributor

Looks reasonable to me.

I guess the environment settings that are there in the EnvironmentDefaults apply only when the main program is compiled with some flags. It would be good to check the options in EnvironmentDefaults and see that they are all applicable only when compiled for the main program.

@mjklemm mjklemm requested a review from kkwli December 24, 2023 09:26
Copy link
Collaborator

@kkwli kkwli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG. Thanks.

@mjklemm mjklemm force-pushed the fix_shared_lib_linking branch from 8ff6553 to b29a7fd Compare December 25, 2023 16:35
@mjklemm mjklemm merged commit 9d6837d into llvm:main Dec 25, 2023
@mjklemm
Copy link
Contributor Author

mjklemm commented Dec 26, 2023

Thanks for all the good suggestions!

@mjklemm mjklemm deleted the fix_shared_lib_linking branch December 27, 2023 06:34
@h-vetinari
Copy link
Contributor

For anyone (like me) having to deal with correctly linking Fortran_main with flang 18+, it's worth noting that much of this got removed again in 8d53866.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category flang:driver flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants