CMakeLists.txt 逐段解释
c
cmake_minimum_required(VERSION 3.10)
project(_raisim_gym_torch)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/bin)
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/bin)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/bin)
MACRO(SUBDIRLIST result curdir)
SET(dirlist "")
LIST(APPEND dirlist rsg_a1_task)
LIST(APPEND dirlist dagger_a1)
SET(${result} ${dirlist})
ENDMACRO()
####################
### dependencies ###
####################
set(Dependencies)
add_subdirectory(../thirdParty/pybind11 pybind11)
find_package(Eigen3 REQUIRED)
find_package(OpenMP REQUIRED)
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT WEBGL AND NOT WIN32)
set(RAISIM_OS linux)
list(APPEND CMAKE_PREFIX_PATH ../raisim/${RAISIM_OS})
elseif(APPLE)
set(RAISIM_OS mac)
list(APPEND CMAKE_PREFIX_PATH ../raisim/${RAISIM_OS})
list(APPEND Dependencies OpenMP::OpenMP_CXX)
elseif(WIN32)
set(RAISIM_OS win32)
list(APPEND CMAKE_PREFIX_PATH ../raisim/${RAISIM_OS}/mt_debug)
list(APPEND CMAKE_PREFIX_PATH ../thirdParty)
list(APPEND Dependencies Ws2_32)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/bin)
endif()
find_package(raisim CONFIG REQUIRED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
#######################
### src and linking ###
#######################
SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/envs)
set(RAISIMGYM_ENV_DIR ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/envs)
FOREACH(subdir ${SUBDIRS})
pybind11_add_module(${subdir} raisimGymTorch/env/raisim_gym.cpp raisimGymTorch/env/Yaml.cpp)
target_link_libraries(${subdir} PRIVATE raisim::raisim ${Dependencies})
target_include_directories(${subdir} PUBLIC ${EIGEN3_INCLUDE_DIRS} ${RAISIMGYM_ENV_DIR}/${subdir})
target_compile_options(${subdir} PRIVATE -mtune=native -fPIC -O3 -g -mno-avx2)
target_compile_definitions(${subdir} PRIVATE "-DRAISIMGYM_TORCH_ENV_NAME=${subdir}")
if (CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "Debug")
message("[RAISIM_GYM] BUILDING THE DEBUG APP for ${subdir}")
add_executable(${subdir}_debug_app raisimGymTorch/env/debug_app.cpp raisimGymTorch/env/Yaml.cpp)
target_link_libraries(${subdir}_debug_app PRIVATE raisim::raisim)
target_include_directories(${subdir}_debug_app PUBLIC raisimGymTorch/env/envs/${subdir} ${EIGEN3_INCLUDE_DIRS})
if(WIN32)
target_link_libraries(${subdir}_debug_app PRIVATE Ws2_32)
else()
target_compile_options(${subdir}_debug_app PRIVATE -mtune=native -fPIC -g -O0 -mno-avx2)
endif()
endif()
ENDFOREACH()
1. 基础设置
cmake
cmake_minimum_required(VERSION 3.10)
project(_raisim_gym_torch)
set(CMAKE_CXX_STANDARD 14)
项目名称为 _raisim_gym_torch,使用 C++14 标准。
2. 输出目录
cmake
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/raisimGymTorch/env/bin)
所有编译产物(.so、.a、可执行文件)统一输出到 raisimGymTorch/env/bin/。
3. 子目录列表宏
cmake
MACRO(SUBDIRLIST result curdir)
SET(dirlist "")
LIST(APPEND dirlist rsg_a1_task)
LIST(APPEND dirlist dagger_a1)
SET(${result} ${dirlist})
ENDMACRO()
定义了两个编译目标:rsg_a1_task(特权策略环境)和 dagger_a1(蒸馏环境)。每增加一个新任务环境,只需在这里加一行 LIST(APPEND ...)。
- 这是一个CMake宏(MACRO),名为
SUBDIRLIST - 它接受两个参数:
result和curdir - 函数内部:
- 创建一个空列表
dirlist - 向列表中添加两个元素:
rsg_a1_task和dagger_a1 - 将
dirlist的值赋给result参数指定的变量
- 创建一个空列表
这个宏的作用是返回一个包含两个子目录名称的列表:rsg_a1_task和dagger_a1。
虽然参数curdir被声明了,但在函数体内并没有使用它,这可能是一个设计上的疏忽或者是为了保持接口一致性而保留的。
详细解释:
| 代码行 | 功能说明 |
|---|---|
MACRO(SUBDIRLIST result curdir) |
定义宏,接受两个参数:result(输出变量名)和 curdir(当前目录,未使用) |
SET(dirlist "") |
初始化一个空列表 dirlist |
LIST(APPEND dirlist rsg_a1_task) |
向列表添加第一个子目录名:rsg_a1_task |
LIST(APPEND dirlist dagger_a1) |
向列表添加第二个子目录名:dagger_a1 |
SET(${result} ${dirlist}) |
将列表内容赋值给调用者指定的输出变量 |
ENDMACRO() |
宏定义结束 |
使用方式:
less
SUBDIRLIST(my_subdirs ${CMAKE_CURRENT_SOURCE_DIR})
# 执行后,my_subdirs 将包含:["rsg_a1_task", "dagger_a1"]
注意点:
- 参数
curdir在宏体内并未被使用,这可能是为了保持接口兼容性而保留的占位参数 - 返回的子目录列表是硬编码的,不依赖于实际的文件系统扫描
- 这是一个典型的 CMake 模块化技巧,用于集中管理需要处理的子项目列表
4. 依赖项
cmake
add_subdirectory(../thirdParty/pybind11 pybind11) # Python-C++ 桥接
find_package(Eigen3 REQUIRED) # 矩阵运算库
find_package(OpenMP REQUIRED) # CPU 并行
find_package(raisim CONFIG REQUIRED) # Raisim 物理引擎
假设 raisim 安装在 ../raisim/linux/ 下。Windows/Mac 走不同的路径分支。
5. 核心编译逻辑 --- 循环构建
cmake
FOREACH(subdir ${SUBDIRS}) # subdir = rsg_a1_task, dagger_a1
# ① pybind11 模块
pybind11_add_module(${subdir}
raisimGymTorch/env/raisim_gym.cpp # 绑定代码
raisimGymTorch/env/Yaml.cpp # YAML 解析
)
target_link_libraries(${subdir} PRIVATE raisim::raisim ${Dependencies})
target_include_directories(${subdir} PUBLIC
${EIGEN3_INCLUDE_DIRS}
${RAISIMGYM_ENV_DIR}/${subdir} # 各自的 Environment.hpp
)
target_compile_options(${subdir} PRIVATE -mtune=native -fPIC -O3 -g -mno-avx2)
target_compile_definitions(${subdir} PRIVATE
"-DRAISIMGYM_TORCH_ENV_NAME=${subdir}" # 关键宏!
)
ENDFOREACH()
关键设计 ------ 宏 RAISIMGYM_TORCH_ENV_NAME:
两个目标(rsg_a1_task 和 dagger_a1)编译同一份 raisim_gym.cpp,但通过不同的宏定义,产生不同的 pybind11 模块名:
cpp
// raisim_gym.cpp
#ifndef ENVIRONMENT_NAME
#define ENVIRONMENT_NAME RaisimGymEnv
#endif
PYBIND11_MODULE(RAISIMGYM_TORCH_ENV_NAME, m) {
// 模块名: rsg_a1_task 或 dagger_a1
py::class_<VectorizedEnvironment<ENVIRONMENT>>(m, RSG_MAKE_STR(ENVIRONMENT_NAME))
...
}
而 ENVIRONMENT 类本身来自各自子目录下的 Environment.hpp(通过 target_include_directories 区分)。
-mno-avx2 标志:禁用 AVX2 指令集。Raisim 的某些内部实现在 AVX2 上有兼容性问题(可能是数值精度差异),故显式禁用。
执行结果总结
运行 python setup.py develop(内部调用 cmake + make)后:
less
raisimGymTorch/env/bin/
├── rsg_a1_task.cpython-38-x86_64-linux-gnu.so ← 特权策略环境模块
├── dagger_a1.cpython-38-x86_64-linux-gnu.so ← 蒸馏策略环境模块
├── (Debug模式下还有 rsg_a1_task_debug_app, dagger_a1_debug_app)
| 产物 | 编译自 | 模块名 | Environment.hpp 来源 |
|---|---|---|---|
rsg_a1_task.so |
raisim_gym.cpp + Yaml.cpp + raisim |
rsg_a1_task |
envs/rsg_a1_task/ |
dagger_a1.so |
同一份 raisim_gym.cpp + Yaml.cpp + raisim |
dagger_a1 |
envs/dagger_a1/ |
Python 侧导入:
python
from raisimGymTorch.env.bin import rsg_a1_task # 加载 .so
from raisimGymTorch.env.bin import dagger_a1 # 加载 .so
# 使用
env = rsg_a1_task.RaisimGymEnv(resourceDir, cfg_yaml_string)
env = dagger_a1.RaisimGymEnv(resourceDir, cfg_yaml_string)
一句话总结 :CMakeLists.txt 通过一个循环 + 宏定义,用同一套 C++ 模板代码 (VectorizedEnvironment<ENVIRONMENT> + raisim_gym.cpp)编译出两个独立的 Python 扩展模块 ,分别加载不同的 Environment.hpp 头文件,对应两个训练阶段的不同观测空间和环境逻辑。