diff --git a/docs/doc/zh/source_code/add_c_module.md b/docs/doc/zh/source_code/add_c_module.md index 5139b127..3155b7df 100644 --- a/docs/doc/zh/source_code/add_c_module.md +++ b/docs/doc/zh/source_code/add_c_module.md @@ -50,8 +50,9 @@ namespace maix::test * 首先[编译 MaixPy 源码](./build.md) 通过,保证我们的编译环境没问题。 * 复制一份 [MaixPy/tools/maix_module](https://github.com/sipeed/MaixPy/tree/main/tools/maix_module) 工程模板到一个新的目录,可以和`MaixPy`放在同一个目录。比如将所有文件和目录复制到了`maix_xxx` 目录下。 -* 在`maix_xxx`目录下,终端执行`python init_files.py`来初始化项目文件。 * 修改项目名:修改`module_name.txt` 文件,改成你要的模块名称,必须以`maix_`开头,这样方便其它用户能在 [pypi.org](https://pypi.org) 或者 [github.com](https://github.com) 搜索到你的项目。 +* 在`maix_xxx`目录下,终端执行`python init_files.py`来初始化项目文件。 +* 设置MaixCDK目录:`export MAIXCDK_PATH=/home/yourname/MaixCDK` * 和 MaixPy 一样执行`python setup.py bdist_wheel linux` 就可以开始为电脑构建。 * 构建完成后可以直接在项目根目录执行`python -c "import maix_xxx;maix_xxx.basic.print('Li Hua')"`就能运行你的模块函数了。 * 执行`python setup.py bdist_wheel maixcam` 就可以为`MaixCAM` 构建软件包了。需要注意的是,构建过程种的代码提示文件(pyi文件)只能在给`linux` 平台构建的时候生成,所以在正式发布的时候需要先执行上一步的`linux`平台构建生成代码提示文件,然后再执行本步的命令生成`MaixCAM`平台的软件包。 @@ -60,9 +61,19 @@ namespace maix::test * 当你调试好代码后,可以考虑将代码开源到[github.com](https://github.com),并且上传到[pypi.org](https://pypi.org)(具体上传方法可以看官方文档或者搜索教程,大概就是`pip install twine`然后 `twine upload dist/maix_xxx***.whl`就可以了。),写好后欢迎到[maixhub.com/share](https://maixhub.com/share)来分享告诉大家你的成果! 修改代码: -正如 [查看 MaixPy API 源码](../basic/view_src_code.md) 问种所描述的查看和修改源码的方式,在`components/maix/include` 和 `components/maix/src` 下增加源文件,增加 C++ 函数,并且填加注释,然后编译后就直接能调用了,非常简单。 -比如: - +正如 [查看 MaixPy API 源码](../basic/view_src_code.md) 问种所描述的查看和修改源码的方式,在`components/maix/include` 和 `components/maix/src` 下增加源文件,增加 C++ 函数,并且在对应的.hpp填加注释,然后编译后就直接能调用了,非常简单。(注意不要改main的文件) +比如, +cpp例子: +```cpp +namespace maix_xxx::test +{//直接在下面写对应的C++函数即可 + int add(int a, int b) + { + return a + b; + } +} // namespace maix_xxx +``` +.hpp头文件例子: ```cpp namespace maix_xxx::test { diff --git a/tools/maix_module/init_files.py b/tools/maix_module/init_files.py index 9ac1ed12..5a237089 100644 --- a/tools/maix_module/init_files.py +++ b/tools/maix_module/init_files.py @@ -1,58 +1,91 @@ import os +import sys -with open("module_name.txt", "r") as f: - module_name = f.readline().strip() +def main(): + # ===================== 1. Read and validate module name ===================== + try: + with open("module_name.txt", "r", encoding="utf-8") as f: + module_name = f.readline().strip() + except FileNotFoundError: + raise Exception("Error: module_name.txt file not found. Please create it first and fill in the module name (e.g., maix_kkk)") + except Exception as e: + raise Exception(f"Failed to read module_name.txt: {e}") -if not module_name.startswith("maix_"): - raise Exception("module name must starts with maix_") + # Validate module name must start with maix_ + if not module_name.startswith("maix_"): + raise Exception("Error: Module name must start with 'maix_' (e.g., maix_kkk)") + # Optional: Specify initial version number from command line (Example: python init_files.py 1.0.1) + init_version = sys.argv[1] if len(sys.argv) > 1 else "1.0.0" + try: + version_major, version_minor, version_patch = init_version.split(".") + # Verify version number is numeric + int(version_major), int(version_minor), int(version_patch) + except ValueError: + raise Exception(f"Error: Invalid version number format (Please use format like 1.0.0, current: {init_version})") -# Create test dir, and test_import.py -def write_test_dir(): - if os.path.exists("test/test_import.py"): - return - content = f"import {module_name}" - os.makedirs("test", exist_ok=True) - with open("test/test_import.py", "w", encoding="utf-8") as f: - f.write(content) -write_test_dir() + # ===================== 2. Generate test file (test/test_import.py) ===================== + def write_test_import_file(): + test_file = "test/test_import.py" + if os.path.exists(test_file): + print(f"Note: {test_file} already exists, skip generation") + return + try: + os.makedirs("test", exist_ok=True) + content = f"import {module_name}\nprint(f'Successfully imported module: {module_name}')" + with open(test_file, "w", encoding="utf-8") as f: + f.write(content) + print(f"Successfully generated: {test_file}") + except PermissionError: + raise Exception(f"Error: Insufficient permissions to create {test_file}") + except Exception as e: + raise Exception(f"Failed to generate test file: {e}") -# Create maix_xxx dir, write __init__.py and version.py -def write_module_dir(): - init_content = f'''from .version import __version__ -from ._maix_xxx import * + # ===================== 3. Generate core module files (__init__.py / version.py) ===================== + def write_module_dir(): + # Generate __init__.py content (Fix hardcoded extension module name) + init_content = f'''from .version import __version__ +from ._{module_name} import * ''' - version_content = '''# Versions should comply with PEP440: https://peps.python.org/pep-0440/ + # Generate version.py content (Dynamic version number) + version_content = f'''# Versions should comply with PEP440: https://peps.python.org/pep-0440/ -version_major = 1 -version_minor = 0 -version_patch = 0 +version_major = {version_major} +version_minor = {version_minor} +version_patch = {version_patch} -__version__ = "{}.{}.{}".format(version_major, version_minor, version_patch) +__version__ = "{version_major}.{version_minor}.{version_patch}" ''' - os.makedirs(module_name, exist_ok=True) - if not os.path.exists(f"{module_name}/__init__.py"): - with open(f"{module_name}/__init__.py", "w", encoding="utf-8") as f: - f.write(init_content) - if not os.path.exists(f"{module_name}/version.py"): - with open(f"{module_name}/version.py", "w", encoding="utf-8") as f: - f.write(version_content) -write_module_dir() + try: + # Create module directory + os.makedirs(module_name, exist_ok=True) + # Generate __init__.py + init_file = f"{module_name}/__init__.py" + if not os.path.exists(init_file): + with open(init_file, "w", encoding="utf-8") as f: + f.write(init_content) + print(f"Successfully generated: {init_file}") + else: + print(f"Note: {init_file} already exists, skip generation") -# Create compent dir and files -def write_component_dir(): - cpp_content = f'''#include "{module_name}.hpp" + # Generate version.py + version_file = f"{module_name}/version.py" + if not os.path.exists(version_file): + with open(version_file, "w", encoding="utf-8") as f: + f.write(version_content) + print(f"Successfully generated: {version_file}") + else: + print(f"Note: {version_file} already exists, skip generation") + except PermissionError: + raise Exception(f"Error: Insufficient permissions to create {module_name} directory/files") + except Exception as e: + raise Exception(f"Failed to generate core module files: {e}") -namespace {module_name}::basic -{{ - void hello(const std::string &name) - {{ - maix::log::info(("hello: " + name).c_str()); - }} -}} // namespace {module_name} -''' - hpp_content = f''' + # ===================== 4. Generate C++ extension module files (hpp/cpp) ===================== + def write_component_dir(): + # Generate .hpp header file content + hpp_content = f''' #include "maix_basic.hpp" namespace {module_name}::basic @@ -66,25 +99,116 @@ def write_component_dir(): }} // namespace {module_name} ''' - os.makedirs("components/maix/include", exist_ok=True) - os.makedirs("components/maix/src", exist_ok=True) - if not os.path.exists(f"components/maix/include/{module_name}.hpp"): - with open(f"components/maix/include/{module_name}.hpp", "w", encoding="utf-8") as f: - f.write(hpp_content) - if not os.path.exists(f"components/maix/src/{module_name}.cpp"): - with open(f"components/maix/src/{module_name}.cpp", "w", encoding="utf-8") as f: - f.write(cpp_content) -write_component_dir() - -# Create readme -def write_test_dir(): - if os.path.exists("README.md"): - return - content = f"MaixPy module {module_name}\n====\n\nTODO: Add readme\n" - with open("README.md", "w", encoding="utf-8") as f: - f.write(content) - content = f"MaixPy 模块 {module_name}\n====\n\nTODO: 增加 readme\n" - with open("README_ZH.md", "w", encoding="utf-8") as f: - f.write(content) -write_test_dir() + # Generate .cpp source file content + cpp_content = f'''#include "{module_name}.hpp" + +namespace {module_name}::basic +{{ + void hello(const std::string &name) + {{ + maix::log::info(("hello: " + name).c_str()); + }} +}} // namespace {module_name} +''' + try: + # Create directories + include_dir = "components/maix/include" + src_dir = "components/maix/src" + os.makedirs(include_dir, exist_ok=True) + os.makedirs(src_dir, exist_ok=True) + + # Generate .hpp file + hpp_file = f"{include_dir}/{module_name}.hpp" + if not os.path.exists(hpp_file): + with open(hpp_file, "w", encoding="utf-8") as f: + f.write(hpp_content) + print(f"Successfully generated: {hpp_file}") + else: + print(f"Note: {hpp_file} already exists, skip generation") + + # Generate .cpp file + cpp_file = f"{src_dir}/{module_name}.cpp" + if not os.path.exists(cpp_file): + with open(cpp_file, "w", encoding="utf-8") as f: + f.write(cpp_content) + print(f"Successfully generated: {cpp_file}") + else: + print(f"Note: {cpp_file} already exists, skip generation") + except PermissionError: + raise Exception("Error: Insufficient permissions to create components directory/files") + except Exception as e: + raise Exception(f"Failed to generate C++ extension files: {e}") + + # ===================== 5. Generate README documentation ===================== + def write_readme_files(): + # English README + readme_en = "README.md" + if not os.path.exists(readme_en): + en_content = f"""# MaixPy Module: {module_name} + +## Quick Start +1. Compile module: `python setup.py bdist_wheel maixcam` +2. Install module: `pip install dist/{module_name}*.whl` +3. Test import: `python test/test_import.py` + +## Development Guide +- Python module root: `{module_name}/` +- C++ source code: `components/maix/src/{module_name}.cpp` +- C++ header file: `components/maix/include/{module_name}.hpp` +- Version management: `{module_name}/version.py` + +## TODO +- Add detailed API documentation +- Add unit tests for core functions +""" + with open(readme_en, "w", encoding="utf-8") as f: + f.write(en_content) + print(f"Successfully generated: {readme_en}") + else: + print(f"Note: {readme_en} already exists, skip generation") + + # Chinese README (renamed to README_CN.md for consistency) + readme_cn = "README_CN.md" + if not os.path.exists(readme_cn): + cn_content = f"""# MaixPy Module: {module_name} + +## Quick Start +1. Compile module: `python setup.py bdist_wheel 'platform'` +2. Install module: `pip install dist/{module_name}*.whl` +3. Test import: `python test/test_import.py` + +## Development Guide +- Python module root directory: `{module_name}/` +- C++ source file: `components/maix/src/{module_name}.cpp` +- C++ header file: `components/maix/include/{module_name}.hpp` +- Version management file: `{module_name}/version.py` + +## TODO +- Add detailed API documentation +- Add unit tests for core functions +""" + with open(readme_cn, "w", encoding="utf-8") as f: + f.write(cn_content) + print(f"Successfully generated: {readme_cn}") + else: + print(f"Note: {readme_cn} already exists, skip generation") + + # ===================== Execute all generation logic ===================== + write_test_import_file() + write_module_dir() + write_component_dir() + write_readme_files() + + print(f"\n✅ Module project skeleton generation completed! Module name: {module_name}") + print(f"📌 Next steps:") + print(f" 1. Modify {module_name}/__init__.py to add custom interfaces") + print(f" 2. Improve components/maix/src/{module_name}.cpp to implement business logic") + print(f" 3. Execute python setup.py bdist_wheel 'platform' to compile the module") + print(f" 4. Modify whl package version: in {module_name}/version.py file") +if __name__ == "__main__": + try: + main() + except Exception as e: + print(f"\n❌ Generation failed: {e}") + sys.exit(1) \ No newline at end of file diff --git a/tools/maix_module/setup.py b/tools/maix_module/setup.py index 37d0f8bb..6115dfeb 100644 --- a/tools/maix_module/setup.py +++ b/tools/maix_module/setup.py @@ -3,6 +3,7 @@ import os import platform import shutil +import zipfile #################################################################### # supported platforms @@ -272,7 +273,7 @@ def has_ext_modules(foo): # os.rename(os.path.join("dist", name), os.path.join("dist", # "MaixPy-{}-{}-{}-{}.whl".format(__version__, py_tag, py_tag, platform_names[board])) # ) - if name.find("linux_riscv64") != -1: + if name.find("linux_riscv64") != -1 or name.find("manylinux2014_") != -1:# 增加linux平台判断,使linux平台和maixcam平台执行相同的whl打包逻辑 # pypi not support riscv64 yet, so we have to change to py3-none-any pkg # unzip to dist/temp, change dist-info/WHEEL file # zip back and rename @@ -294,5 +295,4 @@ def has_ext_modules(foo): shutil.rmtree("dist/temp") os.rename(os.path.join("dist", name), os.path.join("dist", "{}-{}-py3-none-any.whl".format(module_name, __version__)) - ) - + ) \ No newline at end of file