Skip to content

Commit 3799114

Browse files
committed
support 0 to many config files (#371)
Summary: Previously OID/OIL required exactly one configuration file. This change makes it so you can supply 0 or more configuration files. 0 is useful if you have pre-generated the cache or use some sort of remote generation system. 1 is useful for the common case, where you have a configuration file that describes your entire source and use just that. More are useful if you have supplemental bits of config you wish to apply/override - see the changes to the integration test framework where we do exactly this. Test Plan: This isn't super well tested. It works for the test cases which add features via the config or enable `codegen.ignore`. - CI Reviewed By: ajor Differential Revision: D49758032 Pulled By: JakeHillion
1 parent 35d45c2 commit 3799114

File tree

12 files changed

+126
-120
lines changed

12 files changed

+126
-120
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,11 +278,11 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
278278
add_subdirectory(oi)
279279
add_subdirectory(resources)
280280
add_library(oicore
281+
oi/Config.cpp
281282
oi/Descs.cpp
282283
oi/Metrics.cpp
283284
oi/OICache.cpp
284285
oi/OICompiler.cpp
285-
oi/OIUtils.cpp
286286
oi/PaddingHunter.cpp
287287
oi/Serialize.cpp
288288
)

include/oi/oi-jit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class OILibraryImpl;
3434
namespace oi {
3535

3636
struct GeneratorOptions {
37-
std::filesystem::path configFilePath;
37+
std::vector<std::filesystem::path> configFilePaths;
3838
std::filesystem::path sourceFileDumpPath;
3939
int debugLevel = 0;
4040
};

oi/OIUtils.cpp renamed to oi/Config.cpp

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
#include "oi/OIUtils.h"
16+
#include "oi/Config.h"
1717

1818
#include <glog/logging.h>
1919

@@ -27,16 +27,48 @@
2727

2828
namespace fs = std::filesystem;
2929

30-
namespace oi::detail::utils {
30+
namespace oi::detail::config {
3131

3232
using namespace std::literals;
3333

34+
namespace {
35+
36+
std::optional<FeatureSet> processConfigFile(const std::string& configFilePath,
37+
OICompiler::Config& compilerConfig,
38+
OICodeGen::Config& generatorConfig);
39+
40+
}
41+
42+
std::optional<FeatureSet> processConfigFiles(
43+
std::span<const fs::path> configFilePaths,
44+
std::map<Feature, bool> featureMap,
45+
OICompiler::Config& compilerConfig,
46+
OICodeGen::Config& generatorConfig) {
47+
FeatureSet enables;
48+
FeatureSet disables;
49+
50+
for (fs::path p : configFilePaths) {
51+
auto fs = processConfigFile(p, compilerConfig, generatorConfig);
52+
if (!fs.has_value())
53+
return std::nullopt;
54+
enables |= *fs;
55+
}
56+
57+
// Override anything from the config files with command line options
58+
for (auto [k, v] : featureMap) {
59+
enables[k] = v;
60+
disables[k] = !v;
61+
}
62+
return handleFeatureConflicts(enables, disables);
63+
}
64+
65+
namespace {
66+
3467
std::optional<FeatureSet> processConfigFile(
3568
const std::string& configFilePath,
36-
std::map<Feature, bool> featureMap,
3769
OICompiler::Config& compilerConfig,
3870
OICodeGen::Config& generatorConfig) {
39-
fs::path configDirectory = fs::path(configFilePath).remove_filename();
71+
fs::path configDirectory = fs::path{configFilePath}.remove_filename();
4072

4173
toml::table config;
4274
try {
@@ -47,6 +79,7 @@ std::optional<FeatureSet> processConfigFile(
4779
return {};
4880
}
4981

82+
FeatureSet enabledFeatures;
5083
if (toml::array* features = config["features"].as_array()) {
5184
for (auto&& el : *features) {
5285
auto* featureStr = el.as_string();
@@ -57,10 +90,7 @@ std::optional<FeatureSet> processConfigFile(
5790

5891
if (auto f = featureFromStr(featureStr->get());
5992
f != Feature::UnknownFeature) {
60-
// Inserts element(s) into the container, if the container doesn't
61-
// already contain an element with an equivalent key. Hence prefer
62-
// command line enabling/disabling.
63-
featureMap.insert({f, true});
93+
enabledFeatures[f] = true;
6494
} else {
6595
LOG(ERROR) << "unrecognised feature: " << featureStr->get()
6696
<< " specified in config";
@@ -204,16 +234,8 @@ std::optional<FeatureSet> processConfigFile(
204234
}
205235
}
206236

207-
FeatureSet enabledFeatures;
208-
FeatureSet disabledFeatures;
209-
for (auto [k, v] : featureMap) {
210-
if (v) {
211-
enabledFeatures[k] = true;
212-
} else {
213-
disabledFeatures[k] = true;
214-
}
215-
}
216-
return handleFeatureConflicts(enabledFeatures, disabledFeatures);
237+
return enabledFeatures;
217238
}
218239

219-
} // namespace oi::detail::utils
240+
} // namespace
241+
} // namespace oi::detail::config

oi/OIUtils.h renamed to oi/Config.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,21 @@
1515
*/
1616
#pragma once
1717

18+
#include <filesystem>
1819
#include <optional>
1920
#include <set>
21+
#include <span>
2022

2123
#include "oi/Features.h"
2224
#include "oi/OICodeGen.h"
2325
#include "oi/OICompiler.h"
2426

25-
namespace oi::detail::utils {
27+
namespace oi::detail::config {
2628

27-
std::optional<FeatureSet> processConfigFile(const std::string& configFilePath,
28-
std::map<Feature, bool> featureMap,
29-
OICompiler::Config& compilerConfig,
30-
OICodeGen::Config& generatorConfig);
29+
std::optional<FeatureSet> processConfigFiles(
30+
std::span<const std::filesystem::path> configFilePaths,
31+
std::map<Feature, bool> featureMap,
32+
OICompiler::Config& compilerConfig,
33+
OICodeGen::Config& generatorConfig);
3134

32-
} // namespace oi::detail::utils
35+
} // namespace oi::detail::config

oi/EnumBitset.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ class EnumBitset {
4747
return bitset.none();
4848
}
4949

50+
EnumBitset<T, N>& operator|=(const EnumBitset<T, N>& that) {
51+
bitset |= that.bitset;
52+
return *this;
53+
}
54+
5055
private:
5156
BitsetType bitset;
5257
};

oi/OID.cpp

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,19 @@
2323
#include <filesystem>
2424
#include <iostream>
2525
#include <map>
26+
#include <string>
27+
#include <vector>
2628

2729
extern "C" {
2830
#include <getopt.h>
2931
#include <libgen.h>
3032
}
3133

34+
#include "oi/Config.h"
3235
#include "oi/Features.h"
3336
#include "oi/Metrics.h"
3437
#include "oi/OIDebugger.h"
3538
#include "oi/OIOpts.h"
36-
#include "oi/OIUtils.h"
3739
#include "oi/PaddingHunter.h"
3840
#include "oi/TimeUtils.h"
3941
#include "oi/TreeBuilder.h"
@@ -249,7 +251,7 @@ namespace Oid {
249251
struct Config {
250252
pid_t pid;
251253
std::string debugInfoFile;
252-
std::string configFile;
254+
std::vector<fs::path> configFiles;
253255
fs::path cacheBasePath;
254256
fs::path customCodeFile;
255257
size_t dataSegSize;
@@ -563,10 +565,11 @@ int main(int argc, char* argv[]) {
563565
oidConfig.compAndExit = true;
564566
break;
565567
case 'c':
566-
oidConfig.configFile = std::string(optarg);
568+
oidConfig.configFiles.emplace_back(optarg);
567569

568-
if (!fs::exists(oidConfig.configFile)) {
569-
LOG(ERROR) << "Non existent config file: " << oidConfig.configFile;
570+
if (!fs::exists(oidConfig.configFiles.back())) {
571+
LOG(ERROR) << "Non existent config file: "
572+
<< oidConfig.configFiles.back();
570573
usage();
571574
return ExitStatus::FileNotFoundError;
572575
}
@@ -630,27 +633,13 @@ int main(int argc, char* argv[]) {
630633
}
631634
}
632635

633-
if (oidConfig.configFile.empty()) {
634-
oidConfig.configFile = "/usr/local/share/oi/base.oid.toml";
635-
636-
if (!fs::exists(oidConfig.configFile)) {
637-
LOG(ERROR) << "Non existent default config file: "
638-
<< oidConfig.configFile;
639-
usage();
640-
return ExitStatus::FileNotFoundError;
641-
}
642-
643-
LOG(INFO) << "Using default config file " << oidConfig.configFile;
644-
}
645-
646636
if (oidConfig.pid != 0 && !oidConfig.debugInfoFile.empty()) {
647637
LOG(INFO) << "'-p' and '-b' are mutually exclusive";
648638
usage();
649639
return ExitStatus::UsageError;
650640
}
651641

652-
if ((oidConfig.pid == 0 && oidConfig.debugInfoFile.empty()) ||
653-
oidConfig.configFile.empty()) {
642+
if ((oidConfig.pid == 0 && oidConfig.debugInfoFile.empty())) {
654643
usage();
655644
return ExitStatus::UsageError;
656645
}
@@ -682,8 +671,8 @@ int main(int argc, char* argv[]) {
682671
.jsonPath = jsonPath,
683672
};
684673

685-
auto featureSet = utils::processConfigFile(oidConfig.configFile, features,
686-
compilerConfig, codeGenConfig);
674+
auto featureSet = config::processConfigFiles(oidConfig.configFiles, features,
675+
compilerConfig, codeGenConfig);
687676
if (!featureSet) {
688677
return ExitStatus::UsageError;
689678
}

oi/OIDebugger.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ extern "C" {
4545
#include <glog/logging.h>
4646

4747
#include "oi/CodeGen.h"
48+
#include "oi/Config.h"
4849
#include "oi/ContainerInfo.h"
4950
#include "oi/Headers.h"
5051
#include "oi/Metrics.h"
5152
#include "oi/OILexer.h"
52-
#include "oi/OIUtils.h"
5353
#include "oi/PaddingHunter.h"
5454
#include "oi/Syscall.h"
5555
#include "oi/type_graph/DrgnParser.h"

oi/OIGenerator.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
#include <variant>
2727

2828
#include "oi/CodeGen.h"
29+
#include "oi/Config.h"
2930
#include "oi/DrgnUtils.h"
3031
#include "oi/Headers.h"
31-
#include "oi/OIUtils.h"
3232

3333
namespace oi::detail {
3434

@@ -193,8 +193,9 @@ int OIGenerator::generate(fs::path& primaryObject, SymbolService& symbols) {
193193
OICompiler::Config compilerConfig{};
194194
compilerConfig.usePIC = pic;
195195

196-
auto features = utils::processConfigFile(configFilePath, featuresMap,
197-
compilerConfig, generatorConfig);
196+
auto features =
197+
config::processConfigFiles(std::vector<fs::path>{configFilePath},
198+
featuresMap, compilerConfig, generatorConfig);
198199
if (!features) {
199200
LOG(ERROR) << "failed to process config file";
200201
return -1;

oi/OILibraryImpl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
#include <fstream>
2626
#include <stdexcept>
2727

28+
#include "oi/Config.h"
2829
#include "oi/DrgnUtils.h"
2930
#include "oi/Headers.h"
30-
#include "oi/OIUtils.h"
3131

3232
namespace oi::detail {
3333
namespace {
@@ -94,8 +94,8 @@ std::pair<void*, const exporters::inst::Inst&> OILibraryImpl::init() {
9494

9595
void OILibraryImpl::processConfigFile() {
9696
auto features =
97-
utils::processConfigFile(opts_.configFilePath, requestedFeatures_,
98-
compilerConfig_, generatorConfig_);
97+
config::processConfigFiles(opts_.configFilePaths, requestedFeatures_,
98+
compilerConfig_, generatorConfig_);
9999
if (!features)
100100
throw std::runtime_error("failed to process configuration");
101101

test/integration/gen_tests.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def define_traceable_func(name, params, body):
136136

137137
oil_func_body = (
138138
f" oi::GeneratorOptions opts{{\n"
139-
f" .configFilePath = configFile,\n"
139+
f" .configFilePaths = configFiles,\n"
140140
f' .sourceFileDumpPath = "oil_jit_code.cpp",\n'
141141
f" .debugLevel = 3,\n"
142142
f" }};\n\n"
@@ -164,11 +164,11 @@ def add_common_code(f):
164164
"""
165165
void usage(const std::string &argv0) {
166166
std::cerr << "usage: " << argv0 << " oid CASE ITERATIONS" << std::endl;
167-
std::cerr << " " << argv0 << " oil CASE CONFIG_FILE" << std::endl;
167+
std::cerr << " " << argv0 << " oil CASE CONFIG_FILE..." << std::endl;
168168
}
169169
170170
int main(int argc, char *argv[]) {
171-
if (argc != 4) {
171+
if (argc < 4) {
172172
usage(argv[0]);
173173
return -1;
174174
}
@@ -179,6 +179,10 @@ def add_common_code(f):
179179
int iterations = 1;
180180
181181
if (mode == "oid") {
182+
if (argc != 4) {
183+
usage(argv[0]);
184+
return -1;
185+
}
182186
std::istringstream iss(argv[3]);
183187
iss >> iterations;
184188
if (iss.fail()) {
@@ -187,7 +191,9 @@ def add_common_code(f):
187191
}
188192
}
189193
else if (mode == "oil") {
190-
configFile = argv[3];
194+
for (int i = 3; i < argc; i++) {
195+
configFiles.emplace_back(argv[i]);
196+
}
191197
}
192198
else {
193199
usage(argv[0]);
@@ -241,7 +247,7 @@ def gen_target(output_target_name, test_configs):
241247
f"thrift/annotation/gen-cpp2/{config['suite']}_types.h"
242248
]
243249
add_headers(f, sorted(headers), thrift_headers)
244-
f.write("std::string configFile;")
250+
f.write("std::vector<std::filesystem::path> configFiles;")
245251

246252
for config in test_configs:
247253
add_test_setup(f, config)
@@ -415,11 +421,13 @@ def gen_runner(output_runner_name, test_configs):
415421
f.write(
416422
"#include <boost/property_tree/json_parser.hpp>\n"
417423
"#include <boost/property_tree/ptree.hpp>\n"
424+
"#include <filesystem>\n"
418425
"#include <fstream>\n"
419426
"#include <gmock/gmock.h>\n"
420427
"#include <gtest/gtest.h>\n"
421-
"#include <string>\n"
422428
"#include <sstream>\n"
429+
"#include <string>\n"
430+
"#include <vector>\n"
423431
'#include "runner_common.h"\n'
424432
"\n"
425433
"namespace ba = boost::asio;\n"

0 commit comments

Comments
 (0)