Browse Source

Kill the old parser (good riddance :).

pull/284/head
triton 11 years ago
parent
commit
1802470013
  1. 30
      build/GenerateProjects.bat
  2. 18
      build/Parser.lua
  3. 4
      build/premake4.lua
  4. 4
      examples/SDL/SDL.cs
  5. 6
      src/Core/Parser/ASTConverter.cs
  6. 12
      src/Core/Parser/Parser.cs
  7. 3
      src/Core/Project.cs
  8. 16
      src/CppParser/Bindings/ParserGen.cs
  9. 5
      src/Generator.Tests/ASTTestFixture.cs
  10. 5
      src/Generator.Tests/GeneratorTest.cs
  11. 56
      src/Generator/Driver.cs
  12. 2
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  13. 2
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  14. 2
      src/Generator/Options.cs
  15. 6
      src/Generator/Passes/CleanUnitPass.cs
  16. 3
      src/Generator/Passes/GenerateAbstractImplementationsPass.cs
  17. 3
      src/Generator/Passes/GenerateInlinesCodePass.cs
  18. 48
      src/Parser/CXXABI.h
  19. 268
      src/Parser/Comments.cpp
  20. 203
      src/Parser/Interop.h
  21. 46
      src/Parser/Main.cpp
  22. 102
      src/Parser/Options.h
  23. 3031
      src/Parser/Parser.cpp
  24. 130
      src/Parser/Parser.h
  25. 51
      src/Parser/Parser.lua
  26. 69
      src/Parser/Target.h
  27. 269
      src/Parser/VSLookup.cpp

30
build/GenerateProjects.bat

@ -5,48 +5,30 @@ goto menu @@ -5,48 +5,30 @@ goto menu
echo Build Project Generator:
echo.
echo [0] Clean
echo [1] Visual C++ 2010
echo [2] Visual C++ 2012
echo [3] Visual C++ 2012 (C++ parser)
echo [4] Visual C++ 2013
echo [5] Visual C++ 2013 (C++ parser)
echo [6] GNU Make
echo [1] Visual C++ 2012
echo [2] Visual C++ 2013
echo [3] GNU Make
echo.
:choice
set /P C="Choice: "
if "%C%"=="6" goto gmake
if "%C%"=="5" goto vs2013_cpp
if "%C%"=="4" goto vs2013
if "%C%"=="3" goto vs2012_cpp
if "%C%"=="2" goto vs2012
if "%C%"=="1" goto vs2010
if "%C%"=="3" goto gmake
if "%C%"=="2" goto vs2013
if "%C%"=="1" goto vs2012
if "%C%"=="0" goto clean
:clean
"premake5" --file=premake4.lua clean
goto quit
:vs2010
"premake5" --file=premake4.lua vs2010
goto quit
:vs2012
"premake5" --file=premake4.lua vs2012
goto quit
:vs2012_cpp
"premake5" --file=premake4.lua --parser=cpp vs2012
goto quit
:vs2013
"premake5" --file=premake4.lua vs2013
goto quit
:vs2013_cpp
"premake5" --file=premake4.lua --parser=cpp vs2013
goto quit
:gmake
"premake5" --file=premake4.lua gmake
goto quit

18
build/Parser.lua

@ -1,21 +1,5 @@ @@ -1,21 +1,5 @@
newoption {
trigger = "parser",
description = "Controls which version of the parser is enabled.",
value = "version",
allowed = {
{ "cpp", "Cross-platform C++ parser."},
{ "cli", "VS-only C++/CLI parser."},
}
}
function SetupCLIParser()
local parser = _OPTIONS["parser"]
if not parser or parser == "cli" then
defines { "OLD_PARSER" }
links { "CppSharp.Parser" }
else
links { "CppSharp.Parser.CLI" }
end
links { "CppSharp.Parser.CLI" }
end
function SetupCSharpParser()

4
build/premake4.lua

@ -49,7 +49,3 @@ solution "CppSharp" @@ -49,7 +49,3 @@ solution "CppSharp"
include (srcdir .. "/Generator.Tests/Generator.Tests.lua")
include (srcdir .. "/Runtime/Runtime.lua")
include (srcdir .. "/CppParser")
if string.starts(action, "vs") and os.is_windows() then
include (srcdir .. "/Parser/Parser.lua")
end

4
examples/SDL/SDL.cs

@ -10,11 +10,7 @@ namespace CppSharp @@ -10,11 +10,7 @@ namespace CppSharp
var options = driver.Options;
options.LibraryName = "SDL";
options.Headers.Add("SDL.h");
#if OLD_PARSER
options.IncludeDirs.Add("../../../examples/SDL/SDL-2.0/include");
#else
options.addIncludeDirs("../../../examples/SDL/SDL-2.0/include");
#endif
options.OutputDir = "SDL";
}

6
src/Core/Parser/ASTConverter.cs

@ -1,6 +1,4 @@ @@ -1,6 +1,4 @@
#if !OLD_PARSER
using System;
using System;
using System.Collections.Generic;
using CppSharp.Parser.AST;
@ -1459,5 +1457,3 @@ namespace CppSharp @@ -1459,5 +1457,3 @@ namespace CppSharp
#endregion
}
#endif

12
src/Core/Parser/Parser.cs

@ -1,13 +1,8 @@ @@ -1,13 +1,8 @@
using System;
#if !OLD_PARSER
using CppSharp.AST;
using CppSharp.Parser;
using ASTContext = CppSharp.Parser.AST.ASTContext;
using NativeLibrary = CppSharp.Parser.AST.NativeLibrary;
#else
using CppSharp.AST;
#endif
namespace CppSharp
{
@ -89,7 +84,6 @@ namespace CppSharp @@ -89,7 +84,6 @@ namespace CppSharp
return result;
}
#if !OLD_PARSER
/// <summary>
/// Converts a native parser AST to a managed AST.
/// </summary>
@ -103,19 +97,13 @@ namespace CppSharp @@ -103,19 +97,13 @@ namespace CppSharp
{
var newLibrary = new AST.NativeLibrary { FileName = library.FileName };
#if OLD_PARSER
foreach (var symbol in library.Symbols)
newLibrary.Symbols.Add(symbol);
#else
for (uint i = 0; i < library.SymbolsCount; ++i)
{
var symbol = library.getSymbols(i);
newLibrary.Symbols.Add(symbol);
}
#endif
return newLibrary;
}
#endif
}
}

3
src/Core/Project.cs

