Skip to content

Commit 63e84fa

Browse files
Add MacOS build and test workflows
* Move to scikit-build-core * Fix wallet bindings * Fix missing override keywords causing crash
1 parent d340792 commit 63e84fa

File tree

11 files changed

+213
-101
lines changed

11 files changed

+213
-101
lines changed

.github/workflows/build-macos.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Build MacOS
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
workflow_dispatch:
7+
8+
jobs:
9+
build:
10+
name: ${{ matrix.os }} (arm64)
11+
runs-on: ${{ matrix.os }}
12+
13+
strategy:
14+
matrix:
15+
os: [macos-14, macos-15]
16+
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
with:
21+
submodules: recursive
22+
23+
- name: Install dependencies
24+
run: |
25+
HOMEBREW_NO_AUTO_UPDATE=1 brew install python boost@1.85 hidapi openssl zmq libpgm miniupnpc expat libunwind-headers protobuf unbound
26+
brew unlink boost || true
27+
brew link boost@1.85 --force
28+
pip3 install pytest pytest-cov setuptools wheel scikit-build-core --break-system-packages
29+
30+
- name: Install pybind11 v2.13.6
31+
run: |
32+
pip3 install pybind11==2.13.6 pybind11-stubgen --break-system-packages
33+
34+
- name: Build monero
35+
run: |
36+
cd external/monero-cpp/external/monero-project
37+
mkdir -p build/release
38+
cd build/release
39+
cmake -DSTATIC=ON -DBUILD_64=ON -DCMAKE_BUILD_TYPE=Release ../../
40+
make -j3 wallet cryptonote_protocol
41+
cd ../../../../../../
42+
43+
- name: Build monero-cpp
44+
run: |
45+
cd external/monero-cpp
46+
mkdir -p build
47+
cd build
48+
cmake ..
49+
cmake --build .
50+
make -j3
51+
cd ../../../
52+
53+
- name: Build monero-python
54+
run: |
55+
mkdir -p build
56+
python3 -m pip wheel . -w dist --no-build-isolation
57+
58+
- name: Upload artifacts
59+
uses: actions/upload-artifact@v4
60+
with:
61+
name: monero-${{ matrix.os }}
62+
path: |
63+
dist/*.whl
64+
external/monero-cpp/build/libmonero-cpp.dylib

.github/workflows/test.yml

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ jobs:
2121
- name: Install dependencies
2222
run: |
2323
sudo apt update
24-
sudo apt install -y build-essential cmake pkg-config libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libexpat1-dev libpgm-dev qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev python3 ccache doxygen graphviz git curl autoconf libtool gperf nettle-dev libevent-dev debhelper python3-all python3-pip python3-pybind11 python3-pytest python3-pytest-rerunfailures python3-pytest-cov lcov
25-
pip3 install pybind11-stubgen pytest --break-system-packages
24+
sudo apt install -y build-essential cmake pkg-config libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libexpat1-dev libpgm-dev qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev python3 ccache doxygen graphviz git curl autoconf libtool gperf nettle-dev libevent-dev debhelper python3-all python3-pip python3-pybind11 python3-pytest python3-pytest-rerunfailures python3-pytest-cov lcov python3-scikit-build-core
25+
pip3 install pybind11-stubgen pytest pyproject-metadata --break-system-packages
2626
2727
- name: Install expat
2828
run: |
@@ -80,10 +80,9 @@ jobs:
8080
- name: Install monero-python
8181
run: |
8282
mkdir -p build
83-
export CFLAGS="--coverage -fprofile-update=atomic -O0 -g"
84-
export CXXFLAGS="--coverage -fprofile-update=atomic -O0 -g"
85-
export LDFLAGS="--coverage"
86-
COVERAGE=1 pip3 install -vvv .
83+
cmake -B build -DENABLE_COVERAGE=ON
84+
cmake --build build
85+
cp build/monero.cpython-312-x86_64-linux-gnu.so ~/.local/lib/python3.12/site-packages/
8786
8887
- name: Setup test environment
8988
run: |
@@ -105,7 +104,7 @@ jobs:
105104

106105
- name: Generate coverage report
107106
run: |
108-
lcov --capture --directory . --ignore-errors mismatch,mismatch,inconsistent,source,source,gcov,gcov --output-file coverage_full.info
107+
lcov --capture --directory build --ignore-errors mismatch,mismatch,inconsistent,source,source,gcov,gcov --output-file coverage_full.info
109108
lcov --ignore-errors unused,unused --remove coverage_full.info '/usr/*' '*/external/*' '*/pybind11/*' '*monero-cpp/*' '*monero-project/*' --output-file coverage.info
110109
sed -i "s|$(pwd)/||g" coverage.info
111110
@@ -140,7 +139,7 @@ jobs:
140139
- name: Install pytest
141140
shell: bash
142141
run: |
143-
python -m pip install pytest pytest-rerunfailures typing_extensions
142+
python -m pip install pytest pytest-rerunfailures typing_extensions scikit-build-core
144143
145144
- name: Setup MSYS2 MINGW64
146145
uses: msys2/setup-msys2@v2
@@ -243,3 +242,57 @@ jobs:
243242
PATH: "${{ github.workspace }}/dist:/usr/bin:$PATH"
244243
run: |
245244
python -m pytest -m unit
245+
246+
macos:
247+
runs-on: macos-15
248+
name: macos (pytest)
249+
250+
steps:
251+
- uses: actions/checkout@v4
252+
253+
- name: Install dependencies
254+
run: |
255+
HOMEBREW_NO_AUTO_UPDATE=1 brew install python boost@1.85 hidapi openssl zmq libpgm miniupnpc expat libunwind-headers protobuf unbound
256+
brew unlink boost || true
257+
brew link boost@1.85 --force
258+
pip3 install pytest pytest-rerunfailures pytest-cov setuptools wheel scikit-build-core --break-system-packages
259+
260+
- name: Install pybind11 v2.13.6
261+
run: |
262+
pip3 install pybind11==2.13.6 pybind11-stubgen --break-system-packages
263+
264+
- name: Clone monero-cpp (regtest)
265+
run: |
266+
cd external
267+
rm -rf monero-cpp
268+
git clone -b regtest-env --single-branch --recurse-submodules https://github.com/everoddandeven/monero-cpp.git
269+
cd ..
270+
271+
- name: Build monero
272+
run: |
273+
cd external/monero-cpp/external/monero-project
274+
mkdir -p build/release
275+
cd build/release
276+
cmake -DSTATIC=ON -DBUILD_64=ON -DCMAKE_BUILD_TYPE=Release ../../
277+
make -j3 wallet cryptonote_protocol
278+
cd ../../../../../../
279+
280+
- name: Install monero-cpp
281+
run: |
282+
cd external/monero-cpp
283+
mkdir -p build
284+
cd build
285+
cmake ..
286+
cmake --build .
287+
make -j3
288+
cp libmonero-cpp.dylib /opt/homebrew/lib/
289+
cd ../../../
290+
291+
- name: Install monero-python
292+
run: |
293+
mkdir -p build
294+
pip3 install --no-build-isolation -vvv . --break-system-packages
295+
296+
- name: Run unit tests
297+
run: |
298+
pytest -m unit

CMakeLists.txt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,27 @@ endif()
1010

1111
project(monero LANGUAGES CXX)
1212

13+
option(ENABLE_COVERAGE "Enable coverage" OFF)
14+
15+
if(ENABLE_COVERAGE)
16+
message(STATUS "Coverage enabled")
17+
add_compile_options(--coverage -O0 -g -fprofile-update=atomic)
18+
add_link_options(--coverage)
19+
endif()
20+
1321
set(CMAKE_CXX_STANDARD 17)
1422
set(CMAKE_CXX_STANDARD_REQUIRED ON)
1523

1624
find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module)
25+
1726
find_package(pybind11 REQUIRED)
27+
1828
set(Boost_NO_BOOST_CMAKE 1)
1929
set(Boost_USE_MULTITHREADED ON)
2030
find_package(Boost REQUIRED COMPONENTS system thread serialization filesystem)
2131

32+
find_package(OpenSSL REQUIRED)
33+
2234
set(SOURCES
2335
src/cpp/common/py_monero_common.cpp
2436
src/cpp/daemon/py_monero_daemon_model.cpp
@@ -59,8 +71,8 @@ target_link_libraries(monero PRIVATE
5971
Boost::serialization
6072
Boost::filesystem
6173

62-
ssl
63-
crypto
74+
OpenSSL::SSL
75+
OpenSSL::Crypto
6476
)
6577

6678
if (WIN32)
@@ -70,3 +82,5 @@ if (WIN32)
7082
bcrypt
7183
)
7284
endif()
85+
86+
install(TARGETS monero DESTINATION .)

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
[![Build Debian Packages](https://github.com/everoddandeven/monero-python/actions/workflows/build-deb.yml/badge.svg)](https://github.com/everoddandeven/monero-python/actions/workflows/build-deb.yml)
88
[![Build Windows Package](https://github.com/everoddandeven/monero-python/actions/workflows/build-windows.yml/badge.svg?branch=main)](https://github.com/everoddandeven/monero-python/actions/workflows/build-windows.yml)
9+
[![Build MacOS](https://github.com/everoddandeven/monero-python/actions/workflows/build-macos.yml/badge.svg)](https://github.com/everoddandeven/monero-python/actions/workflows/build-macos.yml)
10+
11+
[![Matrix](https://img.shields.io/badge/matrix-monero--python-blue?logo=matrix)](https://matrix.to/#/#monero-python:monero.social)
912

1013
> [!WARNING]
1114
>

pyproject.toml

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
[project]
2+
name = "monero"
3+
version = "0.0.1"
4+
description = "A Python library for using Monero"
5+
authors = [
6+
{ name = "everoddandeven", email = "everoddandeven@protonmail.com" }
7+
]
8+
license = { text = "MIT" }
9+
readme = "README.md"
10+
requires-python = ">=3.8"
11+
dependencies = [
12+
"pybind11>=2.12"
13+
]
14+
115
[build-system]
2-
requires = ["setuptools>=61", "pybind11>=2.12"]
3-
build-backend = "setuptools.build_meta"
16+
requires = [
17+
"scikit-build-core>=0.5",
18+
"pybind11>=2.12",
19+
"cmake>=3.20",
20+
"ninja"
21+
]
22+
build-backend = "scikit_build_core.build"
23+
24+
[tool.scikit-build]
25+
cmake.verbose = true
26+
cmake.build-type = "Release"

setup.py

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,5 @@
1-
import pybind11
2-
import sys
3-
import os
4-
5-
from setuptools import setup
6-
from pathlib import Path
7-
from pybind11.setup_helpers import Pybind11Extension, build_ext
8-
9-
coverage = os.environ.get("COVERAGE") == "1"
10-
this_dir = Path(__file__).parent.resolve()
11-
extra_compile_args: list[str] = ['/std:c++17'] if sys.platform == "win32" else ['-std=c++17']
12-
extra_link_args: list[str] = []
13-
14-
if coverage:
15-
extra_compile_args += ['-O0', '-g', '--coverage']
16-
extra_link_args += ['--coverage']
17-
18-
ext_modules = [
19-
Pybind11Extension(
20-
'monero',
21-
[
22-
'src/cpp/common/py_monero_common.cpp',
23-
'src/cpp/daemon/py_monero_daemon_model.cpp',
24-
'src/cpp/daemon/py_monero_daemon_rpc.cpp',
25-
'src/cpp/wallet/py_monero_wallet_model.cpp',
26-
'src/cpp/wallet/py_monero_wallet.cpp',
27-
'src/cpp/wallet/py_monero_wallet_rpc.cpp',
28-
'src/cpp/utils/py_monero_utils.cpp',
29-
'src/cpp/py_monero.cpp'
30-
],
31-
include_dirs=[
32-
pybind11.get_include(),
33-
str(this_dir / 'external' / 'monero-cpp' / 'src'),
34-
str(this_dir / 'external' / 'monero-cpp' / 'external' / 'monero-project' / 'src'),
35-
str(this_dir / 'external' / 'monero-cpp' / 'external' / 'monero-project' / 'contrib' / 'epee' / 'include'),
36-
str(this_dir / 'external' / 'monero-cpp' / 'external' / 'monero-project' / 'external'),
37-
str(this_dir / 'external' / 'monero-cpp' / 'external' / 'monero-project' / 'external' / 'easylogging++'),
38-
str(this_dir / 'external' / 'monero-cpp' / 'external' / 'monero-project' / 'external' / 'rapidjson' / 'include'),
39-
str(this_dir / 'src' / 'cpp'),
40-
str(this_dir / 'src' / 'cpp' / 'common'),
41-
str(this_dir / 'src' / 'cpp' / 'daemon'),
42-
str(this_dir / 'src' / 'cpp' / 'wallet'),
43-
str(this_dir / 'src' / 'cpp' / 'utils')
44-
],
45-
library_dirs=[
46-
str(this_dir / 'external' / 'monero-cpp' / 'build')
47-
],
48-
libraries=['monero-cpp'],
49-
language='c++',
50-
extra_compile_args=extra_compile_args,
51-
extra_link_args=extra_link_args
52-
),
53-
]
1+
# setup.py
2+
from skbuild import setup
543

554
setup(
565
name='monero',
@@ -60,12 +9,10 @@
609
maintainer='everoddandeven',
6110
maintainer_email='everoddandeven@protonmail.com',
6211
license="MIT",
12+
packages=["monero"],
6313
url='https://github.com/everoddandeven/monero-python',
6414
download_url="https://github.com/everoddandeven/monero-python/releases",
6515
description='A Python library for using Monero.',
6616
long_description='Python bindings for monero-cpp.',
6717
keywords=["monero", "monero-python", "python", "bindings", "pybind11"],
68-
ext_modules=ext_modules,
69-
install_requires=['pybind11>=2.12.0'],
70-
cmdclass={"build_ext": build_ext}
7118
)

src/cpp/daemon/py_monero_daemon_rpc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class PyMoneroDaemonRpc : public PyMoneroDaemon {
8686
std::shared_ptr<PyMoneroDaemonUpdateCheckResult> check_for_update() override;
8787
std::shared_ptr<PyMoneroDaemonUpdateDownloadResult> download_update(const std::string& path = "") override;
8888
void stop() override;
89-
std::shared_ptr<monero::monero_block_header> wait_for_next_block_header();
89+
std::shared_ptr<monero::monero_block_header> wait_for_next_block_header() override;
9090
static void check_response_status(const std::shared_ptr<PyMoneroPathResponse>& response);
9191
static void check_response_status(const std::shared_ptr<PyMoneroJsonResponse>& response);
9292

src/cpp/py_monero.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,10 +1575,10 @@ PYBIND11_MODULE(monero, m) {
15751575
MONERO_CATCH_AND_RETHROW(self.is_view_only());
15761576
})
15771577
.def("set_connection_manager", [](PyMoneroWallet& self, const std::shared_ptr<PyMoneroConnectionManager> &connection_manager) {
1578-
MONERO_CATCH_AND_RETHROW(self.set_connection_manager(connection_manager));
1578+
throw PyMoneroError("MoneroWallet.set_connection_manager(): not supported");
15791579
}, py::arg("connection_manager"))
15801580
.def("get_connection_manager", [](PyMoneroWallet& self) {
1581-
MONERO_CATCH_AND_RETHROW(self.get_connection_manager());
1581+
throw PyMoneroError("MoneroWallet.get_connection_manager(): not supported");
15821582
})
15831583
.def("set_daemon_connection", [](PyMoneroWallet& self, const boost::optional<monero::monero_rpc_connection>& connection) {
15841584
MONERO_CATCH_AND_RETHROW(self.set_daemon_connection(connection));
@@ -1967,17 +1967,17 @@ PYBIND11_MODULE(monero, m) {
19671967
.def("delete_address_book_entry", [](PyMoneroWallet& self, uint64_t index) {
19681968
MONERO_CATCH_AND_RETHROW(self.delete_address_book_entry(index));
19691969
}, py::arg("index"))
1970-
.def("tag_accounts", [](PyMoneroWallet& self, const std::string& tag, const std::vector<uint32_t>& account_indices) {
1971-
MONERO_CATCH_AND_RETHROW(self.tag_accounts(tag, account_indices));
1970+
.def("tag_accounts", [](monero::monero_wallet& self, const std::string& tag, const std::vector<uint32_t>& account_indices) {
1971+
throw PyMoneroError("MoneroWallet.tag_accounts(): not supported");
19721972
}, py::arg("tag"), py::arg("account_indices"))
1973-
.def("untag_accounts", [](PyMoneroWallet& self, const std::vector<uint32_t>& account_indices) {
1974-
MONERO_CATCH_AND_RETHROW(self.untag_accounts(account_indices));
1973+
.def("untag_accounts", [](monero::monero_wallet& self, const std::vector<uint32_t>& account_indices) {
1974+
throw PyMoneroError("MoneroWallet.untag_accounts(): not supported");
19751975
}, py::arg("account_indices"))
1976-
.def("get_account_tags", [](PyMoneroWallet& self) {
1977-
MONERO_CATCH_AND_RETHROW(self.get_account_tags());
1976+
.def("get_account_tags", [](monero::monero_wallet& self) {
1977+
throw PyMoneroError("MoneroWallet.get_account_tags(): not supported");
19781978
})
1979-
.def("set_account_tag_label", [](PyMoneroWallet& self, const std::string& tag, const std::string& label) {
1980-
MONERO_CATCH_AND_RETHROW(self.set_account_tag_label(tag, label));
1979+
.def("set_account_tag_label", [](monero::monero_wallet& self, const std::string& tag, const std::string& label) {
1980+
throw PyMoneroError("MoneroWallet.set_account_tag_label(): not supported");
19811981
}, py::arg("tag"), py::arg("label"))
19821982
.def("set_account_label", [](PyMoneroWallet& self, uint32_t account_idx, const std::string& label) {
19831983
MONERO_CATCH_AND_RETHROW(self.set_subaddress_label(account_idx, 0, label));
@@ -2195,7 +2195,19 @@ PYBIND11_MODULE(monero, m) {
21952195
}, py::arg("connection"), py::arg("is_trusted"), py::arg("ssl_options"))
21962196
.def("stop", [](PyMoneroWalletRpc& self) {
21972197
MONERO_CATCH_AND_RETHROW(self.stop());
2198-
});
2198+
})
2199+
.def("tag_accounts", [](PyMoneroWalletRpc& self, const std::string& tag, const std::vector<uint32_t>& account_indices) {
2200+
MONERO_CATCH_AND_RETHROW(self.tag_accounts(tag, account_indices));
2201+
}, py::arg("tag"), py::arg("account_indices"))
2202+
.def("untag_accounts", [](PyMoneroWalletRpc& self, const std::vector<uint32_t>& account_indices) {
2203+
MONERO_CATCH_AND_RETHROW(self.untag_accounts(account_indices));
2204+
}, py::arg("account_indices"))
2205+
.def("get_account_tags", [](PyMoneroWalletRpc& self) {
2206+
MONERO_CATCH_AND_RETHROW(self.get_account_tags());
2207+
})
2208+
.def("set_account_tag_label", [](PyMoneroWalletRpc& self, const std::string& tag, const std::string& label) {
2209+
MONERO_CATCH_AND_RETHROW(self.set_account_tag_label(tag, label));
2210+
}, py::arg("tag"), py::arg("label"));
21992211

22002212
// monero_utils
22012213
py_monero_utils

0 commit comments

Comments
 (0)