已合并
[ci]支持创建LLM .whl包 #45
gengli8创建于 2025年12月25日
[ci]支持创建LLM .whl包 #45
已合并
gengli8创建于 2025年12月25日
32 个文件变更+396-192
@@ -52,7 +52,6 @@ function fn_build()
52 if [ "$build_type" = "release" ]; then52 if [ "$build_type" = "release" ]; then
53 fn_extract_debug_symbols $OUTPUT_DIR "$CODE_ROOT/llm_debug_symbols"53 fn_extract_debug_symbols $OUTPUT_DIR "$CODE_ROOT/llm_debug_symbols"
54 fi54 fi
55- fn_make_whl
56 fn_build_for_ci55 fn_build_for_ci
57 cp $SCRIPT_DIR/set_env.sh $OUTPUT_DIR56 cp $SCRIPT_DIR/set_env.sh $OUTPUT_DIR
58}57}
The file is empty
The file is empty
The file is empty
The file is empty
The file is empty
@@ -0,0 +1,95 @@
1+#!/usr/bin/env python3
2+# Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
3+# MindIE is licensed under Mulan PSL v2.
4+# You can use this software according to the terms and conditions of the Mulan PSL v2.
5+# You may obtain a copy of Mulan PSL v2 at:
6+# http://license.coscl.org.cn/MulanPSL2
7+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
8+# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9+# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10+# See the Mulan PSL v2 for more details.
11+ 
12+import os
13+import sys
14+import sysconfig
15+import importlib.util
16+from pathlib import Path
17+from mindie_llm.utils.log.logging import logger
18+ 
19+ 
20+def _get_pkg_dir(pkg_name: str) -> Path:
21+ spec = importlib.util.find_spec(pkg_name)
22+ if spec is None or spec.origin is None:
23+ raise ImportError(f"{pkg_name} is not installed")
24+ return Path(spec.origin).resolve().parent
25+ 
26+ 
27+def _prepend_ld_library_path(env: dict, paths: list[Path]) -> None:
28+ """Prepend existing directories to LD_LIBRARY_PATH, warn if missing."""
29+ valid_paths = []
30+ 
31+ for p in paths:
32+ if p.is_dir():
33+ valid_paths.append(str(p))
34+ else:
35+ logger.warning(f"LD_LIBRARY_PATH entry does not exist, skipped: {p}")
36+ 
37+ if not valid_paths:
38+ return
39+ 
40+ old = env.get("LD_LIBRARY_PATH", "")
41+ env["LD_LIBRARY_PATH"] = ":".join(([old] if old else []) + valid_paths)
42+ 
43+ 
44+def main():
45+ pkg_root = Path(__file__).resolve().parents[1]
46+ 
47+ daemon_path = pkg_root / "bin" / "mindieservice_daemon"
48+ if not daemon_path.is_file():
49+ raise RuntimeError(f"mindieservice_daemon not found at {daemon_path}")
50+ 
51+ # Set configure file permission to meet safety requirement
52+ config_path = pkg_root / "conf" / "config.json"
53+ if not config_path.is_file():
54+ raise RuntimeError(f"config.json not found at {config_path}")
55+ 
56+ # Set environment variables
57+ env = os.environ.copy()
58+ env["MIES_INSTALL_PATH"] = str(pkg_root)
59+ 
60+ lib_str = "lib"
61+ lib_dir = pkg_root / lib_str
62+ if not lib_dir.is_dir():
63+ raise RuntimeError(f"Lib directory not found at {lib_dir}")
64+ 
65+ # torch
66+ torch_dir = _get_pkg_dir("torch")
67+ torch_lib = torch_dir / lib_str
68+ torch_libs = torch_dir.parent / "torch.libs" # torch.libs is a sibling of torch/
69+ 
70+ # atb_llm
71+ atb_llm_dir = _get_pkg_dir("atb_llm")
72+ atb_llm_lib = atb_llm_dir / lib_str
73+ 
74+ _prepend_ld_library_path(
75+ env,
76+ [
77+ torch_lib,
78+ torch_libs,
79+ atb_llm_lib,
80+ lib_dir,
81+ lib_dir / "grpc",
82+ ],
83+ )
84+ 
85+ env["PYTHONPATH"] = f"{lib_dir}:{env.get('PYTHONPATH', '')}"
86+ 
87+ os.execve(
88+ str(daemon_path),
89+ [str(daemon_path)] + sys.argv[1:],
90+ env,
91+ )
92+ 
93+ 
94+if __name__ == "__main__":
95+ main()
@@ -10,6 +10,6 @@
10# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.10# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11# See the Mulan PSL v2 for more details.11# See the Mulan PSL v2 for more details.
12 12 
13-from .base import MemPool13+__all__ = ["MemPool"]
14 14 
15-__all__ = ["MemPool"]15+from .base import MemPool
Rsrc/server/tokenizer/mies_tokenizer/__init__.pymindie_llm/tokenizer/__init__.py+2-2
@@ -10,6 +10,6 @@
10# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.10# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11# See the Mulan PSL v2 for more details.11# See the Mulan PSL v2 for more details.
12 12 
13-from .tokenizer import IbisTokenizer13+__all__ = ["IbisTokenizer"]
14 14 
15-__all__ = ["IbisTokenizer"]15+from .tokenizer import IbisTokenizer
Rsrc/server/tokenizer/mies_tokenizer/file_utils.pymindie_llm/tokenizer/file_utils.py+0-0
文件重命名但无更改。
Rsrc/server/tokenizer/mies_tokenizer/io_utils.pymindie_llm/tokenizer/io_utils.py+0-0
文件重命名但无更改。
Rsrc/server/tokenizer/mies_tokenizer/tokenizer.pymindie_llm/tokenizer/tokenizer.py+0-0
文件重命名但无更改。
@@ -15,7 +15,7 @@ if(NOT EXISTS "${PROTO_SRCS}" OR "${PROTO_FILE}" IS_NEWER_THAN "${PROTO_SRCS}")
15 RESULT_VARIABLE CPP_GENERATE_RESULT15 RESULT_VARIABLE CPP_GENERATE_RESULT
16 ERROR_VARIABLE CPP_GENERATE_ERROR16 ERROR_VARIABLE CPP_GENERATE_ERROR
17 )17 )
18- 18+ 
19 # 检查 C++ 生成结果19 # 检查 C++ 生成结果
20 if(NOT CPP_GENERATE_RESULT EQUAL 0)20 if(NOT CPP_GENERATE_RESULT EQUAL 0)
21 message(FATAL_ERROR "Failed to generate C++ files: ${CPP_GENERATE_ERROR}")21 message(FATAL_ERROR "Failed to generate C++ files: ${CPP_GENERATE_ERROR}")
@@ -23,7 +23,7 @@ if(NOT EXISTS "${PROTO_SRCS}" OR "${PROTO_FILE}" IS_NEWER_THAN "${PROTO_SRCS}")
23else()23else()
24 message(STATUS "No need to convert. ${PROTO_SRCS} is up to date.")24 message(STATUS "No need to convert. ${PROTO_SRCS} is up to date.")
25endif()25endif()
26- 26+ 
27add_library(mindie_protobuf STATIC ${PROTO_SRCS} ${PROTO_HDRS})27add_library(mindie_protobuf STATIC ${PROTO_SRCS} ${PROTO_HDRS})
28 28 
29set_target_properties(mindie_protobuf PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")29set_target_properties(mindie_protobuf PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")
@@ -48,7 +48,7 @@ if(NOT EXISTS "${GRPC_DST_FILE}" OR "${PROTO_FILE}" IS_NEWER_THAN "${GRPC_DST_FI
48 RESULT_VARIABLE GRPC_GENERATE_RESULT48 RESULT_VARIABLE GRPC_GENERATE_RESULT
49 ERROR_VARIABLE GRPC_GENERATE_ERROR49 ERROR_VARIABLE GRPC_GENERATE_ERROR
50 )50 )
51- 51+ 
52 # 检查 gRPC 生成结果52 # 检查 gRPC 生成结果
53 if(NOT GRPC_GENERATE_RESULT EQUAL 0)53 if(NOT GRPC_GENERATE_RESULT EQUAL 0)
54 message(FATAL_ERROR "Failed to generate gRPC files: ${GRPC_GENERATE_ERROR}")54 message(FATAL_ERROR "Failed to generate gRPC files: ${GRPC_GENERATE_ERROR}")
@@ -69,3 +69,18 @@ target_link_libraries(mindie_grpc
69)69)
70set_target_properties(mindie_grpc PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")70set_target_properties(mindie_grpc PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")
71install(TARGETS mindie_grpc DESTINATION lib)71install(TARGETS mindie_grpc DESTINATION lib)
72+ 
73+set(PY_OUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../mindie_llm/connector/common)
74+set(GENERATED_PY ${PY_OUT_DIR}/model_execute_data_pb2.py)
75+if(NOT EXISTS "${GENERATED_PY}" OR "${PROTO_FILE}" IS_NEWER_THAN "${GENERATED_PY}")
76+ message(STATUS "Generate grpc header file to proto from model_execute_data.proto file...")
77+ execute_process(
78+ COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} -I ${PROTO_PATH}
79+ --experimental_allow_proto3_optional
80+ --python_out=${PY_OUT_DIR}
81+ --proto_path=${CMAKE_CURRENT_SOURCE_DIR}
82+ ${PROTO_FILE}
83+ RESULT_VARIABLE GRPC_GENERATE_RESULT
84+ ERROR_VARIABLE GRPC_GENERATE_ERROR
85+ )
86+endif()
@@ -1,5 +1,5 @@
1#!/bin/bash1#!/bin/bash
2cd $CODE_ROOT/src/kernels2cd $CODE_ROOT/src/kernels
3bash build.sh3bash build.sh
4-cp dist/mie_ops*.whl $OUTPUT_DIR4+pip install dist/mie_ops*.whl --force-reinstall --target $OUTPUT_DIR/lib
5cd -5cd -
@@ -1,27 +1,12 @@
1#!/bin/bash1#!/bin/bash
2function fn_build_version_info()2function fn_build_version_info()
3{3{
4- if [ ! -f "$CODE_ROOT"/../CI/config/version.ini ]; then4+ version=${MINDIE_LLM_VERSION_OVERRIDE:-1.0.0}
5- echo "version.ini is not existed,user default Version-config!"
6- PACKAGE_NAME='1.0.RC3'
7- MINDIEVERSION='1.0.RC3'
8- else
9- PACKAGE_NAME=$(cat $VERSION_INFO_FILE | grep "PackageName" | cut -d "=" -f 2)
10- MINDIEVERSION=$(cat $VERSION_INFO_FILE | grep "MindIEVersion" | cut -d " " -f 2)
11- fi
12- echo "PackageName: $PACKAGE_NAME"
13- echo "MindIEVersion: $MINDIEVERSION"
14- if [[ ! "${PACKAGE_NAME}" =~ ^[1-9]\.[0-9]\. ]]; then
15- echo "VERSION is invalid"
16- exit 1
17- fi
18-
19 branch=$(git symbolic-ref -q --short HEAD || git describe --tags --exact-match 2> /dev/null || echo $branch)5 branch=$(git symbolic-ref -q --short HEAD || git describe --tags --exact-match 2> /dev/null || echo $branch)
20 commit_id=$(git rev-parse HEAD)6 commit_id=$(git rev-parse HEAD)
21 touch $OUTPUT_DIR/version.info7 touch $OUTPUT_DIR/version.info
22 cat>$OUTPUT_DIR/version.info<<EOF8 cat>$OUTPUT_DIR/version.info<<EOF
23- MindIE-LLM : ${PACKAGE_NAME}9+ MindIE-LLM Version : ${version}
24- MindIE-LLM Version : ${MINDIEVERSION}
25 Platform : ${ARCH}10 Platform : ${ARCH}
26 branch : ${branch}11 branch : ${branch}
27 commit id : ${commit_id}12 commit id : ${commit_id}
@@ -45,7 +45,7 @@ function fn_make_run_package()
45 fi45 fi
46 46 
47 (47 (
48- cd "${src_dir}" 48+ cd "${src_dir}"
49 shopt -s nullglob49 shopt -s nullglob
50 for pattern in "${patterns[@]}"; do50 for pattern in "${patterns[@]}"; do
51 for file in ${pattern}; do51 for file in ${pattern}; do
@@ -99,38 +99,9 @@ function fn_make_debug_symbols_package() {
99 cd -99 cd -
100}100}
101 101 
102-function fn_make_whl() {
103- PACKAGE_NAME=$(echo $PACKAGE_NAME | sed -E 's/([0-9]+)\.([0-9]+)\.RC([0-9]+)\.([0-9]+)/\1.\2rc\3.post\4/')
104- PACKAGE_NAME=$(echo $PACKAGE_NAME | sed -s 's!.T!.alpha!')
105- echo "MindIELLMWHLVersion $PACKAGE_NAME"
106- echo "make mindie-llm whl package"
107- cd $CODE_ROOT
108- python3 setup.py --setup_cmd="bdist_wheel" --version=${PACKAGE_NAME}
109- cp dist/*.whl $OUTPUT_DIR
110- rm -rf dist mindie_llm.egg-info
111- cd -
112- if [ "$build_type" = "release" ]; then
113- cd $CODE_ROOT/tools
114- cp $OUTPUT_DIR/lib/llm_manager_python.so $CODE_ROOT/tools/llm_manager_python_api_demo
115- python3 setup.py --setup_cmd="bdist_wheel" --version=${PACKAGE_NAME}
116- cp dist/*.whl $OUTPUT_DIR
117- rm -rf dist llm_manager_python_api_demo.egg-info
118- cd -
119- fi
120- echo "start to build mies tokenizer wheel"
121- cd "$CODE_ROOT/src/server/tokenizer"
122- python3 setup_tokenizer.py bdist_wheel
123- cp -v dist/mies_tokenizer-*.whl $OUTPUT_DIR
124- rm -rf *.egg-info dist
125- cd -
126-}
127- 
128function fn_build_for_ci()102function fn_build_for_ci()
129{103{
130 cd $OUTPUT_DIR104 cd $OUTPUT_DIR
131 mkdir -p include105 mkdir -p include
132- if ! [ "$build_type" = "release" ]; then
133- cp -r $CODE_ROOT/mindie_llm .
134- fi
135 cp -r $CODE_ROOT/src/include/* ./include/106 cp -r $CODE_ROOT/src/include/* ./include/
136-}107+}
@@ -15,55 +15,61 @@
15 15 
16path="${BASH_SOURCE[0]}"16path="${BASH_SOURCE[0]}"
17 17 
18-if [[ -f "$path" ]] && [[ "$path" =~ set_env.sh ]];then18+mindie_llm_path=$(cd $(dirname $path); pwd)
19- mindie_llm_path=$(cd $(dirname $path); pwd)19+chmod u+w "${mindie_llm_path}"
20- chmod u+w "${mindie_llm_path}"20+rm -rf /dev/shm/* #对于共享内存小的测试场景,每次启动前都清一下
21- rm -rf /dev/shm/* #对于共享内存小的测试场景,每次启动前都清一下21+export MINDIE_LLM_HOME_PATH="${mindie_llm_path}"
22- export MINDIE_LLM_HOME_PATH="${mindie_llm_path}"
23 22 
24- export MINDIE_LLM_RECOMPUTE_THRESHOLD=0.523+export MINDIE_LLM_RECOMPUTE_THRESHOLD=0.5
25- export PYTORCH_INSTALL_PATH="$(python3 -c 'import torch, os; print(os.path.dirname(os.path.abspath(torch.__file__)))')"24+export PYTORCH_INSTALL_PATH="$(python3 -c 'import torch, os; print(os.path.dirname(os.path.abspath(torch.__file__)))')"
26- if [ -n "$PYTORCH_INSTALL_PATH" ]; then25+if [ -n "$PYTORCH_INSTALL_PATH" ]; then
27- export LD_LIBRARY_PATH="$PYTORCH_INSTALL_PATH/lib:$PYTORCH_INSTALL_PATH/../torch.libs:$LD_LIBRARY_PATH"26+ export LD_LIBRARY_PATH="$PYTORCH_INSTALL_PATH/lib:$PYTORCH_INSTALL_PATH/../torch.libs:$LD_LIBRARY_PATH"
28- fi
29- export LD_LIBRARY_PATH=$(find "$MINDIE_LLM_HOME_PATH/lib" -type d | tr '\n' ':' | sed 's/:$//'):${LD_LIBRARY_PATH}
30- export PYTHONPATH=$MINDIE_LLM_HOME_PATH:$PYTHONPATH
31- export PYTHONPATH=$MINDIE_LLM_HOME_PATH/lib:$PYTHONPATH
32- 
33- export MINDIE_LOG_LEVEL=INFO
34- export MINDIE_LOG_TO_STDOUT=0
35- export MINDIE_LOG_TO_FILE=1
36- export GRPC_POLL_STRATEGY=poll
37- if [[ -z "$1" ]]; then
38- MINDIE_LLM_BACKEND=("atb" "pt" "ms")
39- else
40- if [[ "$1" == "--backend="* ]]; then
41- MINDIE_LLM_BACKEND="${1#*=}"
42- else
43- echo "Usage: source set_env.sh --backend=<backend>"
44- fi
45- fi
46- 
47- for backend_opt in "${MINDIE_LLM_BACKEND[@]}"; do
48- case "$backend_opt" in
49- atb)
50- ATB_SET_ENV_PATH=$MINDIE_LLM_HOME_PATH/../examples/atb_models/output/atb_models/set_env.sh
51- if [ ! -f "$ATB_SET_ENV_PATH" ]; then
52- ATB_SET_ENV_PATH=ATBMODELSETENV
53- fi
54- if [ -f "$ATB_SET_ENV_PATH" ]; then
55- source $ATB_SET_ENV_PATH
56- fi
57- ;;
58- pt)
59- ;;
60- ms)
61- ;;
62- *)
63- echo "Inner Error: unknown option'$backend_opt'"
64- ;;
65- esac
66- done
67-else
68- echo "There is no 'set_env.sh' to import"
69fi27fi
28+export LD_LIBRARY_PATH=$(find "$MINDIE_LLM_HOME_PATH/lib" -type d | tr '\n' ':' | sed 's/:$//'):${LD_LIBRARY_PATH}
29+export PYTHONPATH=$MINDIE_LLM_HOME_PATH:$PYTHONPATH
30+export PYTHONPATH=$MINDIE_LLM_HOME_PATH/lib:$PYTHONPATH
31+ 
32+export MINDIE_LOG_LEVEL=INFO
33+export MINDIE_LOG_TO_STDOUT=0
34+export MINDIE_LOG_TO_FILE=1
35+export GRPC_POLL_STRATEGY=poll
36+ 
37+export ATB_OPERATION_EXECUTE_ASYNC=1
38+export TASK_QUEUE_ENABLE=1
39+export HCCL_BUFFSIZE=120
40+ 
41+# Plog日志
42+export ASCEND_SLOG_PRINT_TO_STDOUT=0
43+export ASCEND_GLOBAL_LOG_LEVEL=3
44+export ASCEND_GLOBAL_EVENT_ENABLE=0
45+ 
46+if [[ -z "$1" ]]; then
47+ MINDIE_LLM_BACKEND=("atb" "pt" "ms")
48+else
49+ if [[ "$1" == "--backend="* ]]; then
50+ MINDIE_LLM_BACKEND="${1#*=}"
51+ else
52+ echo "Usage: source set_env.sh --backend=<backend>"
53+ fi
54+fi
55+ 
56+for backend_opt in "${MINDIE_LLM_BACKEND[@]}"; do
57+ case "$backend_opt" in
58+ atb)
59+ ATB_SET_ENV_PATH=$MINDIE_LLM_HOME_PATH/../examples/atb_models/output/atb_models/set_env.sh
60+ if [ ! -f "$ATB_SET_ENV_PATH" ]; then
61+ ATB_SET_ENV_PATH=ATBMODELSETENV
62+ fi
63+ if [ -f "$ATB_SET_ENV_PATH" ]; then
64+ source $ATB_SET_ENV_PATH
65+ fi
66+ ;;
67+ pt)
68+ ;;
69+ ms)
70+ ;;
71+ *)
72+ echo "Inner Error: unknown option'$backend_opt'"
73+ ;;
74+ esac
75+done
Msetup.py+101-43
@@ -1,6 +1,6 @@
1#!/usr/bin/env python1#!/usr/bin/env python
2# coding=utf-82# coding=utf-8
3-# Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved.3+# Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
4# MindIE is licensed under Mulan PSL v2.4# MindIE is licensed under Mulan PSL v2.
5# You can use this software according to the terms and conditions of the Mulan PSL v2.5# You can use this software according to the terms and conditions of the Mulan PSL v2.
6# You may obtain a copy of Mulan PSL v2 at:6# You may obtain a copy of Mulan PSL v2 at:
@@ -10,69 +10,127 @@
10# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.10# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11# See the Mulan PSL v2 for more details.11# See the Mulan PSL v2 for more details.
12 12 
13-import argparse
14import os13import os
15-import sys
16import subprocess14import subprocess
17-from setuptools import setup15+import logging
18-from setuptools.command.build_py import build_py16+import shutil
17+from pathlib import Path
18+from setuptools.command.build_py import build_py as _build_py
19+from setuptools import setup, find_packages
20+from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
21+import torch
19 22 
20-os.environ["SOURCE_DATE_EPOCH"] = "0"23+logging.basicConfig(level=logging.INFO)
21- 24+# SOURCE_DATE_EPOCH is used to make builds deterministic (reproducible).
22-parser = argparse.ArgumentParser(description="MindIE LLM Setup Parameters")25+os.environ["SOURCE_DATE_EPOCH"] = "315532800" # 315532800 means 1980-01-01 00:00:00 UTC
23-parser.add_argument("--setup_cmd", type=str, default="bdist_wheel")
24-parser.add_argument("--version", type=str, default="1.0.RC3")
25- 
26-args = parser.parse_args()
27-sys.argv = [sys.argv[0], args.setup_cmd]
28-mindie_llm_version = args.version
29 26 
30 27 
31-# 定义.proto文件路径(假设在项目根目录的protos/文件夹下)28+def get_version() -> str:
32-class BuildPyCommand(build_py):29+ """
30+ Return version string.
31+ 
32+ Priority:
33+ 1. Environment variable MINDIE_LLM_VERSION_OVERRIDE
34+ 2. Default version
35+ """
36+ version = os.getenv("MINDIE_LLM_VERSION_OVERRIDE", "1.0.0")
37+ logging.info(f"Use mindie llm version: {version}")
38+ return version
39+ 
40+ 
41+def use_cxx11_abi() -> str:
42+ """
43+ Return whether to use CXX11 ABI as a string ("0" or "1").
44+ """
45+ try:
46+ abi = torch.compiled_with_cxx11_abi()
47+ abi_str = str(int(bool(abi)))
48+ logging.info(f"Detect ABI from torch, set USE_CXX11_ABI to {abi_str}")
49+ return abi_str
50+ except Exception as e:
51+ logging.warning("Detect ABI from torch failed.")
52+ raise RuntimeError("Detect ABI from torch failed.") from e
53+ 
54+ 
55+class CustomBuildPy(_build_py):
33 def run(self):56 def run(self):
34- # 获取当前环境变量57+ logging.info(">>> Running build.sh to compile shared libraries...")
35- env = os.environ.copy()58+ 
36- # 添加protoc所需的动态库路径到LD_LIBRARY_PATH59+ project_root = Path(__file__).resolve().parent
37- protobuf_lib_path = os.path.abspath("./third_party/output/protobuf/lib")60+ build_dir = project_root
38- absl_lib_path = os.path.abspath("./third_party/output/abseil-cpp/lib")61+ subprocess.run(
39- if 'LD_LIBRARY_PATH' in env:62+ ["/bin/bash", "build.sh", f"--use_cxx11_abi={use_cxx11_abi()}"],
40- env['LD_LIBRARY_PATH'] = f"{protobuf_lib_path}:{absl_lib_path}:{env['LD_LIBRARY_PATH']}"63+ cwd=str(build_dir),
41- else:64+ check=True,
42- env['LD_LIBRARY_PATH'] = f"{protobuf_lib_path}:{absl_lib_path}"65+ shell=False
43- subprocess.run([66+ )
44- "./third_party/output/protobuf/bin/protoc", # 使用相对路径调用protoc67+ 
45- "--experimental_allow_proto3_optional",68+ build_pkg = Path(self.build_lib) / "mindie_llm"
46- "--python_out=./mindie_llm/connector/common/",69+ 
47- "--proto_path=./proto/",70+ shutil.copytree("output", build_pkg, dirs_exist_ok=True)
48- "model_execute_data.proto"71+ shutil.copytree("src/server/scripts", build_pkg / "scripts",
49- ], env=env, check=True)72+ dirs_exist_ok=True, ignore=shutil.ignore_patterns("set_env.sh"))
73+ self.copy_third_party()
50 74 
51- # 继续执行默认的build_py逻辑
52 super().run()75 super().run()
53 76 
77+ def copy_third_party(self):
78+ project_root = Path(__file__).resolve().parent
79+ build_pkg = Path(self.build_lib) / "mindie_llm"
80+ lib_dir = build_pkg / "lib"
81+ 
82+ lib_mappings = {
83+ "abseil-cpp": lib_dir,
84+ "boost": lib_dir,
85+ "cares": lib_dir,
86+ "grpc": lib_dir / "grpc",
87+ "libboundscheck": lib_dir,
88+ "openssl": lib_dir,
89+ "prometheus-cpp": lib_dir,
90+ "protobuf": lib_dir,
91+ "re2": lib_dir,
92+ "zlib": lib_dir,
93+ }
94+ 
95+ for lib_name, target_dir in lib_mappings.items():
96+ src_dir = project_root / "third_party" / "output" / lib_name / "lib"
97+ if not src_dir.exists():
98+ logging.warning(f"No such directory when copy it, skip: {src_dir}")
99+ return
100+ 
101+ target_dir.mkdir(parents=True, exist_ok=True)
102+ for item in src_dir.iterdir():
103+ if not item.is_file():
104+ continue
105+ dst_path = target_dir / item.name
106+ shutil.copy2(item, dst_path)
107+ 
108+ 
109+class BDistWheel(_bdist_wheel):
110+ def finalize_options(self):
111+ super().finalize_options()
112+ self.root_is_pure = False
113+ 
54 114 
55setup(115setup(
56 name="mindie_llm",116 name="mindie_llm",
57- version=mindie_llm_version,117+ version=get_version(),
58 author="",118 author="",
59 author_email="",119 author_email="",
60 description="MindIE LLM Project",120 description="MindIE LLM Project",
61 long_description="",121 long_description="",
62- package_dir={'mindie_llm': 'mindie_llm'},
63 install_requires=[],122 install_requires=[],
64- package_data={
65- '': ['*.xlsx', '*.h5', '*.csv', '*.so', '*.avsc', '*.xml', '*.pkl', '*.sql', '*.ini']
66- },
67 zip_safe=False,123 zip_safe=False,
68 python_requires=">=3.10",124 python_requires=">=3.10",
69- cmdclass={125+ packages=find_packages(),
70- "build_py": BuildPyCommand,
71- },
72- include_package_data=True,
73 entry_points={126 entry_points={
74 "console_scripts": [127 "console_scripts": [
75- 'mindie_llm_backend = mindie_llm.connector.main:main'128+ "mindie_llm_server = mindie_llm.server.main:main",
129+ "mindie_llm_backend = mindie_llm.connector.main:main"
76 ]130 ]
131+ },
132+ cmdclass={
133+ "build_py": CustomBuildPy,
134+ "bdist_wheel": BDistWheel
77 }135 }
78)136)
@@ -10,7 +10,7 @@ include_directories(
10 ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/include/mindie_llm10 ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/include/mindie_llm
11 ${THIRD_PARTY_OUTPUT_DIR}/nlohmann/include11 ${THIRD_PARTY_OUTPUT_DIR}/nlohmann/include
12)12)
13- 13+ 
14execute_process(14execute_process(
15 COMMAND bash -c "python3 -m pybind11 --cmakedir"15 COMMAND bash -c "python3 -m pybind11 --cmakedir"
16 OUTPUT_VARIABLE command_output16 OUTPUT_VARIABLE command_output
@@ -70,3 +70,10 @@ add_subdirectory(daemon)
70 70 
71# Add security compile options71# Add security compile options
72include(options.cmake)72include(options.cmake)
73+ 
74+# Install config file
75+install(
76+ FILES ${CMAKE_CURRENT_SOURCE_DIR}/conf/config.json
77+ DESTINATION conf
78+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ
79+)
@@ -23,12 +23,12 @@ if(NOT EXISTS "${DST_FILE_ONE}" OR "${PROTO_FILE}" IS_NEWER_THAN "${DST_FILE_ONE
23 RESULT_VARIABLE GRPC_GENERATE_RESULT23 RESULT_VARIABLE GRPC_GENERATE_RESULT
24 ERROR_VARIABLE GRPC_GENERATE_ERROR24 ERROR_VARIABLE GRPC_GENERATE_ERROR
25 )25 )
26- 26+ 
27 # 检查 gRPC 生成结果27 # 检查 gRPC 生成结果
28 if(NOT GRPC_GENERATE_RESULT EQUAL 0)28 if(NOT GRPC_GENERATE_RESULT EQUAL 0)
29 message(FATAL_ERROR "Failed to generate gRPC files: ${GRPC_GENERATE_ERROR}")29 message(FATAL_ERROR "Failed to generate gRPC files: ${GRPC_GENERATE_ERROR}")
30 endif()30 endif()
31- 31+ 
32 # 生成 C++ 文件32 # 生成 C++ 文件
33 execute_process(33 execute_process(
34 COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} -I ${DMI_PROTO_DIR} --cpp_out=${PROTO_INSTALL_DIR}34 COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} -I ${DMI_PROTO_DIR} --cpp_out=${PROTO_INSTALL_DIR}
@@ -36,7 +36,7 @@ if(NOT EXISTS "${DST_FILE_ONE}" OR "${PROTO_FILE}" IS_NEWER_THAN "${DST_FILE_ONE
36 RESULT_VARIABLE CPP_GENERATE_RESULT36 RESULT_VARIABLE CPP_GENERATE_RESULT
37 ERROR_VARIABLE CPP_GENERATE_ERROR37 ERROR_VARIABLE CPP_GENERATE_ERROR
38 )38 )
39- 39+ 
40 # 检查 C++ 生成结果40 # 检查 C++ 生成结果
41 if(NOT CPP_GENERATE_RESULT EQUAL 0)41 if(NOT CPP_GENERATE_RESULT EQUAL 0)
42 message(FATAL_ERROR "Failed to generate C++ files: ${CPP_GENERATE_ERROR}")42 message(FATAL_ERROR "Failed to generate C++ files: ${CPP_GENERATE_ERROR}")
@@ -64,11 +64,11 @@ include_directories(
64 ${CMAKE_CURRENT_SOURCE_DIR}/health_checker64 ${CMAKE_CURRENT_SOURCE_DIR}/health_checker
65)65)
66 66 
67-if(DEFINED ENV{MINDIE_VERSION})67+if(DEFINED ENV{MINDIE_LLM_VERSION_OVERRIDE})
68- set(MINDIE_VERSION $ENV{MINDIE_VERSION})68+ set(MINDIE_VERSION $ENV{MINDIE_LLM_VERSION_OVERRIDE})
69- add_definitions(-DMINDIE_VERSION="${MINDIE_VERSION}")69+ add_definitions(-DMINDIE_VERSION="${MINDIE_LLM_VERSION_OVERRIDE}")
70else()70else()
71- message(WARNING "Environment MINDIE_VERSION is not set")71+ message(WARNING "Environment MINDIE_LLM_VERSION_OVERRIDE is not set")
72endif()72endif()
73 73 
74# 编译endpoint的proto文件74# 编译endpoint的proto文件
@@ -964,7 +964,7 @@ bool TokenizerProcessPool::InitSubProcessMemory(const std::shared_ptr<ShareToken
964bool TokenizerProcessPool::InitSubProcessTokenizer(std::shared_ptr<InferTokenizer> &tokenizer)964bool TokenizerProcessPool::InitSubProcessTokenizer(std::shared_ptr<InferTokenizer> &tokenizer)
965{965{
966 try {966 try {
967- pybind11::module module = pybind11::module_::import("mies_tokenizer");967+ pybind11::module module = pybind11::module_::import("mindie_llm.tokenizer");
968 if (!pybind11::hasattr(module, "IbisTokenizer")) {968 if (!pybind11::hasattr(module, "IbisTokenizer")) {
969 return false;969 return false;
970 }970 }
@@ -1,24 +0,0 @@
1-#!/usr/bin/env python
2-# coding=utf-8
3-# Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
4-# MindIE is licensed under Mulan PSL v2.
5-# You can use this software according to the terms and conditions of the Mulan PSL v2.
6-# You may obtain a copy of Mulan PSL v2 at:
7-# http://license.coscl.org.cn/MulanPSL2
8-# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9-# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10-# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11-# See the Mulan PSL v2 for more details.
12- 
13-import os
14-from setuptools import setup
15- 
16- 
17-os.environ['SOURCE_DATE_EPOCH'] = '0'
18-setup(
19- name='mies_tokenizer',
20- version='0.0.1',
21- description='ibis tokenizer',
22- packages=['mies_tokenizer'],
23- python_requires=">=3.10",
24-)
@@ -149,10 +149,14 @@ namespace SimpleLLMInference {
149 std::string py = GetCwd() + "/tokenizer.py";149 std::string py = GetCwd() + "/tokenizer.py";
150 ::unlink(py.c_str());150 ::unlink(py.c_str());
151 }151 }
152- std::string pkgDir = GetCwd() + "/mies_tokenizer";152+ std::string pkgDir = GetCwd() + "/mindie_llm/tokenizer";
153 std::string initPy = pkgDir + "/__init__.py";153 std::string initPy = pkgDir + "/__init__.py";
154 ::unlink(initPy.c_str());154 ::unlink(initPy.c_str());
155 ::rmdir(pkgDir.c_str());155 ::rmdir(pkgDir.c_str());
156+ pkgDir = GetCwd() + "/mindie_llm";
157+ initPy = pkgDir + "/__init__.py";
158+ ::unlink(initPy.c_str());
159+ ::rmdir(pkgDir.c_str());
156 }160 }
157 161 
158 static void KillChildrenAndWait()162 static void KillChildrenAndWait()
@@ -372,7 +376,10 @@ class IbisTokenizerDeleteRaise(IbisTokenizer):
372 376 
373 // b) mies_tokenizer(子进程)377 // b) mies_tokenizer(子进程)
374 {378 {
375- std::string pkgDir = GetCwd() + "/mies_tokenizer";379+ std::string pkgDir = GetCwd() + "/mindie_llm";
380+ ::mkdir(pkgDir.c_str(), 0755);
381+ std::ofstream(pkgDir + "/__init__.py").close();
382+ pkgDir = pkgDir + "/tokenizer";
376 ::mkdir(pkgDir.c_str(), 0755);383 ::mkdir(pkgDir.c_str(), 0755);
377 std::ofstream ofs(pkgDir + "/__init__.py", std::ios::out | std::ios::trunc);384 std::ofstream ofs(pkgDir + "/__init__.py", std::ios::out | std::ios::trunc);
378 ofs << R"(385 ofs << R"(
@@ -795,7 +802,7 @@ class IbisTokenizer:
795 {802 {
796 auto &pool = TokenizerProcessPool::GetInstance();803 auto &pool = TokenizerProcessPool::GetInstance();
797 804 
798- auto mies = pybind11::module_::import("mies_tokenizer");805+ auto mies = pybind11::module_::import("mindie_llm.tokenizer");
799 ASSERT_TRUE(pybind11::hasattr(mies, "IbisTokenizer"));806 ASSERT_TRUE(pybind11::hasattr(mies, "IbisTokenizer"));
800 807 
801 std::shared_ptr<InferTokenizer> tk;808 std::shared_ptr<InferTokenizer> tk;
@@ -807,7 +814,7 @@ class IbisTokenizer:
807 TEST_F(InferenceTokenizerTest, InitSubProcessTokenizer_NoClass_ReturnsFalse)814 TEST_F(InferenceTokenizerTest, InitSubProcessTokenizer_NoClass_ReturnsFalse)
808 {815 {
809 auto &pool = TokenizerProcessPool::GetInstance();816 auto &pool = TokenizerProcessPool::GetInstance();
810- auto mies = pybind11::module_::import("mies_tokenizer");817+ auto mies = pybind11::module_::import("mindie_llm.tokenizer");
811 818 
812 bool had = pybind11::hasattr(mies, "IbisTokenizer");819 bool had = pybind11::hasattr(mies, "IbisTokenizer");
813 pybind11::object backup;820 pybind11::object backup;
@@ -825,7 +832,7 @@ class IbisTokenizer:
825 TEST_F(InferenceTokenizerTest, InitSubProcessTokenizer_MissingMethods_ReturnsFalse)832 TEST_F(InferenceTokenizerTest, InitSubProcessTokenizer_MissingMethods_ReturnsFalse)
826 {833 {
827 auto &pool = TokenizerProcessPool::GetInstance();834 auto &pool = TokenizerProcessPool::GetInstance();
828- auto mies = pybind11::module_::import("mies_tokenizer");835+ auto mies = pybind11::module_::import("mindie_llm.tokenizer");
829 836 
830 ASSERT_TRUE(pybind11::hasattr(mies, "IbisTokenizer"));837 ASSERT_TRUE(pybind11::hasattr(mies, "IbisTokenizer"));
831 pybind11::object backup = mies.attr("IbisTokenizer");838 pybind11::object backup = mies.attr("IbisTokenizer");
@@ -847,7 +854,7 @@ class IbisTokenizer:
847 TEST_F(InferenceTokenizerTest, InitSubProcessTokenizer_CtorRaises_ReturnsFalse)854 TEST_F(InferenceTokenizerTest, InitSubProcessTokenizer_CtorRaises_ReturnsFalse)
848 {855 {
849 auto &pool = TokenizerProcessPool::GetInstance();856 auto &pool = TokenizerProcessPool::GetInstance();
850- auto mies = pybind11::module_::import("mies_tokenizer");857+ auto mies = pybind11::module_::import("mindie_llm.tokenizer");
851 858 
852 ASSERT_TRUE(pybind11::hasattr(mies, "IbisTokenizer"));859 ASSERT_TRUE(pybind11::hasattr(mies, "IbisTokenizer"));
853 pybind11::object backup = mies.attr("IbisTokenizer");860 pybind11::object backup = mies.attr("IbisTokenizer");
@@ -873,7 +880,7 @@ class IbisTokenizer:
873 MOCKER_CPP(&ConfigManager::GetConfigJsonStr, std::string (*)())880 MOCKER_CPP(&ConfigManager::GetConfigJsonStr, std::string (*)())
874 .stubs().will(MOCKCPP_NS::invoke(&Ret_MissingKeysConfigJson_Value));881 .stubs().will(MOCKCPP_NS::invoke(&Ret_MissingKeysConfigJson_Value));
875 882 
876- auto mies = pybind11::module_::import("mies_tokenizer");883+ auto mies = pybind11::module_::import("mindie_llm.tokenizer");
877 ASSERT_TRUE(pybind11::hasattr(mies, "IbisTokenizer"));884 ASSERT_TRUE(pybind11::hasattr(mies, "IbisTokenizer"));
878 885 
879 std::shared_ptr<InferTokenizer> tk;886 std::shared_ptr<InferTokenizer> tk;
@@ -893,7 +900,7 @@ class IbisTokenizer:
893 MOCKER_CPP(&ConfigManager::GetConfigJsonStr, std::string (*)())900 MOCKER_CPP(&ConfigManager::GetConfigJsonStr, std::string (*)())
894 .stubs().will(MOCKCPP_NS::invoke(&Ret_InvalidConfigJson_Value));901 .stubs().will(MOCKCPP_NS::invoke(&Ret_InvalidConfigJson_Value));
895 902 
896- auto mies = pybind11::module_::import("mies_tokenizer");903+ auto mies = pybind11::module_::import("mindie_llm.tokenizer");
897 ASSERT_TRUE(pybind11::hasattr(mies, "IbisTokenizer"));904 ASSERT_TRUE(pybind11::hasattr(mies, "IbisTokenizer"));
898 905 
899 std::shared_ptr<InferTokenizer> tk;906 std::shared_ptr<InferTokenizer> tk;
@@ -0,0 +1,85 @@
1+import os
2+import sys
3+import unittest
4+from unittest import mock
5+from pathlib import Path
6+ 
7+from mindie_llm.server.main import main
8+ 
9+ 
10+class TestServerMain(unittest.TestCase):
11+ 
12+ @mock.patch("mindie_llm.server.main._get_pkg_dir")
13+ @mock.patch("mindie_llm.server.main.os.execve")
14+ @mock.patch("mindie_llm.server.main.Path.is_dir")
15+ @mock.patch("mindie_llm.server.main.Path.is_file")
16+ @mock.patch("mindie_llm.server.main.os.environ", new_callable=dict)
17+ def test_main_success_no_args(
18+ self,
19+ mock_environ,
20+ mock_is_file,
21+ mock_is_dir,
22+ mock_execve,
23+ mock_get_pkg_dir,
24+ ):
25+ # daemon + config.json exist
26+ mock_is_file.side_effect = [True, True]
27+ mock_is_dir.return_value = True
28+ 
29+ # Fake package locations
30+ fake_site = Path("/fake/site-packages")
31+ mock_get_pkg_dir.side_effect = [
32+ fake_site / "torch", # torch
33+ fake_site / "atb_llm", # atb_llm
34+ ]
35+ 
36+ mock_environ.update({
37+ "LD_LIBRARY_PATH": "/old/ld",
38+ "PYTHONPATH": "/old/python",
39+ })
40+ 
41+ with mock.patch.object(sys, "argv", ["mindie_llm_server"]):
42+ main()
43+ 
44+ mock_execve.assert_called_once()
45+ exec_path, exec_argv, exec_env = mock_execve.call_args[0]
46+ 
47+ pkg_root = Path(__file__).resolve().parents[4] / "mindie_llm"
48+ daemon_path = pkg_root / "bin" / "mindieservice_daemon"
49+ lib_dir = pkg_root / "lib"
50+ 
51+ self.assertEqual(exec_path, str(daemon_path))
52+ self.assertEqual(exec_argv, [str(daemon_path)])
53+ 
54+ # env checks
55+ self.assertEqual(exec_env["MIES_INSTALL_PATH"], str(pkg_root))
56+ self.assertIn(str(lib_dir), exec_env["LD_LIBRARY_PATH"])
57+ self.assertIn("grpc", exec_env["LD_LIBRARY_PATH"])
58+ self.assertIn(str(lib_dir), exec_env["PYTHONPATH"])
59+ 
60+ @mock.patch("mindie_llm.server.main._get_pkg_dir")
61+ @mock.patch("mindie_llm.server.main.Path.is_file")
62+ def test_daemon_missing_raises(self, mock_is_file, mock_get_pkg_dir):
63+ mock_is_file.return_value = False
64+ 
65+ with self.assertRaises(RuntimeError) as ctx:
66+ main()
67+ 
68+ self.assertIn("mindieservice_daemon not found", str(ctx.exception))
69+ 
70+ @mock.patch("mindie_llm.server.main._get_pkg_dir")
71+ @mock.patch("mindie_llm.server.main.Path.is_file")
72+ @mock.patch("mindie_llm.server.main.Path.is_dir")
73+ def test_lib_dir_missing_raises(
74+ self,
75+ mock_is_dir,
76+ mock_is_file,
77+ mock_get_pkg_dir,
78+ ):
79+ mock_is_file.side_effect = [True, True]
80+ mock_is_dir.return_value = False
81+ 
82+ with self.assertRaises(RuntimeError) as ctx:
83+ main()
84+ 
85+ self.assertIn("Lib directory not found", str(ctx.exception))
@@ -141,7 +141,7 @@ function fn_run_pythontest()
141 grep -o '<class name="[^"]*" filename="[^"]*" complexity="[^"]*" line-rate="[^"]*" branch-rate="[^"]*">' coverage.xml |141 grep -o '<class name="[^"]*" filename="[^"]*" complexity="[^"]*" line-rate="[^"]*" branch-rate="[^"]*">' coverage.xml |
142 while read -r line; do142 while read -r line; do
143 filename=$(echo "$line" | awk -F '"' '{print $4}')143 filename=$(echo "$line" | awk -F '"' '{print $4}')
144- if [[ ! "$line" =~ .*block_copy.* && ! "$line" =~ .*examples/run_generator.* && ! "$line" =~ .*examples/scheduler.* && ! "$line" =~ .*cache_manager.* && ! "$line" =~ .*utils/config.* && ! "$line" =~ .*__init__.* && ! "$line" =~ .*utils/log/logging.* && ! "$line" =~ .*mf_model_wrapper.* && ! "$line" =~ .*generator_ms.* && ! "$line" =~ .*plugin_manager_edge.* && ! "$line" =~ .*runtime.* && ! "$line" =~ .*aclgraph.* ]]; then144+ if [[ ! "$line" =~ .*block_copy.* && ! "$line" =~ .*examples/run_generator.* && ! "$line" =~ .*examples/scheduler.* && ! "$line" =~ .*cache_manager.* && ! "$line" =~ .*utils/config.* && ! "$line" =~ .*__init__.* && ! "$line" =~ .*utils/log/logging.* && ! "$line" =~ .*mf_model_wrapper.* && ! "$line" =~ .*generator_ms.* && ! "$line" =~ .*plugin_manager_edge.* && ! "$line" =~ .*runtime.* && ! "$line" =~ .*aclgraph.* && ! "$line" =~ tokenizer/.*py ]]; then
145 echo "$line" | awk -F '"' '{print "mindie_llm/" $4, $8*100 "%", $10*100 "%"}' >> result.txt145 echo "$line" | awk -F '"' '{print "mindie_llm/" $4, $8*100 "%", $10*100 "%"}' >> result.txt
146 fi146 fi
147 done147 done