2015-02-26 15:02:31 +00:00
# include <iostream>
# include <sstream>
# include <libgen.h>
# include <string.h>
# include <stdio.h>
2016-03-16 18:24:59 +00:00
# include <sys/stat.h>
2015-02-26 15:02:31 +00:00
# include <unistd.h>
# include "llvm/Support/Host.h"
# include "llvm/Support/CommandLine.h"
2018-03-13 14:30:01 +00:00
# include "llvm/Support/raw_ostream.h"
2015-02-26 15:02:31 +00:00
2020-03-31 16:40:30 +00:00
# include "clang/Basic/Builtins.h"
2015-02-26 15:02:31 +00:00
# include "clang/Frontend/CompilerInstance.h"
# include "clang/Basic/TargetOptions.h"
# include "clang/Basic/TargetInfo.h"
# include "clang/Basic/FileManager.h"
# include "clang/Lex/Preprocessor.h"
2017-03-15 15:05:06 +00:00
# include "clang/Lex/PreprocessorOptions.h"
2015-02-26 15:02:31 +00:00
# include "clang/Basic/Diagnostic.h"
# include "clang/Parse/ParseAST.h"
# include "ICGASTConsumer.hh"
# include "HeaderSearchDirs.hh"
# include "CommentSaver.hh"
# include "TranslationUnitVisitor.hh"
# include "PrintAttributes.hh"
# include "Utilities.hh"
2017-01-11 21:02:21 +00:00
# include "FindTrickICG.hh"
2015-02-26 15:02:31 +00:00
2016-10-28 18:21:21 +00:00
/* Command line arguments. These work better as globals, as suggested in llvm/CommandLine documentation */
2016-10-21 20:06:44 +00:00
llvm : : cl : : list < std : : string > include_dirs ( " I " , llvm : : cl : : Prefix , llvm : : cl : : desc ( " Include directory " ) , llvm : : cl : : value_desc ( " directory " ) ) ;
2019-09-27 19:58:54 +00:00
llvm : : cl : : list < std : : string > f_options ( " f " , llvm : : cl : : Prefix , llvm : : cl : : desc ( " Compiler options that have f prefix " ) , llvm : : cl : : value_desc ( " option " ) ) ;
2019-06-20 15:12:33 +00:00
llvm : : cl : : list < std : : string > isystem_dirs ( " isystem " , llvm : : cl : : Prefix , llvm : : cl : : desc ( " Include directory, suppress all warnings " ) , llvm : : cl : : value_desc ( " directory " ) ) ;
2016-10-21 20:06:44 +00:00
llvm : : cl : : list < std : : string > defines ( " D " , llvm : : cl : : Prefix , llvm : : cl : : desc ( " Defines " ) , llvm : : cl : : value_desc ( " define " ) ) ;
2019-06-18 15:59:51 +00:00
// TODO: remove units_truth_is_scary in 2021.
llvm : : cl : : opt < bool > units_truth_is_scary ( " units-truth-is-scary " , llvm : : cl : : desc ( " DEPRECATED: Don't print units conversion messages " ) ) ;
2019-09-27 21:04:16 +00:00
llvm : : cl : : opt < bool > sim_services_flag ( " sim_services " , llvm : : cl : : desc ( " Gernerate io_src for Trick core headers " ) ) ;
2019-09-27 19:58:54 +00:00
llvm : : cl : : opt < bool > force ( " force " , llvm : : cl : : desc ( " Force all io_src files to be generated " ) ) ;
2016-10-28 18:21:21 +00:00
llvm : : cl : : opt < int > attr_version ( " v " , llvm : : cl : : desc ( " Select version of attributes to produce. 10 and 13 are valid " ) , llvm : : cl : : init ( 10 ) ) ;
2016-10-21 20:06:44 +00:00
llvm : : cl : : opt < int > debug_level ( " d " , llvm : : cl : : desc ( " Set debug level " ) , llvm : : cl : : init ( 0 ) , llvm : : cl : : ZeroOrMore ) ;
llvm : : cl : : opt < bool > create_map ( " m " , llvm : : cl : : desc ( " Create map files " ) , llvm : : cl : : init ( false ) ) ;
llvm : : cl : : opt < std : : string > output_dir ( " o " , llvm : : cl : : desc ( " Output directory " ) ) ;
llvm : : cl : : list < std : : string > input_file_names ( llvm : : cl : : Positional , llvm : : cl : : desc ( " <input_file> " ) , llvm : : cl : : ZeroOrMore ) ;
llvm : : cl : : list < std : : string > sink ( llvm : : cl : : Sink , llvm : : cl : : ZeroOrMore ) ;
llvm : : cl : : list < std : : string > pre_compiled_headers ( " include " , llvm : : cl : : Prefix , llvm : : cl : : desc ( " pre-compiled headers " ) , llvm : : cl : : value_desc ( " pre_compiled_headers " ) ) ;
2016-10-28 18:21:21 +00:00
llvm : : cl : : opt < bool > global_compat15 ( " c " , llvm : : cl : : desc ( " Print the offsetof calculations in attributes " ) ) ;
2017-01-11 21:02:21 +00:00
llvm : : cl : : opt < llvm : : cl : : boolOrDefault > print_trick_icg ( " print-TRICK-ICG " , llvm : : cl : : desc ( " Print warnings where TRICK_ICG may cause io_src inconsistencies " ) ) ;
2016-10-28 18:21:21 +00:00
llvm : : cl : : alias compat15_alias ( " compat15 " , llvm : : cl : : desc ( " Alias for -c " ) , llvm : : cl : : aliasopt ( global_compat15 ) ) ;
2017-06-19 19:18:37 +00:00
llvm : : cl : : opt < bool > m32 ( " m32 " , llvm : : cl : : desc ( " Generate io code for use with 32bit mode " ) , llvm : : cl : : init ( false ) , llvm : : cl : : ZeroOrMore ) ;
2015-02-26 15:02:31 +00:00
2020-09-01 20:55:19 +00:00
2021-10-12 16:30:49 +00:00
void set_lang_opts ( clang : : CompilerInstance & ci ) {
ci . getLangOpts ( ) . CXXExceptions = true ;
// Activate C++11 parsing
ci . getLangOpts ( ) . Bool = true ;
ci . getLangOpts ( ) . WChar = true ;
ci . getLangOpts ( ) . CPlusPlus = true ;
ci . getLangOpts ( ) . CPlusPlus11 = true ;
ci . getLangOpts ( ) . CXXOperatorNames = true ;
# if (LIBCLANG_MAJOR >= 6)
ci . getLangOpts ( ) . CPlusPlus14 = true ;
ci . getLangOpts ( ) . DoubleSquareBracketAttributes = true ;
# endif
// Activate C++17 parsing
2022-07-20 16:38:42 +00:00
# ifdef TRICK_GCC_VERSION
const char * gcc_version = TRICK_GCC_VERSION ;
# else
const char * gcc_version = " " ;
# endif
2021-10-12 16:30:49 +00:00
# if (LIBCLANG_MAJOR >= 10)
2022-07-20 16:38:42 +00:00
ci . getLangOpts ( ) . GNUCVersion = gccVersionToIntOrDefault ( gcc_version , 40805 ) ;
2021-10-12 16:30:49 +00:00
ci . getLangOpts ( ) . CPlusPlus17 = true ;
# endif
}
2015-02-26 15:02:31 +00:00
/**
2016-10-21 20:06:44 +00:00
Most of the main program is pieced together from examples on the web . We are doing the following :
2015-02-26 15:02:31 +00:00
- # Creating lists of include directories , defines , and input files from the command line arguments .
2016-10-21 20:06:44 +00:00
- # Initializing the compiler to read C + + code , and setting the compiler to think we are creating code for the default target architecture .
2015-02-26 15:02:31 +00:00
- # Creating the necessary source and file managers as well as the preprocessor .
- # Adding search directories and creating # define statements for - D command line arguments .
- # Telling clang to use our ICGASTConsumer as an ASTConsumer .
2016-10-21 20:06:44 +00:00
- # Parsing the input file .
2015-02-26 15:02:31 +00:00
*/
2016-10-21 20:06:44 +00:00
int main ( int argc , char * argv [ ] ) {
2018-03-13 14:30:01 +00:00
llvm : : cl : : SetVersionPrinter ( [ ]
# if (LIBCLANG_MAJOR >= 6)
( llvm : : raw_ostream & stream ) { stream
# else
{ std : : cout
# endif
< < " Trick Interface Code Generator (trick-ICG) " < < TRICK_VERSION < < ' \n ' ; }
) ;
2016-10-21 20:06:44 +00:00
/**
* Gather all of the command line arguments into lists of include directories , defines , and input files .
* All other arguments will be ignored .
2020-09-01 20:55:19 +00:00
*
* Filter out - W because of LLVM cl option that has been enabled and cannot be disabled in LLVM 10 when linking libclang - cpp . so .
* TODO : Troubleshoot or contact LLVM for a fix .
2016-10-21 20:06:44 +00:00
*/
2020-09-01 20:55:19 +00:00
std : : vector < const char * > filtered_args ;
for ( unsigned int ii = 0 ; ii < argc ; ii + + ) {
if ( strncmp ( argv [ ii ] , " -W " , 2 ) ) {
filtered_args . push_back ( argv [ ii ] ) ;
}
}
llvm : : cl : : ParseCommandLineOptions ( filtered_args . size ( ) , filtered_args . data ( ) ) ;
2016-10-21 20:06:44 +00:00
if ( input_file_names . empty ( ) ) {
std : : cerr < < " No header file specified " < < std : : endl ;
return 1 ;
2016-04-27 16:24:03 +00:00
}
2016-10-28 18:21:21 +00:00
clang : : CompilerInstance ci ;
# if (LIBCLANG_MAJOR == 3) && (LIBCLANG_MINOR < 9)
clang : : CompilerInvocation : : setLangDefaults ( ci . getLangOpts ( ) , clang : : IK_CXX ) ;
# endif
2016-04-27 16:24:03 +00:00
2016-10-28 18:21:21 +00:00
ci . createDiagnostics ( ) ;
ci . getDiagnosticOpts ( ) . ShowColors = 1 ;
ci . getDiagnostics ( ) . setIgnoreAllWarnings ( true ) ;
2021-10-12 16:30:49 +00:00
set_lang_opts ( ci ) ;
2015-02-26 15:02:31 +00:00
2016-10-28 18:21:21 +00:00
// Create all of the necessary managers.
ci . createFileManager ( ) ;
ci . createSourceManager ( ci . getFileManager ( ) ) ;
2015-02-26 15:02:31 +00:00
2016-10-28 18:21:21 +00:00
// Tell the preprocessor to use its default predefines
clang : : PreprocessorOptions & ppo = ci . getPreprocessorOpts ( ) ;
ppo . UsePredefines = true ;
2015-02-26 15:02:31 +00:00
// Set the default target architecture
2016-07-25 19:57:07 +00:00
# if (LIBCLANG_MAJOR > 3) || ((LIBCLANG_MAJOR == 3) && (LIBCLANG_MINOR >= 5))
2016-10-28 18:21:21 +00:00
clang : : TargetOptions to ;
2017-06-19 19:18:37 +00:00
if ( m32 ) {
to . Triple = llvm : : Triple ( llvm : : sys : : getDefaultTargetTriple ( ) ) . get32BitArchVariant ( ) . str ( ) ;
} else {
to . Triple = llvm : : sys : : getDefaultTargetTriple ( ) ;
}
2016-10-28 18:21:21 +00:00
std : : shared_ptr < clang : : TargetOptions > shared_to = std : : make_shared < clang : : TargetOptions > ( to ) ;
clang : : TargetInfo * pti = clang : : TargetInfo : : CreateTargetInfo ( ci . getDiagnostics ( ) , shared_to ) ;
ci . setTarget ( pti ) ;
ci . createPreprocessor ( clang : : TU_Complete ) ;
2015-02-26 15:02:31 +00:00
# else
2016-10-28 18:21:21 +00:00
clang : : TargetOptions * to = new clang : : TargetOptions ( ) ;
2017-06-19 19:18:37 +00:00
if ( m32 ) {
to - > Triple = llvm : : Triple ( llvm : : sys : : getDefaultTargetTriple ( ) ) . get32BitArchVariant ( ) . str ( ) ;
} else {
to - > Triple = llvm : : sys : : getDefaultTargetTriple ( ) ;
}
2016-10-28 18:21:21 +00:00
clang : : TargetInfo * pti = clang : : TargetInfo : : CreateTargetInfo ( ci . getDiagnostics ( ) , to ) ;
ci . setTarget ( pti ) ;
ci . createPreprocessor ( ) ;
2015-02-26 15:02:31 +00:00
# endif
2016-10-28 18:21:21 +00:00
// Set all of the defaults to c++
# if (LIBCLANG_MAJOR > 3) || ((LIBCLANG_MAJOR == 3) && (LIBCLANG_MINOR >= 9))
llvm : : Triple trip ( to . Triple ) ;
2023-02-07 18:46:34 +00:00
# if (LIBCLANG_MAJOR >= 15)
//clang::CompilerInvocation::setLangDefaults(ci.getLangOpts(), clang::Language::CXX, trip, ppo.Includes) ;
# elif (LIBCLANG_MAJOR >= 12)
2021-04-30 16:15:38 +00:00
clang : : CompilerInvocation : : setLangDefaults ( ci . getLangOpts ( ) , clang : : Language : : CXX , trip , ppo . Includes ) ;
# elif (LIBCLANG_MAJOR >= 10)
2020-03-31 16:40:30 +00:00
clang : : CompilerInvocation : : setLangDefaults ( ci . getLangOpts ( ) , clang : : Language : : CXX , trip , ppo ) ;
# elif (LIBCLANG_MAJOR >= 5)
2017-09-13 19:07:23 +00:00
clang : : CompilerInvocation : : setLangDefaults ( ci . getLangOpts ( ) , clang : : InputKind : : CXX , trip , ppo ) ;
# else
2016-10-28 18:21:21 +00:00
clang : : CompilerInvocation : : setLangDefaults ( ci . getLangOpts ( ) , clang : : IK_CXX , trip , ppo ) ;
2017-09-13 19:07:23 +00:00
# endif
2021-10-12 16:30:49 +00:00
// setting the language defaults clears some of the language opts, set them again.
set_lang_opts ( ci ) ;
2015-02-26 15:02:31 +00:00
# endif
2016-10-28 18:21:21 +00:00
clang : : Preprocessor & pp = ci . getPreprocessor ( ) ;
2015-02-26 15:02:31 +00:00
2021-10-12 16:30:49 +00:00
# if (LIBCLANG_MAJOR >= 10)
clang : : InitializePreprocessor ( pp , ppo , ci . getPCHContainerReader ( ) , ci . getFrontendOpts ( ) ) ;
# endif
2015-02-26 15:02:31 +00:00
// Add all of the include directories to the preprocessor
2016-10-28 18:21:21 +00:00
HeaderSearchDirs hsd ( ci . getPreprocessor ( ) . getHeaderSearchInfo ( ) , ci . getHeaderSearchOpts ( ) , pp , sim_services_flag ) ;
2019-06-20 15:12:33 +00:00
hsd . addSearchDirs ( include_dirs , isystem_dirs ) ;
2015-02-26 15:02:31 +00:00
2017-01-11 21:02:21 +00:00
// Add a preprocessor callback to search for TRICK_ICG
2017-01-12 14:42:16 +00:00
# if (LIBCLANG_MAJOR > 3) || ((LIBCLANG_MAJOR == 3) && (LIBCLANG_MINOR >= 6))
2017-01-11 21:59:10 +00:00
std : : unique_ptr < FindTrickICG > ftg ( new FindTrickICG ( ci , hsd , print_trick_icg ! = llvm : : cl : : BOU_FALSE ) ) ;
pp . addPPCallbacks ( std : : move ( ftg ) ) ;
# else
2017-01-11 21:02:21 +00:00
FindTrickICG * ftg = new FindTrickICG ( ci , hsd , print_trick_icg ! = llvm : : cl : : BOU_FALSE ) ;
pp . addPPCallbacks ( ftg ) ;
2017-01-11 21:59:10 +00:00
# endif
2017-01-11 21:02:21 +00:00
2016-07-25 19:57:07 +00:00
# if (LIBCLANG_MAJOR > 3) || ((LIBCLANG_MAJOR == 3) && (LIBCLANG_MINOR >= 8))
2016-10-28 18:21:21 +00:00
pp . getBuiltinInfo ( ) . initializeBuiltins ( pp . getIdentifierTable ( ) , pp . getLangOpts ( ) ) ;
2016-04-18 20:22:52 +00:00
# else
2016-10-28 18:21:21 +00:00
pp . getBuiltinInfo ( ) . InitializeBuiltins ( pp . getIdentifierTable ( ) , pp . getLangOpts ( ) ) ;
2016-04-18 20:22:52 +00:00
# endif
2016-10-21 20:06:44 +00:00
// Add all of the #define from the command line to the default predefines
2016-10-28 18:21:21 +00:00
hsd . addDefines ( defines ) ;
2015-02-26 15:02:31 +00:00
// Add our comment saver as a comment handler in the preprocessor
2016-10-28 18:21:21 +00:00
CommentSaver cs ( ci , hsd ) ;
pp . addCommentHandler ( & cs ) ;
2015-02-26 15:02:31 +00:00
2016-10-28 18:21:21 +00:00
PrintAttributes printAttributes ( attr_version , hsd , cs , ci , force , sim_services_flag , output_dir ) ;
2015-02-26 15:02:31 +00:00
2017-12-19 16:02:41 +00:00
printAttributes . addIgnoreTypes ( ) ;
2016-10-21 20:06:44 +00:00
// Create new class and enum map files
if ( create_map ) {
printAttributes . createMapFiles ( ) ;
2015-06-24 22:49:14 +00:00
}
2015-02-26 15:02:31 +00:00
// Tell the compiler to use our ICGASTconsumer
2016-10-28 18:21:21 +00:00
ICGASTConsumer * astConsumer = new ICGASTConsumer ( ci , hsd , cs , printAttributes ) ;
2016-07-25 19:57:07 +00:00
# if (LIBCLANG_MAJOR > 3) || ((LIBCLANG_MAJOR == 3) && (LIBCLANG_MINOR >= 6))
2016-10-28 18:21:21 +00:00
ci . setASTConsumer ( std : : move ( std : : unique_ptr < clang : : ASTConsumer > ( astConsumer ) ) ) ;
2015-02-11 00:47:01 +00:00
# else
2016-10-28 18:21:21 +00:00
ci . setASTConsumer ( astConsumer ) ;
2015-02-11 00:47:01 +00:00
# endif
2016-10-28 18:21:21 +00:00
ci . createASTContext ( ) ;
2022-06-13 14:56:17 +00:00
ci . createSema ( clang : : TU_Complete , NULL ) ;
2016-10-21 20:06:44 +00:00
// Get the full path of the file to be read
2020-02-11 16:41:09 +00:00
char buffer [ input_file_names [ 0 ] . size ( ) + 1 ] ;
2016-10-21 20:06:44 +00:00
strcpy ( buffer , input_file_names [ 0 ] . c_str ( ) ) ;
std : : string path ( dirname ( buffer ) ) ;
path + = " / " ;
strcpy ( buffer , input_file_names [ 0 ] . c_str ( ) ) ;
path + = basename ( buffer ) ;
char * inputFilePath = almostRealPath ( path ) ;
struct stat dummy ;
if ( stat ( inputFilePath , & dummy ) ) {
std : : cerr < < " Could not open file " < < inputFilePath < < std : : endl ;
exit ( - 1 ) ;
2016-03-16 18:24:59 +00:00
}
2016-10-21 20:06:44 +00:00
// Open up the input file and parse it
2020-03-31 16:40:30 +00:00
# if (LIBCLANG_MAJOR >= 10)
const clang : : FileEntry * fileEntry = ci . getFileManager ( ) . getFile ( inputFilePath ) . get ( ) ;
# else
2016-10-28 18:21:21 +00:00
const clang : : FileEntry * fileEntry = ci . getFileManager ( ) . getFile ( inputFilePath ) ;
2020-03-31 16:40:30 +00:00
# endif
2016-10-21 20:06:44 +00:00
free ( inputFilePath ) ;
2016-07-25 19:57:07 +00:00
# if (LIBCLANG_MAJOR > 3) || ((LIBCLANG_MAJOR == 3) && (LIBCLANG_MINOR >= 5))
2016-10-28 18:21:21 +00:00
ci . getSourceManager ( ) . setMainFileID ( ci . getSourceManager ( ) . createFileID ( fileEntry , clang : : SourceLocation ( ) , clang : : SrcMgr : : C_User ) ) ;
2015-02-26 15:02:31 +00:00
# else
2016-10-28 18:21:21 +00:00
ci . getSourceManager ( ) . createMainFileID ( fileEntry ) ;
2015-02-26 15:02:31 +00:00
# endif
2016-10-28 18:21:21 +00:00
ci . getDiagnosticClient ( ) . BeginSourceFile ( ci . getLangOpts ( ) , & ci . getPreprocessor ( ) ) ;
clang : : ParseAST ( ci . getSema ( ) ) ;
ci . getDiagnosticClient ( ) . EndSourceFile ( ) ;
2015-02-26 15:02:31 +00:00
2016-10-21 20:06:44 +00:00
if ( ! sim_services_flag ) {
printAttributes . printIOMakefile ( ) ;
2015-07-02 15:09:31 +00:00
}
2015-02-26 15:02:31 +00:00
// Close the map files
2016-10-21 20:06:44 +00:00
printAttributes . closeMapFiles ( ) ;
2015-02-26 15:02:31 +00:00
// Print the list of headers that have the ICG:(No) comment
2016-10-21 20:06:44 +00:00
printAttributes . printICGNoFiles ( ) ;
2015-02-26 15:02:31 +00:00
return 0 ;
}