Skip to content

Commit 9d6837d

Browse files
mjklemmkkwli
andauthored
[flang][driver] Remove Fortain_main static library from linking stages (#75816)
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. --------- Co-authored-by: kkwli <[email protected]>
1 parent 95bdbc8 commit 9d6837d

File tree

3 files changed

+83
-2
lines changed

3 files changed

+83
-2
lines changed

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,16 @@ static bool isWholeArchivePresent(const ArgList &Args) {
11331133
return WholeArchiveActive;
11341134
}
11351135

1136+
/// Determine if driver is invoked to create a shared object library (-static)
1137+
static bool isSharedLinkage(const ArgList &Args) {
1138+
return Args.hasArg(options::OPT_shared);
1139+
}
1140+
1141+
/// Determine if driver is invoked to create a static object library (-shared)
1142+
static bool isStaticLinkage(const ArgList &Args) {
1143+
return Args.hasArg(options::OPT_static);
1144+
}
1145+
11361146
/// Add Fortran runtime libs for MSVC
11371147
static void addFortranRuntimeLibsMSVC(const ArgList &Args,
11381148
llvm::opt::ArgStringList &CmdArgs) {
@@ -1164,6 +1174,16 @@ static void addFortranRuntimeLibsMSVC(const ArgList &Args,
11641174
// Add FortranMain runtime lib
11651175
static void addFortranMain(const ToolChain &TC, const ArgList &Args,
11661176
llvm::opt::ArgStringList &CmdArgs) {
1177+
// 0. Shared-library linkage
1178+
// If we are attempting to link a library, we should not add
1179+
// -lFortran_main.a to the link line, as the `main` symbol is not
1180+
// required for a library and should also be provided by one of
1181+
// the translation units of the code that this shared library
1182+
// will be linked against eventually.
1183+
if (isSharedLinkage(Args) || isStaticLinkage(Args)) {
1184+
return;
1185+
}
1186+
11671187
// 1. MSVC
11681188
if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
11691189
addFortranRuntimeLibsMSVC(Args, CmdArgs);

flang/docs/FlangDriver.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,63 @@ forward compiler options to the frontend driver, `flang-new -fc1`.
163163
You can read more on the design of `clangDriver` in Clang's [Driver Design &
164164
Internals](https://clang.llvm.org/docs/DriverInternals.html).
165165

166+
## Linker Driver
167+
When used as a linker, Flang's frontend driver assembles the command line for an
168+
external linker command (e.g., LLVM's `lld`) and invokes it to create the final
169+
executable by linking static and shared libraries together with all the
170+
translation units supplied as object files.
171+
172+
By default, the Flang linker driver adds several libraries to the linker
173+
invocation to make sure that all entrypoints for program start
174+
(Fortran's program unit) and runtime routines can be resolved by the linker.
175+
176+
An abridged example (only showing the Fortran specific linker flags, omission
177+
indicated by `[...]`) for such a linker invocation on a Linux system would look
178+
like this:
179+
180+
```
181+
$ flang -v -o example example.o
182+
"/usr/bin/ld" [...] example.o [...] "--whole-archive" "-lFortran_main"
183+
"--no-whole-archive" "-lFortranRuntime" "-lFortranDecimal" [...]
184+
```
185+
186+
The automatically added libraries are:
187+
188+
* `Fortran_main`: Provides the main entry point `main` that then invokes
189+
`_QQmain` with the Fortran program unit. This library has a dependency to
190+
the `FortranRuntime` library.
191+
* `FortranRuntime`: Provides most of the Flang runtime library.
192+
* `FortranDecimal`: Provides operations for decimal numbers.
193+
194+
The default is that, when using Flang as the linker, one of the Fortran
195+
translation units provides the program unit and therefore it is assumed that
196+
Fortran is the main code part (calling into C/C++ routines via `BIND (C)`
197+
interfaces). When composing the linker commandline, Flang uses
198+
`--whole-archive` and `--no-whole-archive` (Windows: `/WHOLEARCHIVE:`,
199+
Darwin & AIX: *not implemented yet*) to make sure that all for `Fortran_main`
200+
is processed by the linker. This is done to issue a proper error message when
201+
multiple definitions of `main` occur. This happens, for instance, when linking
202+
a code that has a Fortran program unit with a C/C++ code that also defines a
203+
`main` function. A user may be required to explicitly provide the C++ runtime
204+
libraries at link time (e.g., via `-lstdc++` for STL)
205+
206+
If the code is C/C++ based and invokes Fortran routines, one can either use Clang
207+
or Flang as the linker driver. If Clang is used, it will automatically all
208+
required runtime libraries needed by C++ (e.g., for STL) to the linker invocation.
209+
In this case, one has to explicitly provide the Fortran runtime libraries
210+
`FortranRuntime` and/or `FortranDecimal`. An alternative is to use Flang to link
211+
and use the `-fno-fortran-main` flag. This flag removes
212+
`Fortran_main` from the linker stage and hence requires one of the C/C++
213+
translation units to provide a definition of the `main` function. In this case,
214+
it may be required to explicitly supply C++ runtime libraries as mentioned above.
215+
216+
When creating shared or static libraries using Flang with `-shared` or `-static`
217+
flag, Fortran_main is automatically removed from the linker stage (i.e.,
218+
`-fno-fortran-main` is on by default). It is assumed that when creating a
219+
static or shared library, the generated library does not need a `main`
220+
function, as a final link stage will occur that will provide the `Fortran_main`
221+
library when creating the final executable.
222+
166223
## Frontend Driver
167224
Flang's frontend driver is the main interface between compiler developers and
168225
the Flang frontend. The high-level design is similar to Clang's frontend

flang/test/Driver/dynamic-linker.f90

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@
33

44
! RUN: %flang -### --target=x86_64-linux-gnu -rpath /path/to/dir -shared \
55
! RUN: -static %s 2>&1 | FileCheck \
6-
! RUN: --check-prefixes=GNU-LINKER-OPTIONS %s
6+
! RUN: --check-prefixes=GNU-LINKER-OPTIONS \
7+
! RUN: --implicit-check-not=GNU-LINKER-OPTIONS-NOT %s
78
! RUN: %flang -### --target=x86_64-windows-msvc -rpath /path/to/dir -shared \
89
! RUN: -static %s 2>&1 | FileCheck \
9-
! RUN: --check-prefixes=MSVC-LINKER-OPTIONS %s
10+
! RUN: --check-prefixes=MSVC-LINKER-OPTIONS \
11+
! RUN: --implicit-check-not=MSVC-LINKER-OPTIONS-NOT %s
1012
! RUN: %flang -### --target=aarch64-linux-none -rdynamic %s 2>&1 | FileCheck --check-prefixes=RDYNAMIC-LINKER-OPTION %s
1113

1214
! TODO: Could the linker have an extension or a suffix?
1315
! GNU-LINKER-OPTIONS: "{{.*}}ld{{(.exe)?}}"
1416
! GNU-LINKER-OPTIONS-SAME: "-shared"
1517
! GNU-LINKER-OPTIONS-SAME: "-static"
1618
! GNU-LINKER-OPTIONS-SAME: "-rpath" "/path/to/dir"
19+
! GNU-LINKER-OPTIONS-NOT: "-lFortran_main.a"
1720

1821
! RDYNAMIC-LINKER-OPTION: "{{.*}}ld"
1922
! RDYNAMIC-LINKER-OPTION-SAME: "-export-dynamic"
@@ -22,3 +25,4 @@
2225
! MSVC-LINKER-OPTIONS: "{{.*}}link{{(.exe)?}}"
2326
! MSVC-LINKER-OPTIONS-SAME: "-dll"
2427
! MSVC-LINKER-OPTIONS-SAME: "-rpath" "/path/to/dir"
28+
! MSVC-LINKER-OPTIONS-NOT: "/WHOLEARCHIVE:Fortran_main"

0 commit comments

Comments
 (0)