setup.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. # setup.py
  2. from setuptools import setup, Extension
  3. from Cython.Build import cythonize
  4. from Cython.Distutils import build_ext
  5. import os
  6. import sys
  7. from pathlib import Path
  8. import re
  9. # 获取当前目录
  10. current_dir = Path(__file__).parent
  11. COMPILED_DIR = current_dir / "build" / "compiled"
  12. # 定义要排除的文件
  13. EXCLUDE_FILES = {
  14. "app.py", # 不编译主应用文件
  15. "setup.py", # 不编译本文件
  16. "cythonize.py", # 不编译辅助脚本
  17. "check_deploy.py", # 不编译部署检查
  18. "terminal_demo.py", # 不编译终端演示文件
  19. }
  20. # 定义要排除的目录
  21. EXCLUDE_DIRS = {
  22. "build",
  23. "dist",
  24. "__pycache__",
  25. ".git",
  26. ".vscode",
  27. ".idea",
  28. "venv",
  29. "env",
  30. "node_modules",
  31. "chat_logs",
  32. "logs",
  33. "tests",
  34. "test",
  35. "cython_build", # Cython临时目录
  36. }
  37. def should_exclude_dir(dir_name):
  38. """判断是否应该排除目录"""
  39. return dir_name in EXCLUDE_DIRS or dir_name.startswith(".")
  40. def find_py_files(base_dir):
  41. """查找所有需要编译的Python文件"""
  42. py_files = []
  43. for root, dirs, files in os.walk(base_dir):
  44. # 排除不需要的目录
  45. dirs[:] = [d for d in dirs if not should_exclude_dir(d)]
  46. for file in files:
  47. if file.endswith(".py") and file not in EXCLUDE_FILES:
  48. full_path = os.path.join(root, file)
  49. # 排除build目录下的文件
  50. if "build" in full_path.split(os.sep):
  51. continue
  52. py_files.append(full_path)
  53. return py_files
  54. def create_extension_modules():
  55. """创建Cython扩展模块列表"""
  56. extensions = []
  57. py_files = find_py_files(current_dir)
  58. for py_file in py_files:
  59. # 转换为相对路径
  60. rel_path = os.path.relpath(py_file, current_dir)
  61. # 生成模块名(去掉.py)
  62. module_name = rel_path[:-3].replace(os.sep, ".")
  63. # 创建Extension
  64. extension = Extension(
  65. module_name,
  66. [py_file],
  67. extra_compile_args=[
  68. "/O2" if sys.platform == "win32" else "-O3",
  69. "/std:c++17" if sys.platform == "win32" else "-std=c++17",
  70. ],
  71. language="c",
  72. )
  73. extensions.append(extension)
  74. return extensions
  75. def main():
  76. """主编译函数"""
  77. print(f"编译目标目录: {COMPILED_DIR}")
  78. # 确保编译目录存在
  79. COMPILED_DIR.mkdir(parents=True, exist_ok=True)
  80. # 创建扩展模块
  81. extensions = create_extension_modules()
  82. if not extensions:
  83. print("❌ 未找到需要编译的Python文件")
  84. return
  85. print(f"找到 {len(extensions)} 个Python文件需要编译:")
  86. for i, ext in enumerate(extensions[:10], 1): # 只显示前10个
  87. print(f" {i:2}. {ext.name}")
  88. if len(extensions) > 10:
  89. print(f" ... 和 {len(extensions) - 10} 个其他文件")
  90. # 配置编译选项
  91. compiler_directives = {
  92. "language_level": 3,
  93. "boundscheck": False, # 关闭边界检查
  94. "wraparound": False, # 关闭环绕检查
  95. "initializedcheck": False, # 关闭初始化检查
  96. "nonecheck": False, # 关闭None检查
  97. "overflowcheck": False, # 关闭溢出检查
  98. "cdivision": True, # 使用C除法
  99. "infer_types": True, # 类型推断
  100. "optimize.use_switch": True, # 优化switch语句
  101. }
  102. # 编译
  103. cythonized = cythonize(
  104. extensions,
  105. compiler_directives=compiler_directives,
  106. nthreads=0, # 0表示自动使用所有核心
  107. build_dir="./cython_build", # 临时构建目录
  108. )
  109. # 修复:使用自定义BuildExt类
  110. class CustomBuildExt(build_ext):
  111. def initialize_options(self):
  112. super().initialize_options()
  113. # 设置输出目录
  114. self.build_lib = str(COMPILED_DIR)
  115. def get_ext_fullpath(self, ext_name):
  116. """获取扩展的完整路径,确保输出到指定目录"""
  117. # 首先调用父类方法
  118. filename = self.get_ext_filename(ext_name)
  119. # 确保输出到编译目录
  120. return os.path.join(self.build_lib, filename)
  121. # 修复:使用setuptools的setup,但通过cmdclass和options控制
  122. setup(
  123. name="LongjoeAgent",
  124. ext_modules=cythonized,
  125. cmdclass={"build_ext": CustomBuildExt},
  126. options={
  127. "build_ext": {
  128. "build_lib": str(COMPILED_DIR),
  129. "inplace": False, # 不在原地构建
  130. }
  131. },
  132. script_args=["build_ext"], # 只构建扩展
  133. )
  134. if __name__ == "__main__":
  135. main()