Skip to content

Commit 17feb33

Browse files
authored
[flang][Driver] Let the linker fail on multiple definitions of main() (#73124)
The flang driver was silently ignoring the `main()` function in `Fortran_main.a` for entry into the Fortran program unit if an external `main()` as supplied (e.g., via cross-language linkage with Fortran and C/C++). This PR fixes this by making sure that the linker always pulls in the `main()` definition from `Fortran_main.a` and consequently fails due to multiple definitions of the same symbol if another object file also has a definition of `main()`.
1 parent 3a6f02a commit 17feb33

File tree

15 files changed

+81
-14
lines changed

15 files changed

+81
-14
lines changed

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -977,14 +977,60 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
977977
return true;
978978
}
979979

980-
void tools::addFortranRuntimeLibs(const ToolChain &TC,
980+
void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args,
981981
llvm::opt::ArgStringList &CmdArgs) {
982982
// These are handled earlier on Windows by telling the frontend driver to add
983983
// the correct libraries to link against as dependents in the object file.
984984
if (!TC.getTriple().isKnownWindowsMSVCEnvironment()) {
985+
// The --whole-archive option needs to be part of the link line to
986+
// make sure that the main() function from Fortran_main.a is pulled
987+
// in by the linker. Determine if --whole-archive is active when
988+
// flang will try to link Fortran_main.a. If it is, don't add the
989+
// --whole-archive flag to the link line. If it's not, add a proper
990+
// --whole-archive/--no-whole-archive bracket to the link line.
991+
bool WholeArchiveActive = false;
992+
for (auto *Arg : Args.filtered(options::OPT_Wl_COMMA))
993+
if (Arg)
994+
for (StringRef ArgValue : Arg->getValues()) {
995+
if (ArgValue == "--whole-archive")
996+
WholeArchiveActive = true;
997+
if (ArgValue == "--no-whole-archive")
998+
WholeArchiveActive = false;
999+
}
1000+
1001+
if (!WholeArchiveActive)
1002+
CmdArgs.push_back("--whole-archive");
9851003
CmdArgs.push_back("-lFortran_main");
1004+
if (!WholeArchiveActive)
1005+
CmdArgs.push_back("--no-whole-archive");
1006+
1007+
// Perform regular linkage of the remaining runtime libraries.
9861008
CmdArgs.push_back("-lFortranRuntime");
9871009
CmdArgs.push_back("-lFortranDecimal");
1010+
} else {
1011+
unsigned RTOptionID = options::OPT__SLASH_MT;
1012+
if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) {
1013+
RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue())
1014+
.Case("static", options::OPT__SLASH_MT)
1015+
.Case("static_dbg", options::OPT__SLASH_MTd)
1016+
.Case("dll", options::OPT__SLASH_MD)
1017+
.Case("dll_dbg", options::OPT__SLASH_MDd)
1018+
.Default(options::OPT__SLASH_MT);
1019+
}
1020+
switch (RTOptionID) {
1021+
case options::OPT__SLASH_MT:
1022+
CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static.lib");
1023+
break;
1024+
case options::OPT__SLASH_MTd:
1025+
CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static_dbg.lib");
1026+
break;
1027+
case options::OPT__SLASH_MD:
1028+
CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic.lib");
1029+
break;
1030+
case options::OPT__SLASH_MDd:
1031+
CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic_dbg.lib");
1032+
break;
1033+
}
9881034
}
9891035
}
9901036

clang/lib/Driver/ToolChains/CommonArgs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC,
116116
bool IsOffloadingHost = false, bool GompNeedsRT = false);
117117

