Skip to content

Commit c599850

Browse files
committed
[clang][driver] Use $ prefix with config file options to have them added after all of the command line options
Currently, if a -l (or -Wl,) flag is added into a config file (e.g. clang.cfg), it is situated before any object file in the effective command line. If the library requested by given -l flag is static, its symbols will not be made visible to any of the object files provided by the user. Also, the presence of any of the linker flags in a config file confuses the driver whenever the user invokes clang without any parameters (see issue #67209). This patch attempts to solve both of the problems, by allowing a split of the arguments list into two parts. The head part of the list will be used as before, but the tail part will be appended after the command line flags provided by the user and only when it is known that the linking should occur. The $-prefixed arguments will be added to the tail part.
1 parent 691e556 commit c599850

File tree

7 files changed

+122
-16
lines changed

7 files changed

+122
-16
lines changed

clang/docs/UsersManual.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,16 @@ In this way, the user may only need to specify a root configuration file with
10591059
-L <CFGDIR>/lib
10601060
-T <CFGDIR>/ldscripts/link.ld
10611061

1062+
Usually, config file options are placed before command-line options, regardless
1063+
of the actual operation to be performed. The exception is being made for the
1064+
options prefixed with the ``$`` character. These will be used only when linker
1065+
is being invoked, and added after all of the command-line specified linker
1066+
inputs. Here is some example of ``$``-prefixed options:
1067+
1068+
::
1069+
$-Wl,-Bstatic $-lm
1070+
$-Wl,-Bshared
1071+
10621072
Language and Target-Independent Features
10631073
========================================
10641074

clang/include/clang/Driver/Driver.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,11 @@ class Driver {
297297
/// Object that stores strings read from configuration file.
298298
llvm::StringSaver Saver;
299299

300-
/// Arguments originated from configuration file.
301-
std::unique_ptr<llvm::opt::InputArgList> CfgOptions;
300+
/// Arguments originated from configuration file (head part).
301+
std::unique_ptr<llvm::opt::InputArgList> CfgOptionsHead;
302+
303+
/// Arguments originated from configuration file (tail part).
304+
std::unique_ptr<llvm::opt::InputArgList> CfgOptionsTail;
302305

303306
/// Arguments originated from command line.
304307
std::unique_ptr<llvm::opt::InputArgList> CLOptions;

clang/lib/Driver/Driver.cpp

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,34 +1039,59 @@ bool Driver::readConfigFile(StringRef FileName,
10391039
}
10401040

10411041
// Try reading the given file.
1042-
SmallVector<const char *, 32> NewCfgArgs;
1043-
if (llvm::Error Err = ExpCtx.readConfigFile(FileName, NewCfgArgs)) {
1042+
SmallVector<const char *, 32> NewCfgFileArgs;
1043+
if (llvm::Error Err = ExpCtx.readConfigFile(FileName, NewCfgFileArgs)) {
10441044
Diag(diag::err_drv_cannot_read_config_file)
10451045
<< FileName << toString(std::move(Err));
10461046
return true;
10471047
}
10481048

1049+
// Populate head and tail lists. The tail list is used only when linking.
1050+
SmallVector<const char *, 32> NewCfgHeadArgs, NewCfgTailArgs;
1051+
for (const char *Opt : NewCfgFileArgs) {
1052+
// An $-prefixed option should go to the tail list.
1053+
if (Opt[0] == '$' && Opt[1])
1054+
NewCfgTailArgs.push_back(Opt + 1);
1055+
else
1056+
NewCfgHeadArgs.push_back(Opt);
1057+
}
1058+
10491059
// Read options from config file.
10501060
llvm::SmallString<128> CfgFileName(FileName);
10511061
llvm::sys::path::native(CfgFileName);
1052-
bool ContainErrors;
1053-
auto NewOptions = std::make_unique<InputArgList>(
1054-
ParseArgStrings(NewCfgArgs, /*UseDriverMode=*/true, ContainErrors));
1062+
bool ContainErrors = false;
1063+
auto NewHeadOptions = std::make_unique<InputArgList>(
1064+
ParseArgStrings(NewCfgHeadArgs, /*UseDriverMode=*/true, ContainErrors));
1065+
if (ContainErrors)
1066+
return true;
1067+
auto NewTailOptions = std::make_unique<InputArgList>(
1068+
ParseArgStrings(NewCfgTailArgs, /*UseDriverMode=*/true, ContainErrors));
10551069
if (ContainErrors)
10561070
return true;
10571071

10581072
// Claim all arguments that come from a configuration file so that the driver
10591073
// does not warn on any that is unused.
1060-
for (Arg *A : *NewOptions)
1074+
for (Arg *A : *NewHeadOptions)
1075+
A->claim();
1076+
for (Arg *A : *NewTailOptions)
10611077
A->claim();
10621078

1063-
if (!CfgOptions)
1064-
CfgOptions = std::move(NewOptions);
1079+
if (!CfgOptionsHead)
1080+
CfgOptionsHead = std::move(NewHeadOptions);
1081+
else {
1082+
// If this is a subsequent config file, append options to the previous one.
1083+
for (auto *Opt : *NewHeadOptions)
1084+
appendOneArg(*CfgOptionsHead, Opt);
1085+
}
1086+
1087+
if (!CfgOptionsTail)
1088+
CfgOptionsTail = std::move(NewTailOptions);
10651089
else {
10661090
// If this is a subsequent config file, append options to the previous one.
1067-
for (auto *Opt : *NewOptions)
1068-
appendOneArg(*CfgOptions, Opt);
1091+
for (auto *Opt : *NewTailOptions)
1092+
appendOneArg(*CfgOptionsTail, Opt);
10691093
}
1094+
10701095
ConfigFiles.push_back(std::string(CfgFileName));
10711096
return false;
10721097
}
@@ -1243,13 +1268,14 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
12431268
// Try parsing configuration file.
12441269
if (!ContainsError)
12451270
ContainsError = loadConfigFiles();
1246-
bool HasConfigFile = !ContainsError && (CfgOptions.get() != nullptr);
1271+
bool HasConfigFileHead = !ContainsError && CfgOptionsHead;
1272+
bool HasConfigFileTail = !ContainsError && CfgOptionsTail;
12471273

12481274
// All arguments, from both config file and command line.
1249-
InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions)
1250-
: std::move(*CLOptions));
1275+
InputArgList Args =
1276+
HasConfigFileHead ? std::move(*CfgOptionsHead) : std::move(*CLOptions);
12511277

