Skip to content

Commit 558632e

Browse files
committed
Support ldc2.conf being a directory
If ldc2.conf is a directory go through each file (directly) inside it, ordered by name and apply the settings in it. It would be similar to appending all the files and treating it like a normal config file. The specific ordering is the one from llvm::StringRef::compare_numeric. The previous behavior was to always error out if ldc2.conf was a directory, being it passed through `-conf` or being automatically picked up. To account for this change the following restrictions that affect config files have been lifted: - at least one section must match the current triple This is undesirable for cross-compile setups in which one config file is dedicated to one triple - both switches and post-switches must be defined This is undesirable for config files that simply append a CLI switch The above have been replaced by a check that all settings represent valid keys (so switches, post-switches etc.) and that they are of the correct type. Signed-off-by: Andrei Horodniceanu <a.horodniceanu@proton.me>
1 parent a4b1271 commit 558632e

File tree

9 files changed

+228
-58
lines changed

9 files changed

+228
-58
lines changed

driver/config.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class Setting
2626
group,
2727
}
2828

29-
this(string name, Type type)
29+
this(string name, Type type) pure
3030
{
3131
_name = name;
3232
_type = type;

driver/configfile.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
#include "llvm/Support/Path.h"
1717
#include "llvm/Support/Regex.h"
1818
#include <cassert>
19+
#include <cstdio>
1920
#include <cstring>
2021
#include <iostream>
2122
#include <string>
23+
#include <system_error>
2224

2325
#if _WIN32
2426
#define WIN32_LEAN_AND_MEAN
@@ -193,9 +195,42 @@ bool ConfigFile::read(const char *explicitConfFile, const char *triple) {
193195
}
194196

195197
pathcstr = strdup(pathstr.c_str());
196-
auto binpath = exe_path::getBinDir();
198+
return iterateConfigFiles(pathstr, triple);
199+
}
200+
201+
bool ConfigFile::iterateConfigFiles(const std::string &path, const char *triple) {
202+
auto bindirString = exe_path::getBinDir();
203+
auto bindir = bindirString.c_str();
204+
205+
if (!sys::fs::is_directory(path))
206+
return readConfig(pathcstr, triple, bindir);
207+
208+
llvm::SmallVector<std::string, 8> configFiles;
209+
210+
std::error_code ec;
211+
auto it = sys::fs::directory_iterator(path, ec);
212+
do {
213+
if (ec) {
214+
fprintf(stderr, "Could not iterate config directory at %s: %s\n",
215+
path.c_str(), ec.message().c_str());
216+
return false;
217+
}
218+
if (it->type() == sys::fs::file_type::directory_file)
219+
continue;
220+
221+
configFiles.emplace_back(it->path());
222+
} while (it.increment(ec) != sys::fs::directory_iterator{});
223+
224+
llvm::sort(configFiles, [](const std::string &a, const std::string &b) {
225+
auto sa = llvm::StringRef(a), sb = llvm::StringRef(b);
226+
return sa.compare_numeric(sb) < 0;
227+
});
228+
229+
for (const auto &configPath: configFiles)
230+
if (!readConfig(configPath.c_str(), triple, bindir))
231+
return false;
197232

198-
return readConfig(pathcstr, triple, binpath.c_str());
233+
return true;
199234
}
200235

201236
void ConfigFile::extendCommandLine(llvm::SmallVectorImpl<const char *> &args) {

driver/configfile.d

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,19 @@ string normalizeSlashes(const(char)* binDir)
2929
return cast(string)res; // assumeUnique
3030
}
3131

32-
const(string)[] findArraySetting(GroupSetting[] sections, string name)
32+
void findArraySetting(GroupSetting[] sections, string name, scope void delegate(const ArraySetting as) callback)
3333
{
34-
const(string)[] result = null;
3534
foreach (section; sections)
3635
{
3736
foreach (c; section.children)
3837
{
3938
if (c.type == Setting.Type.array && c.name == name)
4039
{
4140
auto as = cast(ArraySetting) c;
42-
if (as.isAppending)
43-
result ~= as.vals;
44-
else
45-
result = as.vals;
41+
callback(as);
4642
}
4743
}
4844
}
49-
return result;
5045
}
5146

5247
string findScalarSetting(GroupSetting[] sections, string name)
@@ -128,6 +123,49 @@ string replacePlaceholders(string str, CfgPaths cfgPaths)
128123
.replace("%%ldcversion%%", cast(string) global.ldc_version);
129124
}
130125

