Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Python bindings installation and support building bindings as standalone projects #398

Merged
merged 7 commits into from
Sep 26, 2024
19 changes: 16 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ jobs:
cd build
cmake -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DCMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/install -DBUILD_TESTING:BOOL=ON \
-DWEARABLES_COMPILE_PYTHON_BINDINGS=ON -DHUMANSTATEPROVIDER_ENABLE_VISUALIZER:BOOL=ON \
-DHUMANSTATEPROVIDER_ENABLE_LOGGER:BOOL=ON ..
-DHDE_COMPILE_PYTHON_BINDINGS:BOOL=ON -DHUMANSTATEPROVIDER_ENABLE_VISUALIZER:BOOL=ON \
-DHUMANSTATEPROVIDER_ENABLE_LOGGER:BOOL=ON -DHDE_DETECT_ACTIVE_PYTHON_SITEPACKAGES:BOOL=ON ..

- name: Build
shell: bash -l {0}
Expand All @@ -59,4 +59,17 @@ jobs:
shell: bash -l {0}
run: |
cd build
ctest --repeat until-pass:5 --output-on-failure -C ${{ matrix.build_type }} .
ctest --output-on-failure -C ${{ matrix.build_type }} .

- name: Install
shell: bash -l {0}
run: |
cd build
cmake --install . --config ${{ matrix.build_type }}

- name: Check install
shell: bash -l {0}
run: |
cd build
python -c "import wearables"
python -c "import hde"
6 changes: 0 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ find_package(YCM REQUIRED)
# Import cmake utilities
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(AddWarningsConfigurationToTarget)
include(AddHDEPythonModule)

# To build shared libraries in Windows, we set CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS to TRUE
# See https://cmake.org/cmake/help/v3.4/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.html
Expand Down Expand Up @@ -74,11 +73,6 @@ if(NOT MSVC)
USE_LINK_PATH)
endif()


#Function to automatize the process of creating python bindings
include(AddWearablesPythonModule)


# Tweak linker flags in Linux
if(UNIX AND NOT APPLE)
get_filename_component(LINKER_BIN ${CMAKE_LINKER} NAME)
Expand Down
49 changes: 49 additions & 0 deletions bindings/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
# SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
# SPDX-License-Identifier: BSD-3-Clause

# Detect if we are doing a standalone build of the bindings, using an external icub-main
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set(HDE_BINDINGS_BUILD_STANDALONE TRUE)
else()
set(HDE_BINDINGS_BUILD_STANDALONE FALSE)
endif()

if(HDE_BINDINGS_BUILD_STANDALONE)
cmake_minimum_required(VERSION 3.16)
# Extract project version from top project
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt cmake_content)
string(REGEX MATCH "VERSION[ ]+([0-9]+\\.[0-9]+\\.[0-9]+)" cmake_version_match ${cmake_content})
set(top_project_version ${CMAKE_MATCH_1})
project(HumanDynamicsEstimationBindings
VERSION ${top_project_version})
set(HDE_COMPILE_PYTHON_BINDINGS ON)
find_package(YARP REQUIRED)
find_package(WearableData REQUIRED)
find_package(HumanDynamicsEstimation REQUIRED)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
endif()

if(HDE_COMPILE_PYTHON_BINDINGS)
include(AddWearablesPythonModule)
include(AddHDEPythonModule)

find_package(Python3 3.6 COMPONENTS Interpreter Development REQUIRED)

Expand All @@ -11,6 +35,31 @@ if(HDE_COMPILE_PYTHON_BINDINGS)
"Do you want HDE to detect and use the active site-package directory? (it could be a system dir)"
FALSE)

# Function to generate __init__.py file for both hde and wearables
# It contains logic to ensure that it works fine on Windows when installing in arbitrary folders,
# See https://docs.python.org/3.8/library/os.html#os.add_dll_directory
function(hde_generate_init_py_file GENERATION_LOCATION_OF_INIT_PY_FILE INSTALLATION_LOCATION_OF_INIT_PY_FILE)
file(WRITE ${GENERATION_LOCATION_OF_INIT_PY_FILE}/__init__.py "")
if(WIN32 AND BUILD_SHARED_LIBS)
if(IS_ABSOLUTE ${INSTALLATION_LOCATION_OF_INIT_PY_FILE})
set(PYTHON_FULL_INSTDIR "${INSTALLATION_LOCATION_OF_INIT_PY_FILE}")
else()
set(PYTHON_FULL_INSTDIR "${CMAKE_INSTALL_PREFIX}/${INSTALLATION_LOCATION_OF_INIT_PY_FILE}")
endif()
file(RELATIVE_PATH RELATIVE_PATH_BETWEEN_INIT_PY_AND_DLL_DIRECTORY ${PYTHON_FULL_INSTDIR} ${CMAKE_INSTALL_FULL_BINDIR})
file(APPEND ${GENERATION_LOCATION_OF_INIT_PY_FILE}/__init__.py "import os\n")
file(APPEND ${GENERATION_LOCATION_OF_INIT_PY_FILE}/__init__.py "library_dll_path = os.path.join(os.path.dirname(__file__),'${RELATIVE_PATH_BETWEEN_INIT_PY_AND_DLL_DIRECTORY}')\n")
file(APPEND ${GENERATION_LOCATION_OF_INIT_PY_FILE}/__init__.py "# Avoid to call add_dll_directory if not necessary,\n")
file(APPEND ${GENERATION_LOCATION_OF_INIT_PY_FILE}/__init__.py "# for example if the library to find are already found in the proper location in a conda\n")
file(APPEND ${GENERATION_LOCATION_OF_INIT_PY_FILE}/__init__.py "if(library_dll_path != os.path.join(os.environ.get('CONDA_PREFIX', ''),'Library','bin') and library_dll_path != os.path.join(os.environ.get('CONDA_PREFIX', ''),'bin')):\n")
file(APPEND ${GENERATION_LOCATION_OF_INIT_PY_FILE}/__init__.py " if(os.path.exists(library_dll_path)):\n")
file(APPEND ${GENERATION_LOCATION_OF_INIT_PY_FILE}/__init__.py " os.add_dll_directory(library_dll_path)$\n")
file(APPEND ${GENERATION_LOCATION_OF_INIT_PY_FILE}/__init__.py "\n")
endif()

