intial stuff

This commit is contained in:
2026-02-16 19:55:01 +01:00
parent f53bb84209
commit fed1844282
7 changed files with 703 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
{
"image": "ubuntu:24.04", // for cuda support: nvidia/cuda:13.1.0-devel-ubuntu24.04
"containerEnv": {
"CONAN_USR": "t", // need to be filled
"CONAN_PSW": "" // need to be filled,
},
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/git-lfs:1": {}
},
"customizations": {
"vscode": {
"settings": {
"git.path": "/usr/bin/git"
},
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"GitHub.copilot-chat",
"njqdev.vscode-python-typehint",
"ms-python.debugpy",
"mhutchie.git-graph",
"ms-vscode.cpptools-themes",
"tamasfe.even-better-toml",
"moshfeu.compare-folders",
"njpwerner.autodocstring",
"ms-python.black-formatter",
"ms-python.isort",
"ms-vscode.live-server",
"yzhang.markdown-all-in-one",
"bierner.markdown-mermaid",
"charliermarsh.ruff",
"shardulm94.trailing-spaces",
"redhat.vscode-yaml",
"ninoseki.vscode-mogami",
"josetr.cmake-language-support-vscode",
"ms-vscode.cmake-tools",
"twxs.cmake",
"cheshirekow.cmake-format",
"ms-azuretools.vscode-docker",
"foxundermoon.shell-format",
"nvidia.nsight-vscode-edition"
]
}
},
"runArgs": [
"--network=host",
"-e HOST_UID=$(id -u)",
"-e HOST_GID=$(id -g)",
"--gpus=all"
],
"postStartCommand": ".devcontainer/postStartCommand.sh"
}

186
.devcontainer/postStartCommand.sh Executable file
View File