1252-
if (HasConfigFile)
1278+
if (HasConfigFileHead)
12531279
for (auto *Opt : *CLOptions)
12541280
if (!Opt->getOption().matches(options::OPT_config))
12551281
appendOneArg(Args, Opt);
@@ -1540,6 +1566,15 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
15401566
// Construct the list of inputs.
15411567
InputList Inputs;
15421568
BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs);
1569+
if (HasConfigFileTail && Inputs.size()) {
1570+
Arg *FinalPhaseArg;
1571+
if (getFinalPhase(*TranslatedArgs, &FinalPhaseArg) == phases::Link) {
1572+
DerivedArgList TranslatedLinkerIns(*CfgOptionsTail);
1573+
for (Arg *A : *CfgOptionsTail)
1574+
TranslatedLinkerIns.append(A);
1575+
BuildInputs(C->getDefaultToolChain(), TranslatedLinkerIns, Inputs);
1576+
}
1577+
}
15431578

15441579
// Populate the tool chains for the offloading devices, if any.
15451580
CreateOffloadingDeviceToolChains(*C, Inputs);

clang/test/Driver/Inputs/config-l.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-Wall $-lm
2+
-Wl,--as-needed $-Wl,-Bstatic
3+
$-lhappy $-Wl,-Bdynamic

clang/test/Driver/config-file.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,29 @@
8282
// CHECK-TWO-CONFIGS: -isysroot
8383
// CHECK-TWO-CONFIGS-SAME: /opt/data
8484
// CHECK-TWO-CONFIGS-SAME: -Wall
85+
86+
//--- The linker input flags should be moved to the end of input list and appear only when linking.
87+
// RUN: %clang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg %s -lmylib -Wl,foo.a -### 2>&1 | FileCheck %s -check-prefix CHECK-LINKING
88+
// RUN: %clang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -fopenmp %s -lmylib -Wl,foo.a -### 2>&1 | FileCheck %s -check-prefix CHECK-LINKING-LIBOMP-GOES-AFTER
89+
// RUN: %clang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -S %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NOLINKING
90+
// RUN: %clang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -fopenmp -S %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NOLINKING-OPENMP
91+
// RUN: %clang --target=x86_64-pc-windows-msvc --config %S/Inputs/config-l.cfg %s -lmylib -Wl,foo.lib -### 2>&1 | FileCheck %s -check-prefix CHECK-LINKING-MSVC
92+
// RUN: %clang --target=x86_64-pc-windows-msvc --config %S/Inputs/config-l.cfg -S %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NOLINKING-MSVC
93+
// CHECK-LINKING: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
94+
// CHECK-LINKING: "-Wall"
95+
// CHECK-LINKING: "--as-needed" "{{.*}}-{{.*}}.o" "-lmylib" "foo.a" "-lm" "-Bstatic" "-lhappy" "-Bdynamic"
96+
// CHECK-LINKING-LIBOMP-GOES-AFTER: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
97+
// CHECK-LINKING-LIBOMP-GOES-AFTER: "-Wall" {{.*}}"-fopenmp"
98+
// CHECK-LINKING-LIBOMP-GOES-AFTER: "--as-needed" "{{.*}}-{{.*}}.o" "-lmylib" "foo.a" "-lm" "-Bstatic" "-lhappy" "-Bdynamic" {{.*}}"-lomp"
99+
// CHECK-NOLINKING: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
100+
// CHECK-NOLINKING: "-Wall"
101+
// CHECK-NOLINKING-NO: "-lm" "-Bstatic" "-lhappy" "-Bdynamic"
102+
// CHECK-NOLINKING-OPENMP: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
103+
// CHECK-NOLINKING-OPENMP: "-Wall" {{.*}}"-fopenmp"
104+
// CHECK-NOLINKING-OPENMP-NO: "-lm" "-Bstatic" "-lhappy" "-Bdynamic" {{.*}}"-lomp"
105+
// CHECK-LINKING-MSVC: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
106+
// CHECK-LINKING-MSVC: "-Wall"
107+
// CHECK-LINKING-MSVC: "--as-needed" "{{.*}}-{{.*}}.o" "mylib.lib" "foo.lib" "m.lib" "-Bstatic" "happy.lib" "-Bdynamic"
108+
// CHECK-NOLINKING-MSVC: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
109+
// CHECK-NOLINKING-MSVC: "-Wall"
110+
// CHECK-NOLINKING-MSVC-NO: "m.lib" "-Bstatic" "happy.lib" "-Bdynamic"

