在命令行执行命令:python setup.py develop后,具体的执行过程分析
完整执行过程
这个命令做了两件事:编译 C++ 扩展+以开发模式安装 Python 包。核心自定义在于用 CMake 替代了 setuptools 默认的 C++ 编译流程。
阶段 1:解析可选参数
# 可选自定义参数(从 sys.argv 中提取后移除,避免干扰 setuptools)--CMAKE_PREFIX_PATH/path/to/raisim# 自定义 Raisim 安装路径--Debug# Debug 模式编译(默认 Release)正常用法不带这些参数,直接python setup.py develop。
阶段 2:setuptools 框架接管
setup(name='raisim_gym_torch',packages=find_packages(),# 自动发现 raisimGymTorch/ 包ext_modules=[CMakeExtension('_raisim_gym')],# 注册一个虚拟扩展cmdclass=dict(build_ext=CMakeBuild),# 用自定义 CMakeBuild 替换默认 build_extinstall_requires=['ruamel.yaml','numpy','torch','tensorboard'],)关键点:
CMakeExtension('_raisim_gym')— 这个扩展没有源码文件(sources=[]),它只是一个触发器,告诉 setuptools"有一个 C++ 扩展需要编译",但实际编译逻辑全在自定义的CMakeBuild中。cmdclass=dict(build_ext=CMakeBuild)— 将 setuptools 原生的build_ext命令替换为自定义类,由它来调用 CMake。
阶段 3:develop命令触发build_ext
develop是setuptools内置命令,执行流程为:
python setup.py develop │ ├── ① 运行 build_ext (被替换为 CMakeBuild) │ └── 见阶段 4 │ └── ② 安装 egg-link └── 见阶段 5阶段 4:CMakeBuild — 编译 C++ 扩展
4.1run()— 检查 CMake 可用性
defrun(self):subprocess.check_output(['cmake','--version'])# 确认 cmake 已安装forextinself.extensions:self.build_extension(ext)# 遍历每个扩展(这里只有1个)4.2build_extension()— 两步:cmake configure + cmake build
defbuild_extension(self,ext):# ext.name = '_raisim_gym'# ext.sourcedir = /home/bob/project/dog/rl_locomotion/ (setup.py 所在目录)# ① 确定输出目录extdir=os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))# extdir 通常为: .../raisimGymTorch/env/bin/Step 1 — CMake 配置:
cmake_args=['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY='+extdir,'-DPYTHON_EXECUTABLE='+sys.executable,]# Linux 下追加:cmake_args+=['-DCMAKE_BUILD_TYPE=Release']# 等效于执行:# cd build_temp/# cmake /home/bob/project/dog/rl_locomotion/ \# -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=.../raisimGymTorch/env/bin \# -DPYTHON_EXECUTABLE=/path/to/conda/envs/cms/bin/python \# -DCMAKE_BUILD_TYPE=Release这会执行 CMakeLists.txt,生成 Makefile。CMakeLists.txt 内部做的事情:
- 找到 pybind11(
../thirdParty/pybind11) - 找到 Eigen3、OpenMP
- 找到 Raisim(
../raisim/linux/) - 为
rsg_a1_task和dagger_a1两个目标各生成编译规则
Step 2 — CMake 编译:
build_args=['--config','Release','--','-j4']# 等效于执行:# cd build_temp/# cmake --build . --config Release -- -j4# ↑ ↑# 调用 make 传给 make: -j4 (4线程并行)这会编译出两个.so文件,输出到之前设好的CMAKE_LIBRARY_OUTPUT_DIRECTORY:
raisimGymTorch/env/bin/ ├── rsg_a1_task.cpython-38-x86_64-linux-gnu.so └── dagger_a1.cpython-38-x86_64-linux-gnu.so编译参数细节
env['CXXFLAGS']='... -DVERSION_INFO="0.0.0"'实际传递给编译器的 flag(来自 CMakeLists.txt 的target_compile_options):
-mtune=native # 针对本机 CPU 优化指令调度 -fPIC # 生成位置无关代码(.so 必需) -O3 # 最高级别优化 -g # 保留调试符号 -mno-avx2 # 禁用 AVX2(Raisim 兼容性)阶段 5:开发模式安装(egg-link)
编译成功后,develop命令执行setuptools的标准流程:
# 在 site-packages 下创建 egg-link 文件 # → 指向项目根目录,而不是复制文件 <conda_env>/lib/python3.8/site-packages/ └── raisim-gym-torch.egg-link # 内容: /path/to/raisimGymTorch/ # . (相对路径)这使得:
import raisimGymTorch直接从源码目录导入(修改 Python 代码后无需重新安装)raisimGymTorch/env/bin/下的.so也可以被直接 import- 注意:
.so不会自动重新编译——修改Environment.hpp后需要重新运行python setup.py develop
完整流程图
python setup.py develop │ ├─ 1. 解析可选参数 (--CMAKE_PREFIX_PATH, --Debug) │ ├─ 2. setuptools 解析 setup() 注册 │ packages = ['raisimGymTorch', 'raisimGymTorch.env', ...] │ ext_modules = [CMakeExtension('_raisim_gym')] │ cmdclass = {build_ext: CMakeBuild} │ ├─ 3. develop → build_ext → CMakeBuild.run() │ │ │ ├─ 3.1 检查 cmake --version │ │ │ └─ 3.2 build_extension(ext) │ │ │ ├─ mkdir build_temp/ │ │ │ ├─ cmake <sourcedir> ← CMake 配置 │ │ -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=.../env/bin │ │ -DCMAKE_BUILD_TYPE=Release │ │ │ │ │ └─ 解析 CMakeLists.txt │ │ ├─ add_subdirectory(pybind11) │ │ ├─ find_package(Eigen3, OpenMP, raisim) │ │ └─ foreach(subdir: rsg_a1_task, dagger_a1) │ │ pybind11_add_module(subdir, │ │ raisim_gym.cpp, │ │ Yaml.cpp) │ │ -DRAISIMGYM_TORCH_ENV_NAME=subdir │ │ include: envs/subdir/Environment.hpp │ │ │ └─ cmake --build . -- -j4 ← 编译 │ │ │ ├─ 编译 rsg_a1_task │ │ g++ raisim_gym.cpp + Yaml.cpp → rsg_a1_task.so │ │ include envs/rsg_a1_task/Environment.hpp │ │ link raisim, eigen, openmp │ │ │ └─ 编译 dagger_a1 │ g++ raisim_gym.cpp + Yaml.cpp → dagger_a1.so │ include envs/dagger_a1/Environment.hpp │ link raisim, eigen, openmp │ │ 产物: │ raisimGymTorch/env/bin/ │ ├── rsg_a1_task.cpython-38-x86_64-linux-gnu.so (pybind11 模块) │ └── dagger_a1.cpython-38-x86_64-linux-gnu.so (pybind11 模块) │ └─ 4. egg-link 安装 <site-packages>/raisim-gym-torch.egg-link → 指向项目根目录何时需要重新运行
| 修改内容 | 是否需要重新python setup.py develop |
|---|---|
Environment.hpp(C++ 环境逻辑) | 是 |
raisim_gym.cpp(绑定层) | 是 |
VectorizedEnvironment.hpp | 是 |
CMakeLists.txt | 是 |
Python 文件 (.py) | 否(egg-link 直接引用源码) |
cfg.yaml | 否 |