@@ -0,0 +1,186 @@
#!/bin/bash
# ==============================================================================
# Conan2 Development Environment Setup
#
# Description: Provisions system dependencies, shell configuration, and Conan2.
# Designed for Debian/Ubuntu-based DevContainers or CI Runners.
# Usage: CONAN_USR=x CONAN_PSW=y ./postStartCommand.sh
# ==============================================================================
set -euo pipefail
# --- Configuration ------------------------------------------------------------
# Versions & Remote Resources
TASK_VERSION="v3.45.5"
GLOW_VERSION="2.1.1"
CONAN_CONFIG_URL="https://package-cloud.dns.army/ros2/conan2-config.git"
CONAN_REMOTE_NAME="package-cloud-ros2-conan2"
# Localization
TIMEZONE="Europe/Berlin"
# Paths
LOCAL_BIN="$HOME/.local/bin"
ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
# --- Helpers ------------------------------------------------------------------
log() {
echo -e "\033[1;34m>>> [SETUP] $1\033[0m"
}
error() {
echo -e "\033[1;31m!!! [ERROR] $1\033[0m" >&2
exit 1
}
cleanup() {
# Remove temp files on exit (successful or not)
rm -f glow.deb install_task.sh
}
trap cleanup EXIT
ensure_env_vars() {
if [[ -z "${CONAN_USR:-}" ]] || [[ -z "${CONAN_PSW:-}" ]]; then
error "CONAN_USR and CONAN_PSW environment variables are required."
fi
}
detect_arch() {
local arch
arch=$(dpkg --print-architecture)
case "$arch" in
amd64) echo "amd64" ;;
arm64) echo "arm64" ;;
*) error "Unsupported architecture: $arch" ;;
esac
}
# --- Installation Functions ---------------------------------------------------
install_system_dependencies() {
log "Installing system dependencies..."
export DEBIAN_FRONTEND=noninteractive
apt-get update -q
apt-get install -y -q --no-install-recommends \
tzdata curl git zsh python3 python3-pip python3-venv \
ca-certificates gnupg pipx
# Ensure pipx path is available immediately for this script
export PATH="$LOCAL_BIN:$PATH"
pipx ensurepath
}
configure_timezone() {
log "Configuring timezone ($TIMEZONE)..."
local tz_path="/usr/share/zoneinfo/$TIMEZONE"
# Validation: Ensure the requested timezone actually exists
if [ ! -f "$tz_path" ]; then
error "Timezone data not found at '$tz_path'. Please check the TIMEZONE variable."
fi
ln -fs "$tz_path" /etc/localtime
echo "$TIMEZONE" >/etc/timezone
dpkg-reconfigure -f noninteractive tzdata
}
install_shell_tools() {
log "Setting up Shell (Oh My Zsh)..."
if [ ! -d "$HOME/.oh-my-zsh" ]; then
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
else
log "Oh My Zsh already installed. Skipping."
fi
}
install_conan() {
log "Installing Conan via pipx (Isolated)..."
# Use pipx to avoid breaking system packages
if ! command -v conan &>/dev/null; then
pipx install conan
else
pipx upgrade conan
fi
# Config
log "Installing Conan Config..."
# Force allows overwriting existing configs which is usually desired in setup scripts
conan config install "$CONAN_CONFIG_URL" --type git --args="--branch main"
log "Authenticating Conan..."
conan remote login "$CONAN_REMOTE_NAME" "$CONAN_USR" -p "$CONAN_PSW"
}
install_utilities() {
local arch
arch=$(detect_arch)
# 1. Taskfile
log "Installing Taskfile ($TASK_VERSION)..."
curl -sL -o install_task.sh https://taskfile.dev/install.sh
sh install_task.sh -d -b "$LOCAL_BIN" "$TASK_VERSION"
# 2. Glow
log "Installing Glow ($GLOW_VERSION for $arch)..."
local glow_url="https://github.com/charmbracelet/glow/releases/download/v${GLOW_VERSION}/glow_${GLOW_VERSION}_${arch}.deb"
curl -L -o glow.deb "$glow_url"
dpkg -i glow.deb
}
configure_persistence() {
log "Persisting configurations..."
local zshrc="$HOME/.zshrc"
touch "$zshrc"
# Helper to append if missing
append_if_missing() {
local file="$1"
local content="$2"
if ! grep -Fxq "$content" "$file"; then
echo "$content" >>"$file"
fi
}
# Add Local Bin to Path
append_if_missing "$HOME/.bashrc" "$path_export"
append_if_missing "$zshrc" "$path_export"
# Shell Completions
append_if_missing "$zshrc" 'eval "$(task --completion zsh)"'
append_if_missing "$zshrc" 'eval "$(glow completion zsh)"'
# Git Safe Directory
git config --global --add safe.directory /workspaces/conan2-ros2-video-to-rosbag
}
run_tasks() {
if [ -f "Taskfile.yml" ] || [ -f "Taskfile.yaml" ]; then
log "Running default Task..."
"$LOCAL_BIN/task" --yes
else
log "No Taskfile found. Skipping 'task --yes'."
fi
}
# --- Main Execution -----------------------------------------------------------
main() {
ensure_env_vars
install_system_dependencies
configure_timezone
install_shell_tools
install_utilities # Task & Glow
install_conan # Depends on pipx (sys deps)
configure_persistence
run_tasks
log "Setup complete successfully."
}
main

3
.taskrc.yml Normal file
View File

@@ -0,0 +1,3 @@
# Enable experimental features
experiments:
REMOTE_TASKFILES: 1

14
LICENSE Normal file
View File

@@ -0,0 +1,14 @@
Copyright (C) 2023 Hesai Technology Co., Ltd.
Copyright (C) 2023 Hesai Technology, zhangyu
Copyright (C) 2023 Hesai Technology, huangzhongbo
All rights reserved.
All code in this repository is released under the terms of the following Modified BSD License. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

181
Taskfile.hesai.yml Normal file
View File