126+
/++ Check that a section only contains known config keys
127+
128+
ldc recognizes:
129+
- switches
130+
- post-switches
131+
- lib-dirs
132+
- rpath
133+
+/
134+
void validateSettingNames(const GroupSetting group, const char* filePath) {
135+
static void fail(const Setting setting, const char* filePath) {
136+
string fmt(Setting.Type type) {
137+
final switch(type) {
138+
static foreach (mem; __traits(allMembers, Setting.Type))
139+
case __traits(getMember, Setting.Type, mem):
140+
return mem;
141+
}
142+
}
143+
144+
import dmd.root.string : toDString;
145+
string msg;
146+
if (setting.type == Setting.Type.group)
147+
msg = "Nested group " ~ setting.name ~ " is unsupported";
148+
else
149+
msg = "Unknown " ~ fmt(setting.type) ~ " setting named " ~ setting.name;
150+
151+
throw new Exception(msg);
152+
}
153+
154+
alias ST = Setting.Type;
155+
static immutable knownSettings = [
156+
new Setting("switches", ST.array),
157+
new Setting("post-switches", ST.array),
158+
new Setting("lib-dirs", ST.array),
159+
new Setting("rpath", ST.scalar),
160+
];
161+
outer: foreach (setting; group.children) {
162+
foreach (known; knownSettings)
163+
if (setting.name == known.name && setting.type == known.type)
164+
continue outer;
165+
fail(setting, filePath);
166+
}
167+
}
168+
131169
extern(C++) struct ConfigFile
132170
{
133171
__gshared ConfigFile instance;
@@ -160,37 +198,34 @@ private:
160198
}
161199
}
162200

163-
if (sections.length == 0)
164-
{
165-
throw new Exception("No matching section for triple '" ~ cast(string) triple.toDString
166-
~ "'");
167-
}
168-
169-
const switches = findArraySetting(sections, "switches");
170-
const postSwitches = findArraySetting(sections, "post-switches");
171-
if (switches.length + postSwitches.length == 0)
172-
throw new Exception("Could not look up switches");
201+
foreach (group; sections)
202+
validateSettingNames(group, cfPath);
173203

174-
void applyArray(ref Array!(const(char)*) output, const(string)[] input)
204+
void readArraySetting(GroupSetting[] sections, string name, ref Array!(const(char)*) output)
175205
{
176-
output.setDim(0);
177-
178-
output.reserve(input.length);
179-
foreach (sw; input)
206+
void applyArray(const ArraySetting input)
180207
{
181-
const finalSwitch = sw.replacePlaceholders(cfgPaths).toCString;
182-
output.push(finalSwitch.ptr);
208+
if (!input.isAppending)
209+
output.setDim(0);
210+
211+
output.reserve(input.vals.length);
212+
foreach (sw; input.vals)
213+
{
214+
const finalSwitch = sw.replacePlaceholders(cfgPaths).toCString;
215+
output.push(finalSwitch.ptr);
216+
}
183217
}
218+
findArraySetting(sections, name, &applyArray);
184219
}
185220

186-
applyArray(this.switches, switches);
187-
applyArray(this.postSwitches, postSwitches);
188-
189-
const libDirs = findArraySetting(sections, "lib-dirs");
190-
applyArray(_libDirs, libDirs);
191-
221+
readArraySetting(sections, "switches", switches);
222+
readArraySetting(sections, "post-switches", postSwitches);
223+
readArraySetting(sections, "lib-dirs", _libDirs);
192224
const rpath = findScalarSetting(sections, "rpath");
193-
this.rpathcstr = rpath.length == 0 ? null : rpath.replacePlaceholders(cfgPaths).toCString.ptr;
225+
// A missing rpath => do nothing
226+
// An empty rpath => clear the setting
227+
if (rpath.ptr !is null)
228+
this.rpathcstr = rpath.length == 0 ? null : rpath.replacePlaceholders(cfgPaths).toCString.ptr;
194229

195230
return true;
196231
}

