1 //===- Configuration.cpp - Configuration Data Mgmt --------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the parsing of configuration files for the LLVM Compiler
13 //===----------------------------------------------------------------------===//
15 #include "Configuration.h"
16 #include "ConfigLexer.h"
17 #include "CompilerDriver.h"
18 #include "llvm/Config/config.h"
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/ADT/StringExtras.h"
27 // From CompilerDriver.cpp (for now)
28 extern bool FileIsReadable(const std::string& fname);
32 ConfigLexerInfo ConfigLexerState;
33 InputProvider* ConfigLexerInput = 0;
35 InputProvider::~InputProvider() {}
36 void InputProvider::error(const std::string& msg) {
37 std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " <<
42 void InputProvider::checkErrors() {
44 std::cerr << name << " had " << errCount << " errors. Terminating.\n";
53 class FileInputProvider : public InputProvider {
55 FileInputProvider(const std::string & fname)
56 : InputProvider(fname)
58 ConfigLexerInput = this;
60 virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
61 virtual unsigned read(char *buffer, unsigned max_size) {
63 F.read(buffer,max_size);
64 if ( F.gcount() ) return F.gcount() - 1;
69 bool okay() { return F.good(); }
74 cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden,
75 cl::init(false), cl::desc("Dump lexical tokens (debug use only)."));
83 ConfigLexerState.lineNum = 1;
84 ConfigLexerState.in_value = false;
85 ConfigLexerState.StringVal.clear();
86 ConfigLexerState.IntegerVal = 0;
89 ConfigLexerTokens token;
90 InputProvider* provider;
91 CompilerDriver::ConfigData* confDat;
96 std::cerr << token << "\n";
100 inline bool next_is_real() {
102 return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
105 inline void eatLineRemnant() {
106 while (next_is_real()) ;
109 void error(const std::string& msg, bool skip = true) {
110 provider->error(msg);
115 bool parseCompleteItem(std::string& result) {
117 while (next_is_real()) {
119 case LLVMGCCDIR_SUBST:
120 case LLVMGCCARCH_SUBST:
123 result += ConfigLexerState.StringVal;
137 std::string parseName() {
139 if (next() == EQUALS) {
140 if (parseCompleteItem(result))
143 error("Name exepected");
145 error("Expecting '='");
149 bool parseBoolean() {
151 if (next() == EQUALS) {
154 if (token == FALSETOK) {
156 } else if (token != TRUETOK) {
157 error("Expecting boolean value");
160 if (next() != EOLTOK && token != 0) {
161 error("Extraneous tokens after boolean");
165 error("Expecting '='");
169 bool parseSubstitution(CompilerDriver::StringVector& optList) {
171 case ARGS_SUBST: optList.push_back("%args%"); break;
172 case BINDIR_SUBST: optList.push_back("%bindir%"); break;
173 case DEFS_SUBST: optList.push_back("%defs%"); break;
174 case IN_SUBST: optList.push_back("%in%"); break;
175 case INCLS_SUBST: optList.push_back("%incls%"); break;
176 case LIBDIR_SUBST: optList.push_back("%libdir%"); break;
177 case LIBS_SUBST: optList.push_back("%libs%"); break;
178 case OPT_SUBST: optList.push_back("%opt%"); break;
179 case OUT_SUBST: optList.push_back("%out%"); break;
180 case TARGET_SUBST: optList.push_back("%target%"); break;
181 case STATS_SUBST: optList.push_back("%stats%"); break;
182 case TIME_SUBST: optList.push_back("%time%"); break;
183 case VERBOSE_SUBST: optList.push_back("%verbose%"); break;
184 case FOPTS_SUBST: optList.push_back("%fOpts%"); break;
185 case MOPTS_SUBST: optList.push_back("%Mopts%"); break;
186 case WOPTS_SUBST: optList.push_back("%Wopts%"); break;
193 void parseOptionList(CompilerDriver::StringVector& optList ) {
194 if (next() == EQUALS) {
195 while (next_is_real()) {
196 if (token == STRING || token == OPTION)
197 optList.push_back(ConfigLexerState.StringVal);
198 else if (!parseSubstitution(optList)) {
199 error("Expecting a program argument or substitution", false);
204 error("Expecting '='");
207 void parseVersion() {
208 if (next() != EQUALS)
209 error("Expecting '='");
210 while (next_is_real()) {
211 if (token == STRING || token == OPTION)
212 confDat->version = ConfigLexerState.StringVal;
214 error("Expecting a version string");
219 if (next() != EQUALS)
220 error("Expecting '='");
222 while (parseCompleteItem(lib)) {
224 confDat->libpaths.push_back(lib);
230 if (next() != SEPARATOR)
231 error("Expecting '.'");
237 confDat->langName = parseName();
240 parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
243 parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
246 parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
249 parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
253 confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
256 error("Expecting 'name' or 'optN' after 'lang.'");
261 bool parseProgramName(std::string& str) {
269 case LLVMCC1PLUS_SUBST:
286 str += ConfigLexerState.StringVal;
307 } while (token != SPACE && token != EOFTOK && token != EOLTOK &&
312 void parseCommand(CompilerDriver::Action& action) {
313 if (next() != EQUALS)
314 error("Expecting '='");
318 action.program.clear();
326 std::string progname;
327 if (parseProgramName(progname))
328 action.program.set(progname);
330 error("Expecting a program name");
333 std::string anOption;
334 while (next_is_real()) {
338 anOption += ConfigLexerState.StringVal;
341 anOption += "assembly";
344 anOption += "bitcode";
356 action.args.push_back(anOption);
360 if (!parseSubstitution(action.args))
361 error("Expecting a program argument or substitution", false);
369 void parsePreprocessor() {
370 if (next() != SEPARATOR)
371 error("Expecting '.'");
374 parseCommand(confDat->PreProcessor);
378 confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
380 confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
383 error("Expecting 'command' or 'required' but found '" +
384 ConfigLexerState.StringVal);
389 bool parseOutputFlag() {
390 if (next() == EQUALS) {
393 if (token == ASSEMBLY) {
395 } else if (token == BITCODE) {
398 error("Expecting output type value");
401 if (next() != EOLTOK && token != 0) {
402 error("Extraneous tokens after output value");
406 error("Expecting '='");
410 void parseTranslator() {
411 if (next() != SEPARATOR)
412 error("Expecting '.'");
415 parseCommand(confDat->Translator);
419 confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
421 confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
425 confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
427 confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
430 if (parseOutputFlag())
431 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
433 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
437 error("Expecting 'command', 'required', 'preprocesses', or "
438 "'output' but found '" + ConfigLexerState.StringVal +
444 void parseOptimizer() {
445 if (next() != SEPARATOR)
446 error("Expecting '.'");
449 parseCommand(confDat->Optimizer);
453 confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
455 confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
459 confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
461 confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
465 confDat->Optimizer.set(CompilerDriver::REQUIRED_FLAG);
467 confDat->Optimizer.clear(CompilerDriver::REQUIRED_FLAG);
470 if (parseOutputFlag())
471 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
473 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
476 error(std::string("Expecting 'command', 'preprocesses', "
477 "'translates' or 'output' but found '") +
478 ConfigLexerState.StringVal + "' instead");
483 void parseAssembler() {
484 if (next() != SEPARATOR)
485 error("Expecting '.'");
488 parseCommand(confDat->Assembler);
491 error("Expecting 'command'");
497 if (next() != SEPARATOR)
498 error("Expecting '.'");
505 error("Expecting 'libs' or 'libpaths'");
510 void parseAssignment() {
512 case VERSION_TOK: parseVersion(); break;
513 case LANG: parseLang(); break;
514 case PREPROCESSOR: parsePreprocessor(); break;
515 case TRANSLATOR: parseTranslator(); break;
516 case OPTIMIZER: parseOptimizer(); break;
517 case ASSEMBLER: parseAssembler(); break;
518 case LINKER: parseLinker(); break;
519 case EOLTOK: break; // just ignore
522 error("Invalid top level configuration item");
528 while ( next() != EOFTOK ) {
529 if (token == ERRORTOK)
530 error("Invalid token");
531 else if (token != EOLTOK)
534 provider->checkErrors();
539 ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
542 p.provider = &provider;
543 p.confDat = &confDat;
549 CompilerDriver::ConfigData*
550 LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
551 CompilerDriver::ConfigData* result = 0;
553 if (configDir.isEmpty()) {
554 // Try the environment variable
555 const char* conf = getenv("LLVM_CONFIG_DIR");
558 confFile.appendComponent(ftype);
559 if (!confFile.canRead())
560 throw std::string("Configuration file for '") + ftype +
561 "' is not available.";
563 // Try the user's home directory
564 confFile = sys::Path::GetUserHomeDirectory();
565 if (!confFile.isEmpty()) {
566 confFile.appendComponent(".llvm");
567 confFile.appendComponent("etc");
568 confFile.appendComponent(ftype);
569 if (!confFile.canRead())
572 if (confFile.isEmpty()) {
573 // Okay, try the LLVM installation directory
574 confFile = sys::Path::GetLLVMConfigDir();
575 confFile.appendComponent(ftype);
576 if (!confFile.canRead()) {
577 // Okay, try the "standard" place
578 confFile = sys::Path::GetLLVMDefaultConfigDir();
579 confFile.appendComponent(ftype);
580 if (!confFile.canRead()) {
581 throw std::string("Configuration file for '") + ftype +
582 "' is not available.";
588 confFile = configDir;
589 confFile.appendComponent(ftype);
590 if (!confFile.canRead())
591 throw std::string("Configuration file for '") + ftype +
592 "' is not available.";
594 FileInputProvider fip( confFile.toString() );
596 throw std::string("Configuration file for '") + ftype +
597 "' is not available.";
599 result = new CompilerDriver::ConfigData();
600 ParseConfigData(fip,*result);
604 LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
606 ConfigDataMap::iterator cIt = Configurations.begin();
607 while (cIt != Configurations.end()) {
608 CompilerDriver::ConfigData* cd = cIt->second;
614 CompilerDriver::ConfigData*
615 LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
616 CompilerDriver::ConfigData* result = 0;
617 if (!Configurations.empty()) {
618 ConfigDataMap::iterator cIt = Configurations.find(filetype);
619 if ( cIt != Configurations.end() ) {
620 // We found one in the case, return it.
621 result = cIt->second;
625 // The configuration data doesn't exist, we have to go read it.
626 result = ReadConfigData(filetype);
627 // If we got one, cache it
629 Configurations[filetype] = result;
631 return result; // Might return 0