@ -1,9 +1,6 @@ @@ -1,9 +1,6 @@
using System.Collections.Generic;
using CppSharp.AST;
#if !OLD_PARSER
using CppSharp.Parser;
#endif
namespace CppSharp
{

16
src/CppParser/Bindings/ParserGen.cs

@ -5,9 +5,7 @@ using CppSharp.AST; @@ -5,9 +5,7 @@ using CppSharp.AST;
using CppSharp.Generators;
using CppSharp.Passes;
using CppSharp.Types;
#if !OLD_PARSER
using CppAbi = CppSharp.Parser.AST.CppAbi;
#endif
namespace CppSharp
{
@ -63,15 +61,8 @@ namespace CppSharp @@ -63,15 +61,8 @@ namespace CppSharp
SetupMacOptions(options);
var basePath = Path.Combine(GetSourceDirectory("src"), "CppParser");
#if OLD_PARSER
options.IncludeDirs.Add(basePath);
options.LibraryDirs.Add(".");
#else
options.addIncludeDirs(basePath);
options.addLibraryDirs(".");
#endif
options.OutputDir = Path.Combine(GetSourceDirectory("src"), @"CppParser\Bindings",
Kind.ToString());
@ -91,17 +82,10 @@ namespace CppSharp @@ -91,17 +82,10 @@ namespace CppSharp
var headersPath = Path.Combine(GetSourceDirectory("build"), "headers",
"osx");
#if OLD_PARSER
options.SystemIncludeDirs.Add(headersPath + @"include\osx");
options.SystemIncludeDirs.Add(headersPath + @"lib\libcxx\include");
options.SystemIncludeDirs.Add(headersPath + @"lib\clang\4.2\include");
options.Arguments.Add("-stdlib=libc++");
#else
options.addSystemIncludeDirs(Path.Combine(headersPath, "include"));
options.addSystemIncludeDirs(Path.Combine(headersPath, "clang", "4.2", "include"));
options.addSystemIncludeDirs(Path.Combine(headersPath, "libcxx", "include"));
options.addArguments("-stdlib=libc++");
#endif
}
public void SetupPasses(Driver driver)

5
src/Generator.Tests/ASTTestFixture.cs

@ -15,12 +15,7 @@ namespace CppSharp.Generator.Tests @@ -15,12 +15,7 @@ namespace CppSharp.Generator.Tests
Options = new DriverOptions();
var testsPath = GeneratorTest.GetTestsDirectory("Native");
#if OLD_PARSER
Options.IncludeDirs.Add(testsPath);
#else
Options.addIncludeDirs(testsPath);
#endif
Options.Headers.AddRange(files);

5
src/Generator.Tests/GeneratorTest.cs

@ -43,12 +43,7 @@ namespace CppSharp.Utils @@ -43,12 +43,7 @@ namespace CppSharp.Utils
options.SharedLibraryName += ".dll";
var path = Path.GetFullPath(GetTestsDirectory(name));
#if OLD_PARSER
options.IncludeDirs.Add(path);
#else
options.addIncludeDirs(path);
#endif
driver.Diagnostics.EmitMessage("Looking for tests in: {0}", path);
var files = Directory.EnumerateFiles(path, "*.h");

56
src/Generator/Driver.cs

@ -12,10 +12,7 @@ using CppSharp.Generators.CSharp; @@ -12,10 +12,7 @@ using CppSharp.Generators.CSharp;
using CppSharp.Passes;
using CppSharp.Types;
using Microsoft.CSharp;
#if !OLD_PARSER
using CppSharp.Parser;
#endif
namespace CppSharp
{
@ -64,25 +61,9 @@ namespace CppSharp @@ -64,25 +61,9 @@ namespace CppSharp
if (string.IsNullOrWhiteSpace(options.LibraryName))
throw new InvalidOptionException();
#if OLD_PARSER
for (var i = 0; i < options.IncludeDirs.Count; i++)
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 (options.NoGenIncludeDirs != null)
for (var i = 0; i < options.NoGenIncludeDirs.Count; i++)
options.NoGenIncludeDirs[i] = Path.GetFullPath(options.NoGenIncludeDirs[i]);
#endif
if (options.NoGenIncludeDirs != null)
foreach (var incDir in options.NoGenIncludeDirs)
#if OLD_PARSER
options.IncludeDirs.Add(incDir);
#else
options.addIncludeDirs(incDir);
#endif
if (string.IsNullOrWhiteSpace(options.OutputNamespace))
options.OutputNamespace = options.LibraryName;
@ -119,22 +100,6 @@ namespace CppSharp @@ -119,22 +100,6 @@ namespace CppSharp
break;
}
#if OLD_PARSER
foreach (var diag in result.Diagnostics)
{
if (Options.IgnoreParseWarnings
&& diag.Level == ParserDiagnosticLevel.Warning)
continue;
if (diag.Level == ParserDiagnosticLevel.Note)
continue;
Diagnostics.EmitMessage(DiagnosticId.ParserDiagnostic,
"{0}({1},{2}): {3}: {4}", diag.FileName, diag.LineNumber,
diag.ColumnNumber, diag.Level.ToString().ToLower(),
diag.Message);
}
#else
for (uint i = 0; i < result.DiagnosticsCount; ++i)
{
var diag = result.getDiagnostics(i);
@ -151,8 +116,6 @@ namespace CppSharp @@ -151,8 +116,6 @@ namespace CppSharp
diag.ColumnNumber, diag.Level.ToString().ToLower(),
diag.Message);
}
#endif
}
ParserOptions BuildParseOptions(SourceFile file)
@ -160,13 +123,6 @@ namespace CppSharp @@ -160,13 +123,6 @@ namespace CppSharp
var options = new ParserOptions
{
FileName = file.Path,
#if OLD_PARSER
Arguments = Options.Arguments,
IncludeDirs = Options.IncludeDirs,
SystemIncludeDirs = Options.SystemIncludeDirs,
Defines = Options.Defines,
LibraryDirs = Options.LibraryDirs,
#endif
Abi = Options.Abi,
ToolSetToUse = Options.ToolSetToUse,
TargetTriple = Options.TargetTriple,
@ -176,7 +132,6 @@ namespace CppSharp @@ -176,7 +132,6 @@ namespace CppSharp
Verbose = Options.Verbose,
};
#if !OLD_PARSER
for (uint i = 0; i < Options.ArgumentsCount; ++i)
{
var arg = Options.getArguments(i);
@ -206,7 +161,6 @@ namespace CppSharp @@ -206,7 +161,6 @@ namespace CppSharp
var lib = Options.getLibraryDirs(i);
options.addLibraryDirs(lib);
}
#endif
return options;
}
@ -219,20 +173,14 @@ namespace CppSharp @@ -219,20 +173,14 @@ namespace CppSharp
source.Options = BuildParseOptions(source);
}
#if !OLD_PARSER
var parser = new ClangParser(new Parser.AST.ASTContext());
#else
var parser = new ClangParser(ASTContext);
#endif
parser.SourceParsed += OnSourceFileParsed;
parser.ParseProject(Project, Options);
TargetInfo = parser.GetTargetInfo(Options);
#if !OLD_PARSER
ASTContext = ClangParser.ConvertASTContext(parser.ASTContext);
#endif
return true;
}
@ -251,11 +199,7 @@ namespace CppSharp @@ -251,11 +199,7 @@ namespace CppSharp
if (res.Kind != ParserResultKind.Success)
continue;
#if !OLD_PARSER
Symbols.Libraries.Add(ClangParser.ConvertLibrary(res.Library));
#else
Symbols.Libraries.Add(res.Library);
#endif
}
return true;

