Merge pull request #1360 from nanoric/autocxxparser

generator.binding:CXXParser:增加include路径的设置
This commit is contained in:
vn.py 2019-01-26 12:19:44 +08:00 committed by GitHub
commit 901664c10a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 29 deletions

16
binding/build.bat Normal file
View File

@ -0,0 +1,16 @@
@echo off
if "%VS150COMNTOOLS%"=="" (
echo Please run this batch file under "x64 Native Tools Command Prompt for VS 2017"
echo Read the doc!
exit 1
)
@echo on
set binding_dir=%~dp0
cd %binding_dir%
rmdir /S /Q build
mkdir build
cd build
cmake -G "Visual Studio 15 2017 Win64" ..
msbuild vnpy_binding.sln /p:Configuration=Release /p:Platform=x64

View File

@ -10,15 +10,21 @@
> 在安装CMake的时候必须勾选将CMake加入PATH > 在安装CMake的时候必须勾选将CMake加入PATH
> 在安装Visual Studio的时候必须勾选使用C++的桌面开发(Desktop Development with C++) > 在安装Visual Studio的时候必须勾选使用C++的桌面开发(Desktop Development with C++)
## 编译步骤 ## 一键编译
打开开始菜单-Visual Studio 2017-x64 Native Tools Command Prompt for VS 2017
将vnpy/binding/build.bat拖入弹出的控制台回车运行即可。
## 手动编译
确保你安装好了Python3CMake还有Visual Studio和C++编译环境,下载好[vnpy]并解压。 确保你安装好了Python3CMake还有Visual Studio和C++编译环境,下载好[vnpy]并解压。
打开开始菜单-Visual Studio 2017-x64 Native Tools Command Prompt for VS 2017 打开开始菜单-Visual Studio 2017-x64 Native Tools Command Prompt for VS 2017
在弹出的控制台中运行以下命令假设你解压到C:\vnpy下 在弹出的控制台中运行以下命令将vnpy解压目录改为你将vnpy解压到的目录
```bat ```bat
cd C:\vnpy cd vnpy解压目录
mkdir binding/build mkdir binding\build
cd binding/build cd binding\build
cmake -G "Visual Studio 15 2017 Win64" .. cmake -G "Visual Studio 15 2017 Win64" ..
msbuild vnpy_binding.sln /p:Configuration=Release /p:Platform=x64 msbuild vnpy_binding.sln /p:Configuration=Release /p:Platform=x64
``` ```

View File

@ -1,7 +1,7 @@
import logging import logging
import os import os
from autocxxpy.cxxparser import CXXParser, CXXParseResult from autocxxpy.cxxparser import CXXFileParser, CXXParseResult
from autocxxpy.generator import GeneratorOptions from autocxxpy.generator import GeneratorOptions
from autocxxpy.preprocessor import PreProcessorResult, PreProcessor from autocxxpy.preprocessor import PreProcessorResult, PreProcessor
@ -19,7 +19,7 @@ class CtpAdaptor:
self.md_header = md_header self.md_header = md_header
def parse(self) -> GeneratorOptions: def parse(self) -> GeneratorOptions:
r0: CXXParseResult = CXXParser( r0: CXXParseResult = CXXFileParser(
[self.md_header, self.td_header] [self.md_header, self.td_header]
).parse() ).parse()
r1: PreProcessorResult = PreProcessor(r0).process() r1: PreProcessorResult = PreProcessor(r0).process()

View File