@@ -0,0 +1,181 @@
# https://taskfile.dev
version: "3"
vars:
BUILD_TYPE: '{{.BUILD_TYPE | default "Release"}}'
VERSION: '{{.CONAN_BUILD_VERSION | default .ENV_CONAN_BUILD_VERSION | default "0.0.0-dev"}}'
# Detect System Architecture (x86_64 or aarch64)
SYSTEM_ARCH:
sh: arch
tasks:
# ============================================================================
# Core Logic (Internal)
# ============================================================================
_validate_arch:
internal: true
silent: true
desc: "Checks if the current system architecture supports the requested build"
requires:
vars: [EXPECTED_ARCH]
cmds:
- |
if [ "{{.SYSTEM_ARCH}}" != "{{.EXPECTED_ARCH}}" ]; then
echo "❌ ARCHITECTURE MISMATCH ERROR:"
echo " - System Arch: {{.SYSTEM_ARCH}}"
echo " - Expected Arch: {{.EXPECTED_ARCH}}"
echo " - Task Type: Native Build"
echo ""
echo " You are trying to run a 'native' build for {{.EXPECTED_ARCH}} on a {{.SYSTEM_ARCH}} machine."
echo " Please use the 'cross-...' task instead."
exit 1
else
echo "✅ Architecture match: System={{.SYSTEM_ARCH}} matches Target={{.EXPECTED_ARCH}}"
fi
_create:
internal: true
desc: "Core wrapper for conan create"
requires:
vars: [PROFILE_HOST, PROFILE_BUILD]
cmds:
- >-
conan create .
--profile:build {{.PROFILE_BUILD}}
--profile:host {{.PROFILE_HOST}}
--build=missing
--version {{.VERSION}}
-s build_type={{.BUILD_TYPE}}
_create_with_cuda:
internal: true
desc: "Core wrapper for conan create"
requires:
vars: [PROFILE_HOST, PROFILE_BUILD]
cmds:
- >-
conan create .
--profile:build {{.PROFILE_BUILD}}
--profile:host {{.PROFILE_HOST}}
--build=missing
--version {{.VERSION}}
-s build_type={{.BUILD_TYPE}}
-o with_cuda=True
# ============================================================================
# GCC 13 (Modern)
# ============================================================================
native-x64:gcc13:
desc: "Build: Native x64 (GCC 13)"
cmds:
# x86_64 is the standard output of 'arch' for Intel/AMD
- task: _validate_arch
vars: { EXPECTED_ARCH: "x86_64" }
- task: _create
vars:
PROFILE_BUILD: x64_linux_gcc_13
PROFILE_HOST: x64_linux_gcc_13
native-x64:gcc13:cuda:
desc: "Build: Native x64 (GCC 13) with cuda support"
cmds:
# x86_64 is the standard output of 'arch' for Intel/AMD
- task: _validate_arch
vars: { EXPECTED_ARCH: "x86_64" }
- task: _create_with_cuda
vars:
PROFILE_BUILD: x64_linux_gcc_13
PROFILE_HOST: x64_linux_gcc_13
native-armv8:gcc13:
desc: "Build: Native ARMv8 (GCC 13)"
cmds:
# aarch64 is the standard output of 'arch' for ARMv8
- task: _validate_arch
vars: { EXPECTED_ARCH: "aarch64" }
- task: _create
vars:
PROFILE_BUILD: armv8_linux_gcc_13
PROFILE_HOST: armv8_linux_gcc_13
native-armv8:gcc13:cuda:
desc: "Build: Native ARMv8 (GCC 13) with cuda support"
cmds:
# aarch64 is the standard output of 'arch' for ARMv8
- task: _validate_arch
vars: { EXPECTED_ARCH: "aarch64" }
- task: _create_with_cuda
vars:
PROFILE_BUILD: armv8_linux_gcc_13
PROFILE_HOST: armv8_linux_gcc_13
cross-armv8:gcc13:
desc: "Build: Cross-Compile x64 -> ARMv8 (GCC 13)"
cmds:
# No validation needed for Cross-Compilation, as mismatch is intended
- echo "⚠️ Cross-compiling for ARMv8 on {{.SYSTEM_ARCH}} (No arch check enforced)"
- task: _create
vars:
PROFILE_BUILD: x64_linux_gcc_13
PROFILE_HOST: armv8_linux_gcc_13_croco
# ============================================================================
# GCC 9 (Legacy)
# ============================================================================
native-x64:gcc9:
desc: "Build: Native x64 (GCC 9)"
cmds:
- task: _validate_arch
vars: { EXPECTED_ARCH: "x86_64" }
- task: _create
vars:
PROFILE_BUILD: x64_linux_gcc_9
PROFILE_HOST: x64_linux_gcc_9
native-x64:gcc9:cuda:
desc: "Build: Native x64 (GCC 9) with cuda support"
cmds:
# x86_64 is the standard output of 'arch' for Intel/AMD
- task: _validate_arch
vars: { EXPECTED_ARCH: "x86_64" }
- task: _create_with_cuda
vars:
PROFILE_BUILD: x64_linux_gcc_9
PROFILE_HOST: x64_linux_gcc_9
native-armv8:gcc9:
desc: "Build: Native ARMv8 (GCC 9)"
cmds:
- task: _validate_arch
vars: { EXPECTED_ARCH: "aarch64" }
- task: _create
vars:
PROFILE_BUILD: armv8_linux_gcc_9
PROFILE_HOST: armv8_linux_gcc_9
native-armv8:gcc9:cuda:
desc: "Build: Native ARMv8 (GCC 9) with cuda support"
cmds:
# aarch64 is the standard output of 'arch' for ARMv8
- task: _validate_arch
vars: { EXPECTED_ARCH: "aarch64" }
- task: _create_with_cuda
vars:
PROFILE_BUILD: armv8_linux_gcc_9
PROFILE_HOST: armv8_linux_gcc_9
cross-armv8:gcc9:
desc: "Build: Cross-Compile x64 -> ARMv8 (GCC 9)"
cmds:
- echo "⚠️ Cross-compiling for ARMv8 on {{.SYSTEM_ARCH}} (No arch check enforced)"
- task: _create
vars:
PROFILE_BUILD: x64_linux_gcc_9
PROFILE_HOST: armv8_linux_gcc_9_croco