flang/test/Driver/Inputs/config-l.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-ffast-math $-lm
2+
-Wl,--as-needed $-Wl,-Bstatic
3+
$-lhappy $-Wl,-Bdynamic

flang/test/Driver/config-file.f90

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,29 @@
6161
! CHECK-TWO-CONFIGS-NEXT: Configuration file: {{.*}}Inputs{{.}}config2{{.}}config-4.cfg
6262
! CHECK-TWO-CONFIGS: -ffp-contract=fast
6363
! CHECK-TWO-CONFIGS: -O3
64+
65+
!--- The linker input flags should be moved to the end of input list and appear only when linking.
66+
! RUN: %flang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg %s -lmylib -Wl,foo.a -### 2>&1 | FileCheck %s -check-prefix CHECK-LINKING
67+
! RUN: %flang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -fopenmp %s -lmylib -Wl,foo.a -### 2>&1 | FileCheck %s -check-prefix CHECK-LINKING-LIBOMP-GOES-AFTER
68+
! RUN: %flang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -S %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NOLINKING
69+
! RUN: %flang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -fopenmp -S %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NOLINKING-OPENMP
70+
! RUN: %flang --target=x86_64-pc-windows-msvc --config %S/Inputs/config-l.cfg %s -lmylib -Wl,foo.lib -### 2>&1 | FileCheck %s -check-prefix CHECK-LINKING-MSVC
71+
! RUN: %flang --target=x86_64-pc-windows-msvc --config %S/Inputs/config-l.cfg -S %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NOLINKING-MSVC
72+
! CHECK-LINKING: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
73+
! CHECK-LINKING: "-ffast-math"
74+
! CHECK-LINKING: "--as-needed" "{{.*}}-{{.*}}.o" "-lmylib" "foo.a" "-lm" "-Bstatic" "-lhappy" "-Bdynamic"
75+
! CHECK-LINKING-LIBOMP-GOES-AFTER: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
76+
! CHECK-LINKING-LIBOMP-GOES-AFTER: "-ffast-math" {{.*}}"-fopenmp"
77+
! CHECK-LINKING-LIBOMP-GOES-AFTER: "--as-needed" "{{.*}}-{{.*}}.o" "-lmylib" "foo.a" "-lm" "-Bstatic" "-lhappy" "-Bdynamic" {{.*}}"-lomp"
78+
! CHECK-NOLINKING: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
79+
! CHECK-NOLINKING: "-ffast-math"
80+
! CHECK-NOLINKING-NO: "-lm" "-Bstatic" "-lhappy" "-Bdynamic"
81+
! CHECK-NOLINKING-OPENMP: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
82+
! CHECK-NOLINKING-OPENMP: "-ffast-math" {{.*}}"-fopenmp"
83+
! CHECK-NOLINKING-OPENMP-NO: "-lm" "-Bstatic" "-lhappy" "-Bdynamic" {{.}}"-lomp"
84+
! CHECK-LINKING-MSVC: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
85+
! CHECK-LINKING-MSVC: "-ffast-math"
86+
! CHECK-LINKING-MSVC: "--as-needed" "{{.*}}-{{.*}}.o" "mylib.lib" "foo.lib" "m.lib" "-Bstatic" "happy.lib" "-Bdynamic"
87+
! CHECK-NOLINKING-MSVC: Configuration file: {{.*}}Inputs{{.}}config-l.cfg
88+
! CHECK-NOLINKING-MSVC: "-ffast-math"
89+
! CHECK-NOLINKING-MSVC-NO: "m.lib" "-Bstatic" "happy.lib" "-Bdynamic"

0 commit comments

Comments
 (0)