1 //===- Configuration.cpp - Configuration Data Mgmt --------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file was developed by Reid Spencer and is distributed under the
6 // University of Illinois Open Source 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
;
612 Configurations
.clear();
615 CompilerDriver::ConfigData
*
616 LLVMC_ConfigDataProvider::ProvideConfigData(const std::string
& filetype
) {
617 CompilerDriver::ConfigData
* result
= 0;
618 if (!Configurations
.empty()) {
619 ConfigDataMap::iterator cIt
= Configurations
.find(filetype
);
620 if ( cIt
!= Configurations
.end() ) {
621 // We found one in the case, return it.
622 result
= cIt
->second
;
626 // The configuration data doesn't exist, we have to go read it.
627 result
= ReadConfigData(filetype
);
628 // If we got one, cache it
630 Configurations
.insert(std::make_pair(filetype
,result
));
632 return result
; // Might return 0