47
Taskfile.yml Normal file
View File

@@ -0,0 +1,47 @@
# https://taskfile.dev
version: "3"
vars:
# Global Configuration
CONAN2_CONFIG_URL: https://package-cloud.dns.army/ros2/conan2-config
CONAN2_CONFIG_BRANCH: main
CONAN2_CONFIG_TASKFILE_PATH: Taskfile.yml
CONAN_BUILD_VERSION: latest
includes:
# Remote includes
conan2-config: "{{.CONAN2_CONFIG_URL}}/raw/branch/{{.CONAN2_CONFIG_BRANCH}}/{{.CONAN2_CONFIG_TASKFILE_PATH}}"
# Local modules
hesai: ./Taskfile.hesai.yml
tasks:
default:
desc: Show available tasks
silent: true
cmds:
- task: version
- task --list
version:
desc: Display component version information
silent: true
vars:
NAME_COMPONENT: conan2-ros2-hesai-lidar
URL_COMPONENT: https://package-cloud.dns.army/ros2/conan2-ros2-hesai-lidar
GIT_SHA:
sh: git rev-parse --short HEAD
GIT_REF:
sh: git rev-parse --abbrev-ref HEAD
cmds:
- printf "{{.B_MAGENTA}}Component{{.RESET}} - {{.CYAN}}{{.NAME_COMPONENT}}{{.RESET}}\n"
- printf "{{.B_MAGENTA}}URL{{.RESET}} - {{.CYAN}}{{.URL_COMPONENT}}{{.RESET}}\n"
- printf "{{.B_MAGENTA}}Branch{{.RESET}} - {{.CYAN}}{{.GIT_REF}} {{.B_WHITE}}{{.RESET}} - {{.B_MAGENTA}}Hash{{.RESET}} - {{.GREEN}}{{.GIT_SHA}}{{.RESET}}\n"
install:gcc:
desc: Install default gcc g++ build-toolchain for ubuntu
cmds:
- apt-get install build-essential --no-install-recommends --yes

219
conanfile.py Normal file
View File