file(APPEND ${GENERATION_LOCATION_OF_INIT_PY_FILE}/__init__.py "from .bindings import *\n")
endfunction()

# Install the resulting Python package for the active interpreter
if(NOT DEFINED HDE_PYTHON_INSTALL_DIR)
if(HDE_DETECT_ACTIVE_PYTHON_SITEPACKAGES)
Expand Down
7 changes: 4 additions & 3 deletions bindings/python-hde/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ target_link_libraries(pybind11_hde PRIVATE
# # module, i.e. `bindings`.
set_target_properties(pybind11_hde PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${HDE_PYTHON_PACKAGE}"
ARCHIVE_OUTPUT_DIRECTORY "${HDE_PYTHON_PACKAGE}"
RUNTIME_OUTPUT_DIRECTORY "${HDE_PYTHON_PACKAGE}"
PDB_OUTPUT_DIRECTORY "${HDE_PYTHON_PACKAGE}"
OUTPUT_NAME "bindings")

# Output package is:
Expand All @@ -40,9 +43,7 @@ set_target_properties(pybind11_hde PROPERTIES
install(TARGETS pybind11_hde DESTINATION ${PYTHON_INSTDIR})

# Create the __init__.py file
file(GENERATE
OUTPUT "${HDE_PYTHON_PACKAGE}/__init__.py"
CONTENT "from .bindings import *\n")
hde_generate_init_py_file("${HDE_PYTHON_PACKAGE}" "${PYTHON_INSTDIR}")
# Install the __init__.py file
install(FILES "${HDE_PYTHON_PACKAGE}/__init__.py"
DESTINATION ${PYTHON_INSTDIR})
Expand Down
4 changes: 4 additions & 0 deletions bindings/python-wearables/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ target_link_libraries(pybind11_wearables PRIVATE
# # module, i.e. `bindings`.
set_target_properties(pybind11_wearables PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${WEARABLES_PYTHON_PACKAGE}"
ARCHIVE_OUTPUT_DIRECTORY "${WEARABLES_PYTHON_PACKAGE}"
RUNTIME_OUTPUT_DIRECTORY "${WEARABLES_PYTHON_PACKAGE}"
PDB_OUTPUT_DIRECTORY "${WEARABLES_PYTHON_PACKAGE}"
OUTPUT_NAME "bindings")

# Output package is:
Expand All @@ -39,6 +42,7 @@ set_target_properties(pybind11_wearables PROPERTIES

install(TARGETS pybind11_wearables DESTINATION ${PYTHON_INSTDIR})

hde_generate_init_py_file("${WEARABLES_PYTHON_PACKAGE}" "${PYTHON_INSTDIR}")
# Install the __init__.py file
install(FILES "${WEARABLES_PYTHON_PACKAGE}/__init__.py"
DESTINATION ${PYTHON_INSTDIR})
Expand Down
2 changes: 1 addition & 1 deletion bindings/python-wearables/msgs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ add_wearables_python_module(
NAME MsgsBindings
SOURCES src/WearableData.cpp src/Module.cpp
HEADERS ${H_PREFIX}/WearableData.h ${H_PREFIX}/BufferedPort.h ${H_PREFIX}/Module.h
LINK_LIBRARIES Wearable::WearableData YARP::YARP_os)
LINK_LIBRARIES WearableData::WearableData YARP::YARP_os)
4 changes: 2 additions & 2 deletions devices/IWearRemapper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ target_include_directories(IWearRemapper PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)

target_link_libraries(IWearRemapper PUBLIC
IWear::IWear
Wearable::WearableData
IWear::IWear
WearableData::WearableData
Wearable::SensorsImpl
YARP::YARP_dev
YARP::YARP_os
Expand Down
4 changes: 2 additions & 2 deletions msgs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
yarp_add_idl(WEARABLEDATA_FILES thrift/WearableData.thrift)

add_library(WearableData ${WEARABLEDATA_FILES} thrift/WearableData.thrift)
add_library(Wearable::WearableData ALIAS WearableData)
add_library(WearableData::WearableData ALIAS WearableData)
target_link_libraries(WearableData YARP::YARP_os)

# Extract the include directory from the files names
Expand Down Expand Up @@ -60,7 +60,7 @@ install(FILES ${WEARABLEDATA_FILES}
yarp_add_idl(WEARABLEACTUATORS_FILES thrift/WearableActuators.thrift)

add_library(WearableActuators ${WEARABLEACTUATORS_FILES} thrift/WearableActuators.thrift)
add_library(Wearable::WearableActuators ALIAS WearableActuators)
add_library(WearableActuators::WearableActuators ALIAS WearableActuators)
S-Dafarra marked this conversation as resolved.
Show resolved Hide resolved
target_link_libraries(WearableActuators YARP::YARP_os)

# Extract the include directory from the files names
Expand Down
Loading