driver/configfile.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ struct ConfigFile {
4343
// implemented in D
4444
bool readConfig(const char *cfPath, const char *triple, const char *binDir);
4545

46+
bool iterateConfigFiles(const std::string &path, const char *triple);
47+
4648
const char *pathcstr = nullptr;
4749
Array<const char *> switches;
4850
Array<const char *> postSwitches;

tests/driver/config_diag.d

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
1-
// RUN: %ldc -o- -conf=%S/inputs/noswitches.conf %s 2>&1 | FileCheck %s --check-prefix=NOSWITCHES
2-
// NOSWITCHES: Error while reading config file: {{.*}}noswitches.conf
3-
// NOSWITCHES-NEXT: Could not look up switches
1+
// RUN: split-file %s %t
42

5-
// RUN: %ldc -o- -conf=%S/inputs/section_aaa.conf %s 2>&1 | FileCheck %s --check-prefix=NO_SEC
6-
// NO_SEC: Error while reading config file: {{.*}}section_aaa.conf
7-
// NO_SEC-NEXT: No matching section for triple '{{.*}}'
3+
// RUN: %ldc -o- -conf=%t/invalid_setting.conf %s 2>&1 | FileCheck %s --check-prefix=INV_SET
4+
// INV_SET: Error while reading config file: {{.*}}invalid_setting.conf
5+
// INV_SET-NEXT: Unknown scalar setting named blah-blah
86

9-
// RUN: %ldc -o- -conf=%S/inputs/invalid_append.conf %s 2>&1 | FileCheck %s --check-prefix=APP
7+
// RUN: %ldc -o- -conf=%t/invalid_append.conf %s 2>&1 | FileCheck %s --check-prefix=APP
108
// APP: Error while reading config file: {{.*}}invalid_append.conf
119
// APP-NEXT: line 3: '~=' is not supported with scalar values
1210

1311
module object;
12+
13+
/+ config dirs used by the tests
14+
15+
//--- invalid_setting.conf
16+
default:
17+
{
18+
blah-blah = "12";
19+
};
20+
21+
//--- invalid_append.conf
22+
default:
23+
{
24+
rpath ~= "/path";
25+
}
26+
//--- end_of_files
27+
+/

tests/driver/config_dir.d

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// RUN: split-file %s %t
2+
module object;
3+
4+
alias string = immutable(char)[];
5+
6+
template Version(string ident) {
7+
mixin(`version(` ~ ident ~ `)
8+
enum Version = true;
9+
else
10+
enum Version = false;
11+
`);
12+
}
13+
14+
// RUN: %ldc -d-version=TEST_ORDER -o- -conf=%t/order.conf %s 2>&1
15+
version (TEST_ORDER) {
16+
static assert(!Version!"File1");
17+
static assert(Version!"File2");
18+
static assert(!Version!"File3");
19+
}
20+
21+
// RUN: %ldc -d-version=TEST_APPENDING -o- -conf=%t/appending.conf %s 2>&1
22+
version (TEST_APPENDING) {
23+
static assert(!Version!"File1_Sec1");
24+
static assert(!Version!"File1_Sec2");
25+
26+
static assert(!Version!"File2_Sec1");
27+
static assert(Version!"File2_Sec2");
28+
29+
static assert(Version!"File3_Sec1");
30+
static assert(Version!"File3_Sec2");
31+
}
32+
33+
version (TEST_RPATH) {}
34+
// RUN: not %ldc -d-version=TEST_RPATH -conf=%t/multiple_rpaths.conf -link-defaultlib-shared=true -v %s 2>&1 | FileCheck %s --check-prefix=RPATHS
35+
// RPATHS-NOT: /first_rpath
36+
37+
// RUN: not %ldc -d-version=TEST_RPATH -conf=%t/rpath_clear.conf -link-defaultlib-shared=true -v %s 2>&1 | FileCheck %s --check-prefix=RPATHSCLEAR
38+
// RPATHSCLEAR-NOT: /first_rpath
39+
40+
41+
/+ config dirs used by the tests
42+
43+
//--- order.conf/conf-11
44+
default: {
45+
switches = [ "-d-version=File1" ]
46+
}
47+
//--- order.conf/conf-102
48+
default: {
49+
switches = [ "-d-version=File2" ]
50+
}
51+
//--- order.conf/conf-103/conf
52+
default: {
53+
switches = [ "-d-version=File3" ];
54+
}
55+
56+
//--- appending.conf/01.conf
57+
default: {
58+
switches ~= [ "-d-version=File1_Sec1" ]
59+
}
60+
".?": {
61+
switches = [ "-d-version=File1_Sec2" ]
62+
}
63+
//--- appending.conf/02.conf
64+
default: {
65+
switches ~= [ "-d-version=File2_Sec1" ]
66+
}
67+
".?": {
68+
switches = [ "-d-version=File2_Sec2" ]
69+
}
70+
//--- appending.conf/03.conf
71+
default: {
72+
switches ~= [ "-d-version=File3_Sec1" ]
73+
}
74+
".?": {
75+
switches ~= [ "-d-version=File3_Sec2" ]
76+
}
77+
78+
//--- multiple_rpaths.conf/01.conf
79+
default: {
80+
switches = [ "-link-defaultlib-shared" ]
81+
rpath = "/first_rpath";
82+
}
83+
//--- multiple_rpaths.conf/02.conf
84+
default: {
85+
rpath = "/second_rpath";
86+
}
87+
//--- multiple_rpaths.conf/03.conf
88+
default: {
89+
// no rpath
90+
}
91+
92+
//--- rpath_clear.conf
93+
default: {
94+
rpath = "/first_rpath"
95+
}
96+
default: {
97+
rpath = "" // this should clear the previous value
98+
}
99+
100+
//--- end_of_files
101+
+/

tests/driver/inputs/invalid_append.conf

Lines changed: 0 additions & 10 deletions
This file was deleted.

tests/driver/inputs/noswitches.conf

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/driver/inputs/section_aaa.conf

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)