mirror of
https://gitee.com/fasiondog/hikyuu.git
synced 2024-12-02 20:08:26 +08:00
commit
e203ff04bd
2
.github/workflows/ubuntu.yml
vendored
2
.github/workflows/ubuntu.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
|||||||
|
|
||||||
- name: test
|
- name: test
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install -y libhdf5-dev libsqlite3-dev
|
sudo apt-get install -y libsqlite3-dev
|
||||||
cd ./hikyuu
|
cd ./hikyuu
|
||||||
export BOOST_ROOT=./boost_1_75_0
|
export BOOST_ROOT=./boost_1_75_0
|
||||||
export BOOST_LIB=./boost_1_75_0/stage/lib
|
export BOOST_LIB=./boost_1_75_0/stage/lib
|
||||||
|
@ -76,3 +76,7 @@ Hikyuu Quant Framework是一款基于C++/Python的开源量化交易研究框架
|
|||||||
- **安全、自由、隐私,搭建自己的专属云量化平台** 结合 Python + Jupyter 的强大能力与云服务器,可以搭建自己专属的云量化平台。将Jupyter部署在云服务器上,随时随地的访问自己的云平台,即刻实现自己新的想法,如下图所示通过手机访问自己的云平台。结合Python强大成熟的数据分析、人工智能工具(如 numpy、scipy、pandas、TensorFlow)搭建更强大的人工智能平台。
|
- **安全、自由、隐私,搭建自己的专属云量化平台** 结合 Python + Jupyter 的强大能力与云服务器,可以搭建自己专属的云量化平台。将Jupyter部署在云服务器上,随时随地的访问自己的云平台,即刻实现自己新的想法,如下图所示通过手机访问自己的云平台。结合Python强大成熟的数据分析、人工智能工具(如 numpy、scipy、pandas、TensorFlow)搭建更强大的人工智能平台。
|
||||||
|
|
||||||
- **数据存储方式可扩展** 目前支持本地HDF5格式、MySQL存储。默认使用HDF5,数据文件体积小、速度更快、备份更便利。截止至2017年4月21日,沪市日线数据文件149M、深市日线数据文件184M、5分钟线数据各不到2G。
|
- **数据存储方式可扩展** 目前支持本地HDF5格式、MySQL存储。默认使用HDF5,数据文件体积小、速度更快、备份更便利。截止至2017年4月21日,沪市日线数据文件149M、深市日线数据文件184M、5分钟线数据各不到2G。
|
||||||
|
|
||||||
|
.. image:: https://api.star-history.com/svg?repos=fasiondog/hikyuu&type=Date
|
||||||
|
:target: https://star-history.com/#fasiondog/hikyuu&Date
|
||||||
|
:alt: Star History Chart
|
||||||
|
@ -71,11 +71,13 @@ Linux、macOSX 执行以下指令安装:
|
|||||||
5、Linux下安装依赖软件包
|
5、Linux下安装依赖软件包
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Linux下需安装依赖的开发软件包:hdf-dev、mysqlclient。如 Ubuntu 下,执行以下命令:
|
Linux下需安装依赖的开发软件包。如 Ubuntu 下,执行以下命令:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
sudo apt-get install -y libhdf5-dev libhdf5-serial-dev libmysqlclient-dev
|
sudo apt-get install -y libsqlite3-dev
|
||||||
|
|
||||||
|
MacOsx 下需要使用 brew 安装 sqlite3, hdf5, mysqlclient 的开发包(具体包名请自行查询)。
|
||||||
|
|
||||||
6、转 Visual Studio 工程
|
6、转 Visual Studio 工程
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -145,6 +145,7 @@ def get_table(connect, market, code, ktype):
|
|||||||
'15min': 'min15',
|
'15min': 'min15',
|
||||||
'30min': 'min30',
|
'30min': 'min30',
|
||||||
'60min': 'min60',
|
'60min': 'min60',
|
||||||
|
'hour2': 'hour2',
|
||||||
'min1': 'min',
|
'min1': 'min',
|
||||||
'min5': 'min5',
|
'min5': 'min5',
|
||||||
'min15': 'min15',
|
'min15': 'min15',
|
||||||
|
@ -12,8 +12,8 @@ CREATE TABLE `hku_base`.`market` (
|
|||||||
COLLATE='utf8_general_ci'
|
COLLATE='utf8_general_ci'
|
||||||
ENGINE=InnoDB
|
ENGINE=InnoDB
|
||||||
;
|
;
|
||||||
INSERT INTO `hku_base`.`market` (marketid,market,name,description,code,lastDate) VALUES (1,'SH','上海证劵交易所','上海市场','000001',19901219);
|
INSERT INTO `hku_base`.`market` (marketid,market,name,description,code,lastDate) VALUES (1,'SH','上海证券交易所','上海市场','000001',19901219);
|
||||||
INSERT INTO `hku_base`.`market` (marketid,market,name,description,code,lastDate) VALUES (2,'SZ','深圳证劵交易所','深圳市场','399001',19901219);
|
INSERT INTO `hku_base`.`market` (marketid,market,name,description,code,lastDate) VALUES (2,'SZ','深圳证券交易所','深圳市场','399001',19901219);
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE `hku_base`.`stkweight` (
|
CREATE TABLE `hku_base`.`stkweight` (
|
||||||
|
@ -25,8 +25,8 @@ INSERT INTO `stocktypeinfo` (tickValue,precision,id,type,description,tick,minTra
|
|||||||
INSERT INTO `stocktypeinfo` (tickValue,precision,id,type,description,tick,minTradeNumber,maxTradeNumber) VALUES (0.01,2,8,8,'创业板',0.01,100,1000000);
|
INSERT INTO `stocktypeinfo` (tickValue,precision,id,type,description,tick,minTradeNumber,maxTradeNumber) VALUES (0.01,2,8,8,'创业板',0.01,100,1000000);
|
||||||
CREATE TABLE Stock (stockid INTEGER PRIMARY KEY, marketid INTEGER, code VARCHAR(20), name VARCHAR(60), type INTEGER, valid INTEGER, startDate INTEGER, endDate INTEGER);
|
CREATE TABLE Stock (stockid INTEGER PRIMARY KEY, marketid INTEGER, code VARCHAR(20), name VARCHAR(60), type INTEGER, valid INTEGER, startDate INTEGER, endDate INTEGER);
|
||||||
CREATE TABLE Market (marketid INTEGER PRIMARY KEY, market VARCHAR(10), name VARCHAR(60), description VARCHAR(100), code VARCHAR(20), lastDate INTEGER);
|
CREATE TABLE Market (marketid INTEGER PRIMARY KEY, market VARCHAR(10), name VARCHAR(60), description VARCHAR(100), code VARCHAR(20), lastDate INTEGER);
|
||||||
INSERT INTO `Market` (marketid,market,name,description,code,lastDate) VALUES (1,'SH','上海证劵交易所','上海市场','000001',19901219);
|
INSERT INTO `Market` (marketid,market,name,description,code,lastDate) VALUES (1,'SH','上海证券交易所','上海市场','000001',19901219);
|
||||||
INSERT INTO `Market` (marketid,market,name,description,code,lastDate) VALUES (2,'SZ','深圳证劵交易所','深圳市场','399001',19901219);
|
INSERT INTO `Market` (marketid,market,name,description,code,lastDate) VALUES (2,'SZ','深圳证券交易所','深圳市场','399001',19901219);
|
||||||
|
|
||||||
CREATE TABLE CodeRuleType (id INTEGER PRIMARY KEY, marketid INTEGER, codepre VARCHAR(20), type INTEGER, description VARCHAR(100));
|
CREATE TABLE CodeRuleType (id INTEGER PRIMARY KEY, marketid INTEGER, codepre VARCHAR(20), type INTEGER, description VARCHAR(100));
|
||||||
INSERT INTO `coderuletype` (id,marketid,codepre,type,description) VALUES (1,1,'000',2,'上证指数');
|
INSERT INTO `coderuletype` (id,marketid,codepre,type,description) VALUES (1,1,'000',2,'上证指数');
|
||||||
|
@ -57,7 +57,6 @@ from .bokeh_draw import ax_draw_macd as bk_ax_draw_macd
|
|||||||
from .bokeh_draw import ax_draw_macd2 as bk_ax_draw_macd2
|
from .bokeh_draw import ax_draw_macd2 as bk_ax_draw_macd2
|
||||||
from .bokeh_draw import sgplot as bk_sgplot
|
from .bokeh_draw import sgplot as bk_sgplot
|
||||||
|
|
||||||
|
|
||||||
g_draw_engine = 'matplotlib'
|
g_draw_engine = 'matplotlib'
|
||||||
|
|
||||||
|
|
||||||
@ -249,6 +248,13 @@ def ax_set_locator_formatter(axes, dates, typ):
|
|||||||
use_draw_engine('matplotlib')
|
use_draw_engine('matplotlib')
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'use_draw_engine', 'get_current_draw_engine', 'create_figure', 'gcf', 'show_gcf', 'gca',
|
'use_draw_engine',
|
||||||
'ax_draw_macd', 'ax_draw_macd2'
|
'get_current_draw_engine',
|
||||||
|
'create_figure',
|
||||||
|
'gcf',
|
||||||
|
'show_gcf',
|
||||||
|
'gca',
|
||||||
|
'ax_draw_macd',
|
||||||
|
'ax_draw_macd2',
|
||||||
|
'use_bokeh_in_notebook',
|
||||||
]
|
]
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
from hikyuu import *
|
from hikyuu import *
|
||||||
from .common import get_draw_title
|
from .common import get_draw_title
|
||||||
|
|
||||||
from bokeh.plotting import Figure, figure, ColumnDataSource
|
from bokeh.plotting import figure, ColumnDataSource
|
||||||
from bokeh.models import DatetimeTickFormatter, HoverTool, Title, Label
|
from bokeh.models import DatetimeTickFormatter, HoverTool, Title, Label
|
||||||
from bokeh.layouts import column
|
from bokeh.layouts import column
|
||||||
from bokeh.io import output_notebook, output_file, show
|
from bokeh.io import output_notebook, output_file, show
|
||||||
@ -31,10 +31,6 @@ def ax_fill_between(self, *args, **kwargs):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
Figure.set_xlim = ax_set_xlim
|
|
||||||
Figure.set_ylim = ax_set_ylim
|
|
||||||
Figure.fill_between = ax_fill_between
|
|
||||||
|
|
||||||
g_use_in_notbook = False
|
g_use_in_notbook = False
|
||||||
g_figure = None
|
g_figure = None
|
||||||
g_axes = None
|
g_axes = None
|
||||||
@ -212,8 +208,8 @@ def kplot(kdata, new=True, axes=None, colorup='r', colordown='g'):
|
|||||||
)
|
)
|
||||||
|
|
||||||
label = Label(
|
label = Label(
|
||||||
x=axes.plot_width * 0.01,
|
x=axes.width * 0.01,
|
||||||
y=axes.plot_height * 0.82,
|
y=axes.height * 0.82,
|
||||||
x_units='screen',
|
x_units='screen',
|
||||||
y_units='screen',
|
y_units='screen',
|
||||||
text=text,
|
text=text,
|
||||||
|
@ -16,7 +16,7 @@ class MarketInfoTest(unittest.TestCase):
|
|||||||
def test_market(self):
|
def test_market(self):
|
||||||
market = sm.get_market_info("Sh")
|
market = sm.get_market_info("Sh")
|
||||||
self.assertEqual(market.market, "SH")
|
self.assertEqual(market.market, "SH")
|
||||||
self.assertEqual(market.name, u"上海证劵交易所")
|
self.assertEqual(market.name, u"上海证券交易所")
|
||||||
self.assertEqual(market.description, u"上海市场")
|
self.assertEqual(market.description, u"上海市场")
|
||||||
self.assertEqual(market.code, "000001")
|
self.assertEqual(market.code, "000001")
|
||||||
self.assertEqual(market.last_datetime, Datetime(201112060000))
|
self.assertEqual(market.last_datetime, Datetime(201112060000))
|
||||||
|
@ -19,8 +19,9 @@ int main(int argc, char* argv[]) {
|
|||||||
SetConsoleOutputCP(CP_UTF8);
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//配置文件的位置自行修改
|
// 配置文件的位置自行修改
|
||||||
hikyuu_init("C:\\Users\\admin\\.hikyuu\\hikyuu.ini");
|
hikyuu_init("C:\\Users\\admin\\.hikyuu\\hikyuu.ini");
|
||||||
|
// hikyuu_init("/home/fasiondog/.hikyuu/hikyuu.ini");
|
||||||
|
|
||||||
StockManager& sm = StockManager::instance();
|
StockManager& sm = StockManager::instance();
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ target("demo")
|
|||||||
set_default(false)
|
set_default(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
add_packages("spdlog", "fmt", "flatbuffers")
|
add_packages("boost", "spdlog", "fmt", "flatbuffers")
|
||||||
add_includedirs("..")
|
add_includedirs("..")
|
||||||
|
|
||||||
if is_plat("windows") then
|
if is_plat("windows") then
|
||||||
|
@ -99,7 +99,7 @@ private:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 输出市场信息,如:
|
* 输出市场信息,如:
|
||||||
* MarketInfo(SH, 上海证劵交易所, 上海市场, 000001, 2011-Dec-06 00:00:00)
|
* MarketInfo(SH, 上海证券交易所, 上海市场, 000001, 2011-Dec-06 00:00:00)
|
||||||
* @ingroup StockManage
|
* @ingroup StockManage
|
||||||
*/
|
*/
|
||||||
HKU_API std::ostream& operator<<(std::ostream&, const MarketInfo&);
|
HKU_API std::ostream& operator<<(std::ostream&, const MarketInfo&);
|
||||||
|
@ -5,8 +5,8 @@ target("hikyuu")
|
|||||||
set_kind("shared")
|
set_kind("shared")
|
||||||
end
|
end
|
||||||
|
|
||||||
add_packages("fmt", "spdlog", "flatbuffers", "nng", "nlohmann_json", "cpp-httplib")
|
add_packages("boost", "fmt", "spdlog", "flatbuffers", "nng", "nlohmann_json", "cpp-httplib")
|
||||||
if is_plat("windows", "linux") then
|
if is_plat("windows", "linux", "cross") then
|
||||||
add_packages("sqlite3")
|
add_packages("sqlite3")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -38,12 +38,8 @@ target("hikyuu")
|
|||||||
add_packages("mysql")
|
add_packages("mysql")
|
||||||
end
|
end
|
||||||
|
|
||||||
if is_plat("linux") then
|
if is_plat("linux", "cross") then
|
||||||
add_packages("hdf5", "mysql")
|
add_packages("hdf5", "mysql")
|
||||||
add_links("boost_date_time")
|
|
||||||
add_links("boost_filesystem")
|
|
||||||
add_links("boost_serialization")
|
|
||||||
add_links("boost_system")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if is_plat("macosx") then
|
if is_plat("macosx") then
|
||||||
@ -51,6 +47,7 @@ target("hikyuu")
|
|||||||
add_links("iconv")
|
add_links("iconv")
|
||||||
add_includedirs("/usr/local/opt/hdf5/include")
|
add_includedirs("/usr/local/opt/hdf5/include")
|
||||||
add_linkdirs("/usr/local/opt/hdf5/lib")
|
add_linkdirs("/usr/local/opt/hdf5/lib")
|
||||||
|
add_links("hdf5", "hdf5_cpp")
|
||||||
if os.exists("/usr/local/opt/mysql-client") then
|
if os.exists("/usr/local/opt/mysql-client") then
|
||||||
add_includedirs("/usr/local/opt/mysql-client/include")
|
add_includedirs("/usr/local/opt/mysql-client/include")
|
||||||
add_linkdirs("/usr/local/opt/mysql-client/lib")
|
add_linkdirs("/usr/local/opt/mysql-client/lib")
|
||||||
@ -63,30 +60,13 @@ target("hikyuu")
|
|||||||
end
|
end
|
||||||
add_links("mysqlclient")
|
add_links("mysqlclient")
|
||||||
add_links("sqlite3")
|
add_links("sqlite3")
|
||||||
add_links("boost_date_time")
|
|
||||||
add_links("boost_filesystem")
|
|
||||||
add_links("boost_serialization")
|
|
||||||
add_links("boost_system")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if is_plat("windows") then
|
|
||||||
-- nng 静态链接需要的系统库
|
|
||||||
add_syslinks("ws2_32", "advapi32")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- add files
|
-- add files
|
||||||
add_files("./**.cpp")
|
add_files("./**.cpp")
|
||||||
|
|
||||||
add_headerfiles("../(hikyuu/**.h)|**doc.h")
|
add_headerfiles("../(hikyuu/**.h)|**doc.h")
|
||||||
|
|
||||||
on_load(function(target)
|
|
||||||
assert(os.getenv("BOOST_ROOT"), [[Missing environment variable: BOOST_ROOT
|
|
||||||
You need to specify where the boost headers is via the BOOST_ROOT variable!]])
|
|
||||||
|
|
||||||
assert(os.getenv("BOOST_LIB"), [[Missing environment variable: BOOST_LIB
|
|
||||||
You need to specify where the boost library is via the BOOST_LIB variable!]])
|
|
||||||
end)
|
|
||||||
|
|
||||||
before_build(function(target)
|
before_build(function(target)
|
||||||
if is_plat("macosx") then
|
if is_plat("macosx") then
|
||||||
if not os.exists("/usr/local/include/mysql") then
|
if not os.exists("/usr/local/include/mysql") then
|
||||||
@ -100,10 +80,6 @@ You need to specify where the boost library is via the BOOST_LIB variable!]])
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
after_build(function(target)
|
after_build(function(target)
|
||||||
if is_plat("linux") then
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_*.so.*", "$(buildir)/$(mode)/$(plat)/$(arch)/lib/")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 不同平台的库后缀名
|
-- 不同平台的库后缀名
|
||||||
local lib_suffix = ".so"
|
local lib_suffix = ".so"
|
||||||
if is_plat("windows") then
|
if is_plat("windows") then
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
target("hkuserver")
|
target("hkuserver")
|
||||||
set_kind("binary")
|
set_kind("binary")
|
||||||
|
|
||||||
add_packages("fmt", "spdlog", "flatbuffers", "nng", "nlohmann_json", "sqlite3", "zlib")
|
add_packages("boost", "fmt", "spdlog", "flatbuffers", "nng", "nlohmann_json", "sqlite3", "zlib")
|
||||||
add_deps("hikyuu")
|
add_deps("hikyuu")
|
||||||
|
|
||||||
add_includedirs(".")
|
add_includedirs(".")
|
||||||
|
@ -29,33 +29,33 @@ namespace bd = boost::gregorian;
|
|||||||
/** @par 检测点 */
|
/** @par 检测点 */
|
||||||
TEST_CASE("test_TimeDelta") {
|
TEST_CASE("test_TimeDelta") {
|
||||||
/** @arg days 超出限定值 */
|
/** @arg days 超出限定值 */
|
||||||
CHECK_THROWS_AS(TimeDelta(99999999LL + 1), hku::exception);
|
CHECK_THROWS(TimeDelta(99999999LL + 1));
|
||||||
CHECK_THROWS_AS(TimeDelta(-99999999LL - 1), hku::exception);
|
CHECK_THROWS(TimeDelta(-99999999LL - 1));
|
||||||
|
|
||||||
#if !HKU_DISABLE_ASSERT
|
#if !HKU_DISABLE_ASSERT
|
||||||
/** @arg hours 超出限定值 */
|
/** @arg hours 超出限定值 */
|
||||||
CHECK_THROWS_AS(TimeDelta(0, 100001), hku::exception);
|
CHECK_THROWS(TimeDelta(0, 100001));
|
||||||
CHECK_THROWS_AS(TimeDelta(0, -100001), hku::exception);
|
CHECK_THROWS(TimeDelta(0, -100001));
|
||||||
|
|
||||||
/** @arg minutes 超出限定值 */
|
/** @arg minutes 超出限定值 */
|
||||||
CHECK_THROWS_AS(TimeDelta(0, 0, 100001), hku::exception);
|
CHECK_THROWS(TimeDelta(0, 0, 100001));
|
||||||
CHECK_THROWS_AS(TimeDelta(0, 0, -100001), hku::exception);
|
CHECK_THROWS(TimeDelta(0, 0, -100001));
|
||||||
|
|
||||||
/** @arg seconds 超出限定值 */
|
/** @arg seconds 超出限定值 */
|
||||||
CHECK_THROWS_AS(TimeDelta(0, 0, 0, 8640000), hku::exception);
|
CHECK_THROWS(TimeDelta(0, 0, 0, 8640000));
|
||||||
CHECK_THROWS_AS(TimeDelta(0, 0, 0, -8640000), hku::exception);
|
CHECK_THROWS(TimeDelta(0, 0, 0, -8640000));
|
||||||
|
|
||||||
/** @arg milliseconds 超出限定值 */
|
/** @arg milliseconds 超出限定值 */
|
||||||
CHECK_THROWS_AS(TimeDelta(0, 0, 0, 0, 8640000000000), hku::exception);
|
CHECK_THROWS(TimeDelta(0, 0, 0, 0, 8640000000000));
|
||||||
CHECK_THROWS_AS(TimeDelta(0, 0, 0, 0, -8640000000000), hku::exception);
|
CHECK_THROWS(TimeDelta(0, 0, 0, 0, -8640000000000));
|
||||||
|
|
||||||
/** @arg microseconds 超出限定值 */
|
/** @arg microseconds 超出限定值 */
|
||||||
CHECK_THROWS_AS(TimeDelta(0, 0, 0, 0, 0, 8640000000000), hku::exception);
|
CHECK_THROWS(TimeDelta(0, 0, 0, 0, 0, 8640000000000));
|
||||||
CHECK_THROWS_AS(TimeDelta(0, 0, 0, 0, 0, -8640000000000), hku::exception);
|
CHECK_THROWS(TimeDelta(0, 0, 0, 0, 0, -8640000000000));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @arg microseconds总值超出限定值 */
|
/** @arg microseconds总值超出限定值 */
|
||||||
CHECK_THROWS_AS(TimeDelta(99999999LL, 23, 59, 60, 999, 999), hku::exception);
|
CHECK_THROWS(TimeDelta(99999999LL, 23, 59, 60, 999, 999));
|
||||||
|
|
||||||
/** @arg 正常初始化,时分秒毫秒微秒都在各自的进制范围内 */
|
/** @arg 正常初始化,时分秒毫秒微秒都在各自的进制范围内 */
|
||||||
TimeDelta td(7, 10, 20, 3, 5, 7);
|
TimeDelta td(7, 10, 20, 3, 5, 7);
|
||||||
@ -298,7 +298,7 @@ TEST_CASE("test_TimeDelta_operator") {
|
|||||||
CHECK(td == TimeDelta(2));
|
CHECK(td == TimeDelta(2));
|
||||||
|
|
||||||
/** @arg 除以 0 */
|
/** @arg 除以 0 */
|
||||||
CHECK_THROWS_AS(TimeDelta(1) / 0, hku::exception);
|
CHECK_THROWS(TimeDelta(1) / 0);
|
||||||
|
|
||||||
/** @arg 正常除法 */
|
/** @arg 正常除法 */
|
||||||
CHECK(TimeDelta(2) / 2 == TimeDelta(1));
|
CHECK(TimeDelta(2) / 2 == TimeDelta(1));
|
||||||
@ -307,16 +307,16 @@ TEST_CASE("test_TimeDelta_operator") {
|
|||||||
CHECK(Microseconds(2) / 3 == Microseconds(1));
|
CHECK(Microseconds(2) / 3 == Microseconds(1));
|
||||||
|
|
||||||
/** @arg 地板除 */
|
/** @arg 地板除 */
|
||||||
CHECK_THROWS_AS(TimeDelta(1).floorDiv(0), hku::exception);
|
CHECK_THROWS(TimeDelta(1).floorDiv(0));
|
||||||
CHECK(TimeDelta(2).floorDiv(2) == TimeDelta(1));
|
CHECK(TimeDelta(2).floorDiv(2) == TimeDelta(1));
|
||||||
CHECK(Microseconds(1).floorDiv(3) == TimeDelta(0));
|
CHECK(Microseconds(1).floorDiv(3) == TimeDelta(0));
|
||||||
CHECK(Microseconds(2).floorDiv(3) == TimeDelta(0));
|
CHECK(Microseconds(2).floorDiv(3) == TimeDelta(0));
|
||||||
|
|
||||||
/** @arg 除以 zero TimeDelta */
|
/** @arg 除以 zero TimeDelta */
|
||||||
CHECK_THROWS_AS(TimeDelta(1) / TimeDelta(), hku::exception);
|
CHECK_THROWS(TimeDelta(1) / TimeDelta());
|
||||||
|
|
||||||
/** @arg 对零时长取余 */
|
/** @arg 对零时长取余 */
|
||||||
CHECK_THROWS_AS(TimeDelta(1) % TimeDelta(), hku::exception);
|
CHECK_THROWS(TimeDelta(1) % TimeDelta());
|
||||||
|
|
||||||
/** @arg 取余 */
|
/** @arg 取余 */
|
||||||
CHECK(TimeDelta(3) % TimeDelta(2) == TimeDelta(1));
|
CHECK(TimeDelta(3) % TimeDelta(2) == TimeDelta(1));
|
||||||
|
@ -72,7 +72,7 @@ TEST_CASE("test_StockManager_getMarketInfo") {
|
|||||||
CHECK_NE(marketInfo, Null<MarketInfo>());
|
CHECK_NE(marketInfo, Null<MarketInfo>());
|
||||||
CHECK_EQ(marketInfo.market(), "SH");
|
CHECK_EQ(marketInfo.market(), "SH");
|
||||||
CHECK_EQ(marketInfo.code(), "000001");
|
CHECK_EQ(marketInfo.code(), "000001");
|
||||||
CHECK_EQ(marketInfo.name(), "上海证劵交易所");
|
CHECK_EQ(marketInfo.name(), "上海证券交易所");
|
||||||
CHECK_EQ(marketInfo.description(), "上海市场");
|
CHECK_EQ(marketInfo.description(), "上海市场");
|
||||||
CHECK_EQ(marketInfo.lastDate(), Datetime(201112060000L));
|
CHECK_EQ(marketInfo.lastDate(), Datetime(201112060000L));
|
||||||
CHECK_EQ(marketInfo.openTime1(), TimeDelta(0, 9, 30));
|
CHECK_EQ(marketInfo.openTime1(), TimeDelta(0, 9, 30));
|
||||||
|
@ -40,7 +40,7 @@ target("unit-test")
|
|||||||
set_kind("binary")
|
set_kind("binary")
|
||||||
set_default(false)
|
set_default(false)
|
||||||
|
|
||||||
add_packages("fmt", "spdlog", "doctest", "mysql", "sqlite3")
|
add_packages("boost", "fmt", "spdlog", "doctest", "mysql", "sqlite3")
|
||||||
|
|
||||||
add_includedirs("..")
|
add_includedirs("..")
|
||||||
|
|
||||||
@ -64,9 +64,9 @@ target("unit-test")
|
|||||||
add_deps("hikyuu")
|
add_deps("hikyuu")
|
||||||
|
|
||||||
if is_plat("linux") or is_plat("macosx") then
|
if is_plat("linux") or is_plat("macosx") then
|
||||||
add_links("boost_unit_test_framework")
|
-- add_links("boost_unit_test_framework")
|
||||||
add_links("boost_filesystem")
|
-- add_links("boost_filesystem")
|
||||||
add_links("boost_serialization")
|
-- add_links("boost_serialization")
|
||||||
add_links("sqlite3")
|
add_links("sqlite3")
|
||||||
add_shflags("-Wl,-rpath=$ORIGIN", "-Wl,-rpath=$ORIGIN/../lib")
|
add_shflags("-Wl,-rpath=$ORIGIN", "-Wl,-rpath=$ORIGIN/../lib")
|
||||||
end
|
end
|
||||||
@ -86,7 +86,7 @@ target("small-test")
|
|||||||
set_kind("binary")
|
set_kind("binary")
|
||||||
set_default(false)
|
set_default(false)
|
||||||
|
|
||||||
add_packages("fmt", "spdlog", "doctest", "mysql", "sqlite3")
|
add_packages("boost", "fmt", "spdlog", "doctest", "mysql", "sqlite3")
|
||||||
add_includedirs("..")
|
add_includedirs("..")
|
||||||
|
|
||||||
--add_defines("BOOST_TEST_DYN_LINK")
|
--add_defines("BOOST_TEST_DYN_LINK")
|
||||||
@ -111,9 +111,9 @@ target("small-test")
|
|||||||
add_deps("hikyuu")
|
add_deps("hikyuu")
|
||||||
|
|
||||||
if is_plat("linux") or is_plat("macosx") then
|
if is_plat("linux") or is_plat("macosx") then
|
||||||
add_links("boost_unit_test_framework")
|
-- add_links("boost_unit_test_framework")
|
||||||
add_links("boost_filesystem")
|
-- add_links("boost_filesystem")
|
||||||
add_links("boost_atomic")
|
-- add_links("boost_atomic")
|
||||||
add_shflags("-Wl,-rpath=$ORIGIN", "-Wl,-rpath=$ORIGIN/../lib")
|
add_shflags("-Wl,-rpath=$ORIGIN", "-Wl,-rpath=$ORIGIN/../lib")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,21 +5,24 @@ package("hdf5")
|
|||||||
set_license("BSD-3-Clause")
|
set_license("BSD-3-Clause")
|
||||||
|
|
||||||
if is_plat("windows") then
|
if is_plat("windows") then
|
||||||
add_urls("https://github.com/fasiondog/hikyuu/releases/download/1.1.9/hdf5-$(version)-win-x64.zip",
|
add_urls("https://github.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/hdf5-$(version)-win-x64.zip",
|
||||||
"https://gitee.com/fasiondog/hikyuu/releases/download/1.1.9/hdf5-$(version)-win-x64.zip")
|
"https://gitee.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/hdf5-$(version)-win-x64.zip")
|
||||||
add_versions("1.12.2", "388d455c917b153f3410e8ca0c857ee37a575d859a70ecb6e16d4fb43b1d201c")
|
add_versions("1.12.2", "388d455c917b153f3410e8ca0c857ee37a575d859a70ecb6e16d4fb43b1d201c")
|
||||||
add_versions("1.10.4", "253b23baada1d9c86cb4424595eba366b6844c384a5e0aafebf0893a1148f25f")
|
elseif is_plat("linux") and is_arch("x86_64") then
|
||||||
elseif is_plat("linux") then
|
add_urls("https://github.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/hdf5-$(version)-linux-x64.zip",
|
||||||
add_urls("https://github.com/fasiondog/hikyuu/releases/download/1.1.9/hdf5-$(version)-linux-x64.zip",
|
"https://gitee.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/hdf5-$(version)-linux-x64.zip")
|
||||||
"https://gitee.com/fasiondog/hikyuu/releases/download/1.1.9/hdf5-$(version)-linux-x64.zip")
|
|
||||||
add_versions("1.12.2", "e0f4357ea7bfa0132c3edba9b517635736191f920ce7a3aeef5e89dbe5b2dd27")
|
add_versions("1.12.2", "e0f4357ea7bfa0132c3edba9b517635736191f920ce7a3aeef5e89dbe5b2dd27")
|
||||||
|
elseif is_plat("linux", "cross") and is_arch("aarch64", "arm64.*") then
|
||||||
|
add_urls("https://github.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/hdf5-$(version)-linux-aarch64.zip",
|
||||||
|
"https://gitee.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/hdf5-$(version)-linux-aarch64.zip")
|
||||||
|
add_versions("1.12.2", "d73a880d9dfede0d5db1e30555fa251ca82efa437a0d93b46f5e64e87e71fc63")
|
||||||
end
|
end
|
||||||
|
|
||||||
on_load("windows", "linux", function (package)
|
on_load("windows", "linux", "cross", function (package)
|
||||||
package:add("defines", "H5_BUILT_AS_DYNAMIC_LIB")
|
package:add("defines", "H5_BUILT_AS_DYNAMIC_LIB")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
on_install("windows", "linux", function (package)
|
on_install("windows", "linux", "cross", function (package)
|
||||||
os.cp("include", package:installdir())
|
os.cp("include", package:installdir())
|
||||||
os.cp("lib", package:installdir())
|
os.cp("lib", package:installdir())
|
||||||
if package:is_plat("windows") then
|
if package:is_plat("windows") then
|
||||||
|
@ -5,10 +5,9 @@ package("hdf5_D")
|
|||||||
set_license("BSD-3-Clause")
|
set_license("BSD-3-Clause")
|
||||||
|
|
||||||
if is_plat("windows") then
|
if is_plat("windows") then
|
||||||
add_urls("https://github.com/fasiondog/hikyuu/releases/download/1.1.9/hdf5_D-$(version)-win-x64.zip",
|
add_urls("https://github.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/hdf5_D-$(version)-win-x64.zip",
|
||||||
"https://gitee.com/fasiondog/hikyuu/releases/download/1.1.9/hdf5_D-$(version)-win-x64.zip")
|
"https://gitee.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/hdf5_D-$(version)-win-x64.zip")
|
||||||
add_versions("1.12.2", "6ea3ab5a4b0bb0f48eaef28cfe747ac5c072c06519a4888c1a59cfaf75399049")
|
add_versions("1.12.2", "6ea3ab5a4b0bb0f48eaef28cfe747ac5c072c06519a4888c1a59cfaf75399049")
|
||||||
add_versions("1.10.4", "5b1bd27e054f885bf9cac0beffcacbe180e251c5d8c12c0652a96055f2784b46")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
on_load("windows", function (package)
|
on_load("windows", function (package)
|
||||||
|
@ -4,16 +4,20 @@ package("mysql")
|
|||||||
set_description("Open source relational database management system.")
|
set_description("Open source relational database management system.")
|
||||||
|
|
||||||
if is_plat("windows") then
|
if is_plat("windows") then
|
||||||
add_urls("https://github.com/fasiondog/hikyuu/releases/download/1.1.9/mysql-$(version)-win-x64.zip",
|
add_urls("https://github.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/mysql-$(version)-win-x64.zip",
|
||||||
"https://gitee.com/fasiondog/hikyuu/attach_files/935339/download/mysql-$(version)-win-x64.zip")
|
"https://gitee.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/mysql-$(version)-win-x64.zip")
|
||||||
add_versions("8.0.21", "de21694aa230a00b52b28babbce9bb150d990ba1f539edf8d193586dce3844ae")
|
add_versions("8.0.21", "de21694aa230a00b52b28babbce9bb150d990ba1f539edf8d193586dce3844ae")
|
||||||
elseif is_plat("linux") then
|
elseif is_plat("linux") and is_arch("x86_64") then
|
||||||
add_urls("https://github.com/fasiondog/hikyuu/releases/download/1.1.9/mysql-$(version)-linux-x86_64.zip",
|
add_urls("https://github.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/mysql-$(version)-linux-x86_64.zip",
|
||||||
"https://gitee.com/fasiondog/hikyuu/releases/download/1.1.9/mysql-$(version)-linux-x86_64.zip")
|
"https://gitee.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/mysql-$(version)-linux-x86_64.zip")
|
||||||
add_versions("8.0.31", "1775a94f4a59cfb03593e6e70891de33a0cc8713573afdfc9ca0482415a8ecd3")
|
add_versions("8.0.31", "1775a94f4a59cfb03593e6e70891de33a0cc8713573afdfc9ca0482415a8ecd3")
|
||||||
|
elseif is_plat("linux", "cross") and is_arch("aarch64", "arm64.*") then
|
||||||
|
add_urls("https://github.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/mysql-$(version)-linux-aarch64.zip",
|
||||||
|
"https://gitee.com/fasiondog/hikyuu_extern_libs/releases/download/1.0.0/mysql-$(version)-linux-aarch64.zip")
|
||||||
|
add_versions("8.0.21", "5ceb31ddc75bfaa0ec5324fa1564dae3abdb7ea9d3f0763f10d06e871d21d7d4")
|
||||||
end
|
end
|
||||||
|
|
||||||
on_install("windows", "linux", function (package)
|
on_install("windows", "linux", "cross", function (package)
|
||||||
os.cp("include", package:installdir())
|
os.cp("include", package:installdir())
|
||||||
os.cp("lib", package:installdir())
|
os.cp("lib", package:installdir())
|
||||||
if package:is_plat("windows") then
|
if package:is_plat("windows") then
|
||||||
|
@ -1,38 +1,18 @@
|
|||||||
option("boost-python-suffix")
|
option("pyver")
|
||||||
set_default("3X")
|
set_default("3.9")
|
||||||
set_showmenu(true)
|
set_showmenu(true)
|
||||||
set_category("hikyuu")
|
set_category("hikyuu")
|
||||||
set_description("Set suffix of libboost_python. ",
|
set_description("Use python version xy")
|
||||||
"Boost.python 1.67 later use 3x like libboost_python35, ",
|
|
||||||
"but older is libboost_python3",
|
|
||||||
" - 3X autocheck for 35, 36, 37, 3x")
|
|
||||||
option_end()
|
option_end()
|
||||||
|
|
||||||
add_includedirs("../hikyuu_cpp")
|
|
||||||
|
|
||||||
-- Can't use static boost.python lib, the function that using 'arg' will load failed!
|
|
||||||
--add_defines("BOOST_PYTHON_STATIC_LIB")
|
|
||||||
|
|
||||||
if is_plat("windows") then
|
|
||||||
add_defines("HKU_API=__declspec(dllimport)")
|
|
||||||
add_cxflags("-wd4566")
|
|
||||||
end
|
|
||||||
|
|
||||||
local cc = get_config("cc")
|
|
||||||
local cxx = get_config("cxx")
|
|
||||||
if (cc and string.find(cc, "clang")) or (cxx and string.find(cxx, "clang")) then
|
|
||||||
add_cxflags("-Wno-error=parentheses-equality -Wno-error=missing-braces")
|
|
||||||
end
|
|
||||||
|
|
||||||
--on_load("xmake_on_load")
|
|
||||||
|
|
||||||
target("core")
|
target("core")
|
||||||
set_kind("shared")
|
set_kind("shared")
|
||||||
if is_mode("debug") then
|
if is_mode("debug") then
|
||||||
set_default(false) --会默认禁用这个target的编译,除非显示指定xmake build _hikyuu才会去编译,但是target还存在,里面的files会保留到vcproj
|
set_default(false) --会默认禁用这个target的编译,除非显示指定xmake build _hikyuu才会去编译,但是target还存在,里面的files会保留到vcproj
|
||||||
--set_enable(false) --set_enable(false)会彻底禁用这个target,连target的meta也不会被加载,vcproj不会保留它
|
--set_enable(false) --set_enable(false)会彻底禁用这个target,连target的meta也不会被加载,vcproj不会保留它
|
||||||
end
|
end
|
||||||
add_packages("fmt", "spdlog", "flatbuffers", "cpp-httplib")
|
|
||||||
|
add_packages("boost", "fmt", "spdlog", "flatbuffers", "cpp-httplib")
|
||||||
add_deps("hikyuu")
|
add_deps("hikyuu")
|
||||||
if is_plat("windows") then
|
if is_plat("windows") then
|
||||||
set_filename("core.pyd")
|
set_filename("core.pyd")
|
||||||
@ -40,71 +20,40 @@ target("core")
|
|||||||
else
|
else
|
||||||
set_filename("core.so")
|
set_filename("core.so")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if is_plat("windows") then
|
||||||
|
add_defines("HKU_API=__declspec(dllimport)")
|
||||||
|
add_cxflags("-wd4566")
|
||||||
|
end
|
||||||
|
|
||||||
|
local cc = get_config("cc")
|
||||||
|
local cxx = get_config("cxx")
|
||||||
|
if (cc and string.find(cc, "clang")) or (cxx and string.find(cxx, "clang")) then
|
||||||
|
add_cxflags("-Wno-error=parentheses-equality -Wno-error=missing-braces")
|
||||||
|
end
|
||||||
|
|
||||||
|
add_includedirs("../hikyuu_cpp")
|
||||||
add_files("./**.cpp")
|
add_files("./**.cpp")
|
||||||
|
|
||||||
add_rpathdirs("$ORIGIN", "$ORIGIN/lib", "$ORIGIN/../lib")
|
add_rpathdirs("$ORIGIN", "$ORIGIN/lib", "$ORIGIN/../lib")
|
||||||
|
|
||||||
on_load(function(target)
|
-- on_load(function(target)
|
||||||
import("lib.detect.find_tool")
|
-- import("lib.detect.find_tool")
|
||||||
if is_plat("windows") then
|
-- import("lib.detect.find_path")
|
||||||
-- detect installed python3
|
-- local python = assert(find_tool("python3", {version = true}), "python not found, please install it first! note: python version must > 3.0")
|
||||||
local python = assert(find_tool("python3", {version = true}), "python not found, please install it first! note: python version must > 3.0")
|
-- local exepath = path.directory(python.program)
|
||||||
assert(python.version > "3", python.version .. " python version must > 3.0, please use python3.0 or later!")
|
-- if is_host("windows") then
|
||||||
|
-- includepath = find_path("Python.h", {exepath}, {suffixes = {"include"}})
|
||||||
-- find python include and libs directory
|
-- else
|
||||||
local pydir = os.iorun("python -c \"import sys; print(sys.executable)\"")
|
-- local pyver = python.version:match("%d+.%d+")
|
||||||
pydir = path.directory(pydir)
|
-- includepath = find_path("Python.h", {path.directory(exepath)}, {suffixes = {"include/python" .. pyver}})
|
||||||
target:add("includedirs", pydir .. "/include")
|
-- end
|
||||||
target:add("linkdirs", pydir .. "/libs")
|
-- target:add("includedirs", includepath)
|
||||||
return
|
-- end)
|
||||||
end
|
|
||||||
|
|
||||||
if is_plat("macosx") then
|
|
||||||
local libdir = os.iorun("python3-config --prefix"):trim() .. "/lib"
|
|
||||||
target:add("linkdirs", libdir)
|
|
||||||
local out, err = os.iorun("python3 --version")
|
|
||||||
local ver = (out .. err):trim()
|
|
||||||
local python_lib = format("python%s.%sm", string.sub(ver,8,8), string.sub(ver,10,10))
|
|
||||||
local pyver = tonumber(format("%s.%s", string.sub(ver,8,8), string.sub(ver,10,10)))
|
|
||||||
if pyver >= 3.8 then
|
|
||||||
python_lib = format("python%s.%s", string.sub(ver,8,8), string.sub(ver,10,10))
|
|
||||||
end
|
|
||||||
target:add("links", python_lib)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get python include directory.
|
|
||||||
local pydir = try { function () return os.iorun("python3-config --includes"):trim() end }
|
|
||||||
assert(pydir, "python3-config not found!")
|
|
||||||
target:add("cxflags", pydir)
|
|
||||||
|
|
||||||
-- get suffix configure for link libboost_pythonX.so
|
|
||||||
local suffix = get_config("boost-python-suffix")
|
|
||||||
if suffix == nil then
|
|
||||||
raise("You need to config --boost-python-suffix specify libboost_python suffix")
|
|
||||||
end
|
|
||||||
|
|
||||||
suffix = string.upper(suffix)
|
|
||||||
if suffix == "3X" then
|
|
||||||
local out, err = os.iorun("python3 --version")
|
|
||||||
local ver = (out .. err):trim()
|
|
||||||
local boost_python_lib = "boost_python"..string.sub(ver,8,8)..string.sub(ver,10,10)
|
|
||||||
target:add("links", boost_python_lib)
|
|
||||||
else
|
|
||||||
target:add("links", "boost_python"..suffix)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
after_build(function(target)
|
after_build(function(target)
|
||||||
if is_plat("macosx") then
|
if is_plat("macosx") then
|
||||||
local out, err = os.iorun("python3 --version")
|
|
||||||
local ver = (out .. err):trim()
|
|
||||||
local boost_python_lib = format("libboost_python%s%s.dylib", string.sub(ver,8,8), string.sub(ver,10,10))
|
|
||||||
os.run(format("install_name_tool -change @rpath/libhikyuu.dylib @loader_path/libhikyuu.dylib %s/%s", target:targetdir(), "core.so"))
|
os.run(format("install_name_tool -change @rpath/libhikyuu.dylib @loader_path/libhikyuu.dylib %s/%s", target:targetdir(), "core.so"))
|
||||||
os.run(format("install_name_tool -change @rpath/libboost_date_time.dylib @loader_path/libboost_date_time.dylib %s/%s", target:targetdir(), "core.so"))
|
|
||||||
os.run(format("install_name_tool -change @rpath/libboost_filesystem.dylib @loader_path/libboost_filesystem.dylib %s/%s", target:targetdir(), "core.so"))
|
|
||||||
os.run(format("install_name_tool -change @rpath/libboost_system.dylib @loader_path/libboost_system.dylib %s/%s", target:targetdir(), "core.so"))
|
|
||||||
os.run(format("install_name_tool -change @rpath/libboost_serialization.dylib @loader_path/libboost_serialization.dylib %s/%s", target:targetdir(), "core.so"))
|
|
||||||
os.run(format("install_name_tool -change @rpath/%s @loader_path/%s %s/%s", boost_python_lib, boost_python_lib, target:targetdir(), "core.so"))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local dst_dir = "$(projectdir)/hikyuu/cpp/"
|
local dst_dir = "$(projectdir)/hikyuu/cpp/"
|
||||||
@ -118,22 +67,6 @@ target("core")
|
|||||||
os.trycp(target:targetdir() .. '/*.so', dst_dir)
|
os.trycp(target:targetdir() .. '/*.so', dst_dir)
|
||||||
os.trycp(target:targetdir() .. '/*.so.*', dst_dir)
|
os.trycp(target:targetdir() .. '/*.so.*', dst_dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
os.cp("$(env BOOST_LIB)/boost_date_time*.dll", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/boost_filesystem*.dll", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/boost_python3*.dll", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/boost_serialization*.dll", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/boost_system*.dll", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_date_time*.so.*", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_filesystem*.so.*", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_python3*.so.*", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_serialization*.so.*", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_system*.so.*", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_date_time*.dylib", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_filesystem*.dylib", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_python3*.dylib", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_serialization*.dylib", dst_dir)
|
|
||||||
os.cp("$(env BOOST_LIB)/libboost_system*.dylib", dst_dir)
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
import("lib.detect.find_tool")
|
|
||||||
|
|
||||||
function main(target)
|
|
||||||
if is_plat("windows") then
|
|
||||||
-- detect installed python3
|
|
||||||
local python = assert(find_tool("python3", {version = true}), "python not found, please install it first! note: python version must > 3.0")
|
|
||||||
assert(python.version > "3", python.version .. " python version must > 3.0, please use python3.0 or later!")
|
|
||||||
|
|
||||||
-- find python include and libs directory
|
|
||||||
local pydir = os.iorun("python -c \"import sys; print(sys.executable)\"")
|
|
||||||
pydir = path.directory(pydir)
|
|
||||||
target:add("includedirs", pydir .. "/include")
|
|
||||||
target:add("linkdirs", pydir .. "/libs")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
target:add("rpathdirs", "$ORIGIN", "$ORIGIN/lib", "$ORIGIN/../lib")
|
|
||||||
|
|
||||||
if is_plat("macosx") then
|
|
||||||
local libdir = os.iorun("python3-config --prefix"):trim() .. "/lib"
|
|
||||||
target:add("linkdirs", libdir)
|
|
||||||
local out, err = os.iorun("python3 --version")
|
|
||||||
local ver = (out .. err):trim()
|
|
||||||
local python_lib = format("python%s.%sm", string.sub(ver,8,8), string.sub(ver,10,10))
|
|
||||||
target:add("links", python_lib)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get python include directory.
|
|
||||||
local pydir = try { function () return os.iorun("python3-config --includes"):trim() end }
|
|
||||||
assert(pydir, "python3-config not found!")
|
|
||||||
target:add("cxflags", pydir)
|
|
||||||
|
|
||||||
-- get suffix configure for link libboost_pythonX.so
|
|
||||||
local suffix = get_config("boost-python-suffix")
|
|
||||||
if suffix == nil then
|
|
||||||
raise("You need to config --boost-python-suffix specify libboost_python suffix")
|
|
||||||
end
|
|
||||||
|
|
||||||
suffix = string.upper(suffix)
|
|
||||||
if suffix == "3X" then
|
|
||||||
local out, err = os.iorun("python3 --version")
|
|
||||||
local ver = (out .. err):trim()
|
|
||||||
local boost_python_lib = "boost_python"..string.sub(ver,8,8)..string.sub(ver,10,10)
|
|
||||||
target:add("links", boost_python_lib)
|
|
||||||
else
|
|
||||||
target:add("links", "boost_python"..suffix)
|
|
||||||
end
|
|
||||||
end
|
|
133
setup.py
133
setup.py
@ -20,38 +20,14 @@ def check_xmake():
|
|||||||
return False if xmake != 0 else True
|
return False if xmake != 0 else True
|
||||||
|
|
||||||
|
|
||||||
def get_boost_envrionment():
|
|
||||||
"""
|
|
||||||
获取 BOOST 环境变量设置
|
|
||||||
@return (current_boost_root, current_boost_lib)
|
|
||||||
"""
|
|
||||||
current_dir = os.getcwd()
|
|
||||||
current_boost_root = ''
|
|
||||||
current_boost_lib = ''
|
|
||||||
if 'BOOST_ROOT' in os.environ:
|
|
||||||
current_boost_root = os.environ['BOOST_ROOT']
|
|
||||||
if 'BOOST_LIB' in os.environ:
|
|
||||||
current_boost_lib = os.environ['BOOST_LIB']
|
|
||||||
else:
|
|
||||||
current_boost_lib = current_boost_root + '/stage/lib'
|
|
||||||
os.environ['BOOST_LIB'] = current_boost_lib
|
|
||||||
else:
|
|
||||||
for dir in os.listdir():
|
|
||||||
if len(dir) >= 5 and dir[:5] == 'boost' and os.path.isdir(dir):
|
|
||||||
current_boost_root = current_dir + '/' + dir
|
|
||||||
current_boost_lib = current_dir + '/' + dir + '/stage/lib'
|
|
||||||
os.environ['BOOST_ROOT'] = current_boost_root
|
|
||||||
os.environ['BOOST_LIB'] = current_boost_lib
|
|
||||||
return (current_boost_root, current_boost_lib)
|
|
||||||
|
|
||||||
|
|
||||||
def get_python_version():
|
def get_python_version():
|
||||||
"""获取当前 python版本"""
|
"""获取当前 python版本"""
|
||||||
py_version = platform.python_version_tuple()
|
py_version = platform.python_version_tuple()
|
||||||
min_version = int(py_version[1])
|
min_version = int(py_version[1])
|
||||||
main_version = int(py_version[0])
|
main_version = int(py_version[0])
|
||||||
py_version = main_version * 10 + min_version if min_version < 10 else main_version * 100 + min_version
|
#py_version = main_version * 10 + min_version if min_version < 10 else main_version * 100 + min_version
|
||||||
print('current python version: {}.{}'.format(main_version, min_version))
|
py_version = f"{main_version}.{min_version}"
|
||||||
|
print(f'current python version: {py_version}')
|
||||||
return py_version
|
return py_version
|
||||||
|
|
||||||
|
|
||||||
@ -64,14 +40,11 @@ def get_current_compile_info():
|
|||||||
current_arch = 'x86_64' if current_bits == 64 else 'i386'
|
current_arch = 'x86_64' if current_bits == 64 else 'i386'
|
||||||
|
|
||||||
py_version = get_python_version()
|
py_version = get_python_version()
|
||||||
current_boost_root, current_boost_lib = get_boost_envrionment()
|
|
||||||
current_compile_info = {
|
current_compile_info = {
|
||||||
'plat': sys.platform,
|
'plat': sys.platform,
|
||||||
'arch': current_arch,
|
'arch': current_arch,
|
||||||
'mode': '',
|
'mode': '',
|
||||||
'py_version': py_version,
|
'py_version': py_version,
|
||||||
'boost_root': current_boost_root,
|
|
||||||
'boost_lib': current_boost_lib
|
|
||||||
}
|
}
|
||||||
return current_compile_info
|
return current_compile_info
|
||||||
|
|
||||||
@ -87,8 +60,6 @@ def get_history_compile_info():
|
|||||||
'arch': '',
|
'arch': '',
|
||||||
'mode': '',
|
'mode': '',
|
||||||
'py_version': 0,
|
'py_version': 0,
|
||||||
'boost_root': '',
|
|
||||||
'boost_lib': ''
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -99,43 +70,6 @@ def save_current_compile_info(compile_info):
|
|||||||
json.dump(compile_info, f)
|
json.dump(compile_info, f)
|
||||||
|
|
||||||
|
|
||||||
def build_boost(mode):
|
|
||||||
""" 编译依赖的 boost 库 """
|
|
||||||
new_mode = 'release' if mode == 'release' else 'debug'
|
|
||||||
current_boost_root, current_boost_lib = get_boost_envrionment()
|
|
||||||
if current_boost_root == '' or current_boost_lib == '':
|
|
||||||
print("Can't get boost environment!")
|
|
||||||
return
|
|
||||||
current_dir = os.getcwd()
|
|
||||||
if sys.platform == 'win32':
|
|
||||||
os.chdir(current_boost_root)
|
|
||||||
if not os.path.exists('b2.exe'):
|
|
||||||
os.system('bootstrap.bat')
|
|
||||||
os.system(
|
|
||||||
'b2 {} link=static runtime-link=shared address-model=64 -j 4 --with-date_time'
|
|
||||||
' --with-filesystem --with-system --with-test'.format(mode))
|
|
||||||
os.system(
|
|
||||||
'b2 {} link=shared runtime-link=shared address-model=64 -j 4 --with-python'
|
|
||||||
' --with-serialization'.format(mode))
|
|
||||||
#os.system(
|
|
||||||
# 'b2 {} link=shared runtime-link=shared address-model=64 -j 4 --with-python'
|
|
||||||
# ' --with-date_time --with-filesystem --with-system --with-test'
|
|
||||||
# ' --with-serialization'.format(mode))
|
|
||||||
os.chdir(current_dir)
|
|
||||||
else:
|
|
||||||
# 新版的 boost 配置 project-cofig.jam 中的 python 版本无效,必须在当前 python 下重新编译 b2
|
|
||||||
cmd = 'cd {boost} ; ./bootstrap.sh; '\
|
|
||||||
'./b2 {mode} link=shared address-model=64 -j 4 --with-python --with-serialization; '\
|
|
||||||
'./b2 {mode} link=static address-model=64 cxxflags=-fPIC -j 4 --with-date_time '\
|
|
||||||
'--with-filesystem --with-system --with-test --with-atomic; '\
|
|
||||||
'cd {current}'.format(boost=current_boost_root, mode=mode, current=current_dir)
|
|
||||||
# cmd = 'cd {boost} ; if [ ! -f "b2" ]; then ./bootstrap.sh ; fi; '\
|
|
||||||
# './b2 {mode} link=shared address-model=64 -j 4 --with-python --with-serialization '\
|
|
||||||
# '--with-date_time --with-filesystem --with-system --with-test; '\
|
|
||||||
# 'cd {current}'.format(boost=current_boost_root, mode=mode, current=current_dir)
|
|
||||||
os.system(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def clear_with_python_changed(mode):
|
def clear_with_python_changed(mode):
|
||||||
"""
|
"""
|
||||||
python版本发生变化时,清理之前的python编译结果
|
python版本发生变化时,清理之前的python编译结果
|
||||||
@ -166,9 +100,6 @@ def clear_with_python_changed(mode):
|
|||||||
exit(0)
|
exit(0)
|
||||||
if os.path.lexists(build_pywrap_dir):
|
if os.path.lexists(build_pywrap_dir):
|
||||||
shutil.rmtree(build_pywrap_dir)
|
shutil.rmtree(build_pywrap_dir)
|
||||||
current_boost_root, _ = get_boost_envrionment()
|
|
||||||
if os.path.lexists('{}/bin.v2/libs/python'.format(current_boost_root)):
|
|
||||||
shutil.rmtree('{}/bin.v2/libs/python'.format(current_boost_root))
|
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
@ -186,27 +117,16 @@ def start_build(verbose=False, mode='release', worker_num=2):
|
|||||||
current_compile_info['mode'] = mode
|
current_compile_info['mode'] = mode
|
||||||
|
|
||||||
py_version = current_compile_info['py_version']
|
py_version = current_compile_info['py_version']
|
||||||
if py_version != 0 and py_version < 31:
|
|
||||||
print("Python version must >= 3.1 !")
|
|
||||||
return
|
|
||||||
|
|
||||||
current_boost_root = current_compile_info['boost_root']
|
|
||||||
current_boost_lib = current_compile_info['boost_lib']
|
|
||||||
if current_boost_root == '' or current_boost_lib == '':
|
|
||||||
print("Please configure BOOST")
|
|
||||||
exit(0)
|
|
||||||
print('BOOST_ROOT:', current_boost_root)
|
|
||||||
print('BOOST_LIB:', current_boost_lib)
|
|
||||||
|
|
||||||
#如果 python版本或者编译模式发生变化,则编译依赖的 boost 库(boost.python)
|
#如果 python版本或者编译模式发生变化,则编译依赖的 boost 库(boost.python)
|
||||||
history_compile_info = get_history_compile_info()
|
history_compile_info = get_history_compile_info()
|
||||||
if py_version != history_compile_info[
|
if py_version != history_compile_info[
|
||||||
'py_version'] or history_compile_info['mode'] != mode:
|
'py_version'] or history_compile_info['mode'] != mode:
|
||||||
clear_with_python_changed(mode)
|
clear_with_python_changed(mode)
|
||||||
print('\ncompile boost ...')
|
cmd = "xmake f {} -c -y -m {} --pyver={}".format(
|
||||||
build_boost(mode)
|
"-v -D" if verbose else "", mode, py_version)
|
||||||
os.system("xmake f {} -c -y -m {}".format("-v -D" if verbose else "",
|
print(cmd)
|
||||||
mode))
|
os.system(cmd)
|
||||||
|
|
||||||
os.system("xmake -j {} -b {} hikyuu".format(worker_num,
|
os.system("xmake -j {} -b {} hikyuu".format(worker_num,
|
||||||
"-v -D" if verbose else ""))
|
"-v -D" if verbose else ""))
|
||||||
@ -277,7 +197,7 @@ def test(all, compile, verbose, mode, case, j):
|
|||||||
'' if case == '' else '--test-case={}'.format(case)))
|
'' if case == '' else '--test-case={}'.format(case)))
|
||||||
|
|
||||||
|
|
||||||
def clear_build(with_boost):
|
def clear_build():
|
||||||
""" 清除当前编译设置及结果 """
|
""" 清除当前编译设置及结果 """
|
||||||
if os.path.lexists('.xmake'):
|
if os.path.lexists('.xmake'):
|
||||||
print('delete .xmake')
|
print('delete .xmake')
|
||||||
@ -291,26 +211,13 @@ def clear_build(with_boost):
|
|||||||
if os.path.exists('compile_info'):
|
if os.path.exists('compile_info'):
|
||||||
print('delete compile_info')
|
print('delete compile_info')
|
||||||
os.remove('compile_info')
|
os.remove('compile_info')
|
||||||
for r, _, f_list in os.walk('hikyuu'):
|
|
||||||
for name in f_list:
|
|
||||||
if (name != 'UnRAR.exe' and len(name) > 4 and name[-4:] in ('.dll','.exe','.pyd')) \
|
|
||||||
or (len(name) > 3 and name[-3:] == '.so') \
|
|
||||||
or (len(name) > 8 and name[:9] == 'libboost_') \
|
|
||||||
or (len(name) > 6 and name[-6:] == '.dylib'):
|
|
||||||
print('delete', r + '/' + name)
|
|
||||||
os.remove(os.path.join(r, name))
|
|
||||||
if with_boost:
|
|
||||||
_, boost_lib_dir = get_boost_envrionment()
|
|
||||||
if os.path.lexists(boost_lib_dir):
|
|
||||||
shutil.rmtree(boost_lib_dir)
|
|
||||||
print('clear finished!')
|
print('clear finished!')
|
||||||
os.system("xmake clean")
|
os.system("xmake clean")
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("-with_boost", "--with_boost", is_flag=True, help='清除相应的BOOST库')
|
def clear():
|
||||||
def clear(with_boost):
|
clear_build()
|
||||||
clear_build(with_boost)
|
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@ -321,8 +228,8 @@ def uninstall():
|
|||||||
else:
|
else:
|
||||||
usr_dir = os.path.expanduser('~')
|
usr_dir = os.path.expanduser('~')
|
||||||
py_version = get_python_version()
|
py_version = get_python_version()
|
||||||
site_lib_dir = '{}/.local/lib/python{:>.1f}/site-packages'.format(
|
site_lib_dir = '{}/.local/lib/python{}/site-packages'.format(
|
||||||
usr_dir, py_version * 0.1)
|
usr_dir, py_version)
|
||||||
for dir in os.listdir(site_lib_dir):
|
for dir in os.listdir(site_lib_dir):
|
||||||
if dir == 'hikyuu' or (len(dir) > 6 and dir[:6] == 'Hikyuu'):
|
if dir == 'hikyuu' or (len(dir) > 6 and dir[:6] == 'Hikyuu'):
|
||||||
print('delete', site_lib_dir + '/' + dir)
|
print('delete', site_lib_dir + '/' + dir)
|
||||||
@ -340,9 +247,8 @@ def install():
|
|||||||
install_dir = sys.base_prefix + "\\Lib\\site-packages\\hikyuu"
|
install_dir = sys.base_prefix + "\\Lib\\site-packages\\hikyuu"
|
||||||
else:
|
else:
|
||||||
usr_dir = os.path.expanduser('~')
|
usr_dir = os.path.expanduser('~')
|
||||||
install_dir = '{}/.local/lib/python{:>.1f}/site-packages/hikyuu'.format(
|
install_dir = '{}/.local/lib/python{}/site-packages/hikyuu'.format(
|
||||||
usr_dir,
|
usr_dir, get_python_version())
|
||||||
get_python_version() * 0.1)
|
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(install_dir)
|
shutil.rmtree(install_dir)
|
||||||
except:
|
except:
|
||||||
@ -356,7 +262,7 @@ def install():
|
|||||||
def wheel(j):
|
def wheel(j):
|
||||||
""" 生成 python 的 wheel 安装包 """
|
""" 生成 python 的 wheel 安装包 """
|
||||||
# 清理之前遗留的打包产物
|
# 清理之前遗留的打包产物
|
||||||
clear_build(with_boost=True)
|
clear_build()
|
||||||
|
|
||||||
# 尝试编译
|
# 尝试编译
|
||||||
start_build(False, 'release', j)
|
start_build(False, 'release', j)
|
||||||
@ -382,14 +288,15 @@ def wheel(j):
|
|||||||
return
|
return
|
||||||
|
|
||||||
py_version = get_python_version()
|
py_version = get_python_version()
|
||||||
|
main_ver, min_ver = py_version.split()
|
||||||
if current_plat == 'win32':
|
if current_plat == 'win32':
|
||||||
cmd = 'python sub_setup.py bdist_wheel --python-tag cp{} -p {}'.format(
|
cmd = 'python sub_setup.py bdist_wheel --python-tag cp{} -p {}{}'.format(
|
||||||
py_version, plat)
|
main_ver, min_ver, plat)
|
||||||
print(cmd)
|
print(cmd)
|
||||||
os.system(cmd)
|
os.system(cmd)
|
||||||
else:
|
else:
|
||||||
cmd = 'python3 sub_setup.py bdist_wheel --python-tag cp{} -p {}'.format(
|
cmd = 'python3 sub_setup.py bdist_wheel --python-tag cp{} -p {}{}'.format(
|
||||||
py_version, plat)
|
main_ver, min_ver, plat)
|
||||||
print(cmd)
|
print(cmd)
|
||||||
os.system(cmd)
|
os.system(cmd)
|
||||||
|
|
||||||
|
Binary file not shown.
32
xmake.lua
32
xmake.lua
@ -37,11 +37,12 @@ else
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- set language: C99, c++ standard
|
-- set language: C99, c++ standard
|
||||||
set_languages("cxx17", "C99")
|
set_languages("cxx17", "c99")
|
||||||
|
|
||||||
|
local boost_version = "1.81.0"
|
||||||
local hdf5_version = "1.12.2"
|
local hdf5_version = "1.12.2"
|
||||||
local mysql_version = "8.0.31"
|
local mysql_version = "8.0.31"
|
||||||
if is_plat("windows") then
|
if is_plat("windows") or (is_plat("linux", "cross") and is_arch("aarch64", "arm64.*"))then
|
||||||
mysql_version = "8.0.21"
|
mysql_version = "8.0.21"
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -54,18 +55,31 @@ if is_plat("windows") then
|
|||||||
add_requires("hdf5_D " .. hdf5_version)
|
add_requires("hdf5_D " .. hdf5_version)
|
||||||
end
|
end
|
||||||
add_requires("mysql " .. mysql_version)
|
add_requires("mysql " .. mysql_version)
|
||||||
elseif is_plat("linux") then
|
elseif is_plat("linux", "cross") then
|
||||||
add_requires("hdf5 " .. hdf5_version, {system = false})
|
add_requires("hdf5 " .. hdf5_version, {system = false})
|
||||||
add_requires("mysql " .. mysql_version, {system = false})
|
add_requires("mysql " .. mysql_version, {system = false})
|
||||||
elseif is_plat("macosx") then
|
elseif is_plat("macosx") then
|
||||||
add_requires("brew::hdf5")
|
add_requires("brew::hdf5")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
add_requires("boost " .. boost_version, {system=false,
|
||||||
|
configs = {
|
||||||
|
shared=is_plat("windows") and true or false,
|
||||||
|
vs_runtime="MD",
|
||||||
|
data_time=true,
|
||||||
|
filesystem=true,
|
||||||
|
serialization=true,
|
||||||
|
system=true,
|
||||||
|
python=true,
|
||||||
|
pyver = get_config("pyver"),
|
||||||
|
}})
|
||||||
|
|
||||||
|
|
||||||
-- add_requires("fmt 8.1.1", {system=false, configs = {header_only = true}})
|
-- add_requires("fmt 8.1.1", {system=false, configs = {header_only = true}})
|
||||||
add_requires("spdlog", {system=false, configs = {header_only = true, fmt_external=true, vs_runtime = "MD"}})
|
add_requires("spdlog", {system=false, configs = {header_only = true, fmt_external=true, vs_runtime = "MD"}})
|
||||||
add_requireconfs("spdlog.fmt", {override = true, version = "8.1.1", configs = {header_only = true}})
|
add_requireconfs("spdlog.fmt", {override = true, version = "8.1.1", configs = {header_only = true}})
|
||||||
add_requires("sqlite3", {system=false, configs = {shared=true, vs_runtime="MD", cxflags="-fPIC"}})
|
add_requires("sqlite3", {system=false, configs = {shared=true, vs_runtime="MD", cxflags="-fPIC"}})
|
||||||
add_requires("flatbuffers", {system=false, configs = {vs_runtime="MD"}})
|
add_requires("flatbuffers 2.0.0", {system=false, configs = {vs_runtime="MD"}})
|
||||||
add_requires("nng", {system=false, configs = {vs_runtime="MD", cxflags="-fPIC"}})
|
add_requires("nng", {system=false, configs = {vs_runtime="MD", cxflags="-fPIC"}})
|
||||||
add_requires("nlohmann_json", {system=false})
|
add_requires("nlohmann_json", {system=false})
|
||||||
add_requires("cpp-httplib", {system=false})
|
add_requires("cpp-httplib", {system=false})
|
||||||
@ -76,12 +90,10 @@ add_defines("SPDLOG_DISABLE_DEFAULT_LOGGER") -- 禁用 spdlog 默认 logger
|
|||||||
set_objectdir("$(buildir)/$(mode)/$(plat)/$(arch)/.objs")
|
set_objectdir("$(buildir)/$(mode)/$(plat)/$(arch)/.objs")
|
||||||
set_targetdir("$(buildir)/$(mode)/$(plat)/$(arch)/lib")
|
set_targetdir("$(buildir)/$(mode)/$(plat)/$(arch)/lib")
|
||||||
|
|
||||||
add_includedirs("$(env BOOST_ROOT)")
|
|
||||||
add_linkdirs("$(env BOOST_LIB)")
|
|
||||||
|
|
||||||
-- modifed to use boost static library, except boost.python, serialization
|
-- modifed to use boost static library, except boost.python, serialization
|
||||||
--add_defines("BOOST_ALL_DYN_LINK")
|
if is_plat("windows") then
|
||||||
add_defines("BOOST_SERIALIZATION_DYN_LINK")
|
add_defines("BOOST_ALL_DYN_LINK")
|
||||||
|
end
|
||||||
|
|
||||||
-- is release now
|
-- is release now
|
||||||
if is_mode("release") then
|
if is_mode("release") then
|
||||||
|
Loading…
Reference in New Issue
Block a user