From d22eeda85b2f70f9c5784fd17a813bd47fe05c3b Mon Sep 17 00:00:00 2001 From: Piotr Majek Date: Wed, 19 Nov 2025 16:23:14 +0100 Subject: [PATCH 1/3] Fixed building PYBINDS. Added github workflow. --- .github/workflows/python-bindings-linux.yml | 60 +++++++++++++++++ .github/workflows/python-bindings-windows.yml | 66 +++++++++++++++++++ .gitignore | 5 ++ .../lidar_odometry_utils.h | 4 ++ apps/lidar_odometry_step_1/toml_io.cpp | 7 ++ pybind/CMakeLists.txt | 49 +++++++++++--- pybind/core_binding.cpp | 6 +- pybind/tls_registration_binding.cpp | 6 +- 8 files changed, 188 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/python-bindings-linux.yml create mode 100644 .github/workflows/python-bindings-windows.yml diff --git a/.github/workflows/python-bindings-linux.yml b/.github/workflows/python-bindings-linux.yml new file mode 100644 index 00000000..c198ce1f --- /dev/null +++ b/.github/workflows/python-bindings-linux.yml @@ -0,0 +1,60 @@ +name: Build Python Bindings on Linux + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + BUILD_TYPE: Release + +jobs: + build: + runs-on: ubuntu-22.04 + strategy: + matrix: + python-version: ["3.12"] + + steps: + - name: Load repository cache + run: sudo apt-get update --allow-releaseinfo-change + + - name: Install system libraries + run: sudo apt-get install -y --no-install-recommends libx11-dev libxi-dev libtbb-dev libegl1-mesa-dev libglu1-mesa-dev libopencv-dev + + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Display Python version + run: python --version + + - name: Install CMake 4.0 + run: | + wget -O cmake.sh https://github.com/Kitware/CMake/releases/download/v4.0.0/cmake-4.0.0-linux-x86_64.sh + sudo sh cmake.sh --skip-license --prefix=/usr/local + cmake --version + + - name: Configure CMake with Python bindings + run: | + cmake -B ${{github.workspace}}/build_pybind \ + -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ + -DPYBIND=ON + + - name: Build Python bindings + run: cmake --build ${{github.workspace}}/build_pybind --config ${{env.BUILD_TYPE}} + + - name: Test Python imports + working-directory: ${{github.workspace}}/pybind + run: | + python -c "import sys; sys.path.insert(0, '.'); import core_py; print('core_py imported successfully')" + python -c "import sys; sys.path.insert(0, '.'); import lidar_odometry_py; print('lidar_odometry_py imported successfully')" + python -c "import sys; sys.path.insert(0, '.'); import multi_view_tls_registration_py; print('multi_view_tls_registration_py imported successfully')" + + diff --git a/.github/workflows/python-bindings-windows.yml b/.github/workflows/python-bindings-windows.yml new file mode 100644 index 00000000..34df3f8b --- /dev/null +++ b/.github/workflows/python-bindings-windows.yml @@ -0,0 +1,66 @@ +name: Build Python Bindings on Windows + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + BUILD_TYPE: Release + +jobs: + build: + runs-on: windows-latest + strategy: + matrix: + python-version: ["3.12"] + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Display Python version + run: python --version + + - name: Install CMake 4.0 on Windows + run: | + choco install cmake --version=4.0.0 -y + refreshenv + cmake --version + shell: pwsh + + - name: Configure CMake with Python bindings + run: | + cmake -B ${{github.workspace}}/build_pybind ` + -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ` + -DPYBIND=ON ` + shell: pwsh + + - name: Build Python bindings + run: cmake --build ${{github.workspace}}/build_pybind --config ${{env.BUILD_TYPE}} + + - name: List pybind directory contents + run: | + echo "Contents of pybind directory:" + dir ${{github.workspace}}\pybind + if (Test-Path "${{github.workspace}}\pybind\${{env.BUILD_TYPE}}") { + echo "Contents of pybind\${{env.BUILD_TYPE}}:" + dir ${{github.workspace}}\pybind\${{env.BUILD_TYPE}} + } + shell: pwsh + + - name: Test Python imports + working-directory: ${{github.workspace}}/pybind/${{env.BUILD_TYPE}} + run: | + python -c "import sys; sys.path.insert(0, '.'); import core_py; print('core_py imported successfully')" + python -c "import sys; sys.path.insert(0, '.'); import lidar_odometry_py; print('lidar_odometry_py imported successfully')" + python -c "import sys; sys.path.insert(0, '.'); import multi_view_tls_registration_py; print('multi_view_tls_registration_py imported successfully')" + shell: pwsh + diff --git a/.gitignore b/.gitignore index bb696964..99eab728 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,8 @@ imgui.ini /out/install/x64-Release/bin /out/install/x64-Release /out_old/install + +#pybind +pybind/Release +pybind/Debug + diff --git a/apps/lidar_odometry_step_1/lidar_odometry_utils.h b/apps/lidar_odometry_step_1/lidar_odometry_utils.h index 81c0456f..f4f26d69 100644 --- a/apps/lidar_odometry_step_1/lidar_odometry_utils.h +++ b/apps/lidar_odometry_step_1/lidar_odometry_utils.h @@ -21,7 +21,9 @@ #include #include #include +#if WITH_GUI == 1 #include +#endif namespace fs = std::filesystem; @@ -134,7 +136,9 @@ struct LidarOdometryParams double total_length_of_calculated_trajectory = 0.0; NDTBucketMapType buckets_indoor; NDTBucketMapType buckets_outdoor; +#if WITH_GUI == 1 ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); +#endif bool use_removie_imu_bias_from_first_stationary_scan = false; diff --git a/apps/lidar_odometry_step_1/toml_io.cpp b/apps/lidar_odometry_step_1/toml_io.cpp index 867de64f..50be097c 100644 --- a/apps/lidar_odometry_step_1/toml_io.cpp +++ b/apps/lidar_odometry_step_1/toml_io.cpp @@ -13,12 +13,17 @@ bool TomlIO::SaveParametersToTomlFile(const std::string &filepath, LidarOdometry if (attribute == "in_out_params_indoor" || attribute == "in_out_params_outdoor") continue; +#if WITH_GUI == 1 if (attribute == "clear_color") { const ImVec4& c = params.clear_color; cat_tbl.insert(attribute, toml::array{ c.x, c.y, c.z, c.w }); continue; } +#else + if (attribute == "clear_color") + continue; // Skip GUI-only parameter when building without GUI +#endif // Check if it's a motion_model_correction parameter auto motion_it = MOTION_MODEL_CORRECTION_POINTERS.find(attribute); @@ -188,6 +193,7 @@ bool TomlIO::LoadParametersFromTomlFile(const std::string &filepath, LidarOdomet } }, it->second); } +#if WITH_GUI == 1 if (cat_tbl && cat_tbl->contains("clear_color")) { auto arr = cat_tbl->at("clear_color").as_array(); @@ -199,6 +205,7 @@ bool TomlIO::LoadParametersFromTomlFile(const std::string &filepath, LidarOdomet params.clear_color.w = static_cast(arr->at(3).as_floating_point()->get()); } } +#endif } read_grid_params(params.in_out_params_indoor, tbl["in_out_params_indoor"].as_table()); read_grid_params(params.in_out_params_outdoor, tbl["in_out_params_outdoor"].as_table()); diff --git a/pybind/CMakeLists.txt b/pybind/CMakeLists.txt index 451b10d6..5e1368c6 100644 --- a/pybind/CMakeLists.txt +++ b/pybind/CMakeLists.txt @@ -134,9 +134,15 @@ if(WIN32) set_target_properties(lidar_odometry_py PROPERTIES SUFFIX ".pyd") set_target_properties(multi_view_tls_registration_py PROPERTIES SUFFIX ".pyd") else() - set_target_properties(core_py PROPERTIES SUFFIX ".so") - set_target_properties(lidar_odometry_py PROPERTIES SUFFIX ".so") - set_target_properties(multi_view_tls_registration_py PROPERTIES SUFFIX ".so") + set_target_properties(core_py PROPERTIES + PREFIX "" + SUFFIX ".so") + set_target_properties(lidar_odometry_py PROPERTIES + PREFIX "" + SUFFIX ".so") + set_target_properties(multi_view_tls_registration_py PROPERTIES + PREFIX "" + SUFFIX ".so") endif() set_target_properties(core_py PROPERTIES @@ -154,13 +160,36 @@ set_target_properties(multi_view_tls_registration_py PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/pybind" ) -set(DLL_SOURCE_DIR "${CMAKE_BINARY_DIR}/bin/Release") -set(DLL_DEST_DIR "${CMAKE_SOURCE_DIR}/pybind/Release") - -file(GLOB DLL_FILES "${CMAKE_BINARY_DIR}/bin/Release/*.dll") -foreach(DLL ${DLL_FILES}) +# Copy DLLs on Windows for runtime dependencies +if(WIN32) + # Generate a config-specific script to copy only DLL files + file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/copy_dlls_$.cmake" + CONTENT " +file(GLOB DLL_FILES \"${CMAKE_BINARY_DIR}/bin/$/*.dll\") +file(MAKE_DIRECTORY \"${CMAKE_SOURCE_DIR}/pybind/$\") +foreach(DLL_FILE \${DLL_FILES}) + file(COPY \"\${DLL_FILE}\" DESTINATION \"${CMAKE_SOURCE_DIR}/pybind/$\") +endforeach() +message(STATUS \"Copied \${DLL_FILES} to ${CMAKE_SOURCE_DIR}/pybind/$\") +" + ) + + add_custom_command( + TARGET core_py POST_BUILD + COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/copy_dlls_$.cmake" + COMMENT "Copying DLLs to pybind/$" + ) + add_custom_command( TARGET lidar_odometry_py POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DLL} "${CMAKE_SOURCE_DIR}/pybind/Release" + COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/copy_dlls_$.cmake" + COMMENT "Copying DLLs to pybind/$" + ) + + add_custom_command( + TARGET multi_view_tls_registration_py POST_BUILD + COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/copy_dlls_$.cmake" + COMMENT "Copying DLLs to pybind/$" ) -endforeach() \ No newline at end of file +endif() \ No newline at end of file diff --git a/pybind/core_binding.cpp b/pybind/core_binding.cpp index e4e03f5b..8c99da1a 100644 --- a/pybind/core_binding.cpp +++ b/pybind/core_binding.cpp @@ -25,12 +25,14 @@ PYBIND11_MODULE(core_py, m) { // Bind WorkerData py::class_(m, "WorkerData") .def(py::init<>()) - .def_readwrite("intermediate_points", &WorkerData::intermediate_points) - .def_readwrite("original_points", &WorkerData::original_points) + .def_readwrite("intermediate_points_cache_file_name", &WorkerData::intermediate_points_cache_file_name) + .def_readwrite("original_points_cache_file_name", &WorkerData::original_points_cache_file_name) + .def_readwrite("original_points_to_save_cache_file_name", &WorkerData::original_points_to_save_cache_file_name) .def_readwrite("intermediate_trajectory", &WorkerData::intermediate_trajectory) .def_readwrite("intermediate_trajectory_motion_model", &WorkerData::intermediate_trajectory_motion_model) .def_readwrite("intermediate_trajectory_timestamps", &WorkerData::intermediate_trajectory_timestamps) .def_readwrite("imu_om_fi_ka", &WorkerData::imu_om_fi_ka) + .def_readwrite("show", &WorkerData::show) ; // Bind Session diff --git a/pybind/tls_registration_binding.cpp b/pybind/tls_registration_binding.cpp index 45ce5c4a..4878a52e 100644 --- a/pybind/tls_registration_binding.cpp +++ b/pybind/tls_registration_binding.cpp @@ -88,7 +88,7 @@ PYBIND11_MODULE(multi_view_tls_registration_py, m) { py::class_(m, "ICP") .def(py::init<>()) - .def_readwrite("search_radious", &ICP::search_radious) + .def_readwrite("search_radius", &ICP::search_radius) .def_readwrite("number_of_threads", &ICP::number_of_threads) .def_readwrite("number_of_iterations", &ICP::number_of_iterations) .def_readwrite("is_adaptive_robust_kernel", &ICP::is_adaptive_robust_kernel) @@ -96,7 +96,7 @@ PYBIND11_MODULE(multi_view_tls_registration_py, m) { py::class_(m, "RegistrationPlaneFeature") .def(py::init<>()) - .def_readwrite("search_radious", &RegistrationPlaneFeature::search_radious) + .def_readwrite("search_radius", &RegistrationPlaneFeature::search_radius) .def_readwrite("number_of_threads", &RegistrationPlaneFeature::number_of_threads) .def_readwrite("number_of_iterations", &RegistrationPlaneFeature::number_of_iterations) .def_readwrite("is_adaptive_robust_kernel", &RegistrationPlaneFeature::is_adaptive_robust_kernel); @@ -105,7 +105,7 @@ PYBIND11_MODULE(multi_view_tls_registration_py, m) { .def(py::init<>()) .def_readwrite("overlap_threshold", &PoseGraphSLAM::overlap_threshold) .def_readwrite("iterations", &PoseGraphSLAM::iterations) - .def_readwrite("search_radious", &PoseGraphSLAM::search_radious); + .def_readwrite("search_radius", &PoseGraphSLAM::search_radius); py::class_(m, "GlobalPose") .def(py::init<>()) From 53dff374bab143e0689d7699638fbaa2623a26de Mon Sep 17 00:00:00 2001 From: Piotr Majek Date: Thu, 20 Nov 2025 11:50:05 +0100 Subject: [PATCH 2/3] Python binaries are now builded in binary dir --- .github/workflows/python-bindings-linux.yml | 2 +- .github/workflows/python-bindings-windows.yml | 12 +---- .gitignore | 4 -- pybind/CMakeLists.txt | 45 +++---------------- 4 files changed, 8 insertions(+), 55 deletions(-) diff --git a/.github/workflows/python-bindings-linux.yml b/.github/workflows/python-bindings-linux.yml index c198ce1f..bc129696 100644 --- a/.github/workflows/python-bindings-linux.yml +++ b/.github/workflows/python-bindings-linux.yml @@ -51,7 +51,7 @@ jobs: run: cmake --build ${{github.workspace}}/build_pybind --config ${{env.BUILD_TYPE}} - name: Test Python imports - working-directory: ${{github.workspace}}/pybind + working-directory: ${{github.workspace}}/build_pybind/bin/${{env.BUILD_TYPE}} run: | python -c "import sys; sys.path.insert(0, '.'); import core_py; print('core_py imported successfully')" python -c "import sys; sys.path.insert(0, '.'); import lidar_odometry_py; print('lidar_odometry_py imported successfully')" diff --git a/.github/workflows/python-bindings-windows.yml b/.github/workflows/python-bindings-windows.yml index 34df3f8b..b1bb622c 100644 --- a/.github/workflows/python-bindings-windows.yml +++ b/.github/workflows/python-bindings-windows.yml @@ -46,18 +46,8 @@ jobs: - name: Build Python bindings run: cmake --build ${{github.workspace}}/build_pybind --config ${{env.BUILD_TYPE}} - - name: List pybind directory contents - run: | - echo "Contents of pybind directory:" - dir ${{github.workspace}}\pybind - if (Test-Path "${{github.workspace}}\pybind\${{env.BUILD_TYPE}}") { - echo "Contents of pybind\${{env.BUILD_TYPE}}:" - dir ${{github.workspace}}\pybind\${{env.BUILD_TYPE}} - } - shell: pwsh - - name: Test Python imports - working-directory: ${{github.workspace}}/pybind/${{env.BUILD_TYPE}} + working-directory: ${{github.workspace}}/build_pybind/bin/${{env.BUILD_TYPE}} run: | python -c "import sys; sys.path.insert(0, '.'); import core_py; print('core_py imported successfully')" python -c "import sys; sys.path.insert(0, '.'); import lidar_odometry_py; print('lidar_odometry_py imported successfully')" diff --git a/.gitignore b/.gitignore index 99eab728..f8336b5f 100644 --- a/.gitignore +++ b/.gitignore @@ -69,7 +69,3 @@ imgui.ini /out/install/x64-Release /out_old/install -#pybind -pybind/Release -pybind/Debug - diff --git a/pybind/CMakeLists.txt b/pybind/CMakeLists.txt index 5e1368c6..92a3bc57 100644 --- a/pybind/CMakeLists.txt +++ b/pybind/CMakeLists.txt @@ -146,50 +146,17 @@ else() endif() set_target_properties(core_py PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/pybind" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/pybind" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" ) set_target_properties(lidar_odometry_py PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/pybind" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/pybind" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" ) set_target_properties(multi_view_tls_registration_py PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/pybind" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/pybind" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" ) -# Copy DLLs on Windows for runtime dependencies -if(WIN32) - # Generate a config-specific script to copy only DLL files - file(GENERATE - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/copy_dlls_$.cmake" - CONTENT " -file(GLOB DLL_FILES \"${CMAKE_BINARY_DIR}/bin/$/*.dll\") -file(MAKE_DIRECTORY \"${CMAKE_SOURCE_DIR}/pybind/$\") -foreach(DLL_FILE \${DLL_FILES}) - file(COPY \"\${DLL_FILE}\" DESTINATION \"${CMAKE_SOURCE_DIR}/pybind/$\") -endforeach() -message(STATUS \"Copied \${DLL_FILES} to ${CMAKE_SOURCE_DIR}/pybind/$\") -" - ) - - add_custom_command( - TARGET core_py POST_BUILD - COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/copy_dlls_$.cmake" - COMMENT "Copying DLLs to pybind/$" - ) - - add_custom_command( - TARGET lidar_odometry_py POST_BUILD - COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/copy_dlls_$.cmake" - COMMENT "Copying DLLs to pybind/$" - ) - - add_custom_command( - TARGET multi_view_tls_registration_py POST_BUILD - COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/copy_dlls_$.cmake" - COMMENT "Copying DLLs to pybind/$" - ) -endif() \ No newline at end of file From 66e8d76fd2ef4efb810805daa873ca9324e831df Mon Sep 17 00:00:00 2001 From: Piotr Majek Date: Thu, 20 Nov 2025 12:33:27 +0100 Subject: [PATCH 3/3] Build only python bidings in separate github workflow --- .github/workflows/python-bindings-linux.yml | 2 +- .github/workflows/python-bindings-windows.yml | 2 +- pybind/CMakeLists.txt | 31 +++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-bindings-linux.yml b/.github/workflows/python-bindings-linux.yml index bc129696..324e7a58 100644 --- a/.github/workflows/python-bindings-linux.yml +++ b/.github/workflows/python-bindings-linux.yml @@ -48,7 +48,7 @@ jobs: -DPYBIND=ON - name: Build Python bindings - run: cmake --build ${{github.workspace}}/build_pybind --config ${{env.BUILD_TYPE}} + run: cmake --build ${{github.workspace}}/build_pybind --target pybind_all --config ${{env.BUILD_TYPE}} - name: Test Python imports working-directory: ${{github.workspace}}/build_pybind/bin/${{env.BUILD_TYPE}} diff --git a/.github/workflows/python-bindings-windows.yml b/.github/workflows/python-bindings-windows.yml index b1bb622c..967b0ca3 100644 --- a/.github/workflows/python-bindings-windows.yml +++ b/.github/workflows/python-bindings-windows.yml @@ -44,7 +44,7 @@ jobs: shell: pwsh - name: Build Python bindings - run: cmake --build ${{github.workspace}}/build_pybind --config ${{env.BUILD_TYPE}} + run: cmake --build ${{github.workspace}}/build_pybind --target pybind_all --config ${{env.BUILD_TYPE}} - name: Test Python imports working-directory: ${{github.workspace}}/build_pybind/bin/${{env.BUILD_TYPE}} diff --git a/pybind/CMakeLists.txt b/pybind/CMakeLists.txt index 92a3bc57..df980fd9 100644 --- a/pybind/CMakeLists.txt +++ b/pybind/CMakeLists.txt @@ -45,6 +45,11 @@ if (MSVC) target_compile_options(multi_view_tls_registration_py PRIVATE /bigobj) endif() +add_custom_target(pybind_all + DEPENDS core_py lidar_odometry_py multi_view_tls_registration_py + COMMENT "Building all Python bindings" +) + target_sources(core_py PRIVATE ${CMAKE_SOURCE_DIR}/core/src/session.cpp @@ -160,3 +165,29 @@ set_target_properties(multi_view_tls_registration_py PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" ) +if(WIN32) + add_custom_command( + TARGET core_py + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ + "${CMAKE_BINARY_DIR}/bin/$" + COMMAND_EXPAND_LISTS + ) + + add_custom_command( + TARGET lidar_odometry_py + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ + "${CMAKE_BINARY_DIR}/bin/$" + COMMAND_EXPAND_LISTS + ) + + add_custom_command( + TARGET multi_view_tls_registration_py + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ + "${CMAKE_BINARY_DIR}/bin/$" + COMMAND_EXPAND_LISTS + ) +endif() +