setup.py 4.5 KB

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