Skip to content

Commit 5fafe0a

Browse files
author
AhmedYasserrr
committed
feat: Add pybind11 bindings, scikit-build-core setup, and CI workflow for Python package
- Implemented initial pybind11 class bindings to expose C++ API to Python. - Integrated scikit-build-core by updating CMakeLists.txt and pyproject.toml. - Added GitHub Actions workflow to build and test the Python package.
1 parent 481c85d commit 5fafe0a

File tree

10 files changed

+170
-37
lines changed

10 files changed

+170
-37
lines changed

.github/workflows/pip.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Pip
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
push:
7+
branches:
8+
- dev_py_pkg_build
9+
10+
jobs:
11+
build:
12+
name: Build on ${{ matrix.platform }} with Python ${{ matrix.python-version }}
13+
runs-on: ${{ matrix.platform }}
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
platform: [ubuntu-latest]
18+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
19+
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@v4
23+
24+
- name: Set up Python
25+
uses: actions/setup-python@v5
26+
with:
27+
python-version: ${{ matrix.python-version }}
28+
allow-prereleases: true
29+
30+
- name: Upgrade pip, build tools
31+
run: |
32+
python -m pip install --upgrade pip
33+
pip install build scikit-build-core pybind11
34+
35+
- name: Build and install the package
36+
run: |
37+
pip install --verbose .
38+
39+
- name: Test import
40+
run: |
41+
python -c "import pyectool; print('pyectool imported')"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
build/*
2+
*/__pycache__/*

CMakeLists.txt

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,43 @@
1-
cmake_minimum_required(VERSION 3.1)
1+
cmake_minimum_required(VERSION 3.15...3.27)
22

3-
if(${CMAKE_VERSION} VERSION_LESS 3.12)
4-
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
5-
endif()
3+
project(
4+
${SKBUILD_PROJECT_NAME}
5+
VERSION ${SKBUILD_PROJECT_VERSION}
6+
LANGUAGES CXX)
7+
8+
# Required for building Python extension modules via pybind11
9+
find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
610

7-
project(ECTool
8-
VERSION 1.0.0
9-
DESCRIPTION "ChromeOS EC Tool"
10-
LANGUAGES CXX)
11+
# Find pybind11 (installed via pip/conda or system-wide)
12+
find_package(pybind11 CONFIG REQUIRED)
1113

1214
if(NOT WIN32)
13-
find_package(PkgConfig REQUIRED)
14-
pkg_check_modules(libusb REQUIRED libusb-1.0)
15-
pkg_check_modules(libftdi1 REQUIRED libftdi1)
15+
find_package(PkgConfig REQUIRED)
16+
pkg_check_modules(libusb REQUIRED libusb-1.0)
17+
pkg_check_modules(libftdi1 REQUIRED libftdi1)
1618
else()
19+
1720
endif()
1821

1922
set(CMAKE_CXX_STANDARD 17)
2023

2124
add_subdirectory(src/core)
25+
add_subdirectory(src/bindings)
2226
add_subdirectory(src/extern)
2327

2428
if(WIN32)
25-
add_subdirectory(src/getopt)
29+
add_subdirectory(src/getopt)
2630
endif()
31+
32+
install(
33+
TARGETS ectool libectool libectool_py
34+
RUNTIME DESTINATION pyectool/bin # ectool CLI binary
35+
LIBRARY DESTINATION pyectool # libectool_py.so (shared Python module)
36+
ARCHIVE DESTINATION pyectool/lib # libectool.a (static lib)
37+
)
38+
39+
install(
40+
DIRECTORY src/include/
41+
DESTINATION pyectool/include
42+
FILES_MATCHING
43+
PATTERN "libectool.h")

pyectool/__init__.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from __future__ import annotations
2+
3+
from .libectool_py import (
4+
__doc__,
5+
__version__,
6+
ascii_mode,
7+
auto_fan_control,
8+
get_max_non_battery_temperature,
9+
get_max_temperature,
10+
init,
11+
is_on_ac,
12+
release,
13+
set_fan_duty,
14+
)
15+
16+
__all__ = [
17+
"__doc__",
18+
"__version__",
19+
"ascii_mode",
20+
"auto_fan_control",
21+
"get_max_non_battery_temperature",
22+
"get_max_temperature",
23+
"init",
24+
"is_on_ac",
25+
"release",
26+
"set_fan_duty",
27+
]

pyectool/__init__.pyi

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from __future__ import annotations
2+
3+
__doc__: str
4+
__version__: str
5+
6+
def init() -> None: ...
7+
def release() -> None: ...
8+
def is_on_ac() -> bool: ...
9+
def auto_fan_control() -> None: ...
10+
def set_fan_duty(duty: int) -> None: ...
11+
def get_max_temperature() -> float: ...
12+
def get_max_non_battery_temperature() -> float: ...
13+
14+
ascii_mode: bool

pyproject.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,15 @@ build-backend = "scikit_build_core.build"
44

55

66
[project]
7-
name = "libectool"
7+
name = "pyectool"
88
version = "0.0.1"
9-
description="A shared library (libectool) that exposes ectool functionalities for seamless integration with other applications"
9+
description="Python bindings for ectool using pybind11, enabling seamless integration with other applications"
1010
readme = "README.md"
1111
authors = [
1212
{ name = "Ahmed Gamea", email = "ahmed.gamea@ejust.edu.eg" },
1313
]
1414

1515
[tool.scikit-build]
16-
wheel.expand-macos-universal-tags = true
1716
minimum-version = "build-system.requires"
1817

1918
[tool.cibuildwheel]

src/bindings/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Create the Python module
2+
python_add_library(libectool_py MODULE libectool_py.cc WITH_SOABI)
3+
4+
# Link against required libraries
5+
target_link_libraries(libectool_py PRIVATE pybind11::headers libectool)
6+
target_include_directories(libectool_py PUBLIC ../include)
7+
target_compile_definitions(libectool_py PUBLIC VERSION_INFO=${PROJECT_VERSION})

src/bindings/libectool_py.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <pybind11/pybind11.h>
2+
#include "libectool.h"
3+
4+
#define STRINGIFY(x) #x
5+
#define MACRO_STRINGIFY(x) STRINGIFY(x)
6+
7+
namespace py = pybind11;
8+
9+
PYBIND11_MODULE(libectool_py, m) {
10+
m.doc() = "Python bindings for ectool";
11+
12+
// Optional: expose init/release explicitly
13+
m.def("init", &libectool_init, "Initialize libectool");
14+
m.def("release", &libectool_release, "Release libectool");
15+
16+
// Expose API functions
17+
m.def("is_on_ac", &is_on_ac, "Check if on AC power");
18+
m.def("auto_fan_control", &auto_fan_control, "Enable automatic fan control");
19+
m.def("set_fan_duty", &set_fan_duty, py::arg("duty"), "Set fan duty cycle (0-100)");
20+
m.def("get_max_temperature", &get_max_temperature, "Get max temperature");
21+
m.def("get_max_non_battery_temperature", &get_max_non_battery_temperature, "Get max non-battery temperature");
22+
23+
// Expose global variable ascii_mode
24+
m.attr("ascii_mode") = py::cast(&ascii_mode, py::return_value_policy::reference);
25+
26+
#ifdef VERSION_INFO
27+
m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO);
28+
#else
29+
m.attr("__version__") = "dev";
30+
#endif
31+
}

src/core/CMakeLists.txt

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ else()
2626
endif()
2727

2828
# ============================
29-
# Add Executable Target: ectool
29+
# Add Executable Target: ectool (CLI)
3030
# ============================
3131
add_executable(ectool ectool.cc ${ECTOOL_COMMON_SOURCES})
3232

@@ -53,37 +53,33 @@ endif()
5353
target_link_libraries(ectool ${libusb_LIBRARIES} ${libftdi1_LIBRARIES})
5454

5555
# ============================
56-
# Add Shared Library : libectool.so
56+
# Add STATIC Library : libectool
5757
# ============================
58+
add_library(libectool STATIC libectool.cc ${ECTOOL_COMMON_SOURCES})
5859

59-
set(LIBECTOOL_SOURCES ${ECTOOL_COMMON_SOURCES} libectool.cc)
60+
target_include_directories(libectool PUBLIC ../include ${libusb_INCLUDE_DIRS})
6061

61-
add_library(libectool SHARED ${LIBECTOOL_SOURCES})
62-
63-
target_include_directories(libectool PRIVATE ../include ${libusb_INCLUDE_DIRS})
64-
65-
target_compile_definitions(libectool PRIVATE CHROMIUM_EC EXTERNAL_ECTOOL_BUILD)
62+
target_compile_definitions(libectool PUBLIC CHROMIUM_EC EXTERNAL_ECTOOL_BUILD)
6663

6764
target_compile_options(
68-
libectool PRIVATE -Wno-c99-designator -Wno-address-of-packed-member
69-
-Wno-format-security)
65+
libectool PUBLIC -Wno-c99-designator -Wno-address-of-packed-member
66+
-Wno-format-security)
7067

71-
target_link_libraries(libectool PRIVATE ${libusb_LIBRARIES}
72-
${libftdi1_LIBRARIES})
68+
target_link_libraries(libectool PUBLIC ${libusb_LIBRARIES}
69+
${libftdi1_LIBRARIES})
7370

7471
if(WIN32)
75-
target_compile_definitions(ectool PRIVATE _CRT_SECURE_NO_WARNINGS)
76-
target_link_libraries(ectool PRIVATE getopt CrosECDriver
77-
onecoreuap_apiset.lib)
72+
target_compile_definitions(libectool PUBLIC _CRT_SECURE_NO_WARNINGS)
73+
target_link_libraries(libectool PUBLIC getopt CrosECDriver
74+
onecoreuap_apiset.lib)
7875
if(MSVC)
79-
target_compile_options(ectool PRIVATE /FI"..\\include\\win32_shim.h")
76+
target_compile_options(libectool PUBLIC /FI"..\\include\\win32_shim.h")
8077
else()
81-
target_compile_options(ectool PRIVATE -include "..\\include\\win32_shim.h")
78+
target_compile_options(libectool PUBLIC -include
79+
"..\\include\\win32_shim.h")
8280
endif()
83-
target_include_directories(ectool PRIVATE ../include/win32)
81+
target_include_directories(libectool PUBLIC ../include/win32)
8482
endif()
8583

86-
set_target_properties(
87-
libectool PROPERTIES OUTPUT_NAME "ectool" # Generates `libectool.so` or
88-
# `libectool.dll`
89-
)
84+
set_target_properties(libectool PROPERTIES OUTPUT_NAME ectool
85+
POSITION_INDEPENDENT_CODE ON)
File renamed without changes.

0 commit comments

Comments
 (0)