@@ -0,0 +1,219 @@
import os
import subprocess
import shutil
from conan import ConanFile
from conan.tools.cmake import CMakeToolchain, CMakeDeps, cmake_layout
from conan.tools.files import copy, rmdir, patch
from conan.tools.scm import Git
from conan.errors import ConanInvalidConfiguration, ConanException
class HesaiLidarDriver(ConanFile):
name = "hesai-lidar-ros2-jazzy-driver"
description = "ROS2 (Jazzy) Driver for Hesai LiDAR sensor"
license = "BSD-3-Clause"
url = "https://github.com/HesaiTechnology/HesaiLidar_ROS_2.0"
author = "thommyho1988@gmail.com"
topics = ("ros2", "lidar", "hesai", "driver")
settings = "os", "compiler", "build_type", "arch"
options = {
"with_cuda": [True, False],
}
default_options = {
"with_cuda": False,
}
def export_sources(self):
copy(self, "patches/**", self.recipe_folder, self.export_sources_folder)
copy(self, "LICENSE", self.recipe_folder, self.export_sources_folder)
copy(self, "README.md", self.recipe_folder, self.export_sources_folder)
def layout(self):
cmake_layout(self)
def build_requirements(self):
self.tool_requires("make/4.4.1")
self.tool_requires("cmake/3.31.9")
self.tool_requires("ros2-jazzy-toolchain/latest")
def requirements(self):
self.requires("ros2-jazzy-python/latest")
self.requires("ros2-jazzy-toolchain/latest")
self.requires("openssl/1.1.1w")
self.requires("yaml-cpp/0.8.0")
self.requires("tinyxml2/7.1.0")
self.requires("boost/1.74.0", options={
"without_thread": False,
"without_system": False,
"without_chrono": False,
})
def validate(self):
if self.options.with_cuda and self.settings.arch not in ["x86_64", "armv8"]:
raise ConanInvalidConfiguration("CUDA is only supported on x86_64 and armv8")
def source(self):
if self.version not in self.conan_data.get("sources", {}):
raise ConanInvalidConfiguration(f"Version '{self.version}' not found in conandata.yml")
data = self.conan_data["sources"][self.version]
tmp_src = "src_tmp"
try:
self.output.info(f"Cloning {data['url']} into temporary directory...")
git = Git(self)
git.clone(url=data["url"], target=tmp_src, args=["--recursive"])
if "revision" in data:
self.output.info(f"Checking out revision {data['revision']}")
git_tmp = Git(self, folder=tmp_src)
git_tmp.checkout(commit=data["revision"])
git_tmp.run("submodule update --init --recursive")
self.output.info("Moving sources to recipe root...")
copy(self, "*", src=tmp_src, dst=".")
except Exception as e:
raise ConanException(f"Source retrieval failed: {e}")
finally:
if os.path.exists(tmp_src):
rmdir(self, tmp_src)
patch_dir = os.path.join(self.source_folder, "patches", self.version)
if os.path.exists(patch_dir):
patches = sorted([p for p in os.listdir(patch_dir) if p.endswith(".patch")])
for p in patches:
self.output.info(f"Applying patch: {p}")
patch(self, patch_file=os.path.join(patch_dir, p))
def _get_numpy_include(self, python_exe):
try:
cmd = [python_exe, "-c", "import numpy; print(numpy.get_include())"]
return subprocess.check_output(cmd, text=True).strip()
except (subprocess.CalledProcessError, FileNotFoundError, OSError) as e:
self.output.warning(f"Failed to determine NumPy include path: {e}")
return ""
def generate(self):
deps = CMakeDeps(self)
deps.generate()
tc = CMakeToolchain(self)
python_dep = self.dependencies["ros2-jazzy-python"]
python_exe = python_dep.conf_info.get("user.ros2:python_interpreter", check_type=str)
if python_exe:
numpy_include = self._get_numpy_include(python_exe)
tc.variables["Python3_EXECUTABLE"] = python_exe
tc.variables["Python_EXECUTABLE"] = python_exe
if numpy_include:
tc.variables["Python3_NumPy_INCLUDE_DIR"] = numpy_include
self._configure_special_flags(tc, python_dep)
tc.generate()
def _configure_special_flags(self, tc, python_dep):
cross_blob = False
if "cross_blob" in python_dep.options:
cross_blob = bool(python_dep.options.cross_blob)
if self.options.with_cuda:
if cross_blob:
raise ConanInvalidConfiguration("CUDA not available as conan package due to NVIDIA license.")
self.output.info("Enabling CUDA Support")
tc.variables["FIND_CUDA"] = "ON"
if cross_blob:
self.output.info("Enabling Cross-Blob workarounds (No LTO)")
tc.variables["CMAKE_INTERPROCEDURAL_OPTIMIZATION"] = "OFF"
tc.cache_variables["CMAKE_C_FLAGS"] = "-fno-lto"
tc.cache_variables["CMAKE_CXX_FLAGS"] = "-fno-lto"
def build(self):
# 1. Resolve Setup Script
build_dep = self.dependencies.get("ros2-jazzy-toolchain")
setup_script = None
if build_dep:
env_vars = build_dep.buildenv_info.vars(self)
raw_cmd = env_vars.get("CONAN_ROS2_SOURCE_CMD", "")
if "source " in raw_cmd:
setup_script = raw_cmd.split("source ")[1].strip().split(" ")[0]
elif raw_cmd.strip().endswith((".sh", ".bash")):
setup_script = raw_cmd.strip()
# 2. Paths
tc_file = os.path.join(self.generators_folder, "conan_toolchain.cmake")
abs_build_base = os.path.join(self.build_folder, "colcon_build")
abs_install_base = os.path.join(self.build_folder, "install")
# 3. Colcon Command
colcon_cmd = (
f"colcon build --merge-install "
f"--build-base '{abs_build_base}' "
f"--install-base '{abs_install_base}' "
f"--event-handlers console_direct+ "
f"--cmake-args -DCMAKE_TOOLCHAIN_FILE='{tc_file}' "
f"-DCMAKE_BUILD_TYPE={self.settings.build_type}"
)
# 4. Execute (Bash wrapper for 'source')
if setup_script:
full_cmd = f'/bin/bash -c "source {setup_script} && {colcon_cmd}"'
else:
full_cmd = colcon_cmd
self.output.info(f"Building with: {full_cmd}")
self.run(full_cmd, shell=True, cwd=self.source_folder)
def package(self):
install_dir = os.path.join(self.build_folder, "install")
if not os.path.exists(install_dir):
raise ConanException(f"Build failed to produce install directory: {install_dir}")
# 1. Define Subdirectory
ros_package_dir = os.path.join(self.package_folder, "hesai_ros_driver")
# 2. Copy ROS Artifacts to Subdirectory
copy(self, "*", src=install_dir, dst=ros_package_dir)
# 3. Copy Metadata to Root
copy(self, "LICENSE", src=self.source_folder, dst=self.package_folder)
copy(self, "README.md", src=self.source_folder, dst=self.package_folder)
# 4. Cleanup
rmdir(self, os.path.join(ros_package_dir, "share", "doc"))
rmdir(self, os.path.join(ros_package_dir, "colcon_build"))
def package_info(self):
# 1. Define the ROS Root inside the package
ros_root = os.path.join(self.package_folder, "hesai_ros_driver")
# 2. Cpp Info (Relative to package_folder)
self.cpp_info.libs = ["hesai_ros_driver"]
self.cpp_info.libdirs = [os.path.join("hesai_ros_driver", "lib")]
self.cpp_info.includedirs = [os.path.join("hesai_ros_driver", "include")]
self.cpp_info.bindirs = [os.path.join("hesai_ros_driver", "bin")]
# 3. Environment Variables (Absolute Paths)
# Critical: These ensure ROS 2 finds the package in the subdirectory
self.runenv_info.prepend_path("AMENT_PREFIX_PATH", ros_root)
self.buildenv_info.prepend_path("AMENT_PREFIX_PATH", ros_root)
self.runenv_info.prepend_path("CMAKE_PREFIX_PATH", ros_root)
self.buildenv_info.prepend_path("CMAKE_PREFIX_PATH", ros_root)
self.runenv_info.prepend_path("PATH", os.path.join(ros_root, "bin"))
self.runenv_info.prepend_path("LD_LIBRARY_PATH", os.path.join(ros_root, "lib"))
# 4. Python Path Calculation
lib_dir = os.path.join(ros_root, "lib")
if os.path.exists(lib_dir):
for item in os.listdir(lib_dir):
if item.startswith("python"):
site_packages = os.path.join(lib_dir, item, "site-packages")
if os.path.exists(site_packages):
self.runenv_info.prepend_path("PYTHONPATH", site_packages)
self.buildenv_info.prepend_path("PYTHONPATH", site_packages)
break