2
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -12,9 +12,7 @@ using CppSharp.Types; @@ -12,9 +12,7 @@ using CppSharp.Types;
using CppSharp.Utils;
using Attribute = CppSharp.AST.Attribute;
using Type = CppSharp.AST.Type;
#if !OLD_PARSER
using CppAbi = CppSharp.Parser.AST.CppAbi;
#endif
namespace CppSharp.Generators.CSharp
{

2
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -4,9 +4,7 @@ using CppSharp.AST; @@ -4,9 +4,7 @@ using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Types;
using Type = CppSharp.AST.Type;
#if !OLD_PARSER
using ParserTargetInfo = CppSharp.Parser.ParserTargetInfo;
#endif
namespace CppSharp.Generators.CSharp
{

2
src/Generator/Options.cs

@ -4,10 +4,8 @@ using System.IO; @@ -4,10 +4,8 @@ using System.IO;
using System.Text;
using CppSharp.AST;
using CppSharp.Generators;
#if !OLD_PARSER
using CppSharp.Parser;
using CppAbi = CppSharp.Parser.AST.CppAbi;
#endif
namespace CppSharp
{

6
src/Generator/Passes/CleanUnitPass.cs

@ -31,15 +31,9 @@ namespace CppSharp.Passes @@ -31,15 +31,9 @@ namespace CppSharp.Passes
var includePath = filePath;
var shortestIncludePath = filePath;
#if OLD_PARSER
foreach (var path in DriverOptions.IncludeDirs)
#else
for (uint i = 0; i < DriverOptions.IncludeDirsCount; ++i)
#endif
{
#if !OLD_PARSER
var path = DriverOptions.getIncludeDirs(i);
#endif
int idx = filePath.IndexOf(path, System.StringComparison.Ordinal);
if (idx == -1) continue;

3
src/Generator/Passes/GenerateAbstractImplementationsPass.cs

@ -1,10 +1,7 @@ @@ -1,10 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
#if !OLD_PARSER
using CppAbi = CppSharp.Parser.AST.CppAbi;
#endif
namespace CppSharp.Passes
{

3
src/Generator/Passes/GenerateInlinesCodePass.cs

@ -2,10 +2,7 @@ @@ -2,10 +2,7 @@
using System.IO;
using System.Text;
using CppSharp.AST;
#if !OLD_PARSER
using CppAbi = CppSharp.Parser.AST.CppAbi;
#endif
namespace CppSharp.Passes
{

48
src/Parser/CXXABI.h

@ -1,48 +0,0 @@ @@ -1,48 +0,0 @@
//===----- CXXABI.h - Interface to C++ ABIs ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This provides an abstract class for C++ AST support. Concrete
// subclasses of this implement AST support for specific C++ ABIs.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_CXXABI_H
#define LLVM_CLANG_AST_CXXABI_H
#include "clang/AST/Type.h"
namespace clang {
class ASTContext;
class MemberPointerType;
/// Implements C++ ABI-specific semantic analysis functions.
class CXXABI {
public:
virtual ~CXXABI();
/// Returns the size of a member pointer in multiples of the target
/// pointer size.
virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0;
/// Returns the default calling convention for C++ methods.
virtual CallingConv getDefaultMethodCallConv() const = 0;
// Returns whether the given class is nearly empty, with just virtual pointers
// and no data except possibly virtual bases.
virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0;
};
/// Creates an instance of a C++ ABI class.
CXXABI *CreateARMCXXABI(ASTContext &Ctx);
CXXABI *CreateItaniumCXXABI(ASTContext &Ctx);
CXXABI *CreateMicrosoftCXXABI(ASTContext &Ctx);
}
#endif

268
src/Parser/Comments.cpp

@ -1,268 +0,0 @@ @@ -1,268 +0,0 @@
/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#include "Parser.h"
#include "Interop.h"
#include <clang/AST/ASTContext.h>
//-----------------------------------//
static CppSharp::AST::RawCommentKind
ConvertCommentKind(clang::RawComment::CommentKind Kind)
{
using clang::RawComment;
using namespace CppSharp::AST;
switch(Kind)
{
case RawComment::RCK_Invalid: return RawCommentKind::Invalid;
case RawComment::RCK_OrdinaryBCPL: return RawCommentKind::OrdinaryBCPL;
case RawComment::RCK_OrdinaryC: return RawCommentKind::OrdinaryC;
case RawComment::RCK_BCPLSlash: return RawCommentKind::BCPLSlash;
case RawComment::RCK_BCPLExcl: return RawCommentKind::BCPLExcl;
case RawComment::RCK_JavaDoc: return RawCommentKind::JavaDoc;
case RawComment::RCK_Qt: return RawCommentKind::Qt;
case RawComment::RCK_Merged: return RawCommentKind::Merged;
}
llvm_unreachable("Unknown comment kind");
}
CppSharp::AST::RawComment^ Parser::WalkRawComment(const clang::RawComment* RC)
{
using namespace clang;
using namespace clix;
auto &SM = C->getSourceManager();
auto Comment = gcnew CppSharp::AST::RawComment();
Comment->Kind = ConvertCommentKind(RC->getKind());
Comment->Text = marshalString<E_UTF8>(RC->getRawText(SM));
Comment->BriefText = marshalString<E_UTF8>(RC->getBriefText(*AST));
return Comment;
}
static CppSharp::AST::InlineCommandComment::RenderKind
ConvertRenderKind(clang::comments::InlineCommandComment::RenderKind Kind)
{
using namespace clang::comments;
switch(Kind)
{
case InlineCommandComment::RenderNormal:
return CppSharp::AST::InlineCommandComment::RenderKind::RenderNormal;
case InlineCommandComment::RenderBold:
return CppSharp::AST::InlineCommandComment::RenderKind::RenderBold;
case InlineCommandComment::RenderMonospaced:
return CppSharp::AST::InlineCommandComment::RenderKind::RenderMonospaced;
case InlineCommandComment::RenderEmphasized:
return CppSharp::AST::InlineCommandComment::RenderKind::RenderEmphasized;
}
llvm_unreachable("Unknown render kind");
}
static CppSharp::AST::ParamCommandComment::PassDirection
ConvertParamPassDirection(clang::comments::ParamCommandComment::PassDirection Dir)
{
using namespace clang::comments;
switch(Dir)
{
case ParamCommandComment::In:
return CppSharp::AST::ParamCommandComment::PassDirection::In;
case ParamCommandComment::Out:
return CppSharp::AST::ParamCommandComment::PassDirection::Out;
case ParamCommandComment::InOut:
return CppSharp::AST::ParamCommandComment::PassDirection::InOut;
}
llvm_unreachable("Unknown parameter pass direction");
}
static void HandleBlockCommand(const clang::comments::BlockCommandComment *CK,
CppSharp::AST::BlockCommandComment^ BC)
{
using namespace clix;
BC->CommandId = CK->getCommandID();
for (unsigned I = 0, E = CK->getNumArgs(); I != E; ++I)
{
auto Arg = CppSharp::AST::BlockCommandComment::Argument();
Arg.Text = marshalString<E_UTF8>(CK->getArgText(I));
BC->Arguments->Add(Arg);
}
}
static CppSharp::AST::Comment^ ConvertCommentBlock(clang::comments::Comment* C)
{
using namespace clang;
using clang::comments::Comment;
using namespace clix;
using namespace CppSharp::AST;
// This needs to have an underscore else we get an ICE under VS2012.
CppSharp::AST::Comment^ _Comment;
switch(C->getCommentKind())
{
case Comment::BlockCommandCommentKind:
{
auto CK = cast<const clang::comments::BlockCommandComment>(C);
auto BC = gcnew BlockCommandComment();
_Comment = BC;
HandleBlockCommand(CK, BC);
break;
}
case Comment::ParamCommandCommentKind:
{
auto CK = cast<clang::comments::ParamCommandComment>(C);
auto PC = gcnew ParamCommandComment();
_Comment = PC;
HandleBlockCommand(CK, PC);
PC->Direction = ConvertParamPassDirection(CK->getDirection());
if (CK->isParamIndexValid() && !CK->isVarArgParam())
PC->ParamIndex = CK->getParamIndex();
break;
}
case Comment::TParamCommandCommentKind:
{
auto CK = cast<clang::comments::TParamCommandComment>(C);
_Comment = gcnew TParamCommandComment();
auto TC = gcnew TParamCommandComment();
_Comment = TC;
HandleBlockCommand(CK, TC);
if (CK->isPositionValid())
for (unsigned I = 0, E = CK->getDepth(); I != E; ++I)
TC->Position->Add(CK->getIndex(I));
break;
}
case Comment::VerbatimBlockCommentKind:
{
auto CK = cast<clang::comments::VerbatimBlockComment>(C);
auto VB = gcnew VerbatimBlockComment();
_Comment = VB;
for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
{
auto Line = ConvertCommentBlock(*I);
VB->Lines->Add(dynamic_cast<VerbatimBlockLineComment^>(Line));
}
break;
}
case Comment::VerbatimLineCommentKind:
{
auto CK = cast<clang::comments::VerbatimLineComment>(C);
auto VL = gcnew VerbatimLineComment();
_Comment = VL;
VL->Text = marshalString<E_UTF8>(CK->getText());
break;
}
case Comment::ParagraphCommentKind:
{
auto CK = cast<clang::comments::ParagraphComment>(C);
auto PC = gcnew ParagraphComment();
_Comment = PC;
for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
{
auto Content = ConvertCommentBlock(*I);
PC->Content->Add(dynamic_cast<InlineContentComment^>(Content));
}
PC->IsWhitespace = CK->isWhitespace();
break;
}
case Comment::FullCommentKind:
{
auto CK = cast<clang::comments::FullComment>(C);
auto FC = gcnew FullComment();
_Comment = FC;
for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
{
auto Content = ConvertCommentBlock(*I);
FC->Blocks->Add(dynamic_cast<BlockContentComment^>(Content));
}
break;
}
case Comment::HTMLStartTagCommentKind:
{
auto CK = cast<clang::comments::HTMLStartTagComment>(C);
auto TC = gcnew HTMLStartTagComment();
_Comment = TC;
TC->TagName = marshalString<E_UTF8>(CK->getTagName());
for (unsigned I = 0, E = CK->getNumAttrs(); I != E; ++I)
{
auto A = CK->getAttr(I);
auto Attr = CppSharp::AST::HTMLStartTagComment::Attribute();
Attr.Name = marshalString<E_UTF8>(A.Name);
Attr.Value = marshalString<E_UTF8>(A.Value);
TC->Attributes->Add(Attr);
}
break;
}
case Comment::HTMLEndTagCommentKind:
{
auto CK = cast<clang::comments::HTMLEndTagComment>(C);
auto TC = gcnew HTMLEndTagComment();
_Comment = TC;
TC->TagName = marshalString<E_UTF8>(CK->getTagName());
break;
}
case Comment::TextCommentKind:
{
auto CK = cast<clang::comments::TextComment>(C);
auto TC = gcnew TextComment();
_Comment = TC;
TC->Text = marshalString<E_UTF8>(CK->getText());
break;
}
case Comment::InlineCommandCommentKind:
{
auto CK = cast<clang::comments::InlineCommandComment>(C);
auto IC = gcnew InlineCommandComment();
_Comment = IC;
IC->Kind = ConvertRenderKind(CK->getRenderKind());
for (unsigned I = 0, E = CK->getNumArgs(); I != E; ++I)
{
auto Arg = CppSharp::AST::InlineCommandComment::Argument();
Arg.Text = marshalString<E_UTF8>(CK->getArgText(I));
IC->Arguments->Add(Arg);
}
break;
}
case Comment::VerbatimBlockLineCommentKind:
{
auto CK = cast<clang::comments::VerbatimBlockLineComment>(C);
auto VL = gcnew VerbatimBlockLineComment();
_Comment = VL;
VL->Text = marshalString<E_UTF8>(CK->getText());
break;
}
case Comment::NoCommentKind: return nullptr;
default:
llvm_unreachable("Unknown comment kind");
}
assert(_Comment && "Invalid comment instance");
return _Comment;
}
void Parser::HandleComments(clang::Decl* D, CppSharp::AST::Declaration^ Decl)
{
using namespace clang;
using namespace clang::comments;
using namespace clix;
const RawComment* RC = 0;
if (!(RC = AST->getRawCommentForAnyRedecl(D)))
return;
auto RawComment = WalkRawComment(RC);
Decl->Comment = RawComment;
if (FullComment* FC = RC->parse(*AST, &C->getPreprocessor(), D))
{
auto CB = safe_cast<CppSharp::AST::FullComment^>(ConvertCommentBlock(FC));
RawComment->FullComment = CB;
}
}

203
src/Parser/Interop.h

@ -1,203 +0,0 @@ @@ -1,203 +0,0 @@
// ------------------------------------------------------------------------------------------- //
// clix.hpp (from http://blog.nuclex-games.com/mono-dotnet/cxx-cli-string-marshaling)
//
// Marshals strings between .NET and C++ using C++/CLI (Visual C++ 2005 and later only).
// Faster and cleaner than the System::Interop method because it uses garbage collected memory.
// Use at your own leisure. No warranties whatsoever provided.
//
// Original code by Markus Ewald
// Updated version including several improvements suggested by Neil Hunt
//
// Licensed under the IBM CPL (free of charge, closed source commercial use is okay)
// ------------------------------------------------------------------------------------------- //
#pragma once
#include <string>
#include <vcclr.h>
// CLI extensions namespace
namespace clix {
/// <summary>Encoding types for strings</summary>
enum Encoding {
/// <summary>ANSI encoding</summary>
/// <remarks>
/// This is the default encoding you've most likely been using all around in C++. ANSI
/// means 8 Bit encoding with character codes depending on the system's selected code page.
/// <remarks>
E_ANSI,
/// <summary>UTF-8 encoding</summary>
/// <remarks>
/// This is the encoding commonly used for multilingual C++ strings. All ASCII characters
/// (0-127) will be represented as single bytes. Be aware that UTF-8 uses more than one
/// byte for extended characters, so std::string::length() might not reflect the actual
/// length of the string in characters if it contains any non-ASCII characters.
/// <remarks>
E_UTF8,
/// <summary>UTF-16 encoding</summary>
/// <remarks>
/// This is the suggested to be used for marshaling and the native encoding of .NET
/// strings. It is similar to UTF-8 but uses a minimum of two bytes per character, making
/// the number of bytes required for a given string better predictable. Be aware, however,
/// that UTF-16 can still use more than two bytes for a character, so std::wstring::length()
/// might not reflect the actual length of the string.
/// </remarks>
E_UTF16, E_UNICODE = E_UTF16
};
// Ignore this if you're just scanning the headers for informations!
/* All this template stuff might seem like overkill, but it is well thought out and enables
you to use a readable and convenient call while still keeping the highest possible code
efficiency due to compile-time evaluation of the required conversion path.
*/
namespace detail {
// Get C++ string type for specified encoding
template<Encoding encoding> struct StringTypeSelector;
template<> struct StringTypeSelector<E_ANSI> { typedef std::string Type; };
template<> struct StringTypeSelector<E_UTF8> { typedef std::string Type; };
template<> struct StringTypeSelector<E_UTF16> { typedef std::wstring Type; };
// Compile-time selection depending on whether a string is managed
template<typename StringType> struct IfManaged {
struct Select {
template<typename TrueType, typename FalseType>
struct Either { typedef FalseType Type; };
};
enum { Result = false };
};
template<> struct IfManaged<System::String ^> {
struct Select {
template<typename TrueType, typename FalseType>
struct Either { typedef TrueType Type; };
};
enum { Result = true };
};
// Direction of the marshaling process
enum MarshalingDirection {
CxxFromNet,
NetFromCxx
};
// The actual marshaling code
template<MarshalingDirection direction> struct StringMarshaler;
// Marshals to .NET from C++ strings
template<> struct StringMarshaler<NetFromCxx> {
template<Encoding encoding, typename SourceType>
static System::String ^marshal(const SourceType &string) {
// Constructs a std::[w]string in case someone gave us a char * to choke on
return marshalCxxString<encoding, SourceType>(string);
}
template<Encoding encoding, typename SourceType>
static System::String ^marshalCxxString(
const typename StringTypeSelector<encoding>::Type &cxxString
) {
typedef typename StringTypeSelector<encoding>::Type SourceStringType;
size_t byteCount = cxxString.length() * sizeof(SourceStringType::value_type);
if(byteCount == 0) return System::String::Empty;
// Copy the C++ string contents into a managed array of bytes
array<unsigned char> ^bytes = gcnew array<unsigned char>(byteCount);
{ pin_ptr<unsigned char> pinnedBytes = &bytes[0];
memcpy(pinnedBytes, cxxString.c_str(), byteCount);
}
// Now let one of .NET's encoding classes do the rest
return decode<encoding>(bytes);
}
private:
// Converts a byte array based on the selected encoding
template<Encoding encoding> static System::String ^decode(array<unsigned char> ^bytes);
template<> static System::String ^decode<E_ANSI>(array<unsigned char> ^bytes) {
return System::Text::Encoding::Default->GetString(bytes);
}
template<> static System::String ^decode<E_UTF8>(array<unsigned char> ^bytes) {
return System::Text::Encoding::UTF8->GetString(bytes);
}
template<> static System::String ^decode<E_UTF16>(array<unsigned char> ^bytes) {
return System::Text::Encoding::Unicode->GetString(bytes);
}
};
// Marshals to C++ strings from .NET
template<> struct StringMarshaler<CxxFromNet> {
template<Encoding encoding, typename SourceType>
static typename detail::StringTypeSelector<encoding>::Type marshal(
System::String ^string
) {
typedef typename StringTypeSelector<encoding>::Type StringType;
// First, we use .NET's encoding classes to convert the string into a byte array
array<unsigned char> ^bytes = encode<encoding>(string);
if(bytes->Length == 0) return StringType();
// Then we construct our native string from that byte array
pin_ptr<unsigned char> pinnedBytes(&bytes[0]);
return StringType(
reinterpret_cast<StringType::value_type *>(static_cast<unsigned char *>(pinnedBytes)),
bytes->Length / sizeof(StringType::value_type)
);
}
template<> static std::wstring marshal<E_UTF16, System::String ^>(
System::String ^string
) {
// We can directly accesss the characters in the managed string
pin_ptr<const wchar_t> pinnedChars(::PtrToStringChars(string));
return std::wstring(pinnedChars, string->Length);
}
private:
// Converts a string based on the selected encoding
template<Encoding encoding> static array<unsigned char> ^encode(System::String ^string);
template<> static array<unsigned char> ^encode<E_ANSI>(System::String ^string) {
return System::Text::Encoding::Default->GetBytes(string);
}
template<> static array<unsigned char> ^encode<E_UTF8>(System::String ^string) {
return System::Text::Encoding::UTF8->GetBytes(string);
}
template<> static array<unsigned char> ^encode<E_UTF16>(System::String ^string) {
return System::Text::Encoding::Unicode->GetBytes(string);
}
};
} // namespace detail
// ----------------------------------------------------------------------------------------- //
// clix::marshalString()
// ----------------------------------------------------------------------------------------- //
/// <summary>Marshals strings between .NET managed and C++ native</summary>
/// <remarks>
/// This all-in-one function marshals native C++ strings to .NET strings and vice versa.
/// You have to specify an encoding to use for the conversion, which always applies to the
/// native C++ string as .NET always uses UTF-16 for its own strings.
/// </remarks>
/// <param name="string">String to be marshalled to the other side</param>
/// <returns>The marshaled representation of the string</returns>
template<Encoding encoding, typename SourceType>
typename detail::IfManaged<SourceType>::Select::Either<
typename detail::StringTypeSelector<encoding>::Type,
System::String ^
>::Type marshalString(SourceType string) {
// Pass on the call to our nifty template routines
return detail::StringMarshaler<
detail::IfManaged<SourceType>::Result ? detail::CxxFromNet : detail::NetFromCxx
>::marshal<encoding, SourceType>(string);
}
} // namespace clix

46
src/Parser/Main.cpp

@ -1,46 +0,0 @@ @@ -1,46 +0,0 @@
/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#include "Parser.h"
#include "Interop.h"
namespace CppSharp { namespace Parser {
public ref class ClangParser
{
public:
static ParserTargetInfo^ GetTargetInfo(ParserOptions^ Opts)
{
::Parser parser(Opts);
return parser.GetTargetInfo();
}
static ParserResult^ ParseHeader(ParserOptions^ Opts)
{
if (!Opts->FileName) return nullptr;
using namespace clix;
std::string File = marshalString<E_UTF8>(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<E_UTF8>(Opts->FileName);
::Parser parser(Opts);
return parser.ParseLibrary(File);
}
};
} }

102
src/Parser/Options.h

@ -1,102 +0,0 @@ @@ -1,102 +0,0 @@
/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#using <CppSharp.AST.dll>
using namespace System::Collections::Generic;
public enum struct CppAbi
{
Itanium,
Microsoft,
ARM
};
public ref struct ParserOptions
{
ParserOptions()
{
Arguments = gcnew List<System::String^>();
IncludeDirs = gcnew List<System::String^>();
SystemIncludeDirs = gcnew List<System::String^>();
Defines = gcnew List<System::String^>();
LibraryDirs = gcnew List<System::String^>();
MicrosoftMode = false;
NoStandardIncludes = false;
NoBuiltinIncludes = false;
}
List<System::String^>^ Arguments;
// Include directories
List<System::String^>^ IncludeDirs;
List<System::String^>^ SystemIncludeDirs;
List<System::String^>^ Defines;
List<System::String^>^ LibraryDirs;
// C/C++ header file name.
System::String^ FileName;
CppSharp::AST::ASTContext^ ASTContext;
int ToolSetToUse;
System::String^ TargetTriple;
bool NoStandardIncludes;
bool NoBuiltinIncludes;
bool MicrosoftMode;
CppAbi Abi;
bool Verbose;
};
public enum struct ParserDiagnosticLevel
{
Ignored,
Note,
Warning,
Error,
Fatal
};
public value struct ParserDiagnostic
{
System::String^ FileName;
System::String^ Message;
ParserDiagnosticLevel Level;
int LineNumber;
int ColumnNumber;
};
public enum struct ParserResultKind
{
Success,
Error,
FileNotFound
};
public ref struct ParserResult
{
ParserResult()
{
Diagnostics = gcnew List<ParserDiagnostic>();
}
ParserResultKind Kind;
List<ParserDiagnostic>^ Diagnostics;
CppSharp::AST::ASTContext^ ASTContext;
CppSharp::AST::NativeLibrary^ Library;
};
enum class SourceLocationKind
{
Invalid,
Builtin,
CommandLine,
System,
User
};

3031
src/Parser/Parser.cpp

File diff suppressed because it is too large Load Diff

130
src/Parser/Parser.h

@ -1,130 +0,0 @@ @@ -1,130 +0,0 @@
/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#using <CppSharp.AST.dll>
#include <llvm/Support/Host.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/ASTConsumers.h>
#include <clang/Basic/FileManager.h>
#include <clang/Basic/TargetOptions.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/Basic/IdentifierTable.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/Mangle.h>
#include <clang/AST/RawCommentList.h>
#include <clang/AST/Comment.h>
#include <clang/AST/RecordLayout.h>
#include <clang/AST/VTableBuilder.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Lex/PreprocessingRecord.h>
#include <clang/Parse/ParseAST.h>
#include <clang/Sema/Sema.h>
#include "CXXABI.h"
#include "Options.h"
#include "Target.h"
#include <vcclr.h>
#include <string>
typedef std::string String;
namespace clang {
class TargetCodeGenInfo;
namespace CodeGen {
class CodeGenTypes;
}
}
#define Debug printf
struct Parser
{
Parser(ParserOptions^ Opts);
void SetupHeader();
ParserResult^ ParseHeader(const std::string& File);
ParserResult^ ParseLibrary(const std::string& File);
ParserResultKind ParseArchive(llvm::StringRef File,
llvm::MemoryBuffer *Buffer,
CppSharp::AST::NativeLibrary^ NativeLib);
ParserResultKind ParseSharedLib(llvm::StringRef File,
llvm::MemoryBuffer *Buffer,
CppSharp::AST::NativeLibrary^ NativeLib);
ParserTargetInfo^ GetTargetInfo();
protected:
// AST traversers
void WalkAST();
CppSharp::AST::Declaration^ WalkDeclaration(clang::Decl* D,
bool IgnoreSystemDecls = true, bool CanBeDefinition = false);
CppSharp::AST::Declaration^ WalkDeclarationDef(clang::Decl* D);
CppSharp::AST::Enumeration^ WalkEnum(clang::EnumDecl* ED);
CppSharp::AST::Function^ WalkFunction(clang::FunctionDecl* FD, bool IsDependent = false,
bool AddToNamespace = true);
CppSharp::AST::Class^ WalkRecordCXX(clang::CXXRecordDecl* Record);
void WalkRecordCXX(clang::CXXRecordDecl* Record, CppSharp::AST::Class^ RC);
CppSharp::AST::ClassTemplateSpecialization^
WalkClassTemplateSpecialization(clang::ClassTemplateSpecializationDecl* CTS);
CppSharp::AST::ClassTemplatePartialSpecialization^
WalkClassTemplatePartialSpecialization(clang::ClassTemplatePartialSpecializationDecl* CTS);
CppSharp::AST::Method^ WalkMethodCXX(clang::CXXMethodDecl* MD, bool AddToClass = true);
CppSharp::AST::Field^ WalkFieldCXX(clang::FieldDecl* FD, CppSharp::AST::Class^ Class);
CppSharp::AST::ClassTemplate^ Parser::WalkClassTemplate(clang::ClassTemplateDecl* TD);
CppSharp::AST::FunctionTemplate^ Parser::WalkFunctionTemplate(
clang::FunctionTemplateDecl* TD);
CppSharp::AST::FunctionTemplateSpecialization^ WalkFunctionTemplateSpec(clang::FunctionTemplateSpecializationInfo* FTS, CppSharp::AST::Function^ Function);
CppSharp::AST::Variable^ WalkVariable(clang::VarDecl* VD);
CppSharp::AST::RawComment^ WalkRawComment(const clang::RawComment* RC);
CppSharp::AST::Type^ WalkType(clang::QualType QualType, clang::TypeLoc* TL = 0,
bool DesugarType = false);
CppSharp::AST::TemplateArgument WalkTemplateArgument(const clang::TemplateArgument& TA, clang::TemplateArgumentLoc* ArgLoc);
List<CppSharp::AST::TemplateArgument>^ WalkTemplateArgumentList(const clang::TemplateArgumentList* TAL, clang::TemplateSpecializationTypeLoc* TSTL);
List<CppSharp::AST::TemplateArgument>^ WalkTemplateArgumentList(const clang::TemplateArgumentList* TAL, const clang::ASTTemplateArgumentListInfo* TSTL);
CppSharp::AST::QualifiedType^ WalkQualifiedType(clang::TypeSourceInfo* TSI);
void WalkVTable(clang::CXXRecordDecl* RD, CppSharp::AST::Class^ C);
CppSharp::AST::VTableLayout^ WalkVTableLayout(const clang::VTableLayout& VTLayout);
CppSharp::AST::VTableComponent WalkVTableComponent(const clang::VTableComponent& Component);
CppSharp::AST::PreprocessedEntity^ WalkPreprocessedEntity(CppSharp::AST::Declaration^ Decl,
clang::PreprocessedEntity* PPEntity);
// Clang helpers
SourceLocationKind GetLocationKind(const clang::SourceLocation& Loc);
bool IsValidDeclaration(const clang::SourceLocation& Loc);
std::string GetDeclMangledName(clang::Decl* D, clang::TargetCXXABI ABI,
bool IsDependent = false);
std::string GetTypeName(const clang::Type* Type);
void WalkFunction(clang::FunctionDecl* FD, CppSharp::AST::Function^ F,
bool IsDependent = false);
void HandlePreprocessedEntities(CppSharp::AST::Declaration^ Decl);
void HandlePreprocessedEntities(CppSharp::AST::Declaration^ Decl, clang::SourceRange sourceRange,
CppSharp::AST::MacroLocation macroLocation = CppSharp::AST::MacroLocation::Unknown);
bool GetDeclText(clang::SourceRange SR, std::string& Text);
CppSharp::AST::TranslationUnit^ GetTranslationUnit(clang::SourceLocation Loc,
SourceLocationKind *Kind = 0);
CppSharp::AST::TranslationUnit^ GetTranslationUnit(const clang::Decl* D);
CppSharp::AST::DeclarationContext^ GetNamespace(clang::Decl* D, clang::DeclContext* Ctx);
CppSharp::AST::DeclarationContext^ GetNamespace(clang::Decl* D);
void HandleDeclaration(clang::Decl* D, CppSharp::AST::Declaration^ Decl);
void HandleOriginalText(clang::Decl* D, CppSharp::AST::Declaration^ Decl);
void HandleComments(clang::Decl* D, CppSharp::AST::Declaration^ Decl);
void HandleDiagnostics(ParserResult^ res);
int Index;
gcroot<CppSharp::AST::ASTContext^> Lib;
gcroot<CppSharp::AST::SymbolContext^> Symbols;
gcroot<ParserOptions^> Opts;
llvm::OwningPtr<clang::CompilerInstance> C;
clang::ASTContext* AST;
clang::TargetCXXABI::Kind TargetABI;
clang::TargetCodeGenInfo* CodeGenInfo;
clang::CodeGen::CodeGenTypes* CodeGenTypes;
};

51
src/Parser/Parser.lua

@ -1,51 +0,0 @@ @@ -1,51 +0,0 @@
clang_msvc_flags =
{
"/wd4146", "/wd4244", "/wd4800", "/wd4345",
"/wd4355", "/wd4996", "/wd4624", "/wd4291"
}
project "CppSharp.Parser"
kind "SharedLib"
language "C++"
SetupNativeProject()
dependson { "CppSharp.AST" }
flags { common_flags, "Managed" }
usingdirs { libdir }
-- usingdirs is only supported in per-file configs in our
-- premake build. remove this once this support is added
-- at the project level.
configuration { "Main.cpp" }
flags { "Managed" }
usingdirs { libdir }
configuration { "Parser.cpp" }
flags { "Managed" }
usingdirs { libdir }
configuration { "Comments.cpp" }
flags { "Managed" }
usingdirs { libdir }
configuration "vs*"
buildoptions { clang_msvc_flags }
files { "VSLookup.cpp" }
configuration "*"
files
{
"*.h",
"*.cpp",
"*.lua"
}
SetupLLVMIncludes()
SetupLLVMLibs()
configuration "*"

69
src/Parser/Target.h

@ -1,69 +0,0 @@ @@ -1,69 +0,0 @@
/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#using <CppSharp.AST.dll>
using namespace System::Collections::Generic;
public enum ParserIntType
{
NoInt = 0,
SignedChar,
UnsignedChar,
SignedShort,
UnsignedShort,
SignedInt,
UnsignedInt,
SignedLong,
UnsignedLong,
SignedLongLong,
UnsignedLongLong
};
public ref struct ParserTargetInfo
{
System::String^ ABI;
ParserIntType Char16Type;
ParserIntType Char32Type;
ParserIntType Int64Type;
ParserIntType IntMaxType;
ParserIntType IntPtrType;
ParserIntType SizeType;
ParserIntType UIntMaxType;
ParserIntType WCharType;
ParserIntType WIntType;
unsigned int BoolAlign;
unsigned int BoolWidth;
unsigned int CharAlign;
unsigned int CharWidth;
unsigned int Char16Align;
unsigned int Char16Width;
unsigned int Char32Align;
unsigned int Char32Width;
unsigned int HalfAlign;
unsigned int HalfWidth;
unsigned int FloatAlign;
unsigned int FloatWidth;
unsigned int DoubleAlign;
unsigned int DoubleWidth;
unsigned int ShortAlign;
unsigned int ShortWidth;
unsigned int IntAlign;
unsigned int IntWidth;
unsigned int IntMaxTWidth;
unsigned int LongAlign;
unsigned int LongWidth;
unsigned int LongDoubleAlign;
unsigned int LongDoubleWidth;
unsigned int LongLongAlign;
unsigned int LongLongWidth;
unsigned int PointerAlign;
unsigned int PointerWidth;
unsigned int WCharAlign;
unsigned int WCharWidth;
};

269
src/Parser/VSLookup.cpp

@ -1,269 +0,0 @@ @@ -1,269 +0,0 @@
/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#ifdef _MSC_VER
#include <string>
#include <vector>
#include <cctype>
// Include the necessary headers to interface with the Windows registry and
// environment.
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#define NOMINMAX
#include <Windows.h>
/// \brief Read registry string.
/// This also supports a means to look for high-versioned keys by use
/// of a $VERSION placeholder in the key path.
/// $VERSION in the key path is a placeholder for the version number,
/// causing the highest value path to be searched for and used.
/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
/// There can be additional characters in the component. Only the numeric
/// characters are compared.
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
char *value, size_t maxLength) {
HKEY hRootKey = NULL;
HKEY hKey = NULL;
const char* subKey = NULL;
DWORD valueType;
DWORD valueSize = maxLength - 1;
long lResult;
bool returnValue = false;
if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
hRootKey = HKEY_CLASSES_ROOT;
subKey = keyPath + 18;
} else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
hRootKey = HKEY_USERS;
subKey = keyPath + 11;
} else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
hRootKey = HKEY_LOCAL_MACHINE;
subKey = keyPath + 19;
} else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
hRootKey = HKEY_CURRENT_USER;
subKey = keyPath + 18;
} else {
return false;
}
const char *placeHolder = strstr(subKey, "$VERSION");
char bestName[256];
bestName[0] = '\0';
// If we have a $VERSION placeholder, do the highest-version search.
if (placeHolder) {
const char *keyEnd = placeHolder - 1;
const char *nextKey = placeHolder;
// Find end of previous key.
while ((keyEnd > subKey) && (*keyEnd != '\\'))
keyEnd--;
// Find end of key containing $VERSION.
while (*nextKey && (*nextKey != '\\'))
nextKey++;
size_t partialKeyLength = keyEnd - subKey;
char partialKey[256];
if (partialKeyLength > sizeof(partialKey))
partialKeyLength = sizeof(partialKey);
strncpy(partialKey, subKey, partialKeyLength);
partialKey[partialKeyLength] = '\0';
HKEY hTopKey = NULL;
lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ, &hTopKey);
if (lResult == ERROR_SUCCESS) {
char keyName[256];
int bestIndex = -1;
double bestValue = 0.0;
DWORD index, size = sizeof(keyName) - 1;
for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL,
NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
const char *sp = keyName;
while (*sp && !isdigit(*sp))
sp++;
if (!*sp)
continue;
const char *ep = sp + 1;
while (*ep && (isdigit(*ep) || (*ep == '.')))
ep++;
char numBuf[32];
strncpy(numBuf, sp, sizeof(numBuf) - 1);
numBuf[sizeof(numBuf) - 1] = '\0';
double value = strtod(numBuf, NULL);
// Check if InstallDir key value exists.
bool isViableVersion = false;
lResult = RegOpenKeyExA(hTopKey, keyName, 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
lResult = RegQueryValueExA(hKey, valueName, NULL, NULL, NULL, NULL);
if (lResult == ERROR_SUCCESS)
isViableVersion = true;
RegCloseKey(hKey);
}
if (isViableVersion && (value > bestValue)) {
bestIndex = (int)index;
bestValue = value;
strcpy(bestName, keyName);
}
size = sizeof(keyName) - 1;
}
// If we found the highest versioned key, open the key and get the value.
if (bestIndex != -1) {
// Append rest of key.
strncat(bestName, nextKey, sizeof(bestName) - 1);
bestName[sizeof(bestName) - 1] = '\0';
// Open the chosen key path remainder.
lResult = RegOpenKeyExA(hTopKey, bestName, 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
lResult = RegQueryValueExA(hKey, valueName, NULL, &valueType,
(LPBYTE)value, &valueSize);
if (lResult == ERROR_SUCCESS)
returnValue = true;
RegCloseKey(hKey);
}
}
RegCloseKey(hTopKey);
}
} else {
lResult = RegOpenKeyExA(hRootKey, subKey, 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
lResult = RegQueryValueExA(hKey, valueName, NULL, &valueType,
(LPBYTE)value, &valueSize);
if (lResult == ERROR_SUCCESS)
returnValue = true;
RegCloseKey(hKey);
}
}
return returnValue;
}
/// \brief Get Windows SDK installation directory.
static bool getWindowsSDKDir(std::string &path) {
char windowsSDKInstallDir[256];
// Try the Windows registry.
bool hasSDKDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
"InstallationFolder",
windowsSDKInstallDir,
sizeof(windowsSDKInstallDir) - 1);
// If we have both vc80 and vc90, pick version we were compiled with.
if (hasSDKDir && windowsSDKInstallDir[0]) {
path = windowsSDKInstallDir;
return true;
}
return false;
}
// Get Visual Studio installation directory.
static bool getVisualStudioDir(std::string &path) {
// First check the environment variables that vsvars32.bat sets.
const char* vcinstalldir = getenv("VCINSTALLDIR");
if (vcinstalldir) {
char *p = const_cast<char *>(strstr(vcinstalldir, "\\VC"));
if (p)
*p = '\0';
path = vcinstalldir;
return true;
}
char vsIDEInstallDir[256];
char vsExpressIDEInstallDir[256];
// Then try the windows registry.
bool hasVCDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
"InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
bool hasVCExpressDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
"InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
// If we have both vc80 and vc90, pick version we were compiled with.
if (hasVCDir && vsIDEInstallDir[0]) {
char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
if (p)
*p = '\0';
path = vsIDEInstallDir;
return true;
}
if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
if (p)
*p = '\0';
path = vsExpressIDEInstallDir;
return true;
}
// Try the environment.
const char *vs120comntools = getenv("VS120COMNTOOLS");
const char *vs110comntools = getenv("VS110COMNTOOLS");
const char *vs100comntools = getenv("VS100COMNTOOLS");
const char *vs90comntools = getenv("VS90COMNTOOLS");
const char *vs80comntools = getenv("VS80COMNTOOLS");
const char *vscomntools = NULL;
// Try to find the version that we were compiled with
if(false) {}
#if (_MSC_VER >= 1800) // VC120
else if (vs120comntools) {
vscomntools = vs120comntools;
}
#elif (_MSC_VER == 1700) // VC110
else if (vs110comntools) {
vscomntools = vs110comntools;
}
#elif (_MSC_VER == 1600) // VC100
else if(vs100comntools) {
vscomntools = vs100comntools;
}
#elif (_MSC_VER == 1500) // VC80
else if(vs90comntools) {
vscomntools = vs90comntools;
}
#elif (_MSC_VER == 1400) // VC80
else if(vs80comntools) {
vscomntools = vs80comntools;
}
#endif
// Otherwise find any version we can
else if (vs120comntools)
vscomntools = vs120comntools;
else if (vs110comntools)
vscomntools = vs110comntools;
else if (vs100comntools)
vscomntools = vs100comntools;
else if (vs90comntools)
vscomntools = vs90comntools;
else if (vs80comntools)
vscomntools = vs80comntools;
if (vscomntools && *vscomntools) {
const char *p = strstr(vscomntools, "\\Common7\\Tools");
path = p ? std::string(vscomntools, p) : vscomntools;
return true;
}
return false;
}
std::vector<std::string> GetWindowsSystemIncludeDirs() {
std::vector<std::string> Paths;
std::string VSDir;
std::string WindowsSDKDir;
// When built with access to the proper Windows APIs, try to actually find
// the correct include paths first.
if (getVisualStudioDir(VSDir)) {
Paths.push_back(VSDir + "\\VC\\include");
if (getWindowsSDKDir(WindowsSDKDir))
Paths.push_back(WindowsSDKDir + "\\include");
else
Paths.push_back(VSDir + "\\VC\\PlatformSDK\\Include");
}
return Paths;
}
#endif
Loading…
Cancel
Save