From ae39ba32d67b8bb868c0bad9db7571755d825560 Mon Sep 17 00:00:00 2001 From: kendryte747 <116556725+kendryte747@users.noreply.github.com> Date: Thu, 10 Oct 2024 20:06:12 +0800 Subject: [PATCH] Add support for cibuildwheel (#2) --- .github/workflows/build.yml | 48 ++++++++++- .gitignore | 4 +- CMakeLists.txt | 11 ++- LICENSE | 26 +++++- README.md | 25 +----- pyproject.toml | 13 ++- setup.py | 26 +++++- src/kburn/CMakeLists.txt | 115 ++++++++++++++----------- src/kburn/cli/CMakeLists.txt | 2 +- src/python/kburn/native/CMakeLists.txt | 29 +++++-- tests/import/__init__.py | 0 tests/import/test_import.py | 26 ++++++ 12 files changed, 230 insertions(+), 95 deletions(-) create mode 100644 tests/import/__init__.py create mode 100644 tests/import/test_import.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 123fdac..33dbf69 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,8 +12,8 @@ concurrency: cancel-in-progress: true jobs: - build-python: - name: build-python-${{matrix.config.name}} + build-wheel: + name: build-wheel-${{matrix.config.name}} runs-on: ${{matrix.config.os}} strategy: matrix: @@ -38,3 +38,47 @@ jobs: - name: Build wheel run: python -m cibuildwheel --output-dir wheelhouse + + - name: Upload k230_flash-python Build Artifact + uses: actions/upload-artifact@v4 + with: + name: k230_flash-python-${{matrix.config.name}} + path: ${{github.workspace}}/wheelhouse + if-no-files-found: error + + pypi-publish: + name: Upload release to PyPI + runs-on: ubuntu-latest + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + needs: ["build-wheel"] + environment: + name: pypi + url: https://pypi.org/p/k230_flash + permissions: + id-token: write + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: k230_flash-python-macos + path: ${{github.workspace}}/dist + + - uses: actions/download-artifact@v4 + with: + name: k230_flash-python-linux + path: ${{github.workspace}}/dist + + - uses: actions/download-artifact@v4 + with: + name: k230_flash-python-windows + path: ${{github.workspace}}/dist + + - name: List dist + run: | + ls -alh ${{github.workspace}}/dist + + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + verbose: true diff --git a/.gitignore b/.gitignore index c806560..8cc18bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ -__py_cache__ +__pycache__ build +install dist wheelhouse +.pytest_cache *.egg-info *.spec diff --git a/CMakeLists.txt b/CMakeLists.txt index 47feaaa..53bd132 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,13 @@ cmake_minimum_required(VERSION 3.18) -if(NOT DEFINED VERSION_INFO) - set(VERSION_INFO "0.0.1") -endif() +set(K230_FLASH_VERSION_MAJOR 0) +set(K230_FLASH_VERSION_MINOR 0) +set(K230_FLASH_VERSION_PATCH 2) -project(kburn VERSION ${VERSION_INFO}) +set(K230_FLASH_VERSION_STRING ${K230_FLASH_VERSION_MAJOR}.${K230_FLASH_VERSION_MINOR}.${K230_FLASH_VERSION_PATCH}) +message(STATUS "K230_FLASH_VERSION_STRING = ${K230_FLASH_VERSION_STRING}") + +project(kburn_top) # libkburn add_subdirectory(src/kburn) diff --git a/LICENSE b/LICENSE index 5bbf7a1..a2418ce 100644 --- a/LICENSE +++ b/LICENSE @@ -1 +1,25 @@ -TDB \ No newline at end of file +Copyright (c) 2022, Canaan Bright Sight Co., Ltd + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md index 8928b64..e656815 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,6 @@ -# K230 Flash Python +# K230 Flash -## Requirements - -```bash -sudo apt install gcc python3-venv pybind11-dev - -# create virtual env, only first time -python3 -m vevn ~/.venv - -# active virtual env, every time -source ~/.venv/bin/activate - -pip3 install pybind11 wheel setuptools -``` - -## Build - -```bash -# active virtual env, every time -source ~/.venv/bin/activate - -python3 setup.py bdist_wheel -``` +K230 Flash is a python tools to program Kendryte K230 and K230D Chips, Supports program firmware to `EMMC`, `SDCARD`, `SPI-NOR`, `SPI-NAND` and `OTP` ## Usage diff --git a/pyproject.toml b/pyproject.toml index 1d3cffe..95f5689 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", - "License :: OSI Approved :: MIT License", + "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Topic :: Utilities", ] @@ -25,7 +25,7 @@ keywords = ["kendryte", "kflash", "k230"] dependencies = [] [project.urls] -homepage = "https://github.com/kendryte747/k230_flash_py" +homepage = "https://github.com/kendryte/k230_flash" [project.scripts] k230_flash = "kburn.k230_flash:main" @@ -35,17 +35,22 @@ requires = ["setuptools>=42", "wheel", "cmake>=3.18", "pybind11"] build-backend = "setuptools.build_meta" [tool.cibuildwheel] -build = ["cp38*", "cp39*", "cp310*", "cp311*", "cp312*", "cp313"] +build = ["cp38*", "cp39*", "cp310*", "cp311*", "cp312*", "cp313*"] skip = "*musllinux*" +test-requires = "pytest" +test-command = [ + "pytest {project}/tests/import" +] [tool.cibuildwheel.windows] -archs = ["AMD64", "x86"] +archs = ["AMD64"] [tool.cibuildwheel.linux] archs = ["x86_64"] before-all = [ "yum install -y libudev-devel", ] +repair-wheel-command = "LD_LIBRARY_PATH=/lib/kburn auditwheel repair -w {dest_dir} {wheel}" [tool.cibuildwheel.macos] archs = ["x86_64"] diff --git a/setup.py b/setup.py index 1919e72..9276e51 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ +import io import os import re import subprocess @@ -30,6 +31,10 @@ def run(self): self.build_cmake(ext) super().run() + def is_in_cibuildwheel(self): + # maybe other env + return ('AUDITWHEEL_PLAT' in os.environ) + def build_cmake(self, ext: Extension): """The steps required to build the extension""" self.announce("Preparing the build environment", level=3) @@ -47,8 +52,10 @@ def build_cmake(self, ext: Extension): except OSError as e: print("Error: %s - %s." % (e.filename, e.strerror)) - cmake_args = [f"-DVERSION_INFO={self.distribution.get_version()}"] + cmake_args = [] + # cmake_args += [f"-DVERSION_INFO={self.distribution.get_version()}"] cmake_args += ['-DPython3_ROOT_DIR=' + os.path.dirname(sys.executable)] + cmake_args += ['-DIS_CIBUILDWHEEL=' + ('ON' if self.is_in_cibuildwheel() else "OFF")] cfg = 'Debug' if self.debug else 'Release' build_args = ['--config', cfg] cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg] @@ -106,9 +113,22 @@ def run(self): """Outfiles are the libraries that were built using cmake""" self.outfiles = self.distribution.data_files +def find_version(): + with io.open("CMakeLists.txt", encoding="utf8") as f: + version_file = f.read() + + version_major = re.findall(r"K230_FLASH_VERSION_MAJOR (.+?)", version_file) + version_minor = re.findall(r"K230_FLASH_VERSION_MINOR (.+?)", version_file) + version_patch = re.findall(r"K230_FLASH_VERSION_PATCH (.+?)", version_file) + + if version_major and version_minor and version_patch: + return version_major[0] + "." + version_minor[0] + "." + version_patch[0] + + raise RuntimeError("Unable to find version string.") + setup( name="k230_flash", - version="0.0.1", + version=find_version(), author="kendryte747", author_email="kendryte747@gmail.com", description="K230 Burning Tool", @@ -118,8 +138,8 @@ def run(self): ext_modules=[CMakeExtension("_kburn")], cmdclass={ 'build_ext': BuildCMakeExt, + 'install_lib': InstallCMakeLibs, 'install_data': InstallCMakeLibsData, - 'install_lib': InstallCMakeLibs }, entry_points={ 'console_scripts': [ diff --git a/src/kburn/CMakeLists.txt b/src/kburn/CMakeLists.txt index 97ceb74..ac06a1d 100644 --- a/src/kburn/CMakeLists.txt +++ b/src/kburn/CMakeLists.txt @@ -1,5 +1,30 @@ cmake_minimum_required(VERSION 3.18) +function(load_binary target variable src) + file(RELATIVE_PATH rel_path "${CMAKE_CURRENT_LIST_DIR}" "${src}") + set(tgt "${CMAKE_CURRENT_BINARY_DIR}/${rel_path}.generate.c") + set(tgt_hdr "${CMAKE_CURRENT_BINARY_DIR}/autogen/generated.${variable}.h") + + if("${src}" IS_NEWER_THAN "${tgt}") + file(READ "${src}" content HEX) + file(SIZE "${src}" size) + + string(REGEX REPLACE "[0-9a-f][0-9a-f]" "0x\\0," content_rep "${content}") + + file( + WRITE "${tgt}" + "#include \n#include \nconst char ${variable}[${size}] = {\n${content_rep}\n};\nconst size_t ${variable}_size = ${size};" + ) + file( + WRITE "${tgt_hdr}" + "#include \n#include \nextern const char ${variable}[${size}];\nextern const size_t ${variable}_size;" + ) + endif() + + target_include_directories("${target}" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/autogen") + target_sources("${target}" PRIVATE "${tgt}") +endfunction() + if(DEFINED ENV{CI}) set(IS_CI TRUE) else() @@ -12,11 +37,11 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE ) -if(NOT DEFINED VERSION_INFO) - set(VERSION_INFO "0.0.1") +if(NOT DEFINED K230_FLASH_VERSION_STRING) + set(K230_FLASH_VERSION_STRING "0.0.1") endif() -project(libkburn VERSION ${VERSION_INFO}) +project(libkburn VERSION ${K230_FLASH_VERSION_STRING}) set(COMPILE_TIME $DATE) string(TIMESTAMP COMPILE_TIME_STRING "%Y-%m-%d %H:%M") @@ -24,24 +49,6 @@ configure_file("${CMAKE_CURRENT_LIST_DIR}/include/version_info.h.in" "${CMAKE_CU add_library(kburn SHARED) -set_target_properties(kburn PROPERTIES - LANGUAGE CXX - LINKER_LANGUAGE CXX - PREFIX lib # to be consistent with mainline libusb build system(s) - INSTALL_RPATH "\$ORIGIN" - BUILD_WITH_INSTALL_RPATH TRUE -) - -if(APPLE) - target_link_options(kburn PRIVATE - "-Wl,-rpath,@loader_path" - "-Wl,-rpath,@executable_path" - ) -else() - target_link_options(kburn PRIVATE - "-Wl,-rpath,.") -endif() - file(GLOB K230_SRCS "burner_k230/*.cpp") set(SRCS @@ -53,43 +60,46 @@ target_sources(kburn PRIVATE ${SRCS}) target_include_directories(kburn PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(kburn PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/autogen) +load_binary(kburn "k230_loader_mmc" "${CMAKE_CURRENT_LIST_DIR}/burner_k230/loader/loader_mmc.bin") +load_binary(kburn "k230_loader_spi_nand" "${CMAKE_CURRENT_LIST_DIR}/burner_k230/loader/loader_spi_nand.bin") +load_binary(kburn "k230_loader_spi_nor" "${CMAKE_CURRENT_LIST_DIR}/burner_k230/loader/loader_spi_nor.bin") + target_compile_definitions(kburn PRIVATE $<$:IS_DEBUG=1> $<$:IS_DEBUG=0> ) -function(load_binary target variable src) - file(RELATIVE_PATH rel_path "${CMAKE_CURRENT_LIST_DIR}" "${src}") - set(tgt "${CMAKE_CURRENT_BINARY_DIR}/${rel_path}.generate.c") - set(tgt_hdr "${CMAKE_CURRENT_BINARY_DIR}/autogen/generated.${variable}.h") - - if("${src}" IS_NEWER_THAN "${tgt}") - file(READ "${src}" content HEX) - file(SIZE "${src}" size) - - string(REGEX REPLACE "[0-9a-f][0-9a-f]" "0x\\0," content_rep "${content}") - - file( - WRITE "${tgt}" - "#include \n#include \nconst char ${variable}[${size}] = {\n${content_rep}\n};\nconst size_t ${variable}_size = ${size};" - ) - file( - WRITE "${tgt_hdr}" - "#include \n#include \nextern const char ${variable}[${size}];\nextern const size_t ${variable}_size;" - ) - endif() +set_target_properties(kburn PROPERTIES + LANGUAGE CXX + LINKER_LANGUAGE CXX + PREFIX lib +) - target_include_directories("${target}" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/autogen") - target_sources("${target}" PRIVATE "${tgt}") -endfunction() +if(APPLE) + # macOS-specific rpath settings + target_link_options(kburn PRIVATE + "-Wl,-rpath,@loader_path" + "-Wl,-rpath,@loader_path/../lib" + "-Wl,-rpath,@executable_path" + ) +elseif(UNIX AND NOT APPLE) + # Linux-specific rpath settings + target_link_options(kburn PRIVATE + "-Wl,-rpath,$ORIGIN" + ) +elseif(WIN32) -load_binary(kburn "k230_loader_mmc" "${CMAKE_CURRENT_LIST_DIR}/burner_k230/loader/loader_mmc.bin") -load_binary(kburn "k230_loader_spi_nand" "${CMAKE_CURRENT_LIST_DIR}/burner_k230/loader/loader_spi_nand.bin") -load_binary(kburn "k230_loader_spi_nor" "${CMAKE_CURRENT_LIST_DIR}/burner_k230/loader/loader_spi_nor.bin") +endif() +# Set RPATH for installed binaries (common for macOS and Linux) +if(NOT WIN32) + set_target_properties(kburn PROPERTIES + INSTALL_RPATH "$ORIGIN" + BUILD_WITH_INSTALL_RPATH TRUE + ) +endif() ####################################### spdlog ################################ -# spdlog should before libusb, becase we don't want compile spdlog shared set(SPDLOG_BUILD_PIC ON) if(APPLE) @@ -112,4 +122,11 @@ target_link_libraries(kburn PUBLIC usb-1.0) # Add k230_flash_cli project add_subdirectory(cli) -install(TARGETS kburn usb-1.0) +if(LINUX AND IS_CIBUILDWHEEL) + message("Build by CIBUILDWHEEL") + + install(TARGETS kburn usb-1.0 + DESTINATION /lib/kburn) +else() + install(TARGETS kburn usb-1.0) +endif() diff --git a/src/kburn/cli/CMakeLists.txt b/src/kburn/cli/CMakeLists.txt index 80f25ee..0db2753 100644 --- a/src/kburn/cli/CMakeLists.txt +++ b/src/kburn/cli/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.4...3.18) -project(k230_flash VERSION ${VERSION_INFO}) +project(k230_flash) add_executable(${PROJECT_NAME} k230_flash.cpp) diff --git a/src/python/kburn/native/CMakeLists.txt b/src/python/kburn/native/CMakeLists.txt index 0dc8386..8d30e38 100644 --- a/src/python/kburn/native/CMakeLists.txt +++ b/src/python/kburn/native/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required(VERSION 3.18) -project(kburn_python VERSION ${VERSION_INFO}) +project(kburn_python) + +set(PACKAGE_VERSION ${NCNN_VERSION_STRING}) +add_definitions(-DVERSION_INFO="${PACKAGE_VERSION}") find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED) @@ -17,25 +20,37 @@ find_package(pybind11 REQUIRED PATHS ${PYBIND11_DIR} NO_DEFAULT_PATH) pybind11_add_module(kburn_python ffi.cpp) add_dependencies(kburn_python kburn) -target_link_libraries(kburn_python PUBLIC kburn) +target_link_libraries(kburn_python PRIVATE kburn) set_target_properties(kburn_python PROPERTIES CXX_STANDARD 17 OUTPUT_NAME _kburn - INSTALL_RPATH "\$ORIGIN" - BUILD_WITH_INSTALL_RPATH TRUE ) if(APPLE) + # macOS-specific rpath settings target_link_options(kburn_python PRIVATE "-Wl,-rpath,@loader_path" + "-Wl,-rpath,@loader_path/../lib" "-Wl,-rpath,@executable_path" ) -else() +elseif(UNIX AND NOT APPLE) + # Linux-specific rpath settings target_link_options(kburn_python PRIVATE - "-Wl,-rpath,." + "-Wl,-rpath,$ORIGIN" + ) +elseif(WIN32) + +endif() + +# Set RPATH for installed binaries (common for macOS and Linux) +if(NOT WIN32) + set_target_properties(kburn_python PROPERTIES + INSTALL_RPATH "$ORIGIN" + BUILD_WITH_INSTALL_RPATH TRUE ) endif() install(TARGETS kburn_python - DESTINATION lib) + DESTINATION lib +) diff --git a/tests/import/__init__.py b/tests/import/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/import/test_import.py b/tests/import/test_import.py new file mode 100644 index 0000000..6b28509 --- /dev/null +++ b/tests/import/test_import.py @@ -0,0 +1,26 @@ +# Copyright 2019-2021 Canaan Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# pylint: disable=invalid-name, unused-argument, import-outside-toplevel + +import pytest +import sys + +def test_import_kburn(): + try: + import kburn + except ImportError: + pytest.fail("Could not import 'kburn'") + +if __name__ == "__main__": + pytest.main(['-vv'] + sys.argv)