diff --git a/src/Bridge/Library.cs b/src/Bridge/Library.cs index ab20dd05..c3978310 100644 --- a/src/Bridge/Library.cs +++ b/src/Bridge/Library.cs @@ -15,6 +15,24 @@ namespace Cxxi Unavailable } + public class NativeLibrary + { + public NativeLibrary(string file) + : this() + { + FileName = file; + } + + public NativeLibrary() + { + Symbols = new List(); + } + + public string FileName; + + public IList Symbols; + } + /// /// A library contains all the modules. /// @@ -23,12 +41,27 @@ namespace Cxxi public string Name; public string SharedLibrary; public List TranslationUnits; + public List Libraries; public Library(string name, string sharedLibrary) { Name = name; SharedLibrary = sharedLibrary; TranslationUnits = new List(); + Libraries = new List(); + } + + public NativeLibrary FindOrCreateLibrary(string file) + { + var library = Libraries.Find(m => m.FileName.Equals(file)); + + if (library == null) + { + library = new NativeLibrary(file); + Libraries.Add(library); + } + + return library; } /// Finds an existing module or creates a new one given a file path. @@ -85,7 +118,6 @@ namespace Cxxi } } - /// Finds an existing typedef in the library modules. public IEnumerable FindTypedef(string name) { diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 9e21cab7..76afbb9c 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -48,11 +48,16 @@ namespace Cxxi Options.IncludeDirs[i] = Path.GetFullPath(Options.IncludeDirs[i]); } + for (var i = 0; i < Options.LibraryDirs.Count; i++) + { + Options.LibraryDirs[i] = Path.GetFullPath(Options.LibraryDirs[i]); + } + if (string.IsNullOrWhiteSpace(Options.OutputNamespace)) Options.OutputNamespace = Options.LibraryName; } - private void OnHeaderParsed(string file, ParserResult result) + private void OnFileParsed(string file, ParserResult result) { switch (result.Kind) { @@ -80,11 +85,26 @@ namespace Cxxi Console.WriteLine("Parsing code..."); var parser = new Parser(Options); - parser.HeaderParsed += OnHeaderParsed; + parser.OnHeaderParsed += OnFileParsed; if( !parser.ParseHeaders(Options.Headers) ) return false; - + + Library = parser.Library; + + return true; + } + + public bool ParseLibraries() + { + Console.WriteLine("Parsing libraries..."); + + var parser = new Parser(Options); + parser.OnLibraryParsed += OnFileParsed; + + if (!parser.ParseLibraries(Options.Libraries)) + return false; + Library = parser.Library; return true; @@ -161,7 +181,7 @@ namespace Cxxi var driver = new Driver(options, library); driver.Setup(); - if (driver.ParseCode()) + if (driver.ParseLibraries() && driver.ParseCode()) { driver.ProcessCode(); driver.GenerateCode(); @@ -183,6 +203,10 @@ namespace Cxxi WriteOnlyWhenChanged = false; GeneratePartialClasses = true; + // Library options + LibraryDirs = new List(); + Libraries = new List(); + var platform = Environment.OSVersion.Platform; Abi = (platform == PlatformID.Unix || platform == PlatformID.MacOSX) ? CppAbi.Itanium : CppAbi.Microsoft; @@ -213,6 +237,10 @@ namespace Cxxi public LanguageGeneratorKind GeneratorKind; public bool WriteOnlyWhenChanged; + // Library options + public List LibraryDirs; + public List Libraries; + public bool IsItaniumAbi { get { return Abi == CppAbi.Itanium; } } public bool IsMicrosoftAbi { get { return Abi == CppAbi.Microsoft; } } } diff --git a/src/Parser/Main.cpp b/src/Parser/Main.cpp index 90d26db4..125095ff 100644 --- a/src/Parser/Main.cpp +++ b/src/Parser/Main.cpp @@ -11,15 +11,26 @@ public ref class ClangParser { public: - - static ParserResult^ Parse(ParserOptions^ Opts) + + static ParserResult^ ParseHeader(ParserOptions^ Opts) + { + if (!Opts->FileName) return nullptr; + + using namespace clix; + std::string File = marshalString(Opts->FileName); + + Parser parser(Opts); + return parser.ParseHeader(File); + } + + static ParserResult^ ParseLibrary(ParserOptions^ Opts) { if (!Opts->FileName) return nullptr; using namespace clix; std::string File = marshalString(Opts->FileName); - Parser p(Opts); - return p.Parse(File); + Parser parser(Opts); + return parser.ParseLibrary(File); } }; \ No newline at end of file diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index b1a1dcbb..8d2779c2 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -9,6 +9,7 @@ #include "Interop.h" #include +#include #include #include #include @@ -27,9 +28,8 @@ //-----------------------------------// -Parser::Parser(ParserOptions^ Opts) : Lib(Opts->Library), Index(0) +Parser::Parser(ParserOptions^ Opts) : Lib(Opts->Library), Opts(Opts), Index(0) { - Setup(Opts); } //-----------------------------------// @@ -68,7 +68,7 @@ static std::string GetClangBuiltinIncludeDir() std::vector GetWindowsSystemIncludeDirs(); #endif -void Parser::Setup(ParserOptions^ Opts) +void Parser::SetupHeader() { using namespace clang; using namespace clix; @@ -1631,7 +1631,7 @@ struct DiagnosticConsumer : public clang::DiagnosticConsumer std::vector Diagnostics; }; -ParserResult^ Parser::Parse(const std::string& File) +ParserResult^ Parser::ParseHeader(const std::string& File) { auto res = gcnew ParserResult(); res->Library = Lib; @@ -1642,6 +1642,8 @@ ParserResult^ Parser::Parse(const std::string& File) return res; } + SetupHeader(); + auto SC = new clang::SemaConsumer(); C->setASTConsumer(SC); @@ -1736,4 +1738,68 @@ ParserResult^ Parser::Parse(const std::string& File) res->Kind = ParserResultKind::Success; return res; - } \ No newline at end of file + } + + ParserResult^ Parser::ParseLibrary(const std::string& File) +{ + using namespace clix; + + auto res = gcnew ParserResult(); + res->Library = Lib; + + if (File.empty()) + { + res->Kind = ParserResultKind::FileNotFound; + return res; + } + + C.reset(new clang::CompilerInstance()); + C->createFileManager(); + + auto &FM = C->getFileManager(); + const clang::FileEntry* FileEntry = 0; + + for each(System::String^ LibDir in Opts->LibraryDirs) + { + auto DirName = marshalString(LibDir); + llvm::sys::Path Path(DirName); + Path.appendComponent(File); + + if (FileEntry = FM.getFile(Path.str())) + break; + } + + if (!FileEntry) + { + res->Kind = ParserResultKind::FileNotFound; + return res; + } + + auto Buffer = FM.getBufferForFile(FileEntry); + + llvm::error_code Code; + llvm::object::Archive Archive(Buffer, Code); + + if (Code) + { + res->Kind = ParserResultKind::Error; + return res; + } + + auto LibName = marshalString(File); + auto NativeLib = Lib->FindOrCreateLibrary(LibName); + + for(auto it = Archive.begin_symbols(); it != Archive.end_symbols(); ++it) + { + llvm::StringRef SymRef; + + if (it->getName(SymRef)) + continue; + + System::String^ SymName = marshalString(SymRef); + NativeLib->Symbols->Add(SymName); + } + + res->Kind = ParserResultKind::Success; + return res; +} \ No newline at end of file diff --git a/src/Parser/Parser.h b/src/Parser/Parser.h index 76f4e7d1..d0ab0156 100644 --- a/src/Parser/Parser.h +++ b/src/Parser/Parser.h @@ -38,11 +38,13 @@ public ref struct ParserOptions { IncludeDirs = gcnew List(); Defines = gcnew List(); + LibraryDirs = gcnew List(); } // Include directories List^ IncludeDirs; List^ Defines; + List^ LibraryDirs; // C/C++ header file name. System::String^ FileName; @@ -96,8 +98,9 @@ struct Parser { Parser(ParserOptions^ Opts); - void Setup(ParserOptions^ Opts); - ParserResult^ Parse(const std::string& File); + void SetupHeader(); + ParserResult^ ParseHeader(const std::string& File); + ParserResult^ ParseLibrary(const std::string& File); protected: @@ -137,6 +140,7 @@ protected: int Index; gcroot Lib; + gcroot Opts; llvm::OwningPtr C; clang::ASTContext* AST; }; diff --git a/src/Parser/Parser.lua b/src/Parser/Parser.lua index 5ec06e14..81471e87 100644 --- a/src/Parser/Parser.lua +++ b/src/Parser/Parser.lua @@ -58,6 +58,7 @@ project "Parser" links { "LLVMSupport", + "LLVMObject", "LLVMAsmParser", "LLVMBitReader", "LLVMBitWriter",