118118
/// Adds Fortran runtime libraries to \p CmdArgs.
119-
void addFortranRuntimeLibs(const ToolChain &TC,
119+
void addFortranRuntimeLibs(const ToolChain &TC, const llvm::opt::ArgList &Args,
120120
llvm::opt::ArgStringList &CmdArgs);
121121

122122
/// Adds the path for the Fortran runtime libraries to \p CmdArgs.

clang/lib/Driver/ToolChains/Darwin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
678678
// to generate executables.
679679
if (getToolChain().getDriver().IsFlangMode()) {
680680
addFortranRuntimeLibraryPath(getToolChain(), Args, CmdArgs);
681-
addFortranRuntimeLibs(getToolChain(), CmdArgs);
681+
addFortranRuntimeLibs(getToolChain(), Args, CmdArgs);
682682
}
683683

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

clang/lib/Driver/ToolChains/DragonFly.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
153153
// AddRunTimeLibs).
154154
if (D.IsFlangMode()) {
155155
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
156-
addFortranRuntimeLibs(ToolChain, CmdArgs);
156+
addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
157157
CmdArgs.push_back("-lm");
158158
}
159159

clang/lib/Driver/ToolChains/FreeBSD.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
310310
// AddRunTimeLibs).
311311
if (D.IsFlangMode()) {
312312
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
313-
addFortranRuntimeLibs(ToolChain, CmdArgs);
313+
addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
314314
if (Profiling)
315315
CmdArgs.push_back("-lm_p");
316316
else

clang/lib/Driver/ToolChains/Gnu.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
564564
// AddRunTimeLibs).
565565
if (D.IsFlangMode()) {
566566
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
567-
addFortranRuntimeLibs(ToolChain, CmdArgs);
567+
addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
568568
CmdArgs.push_back("-lm");
569569
}
570570

clang/lib/Driver/ToolChains/Haiku.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA,
118118
// AddRunTimeLibs).
119119
if (D.IsFlangMode()) {
120120
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
121-
addFortranRuntimeLibs(ToolChain, CmdArgs);
121+
addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
122122
}
123123

124124
CmdArgs.push_back("-lgcc");

clang/lib/Driver/ToolChains/MSVC.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
131131

132132
if (C.getDriver().IsFlangMode()) {
133133
addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
134-
addFortranRuntimeLibs(TC, CmdArgs);
134+
addFortranRuntimeLibs(TC, Args, CmdArgs);
135135

136136
// Inform the MSVC linker that we're generating a console application, i.e.
137137
// one with `main` as the "user-defined" entry point. The `main` function is

clang/lib/Driver/ToolChains/MinGW.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
249249

250250
if (C.getDriver().IsFlangMode()) {
251251
addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
252-
addFortranRuntimeLibs(TC, CmdArgs);
252+
addFortranRuntimeLibs(TC, Args, CmdArgs);
253253
}
254254

255255
// TODO: Add profile stuff here

clang/lib/Driver/ToolChains/NetBSD.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
325325
// AddRunTimeLibs).
326326
if (D.IsFlangMode()) {
327327
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
328-
addFortranRuntimeLibs(ToolChain, CmdArgs);
328+
addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
329329
CmdArgs.push_back("-lm");
330330
}
331331

clang/lib/Driver/ToolChains/OpenBSD.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
237237
// AddRunTimeLibs).
238238
if (D.IsFlangMode()) {
239239
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
240-
addFortranRuntimeLibs(ToolChain, CmdArgs);
240+
addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
241241
if (Profiling)
242242
CmdArgs.push_back("-lm_p");
243243
else

clang/lib/Driver/ToolChains/Solaris.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
226226
// these dependencies need to be listed before the C runtime below.
227227
if (D.IsFlangMode()) {
228228
addFortranRuntimeLibraryPath(getToolChain(), Args, CmdArgs);
229-
addFortranRuntimeLibs(getToolChain(), CmdArgs);
229+
addFortranRuntimeLibs(getToolChain(), Args, CmdArgs);
230230
CmdArgs.push_back("-lm");
231231
}
232232
if (Args.hasArg(options::OPT_fstack_protector) ||
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
; Create the symbol 'main'; does not have to be the correct
2+
; signature for 'main', we just need the symbol for the linker
3+
; to fail during the test.
4+
5+
define i32 @main() {
6+
ret i32 0
7+
}

flang/test/Driver/linker-flags.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
! executable and may find the GNU linker from MinGW or Cygwin.
2929
! UNIX-LABEL: "{{.*}}ld{{(\.exe)?}}"
3030
! UNIX-SAME: "[[object_file]]"
31-
! UNIX-SAME: "-lFortran_main" "-lFortranRuntime" "-lFortranDecimal" "-lm"
31+
! UNIX-SAME: "--whole-archive" "-lFortran_main" "--no-whole-archive" "-lFortranRuntime" "-lFortranDecimal" "-lm"
3232

3333
! DARWIN-LABEL: "{{.*}}ld{{(\.exe)?}}"
3434
! DARWIN-SAME: "[[object_file]]"
@@ -38,7 +38,7 @@
3838

3939
! HAIKU-LABEL: "{{.*}}ld{{(\.exe)?}}"
4040
! HAIKU-SAME: "[[object_file]]"
41-
! HAIKU-SAME: "-lFortran_main" "-lFortranRuntime" "-lFortranDecimal"
41+
! HAIKU-SAME: "--whole-archive" "-lFortran_main" "--no-whole-archive" "-lFortranRuntime" "-lFortranDecimal"
4242

4343
! MINGW-LABEL: "{{.*}}ld{{(\.exe)?}}"
4444
! MINGW-SAME: "[[object_file]]"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
! UNSUPPORTED: system-windows
2+
3+
! RUN: %flang -x ir -o %t.c-object -c %S/Inputs/no_duplicate_main.ll
4+
! RUN: %flang -o %t -c %s
5+
! RUN: not %flang -o %t.exe %t %t.c-object 2>&1
6+
7+
! TODO: potentially add further checks to ensure that proper
8+
! linker error messages are detected and checked via
9+
! FileCheck.
10+
11+
program main_dupes
12+
! Irrelevant what to do in here.
13+
! Test is supposed to fail at link time.
14+
end program main_dupes

0 commit comments

Comments
 (0)