2012-09-05 13:37:39 +04:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Lukasz Janyst <ljanyst@cern.ch>
2014-01-07 14:08:37 +04:00
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
2012-09-05 13:37:39 +04:00
//------------------------------------------------------------------------------
# include "cling/Interpreter/Interpreter.h"
# include "cling/MetaProcessor/MetaProcessor.h"
# include "cling/UserInterface/UserInterface.h"
# include "clang/Basic/LangOptions.h"
# include "clang/Frontend/CompilerInstance.h"
2016-08-09 02:02:10 +03:00
# include "clang/FrontendTool/Utils.h"
2012-09-05 13:37:39 +04:00
# include "llvm/Support/Signals.h"
# include "llvm/Support/PrettyStackTrace.h"
# include "llvm/Support/ManagedStatic.h"
# include <iostream>
2014-08-11 15:38:26 +04:00
# include <fstream>
2012-09-05 13:37:39 +04:00
# include <vector>
# include <string>
2016-08-08 13:09:41 +03:00
# if defined(WIN32) && defined(_MSC_VER)
# include <crtdbg.h>
# endif
2016-07-22 01:29:10 +03:00
// If we are running with -verify a reported has to be returned as unsuccess.
// This is relevant especially for the test suite.
static int checkDiagErrors ( clang : : CompilerInstance * CI , unsigned * OutErrs = 0 ) {
unsigned Errs = CI - > getDiagnostics ( ) . getClient ( ) - > getNumErrors ( ) ;
if ( CI - > getDiagnosticOpts ( ) . VerifyDiagnostics ) {
// If there was an error that came from the verifier we must return 1 as
// an exit code for the process. This will make the test fail as expected.
clang : : DiagnosticConsumer * Client = CI - > getDiagnostics ( ) . getClient ( ) ;
Client - > EndSourceFile ( ) ;
Errs = Client - > getNumErrors ( ) ;
// The interpreter expects BeginSourceFile/EndSourceFiles to be balanced.
Client - > BeginSourceFile ( CI - > getLangOpts ( ) , & CI - > getPreprocessor ( ) ) ;
}
if ( OutErrs )
* OutErrs = Errs ;
return Errs ? EXIT_FAILURE : EXIT_SUCCESS ;
}
2016-08-09 02:02:10 +03:00
2012-09-05 13:37:39 +04:00
int main ( int argc , char * * argv ) {
llvm : : llvm_shutdown_obj shutdownTrigger ;
2016-08-08 13:09:41 +03:00
llvm : : sys : : PrintStackTraceOnErrorSignal ( argv [ 0 ] ) ;
llvm : : PrettyStackTraceProgram X ( argc , argv ) ;
# if defined(_WIN32) && defined(_MSC_VER)
// Suppress error dialogs to avoid hangs on build nodes.
// One can use an environment variable (Cling_GuiOnAssert) to enable
// the error dialogs.
const char * EnablePopups = getenv ( " Cling_GuiOnAssert " ) ;
if ( EnablePopups = = nullptr | | EnablePopups [ 0 ] = = ' 0 ' ) {
: : _set_error_mode ( _OUT_TO_STDERR ) ;
_CrtSetReportMode ( _CRT_WARN , _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG ) ;
_CrtSetReportFile ( _CRT_WARN , _CRTDBG_FILE_STDERR ) ;
_CrtSetReportMode ( _CRT_ERROR , _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG ) ;
_CrtSetReportFile ( _CRT_ERROR , _CRTDBG_FILE_STDERR ) ;
_CrtSetReportMode ( _CRT_ASSERT , _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG ) ;
_CrtSetReportFile ( _CRT_ASSERT , _CRTDBG_FILE_STDERR ) ;
}
# endif
2012-09-05 13:37:39 +04:00
// Set up the interpreter
2017-01-30 02:13:48 +03:00
cling : : Interpreter Interp ( argc , argv ) ;
const cling : : InvocationOptions & Opts = Interp . getOptions ( ) ;
2016-07-02 07:20:48 +03:00
2017-01-30 02:13:48 +03:00
if ( ! Interp . isValid ( ) ) {
2016-07-07 01:50:34 +03:00
if ( Opts . Help | | Opts . ShowVersion )
return EXIT_SUCCESS ;
2016-07-22 01:29:10 +03:00
unsigned ErrsReported = 0 ;
2017-01-30 02:13:48 +03:00
if ( clang : : CompilerInstance * CI = Interp . getCIOrNull ( ) ) {
2016-08-09 02:02:10 +03:00
// If output requested and execution succeeded let the DiagnosticsEngine
// determine the result code
2016-07-07 01:50:34 +03:00
if ( Opts . CompilerOpts . HasOutput & & ExecuteCompilerInvocation ( CI ) )
2016-07-22 01:29:10 +03:00
return checkDiagErrors ( CI ) ;
checkDiagErrors ( CI , & ErrsReported ) ;
}
// If no errors have been reported, try perror
if ( ErrsReported = = 0 )
2016-07-02 07:20:48 +03:00
: : perror ( " Could not create Interpreter instance " ) ;
2016-07-22 01:29:10 +03:00
2016-07-02 07:20:48 +03:00
return EXIT_FAILURE ;
2012-09-05 13:37:39 +04:00
}
2016-08-09 02:02:10 +03:00
2017-01-30 02:13:48 +03:00
Interp . AddIncludePath ( " . " ) ;
2012-09-05 13:37:39 +04:00
2017-01-30 02:13:48 +03:00
for ( const std : : string & Lib : Opts . LibsToLoad )
Interp . loadFile ( Lib ) ;
2013-08-06 14:31:58 +04:00
2017-01-30 02:13:48 +03:00
cling : : UserInterface Ui ( Interp ) ;
2013-08-06 14:31:58 +04:00
// If we are not interactive we're supposed to parse files
2017-01-30 02:13:48 +03:00
if ( ! Opts . IsInteractive ( ) ) {
for ( const std : : string & Input : Opts . Inputs ) {
std : : string Cmd ;
cling : : Interpreter : : CompilationResult Result ;
const std : : string Filepath = Interp . lookupFileOrLibrary ( Input ) ;
if ( ! Filepath . empty ( ) ) {
std : : ifstream File ( Filepath ) ;
std : : string Line ;
std : : getline ( File , Line ) ;
if ( Line [ 0 ] = = ' # ' & & Line [ 1 ] = = ' ! ' ) {
2014-08-11 17:09:02 +04:00
// TODO: Check whether the filename specified after #! is the current
// executable.
2017-01-30 02:13:48 +03:00
while ( std : : getline ( File , Line ) ) {
2017-06-06 18:23:41 +03:00
Ui . getMetaProcessor ( ) - > process ( Line , Result , 0 ) ;
2014-08-11 15:38:26 +04:00
}
continue ;
}
2017-01-30 02:13:48 +03:00
Cmd + = " .x " ;
2014-08-11 15:38:26 +04:00
}
2017-01-30 02:13:48 +03:00
Cmd + = Input ;
2017-06-06 18:23:41 +03:00
Ui . getMetaProcessor ( ) - > process ( Cmd , Result , 0 ) ;
2013-08-06 14:31:58 +04:00
}
}
else {
2017-01-30 02:13:48 +03:00
Ui . runInteractively ( Opts . NoLogo ) ;
2013-08-06 14:31:58 +04:00
}
2016-12-15 16:32:50 +03:00
// Only for test/OutputRedirect.C, but shouldn't affect performance too much.
: : fflush ( stdout ) ;
: : fflush ( stderr ) ;
2016-07-02 07:20:48 +03:00
2017-01-30 02:13:48 +03:00
return checkDiagErrors ( Interp . getCI ( ) ) ;
2012-09-05 13:37:39 +04:00
}