diff --git a/binding/build.bat b/binding/build.bat new file mode 100644 index 00000000..8ce0d8ad --- /dev/null +++ b/binding/build.bat @@ -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 diff --git a/binding/doc/build.windows.md b/binding/doc/build.windows.md index c28989eb..8dc16f4b 100644 --- a/binding/doc/build.windows.md +++ b/binding/doc/build.windows.md @@ -10,15 +10,21 @@ > 在安装CMake的时候必须勾选将CMake加入PATH > 在安装Visual Studio的时候必须勾选使用C++的桌面开发(Desktop Development with C++) -## 编译步骤 +## 一键编译 + +打开开始菜单-Visual Studio 2017-x64 Native Tools Command Prompt for VS 2017 +将vnpy/binding/build.bat拖入弹出的控制台,回车运行即可。 + + +## 手动编译 确保你安装好了Python3,CMake还有Visual Studio和C++编译环境,下载好[vnpy]并解压。 打开开始菜单-Visual Studio 2017-x64 Native Tools Command Prompt for VS 2017 -在弹出的控制台中运行以下命令:(假设你解压到C:\vnpy下) +在弹出的控制台中运行以下命令(将vnpy解压目录改为你将vnpy解压到的目录): ```bat -cd C:\vnpy -mkdir binding/build -cd binding/build +cd vnpy解压目录 +mkdir binding\build +cd binding\build cmake -G "Visual Studio 15 2017 Win64" .. msbuild vnpy_binding.sln /p:Configuration=Release /p:Platform=x64 ``` diff --git a/binding/generator/adaptor/ctpadaptor.py b/binding/generator/adaptor/ctpadaptor.py index ee45bb09..1bbf95a9 100644 --- a/binding/generator/adaptor/ctpadaptor.py +++ b/binding/generator/adaptor/ctpadaptor.py @@ -1,7 +1,7 @@ import logging import os -from autocxxpy.cxxparser import CXXParser, CXXParseResult +from autocxxpy.cxxparser import CXXFileParser, CXXParseResult from autocxxpy.generator import GeneratorOptions from autocxxpy.preprocessor import PreProcessorResult, PreProcessor @@ -19,7 +19,7 @@ class CtpAdaptor: self.md_header = md_header def parse(self) -> GeneratorOptions: - r0: CXXParseResult = CXXParser( + r0: CXXParseResult = CXXFileParser( [self.md_header, self.td_header] ).parse() r1: PreProcessorResult = PreProcessor(r0).process() diff --git a/binding/generator/autocxxpy/cxxparser.py b/binding/generator/autocxxpy/cxxparser.py index f5d57f35..1a02e2fe 100644 --- a/binding/generator/autocxxpy/cxxparser.py +++ b/binding/generator/autocxxpy/cxxparser.py @@ -1,7 +1,7 @@ import logging from collections import defaultdict from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional, Sequence from .clang.cindex import ( Config, @@ -168,16 +168,26 @@ class CXXParseResult(Namespace): macros: Dict[str, str] = field(default_factory=dict) -class CXXFileParser: - def __init__(self, file_path: Optional[str], unsaved_files=None): +class CXXParser: + 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.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: idx = Index.create() rs = idx.parse( self.file_path, - args="-std=c++11 ".split(" "), + args=self.args, unsaved_files=self.unsaved_files, options=( TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD @@ -189,27 +199,27 @@ class CXXFileParser: # todo: parse namespace for c in rs.cursor.walk_preorder(): if c.kind == CursorKind.FUNCTION_DECL: - func = CXXFileParser._process_function(c) + func = CXXParser._process_function(c) result.functions[func.name] = func elif c.kind == CursorKind.ENUM_DECL: - e = CXXFileParser._process_enum(c) + e = CXXParser._process_enum(c) result.enums[e.name] = e elif ( c.kind == CursorKind.CLASS_DECL or c.kind == CursorKind.STRUCT_DECL ): - class_ = CXXFileParser._process_class(c) + class_ = CXXParser._process_class(c) cname = class_.name result.classes[cname] = class_ elif c.kind == CursorKind.VAR_DECL: - name, value = CXXFileParser._process_variable(c) + name, value = CXXParser._process_variable(c) if value: result.variables[name] = value elif c.kind == CursorKind.TYPEDEF_DECL: - name, target = CXXFileParser._process_typedef(c) + name, target = CXXParser._process_typedef(c) result.typedefs[name] = target elif c.kind == CursorKind.MACRO_DEFINITION: - name, definition = CXXFileParser._process_macro_definition(c) + name, definition = CXXParser._process_macro_definition(c) result.macros[name] = definition elif ( False @@ -226,7 +236,7 @@ class CXXFileParser: # ignore any body pass elif ( - CXXFileParser._is_literal_cursor(c) + CXXParser._is_literal_cursor(c) or c.kind == CursorKind.MACRO_INSTANTIATION or c.kind == CursorKind.INCLUSION_DIRECTIVE ): @@ -297,12 +307,12 @@ class CXXFileParser: class_ = Class(name=c.displayname) for ac in c.get_children(): if ac.kind == CursorKind.CONSTRUCTOR: - func = CXXFileParser._process_method(ac, class_) + func = CXXParser._process_method(ac, class_) if func.is_virtual: class_.is_polymorphic = True class_.constructors = func elif ac.kind == CursorKind.DESTRUCTOR: - func = CXXFileParser._process_method(ac, class_) + func = CXXParser._process_method(ac, class_) if func.is_virtual: class_.is_polymorphic = True class_.destructor = func @@ -310,7 +320,7 @@ class CXXFileParser: v = Variable(ac.spelling, ac.type.spelling) class_.variables[v.name] = v elif ac.kind == CursorKind.CXX_METHOD: - func = CXXFileParser._process_method(ac, class_) + func = CXXParser._process_method(ac, class_) if func.is_virtual: class_.is_polymorphic = True class_.functions[func.name].append(func) @@ -339,8 +349,8 @@ class CXXFileParser: length = len(children) if length == 1: child = children[0] - if CXXFileParser._is_literal_cursor(child): - value = CXXFileParser._process_literal(child) + if CXXParser._is_literal_cursor(child): + value = CXXParser._process_literal(child) return c.spelling, value logger.warning( "unable to process variable : %s %s", c.spelling, c.extent @@ -368,7 +378,7 @@ class CXXFileParser: @staticmethod 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.extent.start.offset, token.extent.end.offset, @@ -390,7 +400,7 @@ class CXXFileParser: @staticmethod 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' @staticmethod @@ -403,7 +413,7 @@ class CXXFileParser: elif c.kind == CursorKind.STRING_LITERAL: return str(spelling) 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: return float(spelling) logger.warning( @@ -421,14 +431,26 @@ class CXXFileParser: pass -class CXXParser(CXXFileParser): - def __init__(self, files: List[str]): +class CXXFileParser(CXXParser): + 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 = "" for file in files: dummy_code += f'#include "{file}"\n' 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("")