@ -1,7 +1,7 @@
import logging import logging
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional, Sequence
from .clang.cindex import ( from .clang.cindex import (
Config, Config,
@ -168,16 +168,26 @@ class CXXParseResult(Namespace):
macros: Dict[str, str] = field(default_factory=dict) macros: Dict[str, str] = field(default_factory=dict)
class CXXFileParser: class CXXParser:
def __init__(self, file_path: Optional[str], unsaved_files=None): def __init__(
self,
file_path: Optional[str],
unsaved_files: Sequence[Sequence[str]] = None,
args: List[str] = None,
):
if args is None:
args = []
self.unsaved_files = unsaved_files self.unsaved_files = unsaved_files
self.file_path = file_path self.file_path = file_path
self.args = args
if "-std=c++11" not in self.args:
self.args.append("-std=c++11")
def parse(self) -> CXXParseResult: def parse(self) -> CXXParseResult:
idx = Index.create() idx = Index.create()
rs = idx.parse( rs = idx.parse(
self.file_path, self.file_path,
args="-std=c++11 ".split(" "), args=self.args,
unsaved_files=self.unsaved_files, unsaved_files=self.unsaved_files,
options=( options=(
TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD
@ -189,27 +199,27 @@ class CXXFileParser:
# todo: parse namespace # todo: parse namespace
for c in rs.cursor.walk_preorder(): for c in rs.cursor.walk_preorder():
if c.kind == CursorKind.FUNCTION_DECL: if c.kind == CursorKind.FUNCTION_DECL:
func = CXXFileParser._process_function(c) func = CXXParser._process_function(c)
result.functions[func.name] = func result.functions[func.name] = func
elif c.kind == CursorKind.ENUM_DECL: elif c.kind == CursorKind.ENUM_DECL:
e = CXXFileParser._process_enum(c) e = CXXParser._process_enum(c)
result.enums[e.name] = e result.enums[e.name] = e
elif ( elif (
c.kind == CursorKind.CLASS_DECL c.kind == CursorKind.CLASS_DECL
or c.kind == CursorKind.STRUCT_DECL or c.kind == CursorKind.STRUCT_DECL
): ):
class_ = CXXFileParser._process_class(c) class_ = CXXParser._process_class(c)
cname = class_.name cname = class_.name
result.classes[cname] = class_ result.classes[cname] = class_
elif c.kind == CursorKind.VAR_DECL: elif c.kind == CursorKind.VAR_DECL:
name, value = CXXFileParser._process_variable(c) name, value = CXXParser._process_variable(c)
if value: if value:
result.variables[name] = value result.variables[name] = value
elif c.kind == CursorKind.TYPEDEF_DECL: elif c.kind == CursorKind.TYPEDEF_DECL:
name, target = CXXFileParser._process_typedef(c) name, target = CXXParser._process_typedef(c)
result.typedefs[name] = target result.typedefs[name] = target
elif c.kind == CursorKind.MACRO_DEFINITION: elif c.kind == CursorKind.MACRO_DEFINITION:
name, definition = CXXFileParser._process_macro_definition(c) name, definition = CXXParser._process_macro_definition(c)
result.macros[name] = definition result.macros[name] = definition
elif ( elif (
False False
@ -226,7 +236,7 @@ class CXXFileParser:
# ignore any body # ignore any body
pass pass
elif ( elif (
CXXFileParser._is_literal_cursor(c) CXXParser._is_literal_cursor(c)
or c.kind == CursorKind.MACRO_INSTANTIATION or c.kind == CursorKind.MACRO_INSTANTIATION
or c.kind == CursorKind.INCLUSION_DIRECTIVE or c.kind == CursorKind.INCLUSION_DIRECTIVE
): ):
@ -297,12 +307,12 @@ class CXXFileParser:
class_ = Class(name=c.displayname) class_ = Class(name=c.displayname)
for ac in c.get_children(): for ac in c.get_children():
if ac.kind == CursorKind.CONSTRUCTOR: if ac.kind == CursorKind.CONSTRUCTOR:
func = CXXFileParser._process_method(ac, class_) func = CXXParser._process_method(ac, class_)
if func.is_virtual: if func.is_virtual:
class_.is_polymorphic = True class_.is_polymorphic = True
class_.constructors = func class_.constructors = func
elif ac.kind == CursorKind.DESTRUCTOR: elif ac.kind == CursorKind.DESTRUCTOR:
func = CXXFileParser._process_method(ac, class_) func = CXXParser._process_method(ac, class_)
if func.is_virtual: if func.is_virtual:
class_.is_polymorphic = True class_.is_polymorphic = True
class_.destructor = func class_.destructor = func
@ -310,7 +320,7 @@ class CXXFileParser:
v = Variable(ac.spelling, ac.type.spelling) v = Variable(ac.spelling, ac.type.spelling)
class_.variables[v.name] = v class_.variables[v.name] = v
elif ac.kind == CursorKind.CXX_METHOD: elif ac.kind == CursorKind.CXX_METHOD:
func = CXXFileParser._process_method(ac, class_) func = CXXParser._process_method(ac, class_)
if func.is_virtual: if func.is_virtual:
class_.is_polymorphic = True class_.is_polymorphic = True
class_.functions[func.name].append(func) class_.functions[func.name].append(func)
@ -339,8 +349,8 @@ class CXXFileParser:
length = len(children) length = len(children)
if length == 1: if length == 1:
child = children[0] child = children[0]
if CXXFileParser._is_literal_cursor(child): if CXXParser._is_literal_cursor(child):
value = CXXFileParser._process_literal(child) value = CXXParser._process_literal(child)
return c.spelling, value return c.spelling, value
logger.warning( logger.warning(
"unable to process variable : %s %s", c.spelling, c.extent "unable to process variable : %s %s", c.spelling, c.extent
@ -368,7 +378,7 @@ class CXXFileParser:
@staticmethod @staticmethod
def _get_source(token: Token, encoding="utf-8"): def _get_source(token: Token, encoding="utf-8"):
return CXXFileParser._get_source_from_file( return CXXParser._get_source_from_file(
token.location.file.name, token.location.file.name,
token.extent.start.offset, token.extent.start.offset,
token.extent.end.offset, token.extent.end.offset,
@ -390,7 +400,7 @@ class CXXFileParser:
@staticmethod @staticmethod
def _is_literal_cursor(c: Cursor): def _is_literal_cursor(c: Cursor):
return c.kind in CXXFileParser.LITERAL_KINDS return c.kind in CXXParser.LITERAL_KINDS
# return str(c)[-9:-1] == 'LITERAL' # return str(c)[-9:-1] == 'LITERAL'
@staticmethod @staticmethod
@ -403,7 +413,7 @@ class CXXFileParser:
elif c.kind == CursorKind.STRING_LITERAL: elif c.kind == CursorKind.STRING_LITERAL:
return str(spelling) return str(spelling)
elif c.kind == CursorKind.CHARACTER_LITERAL: elif c.kind == CursorKind.CHARACTER_LITERAL:
return CXXFileParser.character_literal_to_int(spelling) return CXXParser.character_literal_to_int(spelling)
elif c.kind == CursorKind.FLOATING_LITERAL: elif c.kind == CursorKind.FLOATING_LITERAL:
return float(spelling) return float(spelling)
logger.warning( logger.warning(
@ -421,14 +431,26 @@ class CXXFileParser:
pass pass
class CXXParser(CXXFileParser): class CXXFileParser(CXXParser):
def __init__(self, files: List[str]): def __init__(
self,
files: Sequence[str],
include_paths: Sequence[str] = None,
args: List[str] = None,
):
if args is None:
args = []
if include_paths:
for include_path in include_paths:
args.append("-I" + include_path)
dummy_code = "" dummy_code = ""
for file in files: for file in files:
dummy_code += f'#include "{file}"\n' dummy_code += f'#include "{file}"\n'
dummy_name = "dummy.cpp" dummy_name = "dummy.cpp"
super().__init__(dummy_name, unsaved_files=[[dummy_name, dummy_code]]) super().__init__(
dummy_name, unsaved_files=[[dummy_name, dummy_code]], args=args
)
Config.set_library_path("") Config.set_library_path("")