feat: reimplement webots recipe through cmake
This commit is contained in:
parent
bf33aad15e
commit
ded13c428f
|
|
@ -0,0 +1,46 @@
|
|||
cmake_minimum_required(VERSION 3.23)
|
||||
project(webots_controller LANGUAGES C CXX)
|
||||
|
||||
option(WEBOTS_CONTROLLER_NO_PLUGINS "Disable runtime plugin loading (dlopen/LoadLibrary paths)." ON)
|
||||
|
||||
if(NOT DEFINED WEBOTS_REPO_SOURCE_DIR)
|
||||
set(WEBOTS_REPO_SOURCE_DIR "")
|
||||
endif()
|
||||
|
||||
if(WEBOTS_REPO_SOURCE_DIR STREQUAL "")
|
||||
message(FATAL_ERROR "WEBOTS_REPO_SOURCE_DIR must point to cloned Webots repository")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
find_package(dirent CONFIG REQUIRED)
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/cmake")
|
||||
file(
|
||||
DOWNLOAD
|
||||
https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.40.8/CPM.cmake
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake"
|
||||
EXPECTED_HASH
|
||||
SHA256=78ba32abdf798bc616bab7c73aac32a17bbd7b06ad9e26a6add69de8f3ae4791)
|
||||
include("${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake")
|
||||
|
||||
CPMAddPackage(
|
||||
NAME libunistd
|
||||
GITHUB_REPOSITORY robinrowe/libunistd
|
||||
GIT_TAG v1.4
|
||||
DOWNLOAD_ONLY YES)
|
||||
|
||||
add_library(webots_controller_msvc_unix_headers INTERFACE)
|
||||
target_include_directories(
|
||||
webots_controller_msvc_unix_headers
|
||||
SYSTEM
|
||||
INTERFACE "$<TARGET_PROPERTY:dirent::dirent,INTERFACE_INCLUDE_DIRECTORIES>"
|
||||
"${libunistd_SOURCE_DIR}/unistd")
|
||||
target_link_libraries(webots_controller_msvc_unix_headers
|
||||
INTERFACE dirent::dirent)
|
||||
target_compile_definitions(webots_controller_msvc_unix_headers
|
||||
INTERFACE _CRT_DECLARE_NONSTDC_NAMES=0)
|
||||
target_compile_options(webots_controller_msvc_unix_headers
|
||||
INTERFACE /FIunistd.h)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src/controller)
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
sources:
|
||||
"2023a":
|
||||
"r2023a":
|
||||
git_url: "https://github.com/cyberbotics/webots.git"
|
||||
ref: "R2023a"
|
||||
"2023b":
|
||||
"r2023b":
|
||||
git_url: "https://github.com/cyberbotics/webots.git"
|
||||
ref: "R2023b"
|
||||
"2025a":
|
||||
"r2025a":
|
||||
git_url: "https://github.com/cyberbotics/webots.git"
|
||||
ref: "R2025a"
|
||||
|
|
|
|||
|
|
@ -1,116 +1,9 @@
|
|||
from conan import ConanFile
|
||||
from conan.errors import ConanException, ConanInvalidConfiguration
|
||||
from conan.tools.env import Environment
|
||||
from conan.tools.files import chdir, copy, get
|
||||
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
|
||||
from conan.tools.files import copy
|
||||
from conan.tools.scm import Git
|
||||
from pathlib import Path
|
||||
from conan.tools.microsoft import is_msvc
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import platform
|
||||
|
||||
|
||||
def find_webots_install_path() -> str | None:
|
||||
"""Locate an existing Webots installation directory.
|
||||
|
||||
Windows strategy (in order):
|
||||
1. Respect WEBOTS_HOME environment variable if it points to an existing path.
|
||||
2. Query uninstall registry keys (both 64-bit and 32-bit views) for InstallLocation:
|
||||
HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Webots
|
||||
3. Look in common default install directories (Program Files, Program Files (x86)).
|
||||
4. Fallback: derive from a discovered `webots-controller.exe` on PATH.
|
||||
|
||||
macOS strategy:
|
||||
* If a `webots` or `webots-controller` binary is found inside a Webots.app bundle,
|
||||
return the bundle root (…/Webots.app).
|
||||
|
||||
Linux / Other:
|
||||
* Attempt to locate `webots-controller` or `webots` via PATH and return its parent directory.
|
||||
|
||||
Returns None if nothing suitable is found.
|
||||
"""
|
||||
|
||||
system = platform.system()
|
||||
|
||||
# 1. Explicit env var (all platforms)
|
||||
env_home = os.getenv("WEBOTS_HOME")
|
||||
if env_home and os.path.exists(env_home):
|
||||
return env_home
|
||||
|
||||
if system == "Windows":
|
||||
# 2. Registry (both views)
|
||||
try: # pragma: no cover (import guarded for non-Windows)
|
||||
import winreg # type: ignore
|
||||
except ImportError: # pragma: no cover
|
||||
winreg = None # type: ignore
|
||||
|
||||
if winreg:
|
||||
reg_paths = [
|
||||
(
|
||||
winreg.HKEY_LOCAL_MACHINE,
|
||||
r"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Webots",
|
||||
),
|
||||
# 32-bit view on 64-bit systems
|
||||
(
|
||||
winreg.HKEY_LOCAL_MACHINE,
|
||||
r"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Webots",
|
||||
),
|
||||
]
|
||||
for hive, subkey in reg_paths:
|
||||
try:
|
||||
with winreg.OpenKey(hive, subkey) as key: # type: ignore[attr-defined]
|
||||
install_path, _ = winreg.QueryValueEx(key, "InstallLocation") # type: ignore[attr-defined]
|
||||
if install_path and os.path.exists(install_path):
|
||||
return install_path
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# 3. Common default directories
|
||||
program_files = os.environ.get("ProgramFiles", r"C:\\Program Files")
|
||||
program_files_x86 = os.environ.get("ProgramFiles(x86)", r"C:\\Program Files (x86)")
|
||||
candidates = [
|
||||
os.path.join(program_files, "Webots"),
|
||||
os.path.join(program_files_x86, "Webots"),
|
||||
]
|
||||
for c in candidates:
|
||||
if os.path.exists(c):
|
||||
return c
|
||||
|
||||
# 4. PATH discovery of controller exe
|
||||
exe = shutil.which("webots-controller.exe") or shutil.which("webots.exe")
|
||||
if exe:
|
||||
parent = os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(exe)))
|
||||
) # heuristic
|
||||
# Explanation: typical Windows structure:
|
||||
# <WEBOTS_HOME>\msys64\mingw64\bin\webots-controller.exe
|
||||
# So we ascend four levels to reach WEBOTS_HOME.
|
||||
if os.path.exists(parent):
|
||||
return parent
|
||||
return None
|
||||
|
||||
# Non-Windows
|
||||
candidate = shutil.which("webots-controller") or shutil.which("webots")
|
||||
if not candidate:
|
||||
return None
|
||||
|
||||
# Resolve symlinks to get actual installation root. This matters on Linux
|
||||
# distributions where Webots may be installed under /opt/webots but only a
|
||||
# symlink placed into /usr/local/bin or similar locations.
|
||||
resolved = os.path.realpath(candidate)
|
||||
|
||||
if system == "Darwin":
|
||||
token = "Webots.app"
|
||||
# If the resolved path sits inside an app bundle, return the bundle root.
|
||||
if token in resolved:
|
||||
prefix, _sep, _rest = resolved.partition(token)
|
||||
return os.path.join(prefix, token)
|
||||
# Fallback: just use the directory of the (possibly resolved) binary.
|
||||
return os.path.dirname(resolved)
|
||||
|
||||
return os.path.dirname(resolved)
|
||||
|
||||
|
||||
class WebotsControllerConan(ConanFile):
|
||||
|
|
@ -120,229 +13,101 @@ class WebotsControllerConan(ConanFile):
|
|||
url = "https://github.com/cyberbotics/webots"
|
||||
homepage = "https://cyberbotics.com"
|
||||
topics = ("robotics", "simulation", "webots", "controller")
|
||||
package_type = "shared-library"
|
||||
package_type = "library"
|
||||
|
||||
settings = "os", "arch", "compiler", "build_type"
|
||||
options = {"fPIC": [True, False]}
|
||||
default_options = {"fPIC": True}
|
||||
options = {
|
||||
"shared": [True, False],
|
||||
"fPIC": [True, False],
|
||||
"no_plugins": [True, False],
|
||||
}
|
||||
default_options = {
|
||||
"shared": True,
|
||||
"fPIC": True,
|
||||
"no_plugins": True,
|
||||
}
|
||||
|
||||
exports_sources = (
|
||||
"CMakeLists.txt",
|
||||
"src/*",
|
||||
"patches/*.patch",
|
||||
"test_package/conanfile.py",
|
||||
"test_package/CMakeLists.txt",
|
||||
"test_package/test_package.cpp",
|
||||
"test_package/test_package.c",
|
||||
)
|
||||
|
||||
@property
|
||||
def _source_subfolder(self):
|
||||
return "source_subfolder"
|
||||
|
||||
@property
|
||||
def _is_system_package(self):
|
||||
return str(self.version) == "system"
|
||||
|
||||
@property
|
||||
def _system_webots_home(self):
|
||||
webots_home = find_webots_install_path()
|
||||
if not webots_home:
|
||||
raise ConanInvalidConfiguration(
|
||||
f"{self.ref} could not locate an installed Webots root. "
|
||||
"Set WEBOTS_HOME or install Webots in a standard location discoverable by find_webots_install_path()."
|
||||
)
|
||||
return os.path.abspath(os.path.expanduser(webots_home))
|
||||
|
||||
def _validate_system_webots_home(self):
|
||||
webots_home = self._system_webots_home
|
||||
required_paths = [
|
||||
os.path.join(webots_home, "include", "controller", "c", "webots", "robot.h"),
|
||||
os.path.join(webots_home, "include", "controller", "cpp", "webots", "Robot.hpp"),
|
||||
os.path.join(webots_home, "lib", "controller"),
|
||||
]
|
||||
missing = [path for path in required_paths if not os.path.exists(path)]
|
||||
if missing:
|
||||
formatted = ", ".join(f"'{path}'" for path in missing)
|
||||
raise ConanInvalidConfiguration(
|
||||
f"{self.ref} could not find the expected Webots controller files under WEBOTS_HOME='{webots_home}': {formatted}"
|
||||
)
|
||||
|
||||
def config_options(self):
|
||||
if self.settings.os == "Windows":
|
||||
self.options.rm_safe("fPIC")
|
||||
|
||||
def validate(self):
|
||||
if self._is_system_package:
|
||||
self._validate_system_webots_home()
|
||||
def configure(self):
|
||||
if self.options.get_safe("no_plugins", True):
|
||||
return
|
||||
if str(self.settings.compiler) == "msvc":
|
||||
raise ConanInvalidConfiguration("Webots controller libraries are built with GCC/Clang toolchains, not MSVC")
|
||||
if self.settings.os == "Windows" and is_msvc(self):
|
||||
raise ValueError("Official Windows Webots is built with MinGW GCC, not MSVC.")
|
||||
|
||||
def source(self):
|
||||
if self._is_system_package:
|
||||
return
|
||||
source_data = self.conan_data["sources"][self.version]
|
||||
if "git_url" in source_data:
|
||||
git = Git(self)
|
||||
clone_args = [
|
||||
"--depth",
|
||||
"1",
|
||||
]
|
||||
clone_args = ["--depth", "1"]
|
||||
if "ref" in source_data:
|
||||
clone_args.extend(["--branch", source_data["ref"]])
|
||||
git.clone(url=source_data["git_url"], target=self._source_subfolder, args=clone_args)
|
||||
with chdir(self, os.path.join(self.source_folder, self._source_subfolder)):
|
||||
if "ref" in source_data:
|
||||
git.checkout(source_data["ref"])
|
||||
git.run("submodule update --init --recursive --depth 1")
|
||||
if "ref" in source_data:
|
||||
git.run(f"-C {self._source_subfolder} checkout {source_data['ref']}")
|
||||
git.run("-C {} submodule update --init --recursive --depth 1".format(self._source_subfolder))
|
||||
return
|
||||
get(self, **source_data, strip_root=True, destination=self._source_subfolder)
|
||||
raise ValueError("conandata.yml sources entry must provide git_url/ref for this recipe")
|
||||
|
||||
def requirements(self):
|
||||
# [Using a MinGW as tool_requires to build with gcc in Windows](https://docs.conan.io/2/examples/dev_flow/tool_requires/mingw.html#examples-dev-flow-tool-requires-mingw)
|
||||
if not self._is_system_package and self.settings.os == "Windows":
|
||||
self.tool_requires("msys2/cci.latest")
|
||||
def layout(self):
|
||||
cmake_layout(self)
|
||||
|
||||
def package_id(self):
|
||||
if self._is_system_package:
|
||||
self.info.clear()
|
||||
def generate(self):
|
||||
deps = CMakeDeps(self)
|
||||
deps.generate()
|
||||
|
||||
tc = CMakeToolchain(self)
|
||||
tc.variables["WEBOTS_CONTROLLER_NO_PLUGINS"] = bool(self.options.no_plugins)
|
||||
webots_repo_source_dir = os.path.join(self.source_folder, self._source_subfolder).replace("\\", "/")
|
||||
tc.variables["WEBOTS_REPO_SOURCE_DIR"] = webots_repo_source_dir
|
||||
|
||||
libcontroller_version = str(self.version)
|
||||
if libcontroller_version.startswith("r"):
|
||||
libcontroller_version = f"R{libcontroller_version[1:]}"
|
||||
tc.variables["LIBCONTROLLER_VERSION"] = libcontroller_version
|
||||
tc.generate()
|
||||
|
||||
def build(self):
|
||||
if self._is_system_package:
|
||||
return
|
||||
source_root = os.path.join(self.source_folder, self._source_subfolder)
|
||||
if self.settings.os == "Windows":
|
||||
# Webots makefiles invoke POSIX tools and shell fragments, so run MSYS make from bash.
|
||||
bash_exe = None
|
||||
make_exe = None
|
||||
for dep in self.dependencies.build.values():
|
||||
if not dep.ref or not dep.package_folder:
|
||||
continue
|
||||
if dep.ref.name == "msys2":
|
||||
bash_matches = list(Path(dep.package_folder).glob("**/bash.exe"))
|
||||
make_matches = list(Path(dep.package_folder).glob("**/make.exe"))
|
||||
if bash_matches and not bash_exe:
|
||||
bash_exe = str(bash_matches[0])
|
||||
if make_matches and not make_exe:
|
||||
make_exe = str(make_matches[0])
|
||||
if not bash_exe or not make_exe:
|
||||
raise ConanInvalidConfiguration(
|
||||
"Windows build requires bash.exe and make.exe from tool_requires 'msys2'."
|
||||
)
|
||||
mingw_dep = next((dep for dep in self.dependencies.build.values() if dep.ref and dep.ref.name == "mingw-builds"), None)
|
||||
if mingw_dep is None:
|
||||
raise ConanInvalidConfiguration("Windows build requires tool_requires 'mingw-builds'.")
|
||||
env = os.environ.copy()
|
||||
env["WEBOTS_HOME"] = source_root
|
||||
env["PATH"] = os.pathsep.join([
|
||||
os.path.join(mingw_dep.package_folder, "bin"),
|
||||
str(Path(make_exe).parent),
|
||||
env.get("PATH", ""),
|
||||
])
|
||||
drive, tail = os.path.splitdrive(make_exe)
|
||||
msys_make = f"/{drive[0].lower()}{tail.replace('\\', '/')}"
|
||||
for controller_dir in ("c", "cpp"):
|
||||
cwd = os.path.join(source_root, "src", "controller", controller_dir)
|
||||
subprocess.run([bash_exe, "--noprofile", "--norc", "-c", f'"{msys_make}" clean'], cwd=cwd, env=env, check=True)
|
||||
subprocess.run([bash_exe, "--noprofile", "--norc", "-c", f'"{msys_make}" release'], cwd=cwd, env=env, check=True)
|
||||
else:
|
||||
build_env = Environment()
|
||||
build_env.define("WEBOTS_HOME", source_root)
|
||||
with build_env.vars(self).apply():
|
||||
with chdir(self, os.path.join(source_root, "src", "controller", "c")):
|
||||
self.run("make clean")
|
||||
self.run("make release")
|
||||
with chdir(self, os.path.join(source_root, "src", "controller", "cpp")):
|
||||
self.run("make clean")
|
||||
self.run("make release")
|
||||
|
||||
expected_artifacts = {
|
||||
"Linux": ["libController.so", "libCppController.so"],
|
||||
"Macos": ["libController.dylib", "libCppController.dylib"],
|
||||
"Windows": ["Controller.dll", "libController.a", "CppController.dll", "libCppController.a"],
|
||||
}
|
||||
lib_dir = os.path.join(source_root, "lib", "controller")
|
||||
missing = [name for name in expected_artifacts.get(str(self.settings.os), []) if not os.path.exists(os.path.join(lib_dir, name))]
|
||||
if missing:
|
||||
raise ConanException(
|
||||
f"Expected Webots controller artifacts were not produced in '{lib_dir}': {', '.join(missing)}. "
|
||||
"On Windows, the upstream Webots controller build may be incompatible with the current MinGW/MSYS toolchain setup."
|
||||
)
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
|
||||
def package(self):
|
||||
if self._is_system_package:
|
||||
return
|
||||
source_root = os.path.join(self.source_folder, self._source_subfolder)
|
||||
build_root = os.path.join(self.build_folder, self._source_subfolder)
|
||||
copy(self, "LICENSE", src=source_root, dst=os.path.join(self.package_folder, "licenses"))
|
||||
|
||||
copy(self, "*.h", src=os.path.join(source_root, "include", "controller", "c"), dst=os.path.join(self.package_folder, "include", "controller", "c"), keep_path=True)
|
||||
copy(self, "*.hpp", src=os.path.join(source_root, "include", "controller", "cpp"), dst=os.path.join(self.package_folder, "include", "controller", "cpp"), keep_path=True)
|
||||
|
||||
lib_dst = os.path.join(self.package_folder, "lib")
|
||||
bin_dst = os.path.join(self.package_folder, "bin")
|
||||
lib_src_candidates = [
|
||||
os.path.join(build_root, "lib", "controller"),
|
||||
os.path.join(source_root, "lib", "controller"),
|
||||
]
|
||||
for lib_src in lib_src_candidates:
|
||||
copy(self, "*.so*", src=lib_src, dst=lib_dst, keep_path=False)
|
||||
copy(self, "*.dylib*", src=lib_src, dst=lib_dst, keep_path=False)
|
||||
copy(self, "*.a", src=lib_src, dst=lib_dst, keep_path=False)
|
||||
copy(self, "*.dll", src=lib_src, dst=bin_dst, keep_path=False)
|
||||
copy(self, "*.lib", src=lib_src, dst=lib_dst, keep_path=False)
|
||||
|
||||
if self.settings.os == "Linux":
|
||||
patchelf = shutil.which("patchelf")
|
||||
if patchelf:
|
||||
package_lib = os.path.join(self.package_folder, "lib")
|
||||
for soname in ("libController.so", "libCppController.so"):
|
||||
lib_path = os.path.join(package_lib, soname)
|
||||
if os.path.exists(lib_path):
|
||||
self.run(f'"{patchelf}" --set-soname "{soname}" "{lib_path}"')
|
||||
cmake = CMake(self)
|
||||
cmake.install()
|
||||
copy(self, "LICENSE", src=os.path.join(self.source_folder, self._source_subfolder), dst=os.path.join(self.package_folder, "licenses"))
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.set_property("cmake_file_name", "webots-controller")
|
||||
if self._is_system_package:
|
||||
webots_home = self._system_webots_home
|
||||
controller_lib_dir = os.path.join(webots_home, "lib", "controller")
|
||||
controller_include_dir = os.path.join(webots_home, "include", "controller", "c")
|
||||
cpp_controller_include_dir = os.path.join(webots_home, "include", "controller", "cpp")
|
||||
extra_libdirs = []
|
||||
extra_bindirs = []
|
||||
|
||||
self.cpp_info.bindirs = []
|
||||
self.cpp_info.includedirs = []
|
||||
self.cpp_info.libdirs = []
|
||||
controller = self.cpp_info.components["Controller"]
|
||||
controller.libs = ["webots_controller"]
|
||||
controller.includedirs = ["include", "include/controller/c"]
|
||||
controller.set_property("cmake_target_name", "webots-controller::Controller")
|
||||
|
||||
self.buildenv_info.define_path("WEBOTS_HOME", webots_home)
|
||||
self.runenv_info.define_path("WEBOTS_HOME", webots_home)
|
||||
|
||||
if self.settings.os == "Windows":
|
||||
mingw_bin_dir = os.path.join(webots_home, "msys64", "mingw64", "bin")
|
||||
extra_libdirs.append(mingw_bin_dir)
|
||||
extra_bindirs.append(mingw_bin_dir)
|
||||
elif self.settings.os == "Linux":
|
||||
extra_libdirs.append(os.path.join(webots_home, "lib"))
|
||||
|
||||
self.cpp_info.components["controller"].includedirs = [controller_include_dir]
|
||||
self.cpp_info.components["controller"].libdirs = [controller_lib_dir, *extra_libdirs]
|
||||
if self.settings.os == "Windows":
|
||||
self.cpp_info.components["controller"].bindirs = [controller_lib_dir, *extra_bindirs]
|
||||
|
||||
self.cpp_info.components["cpp_controller"].includedirs = [
|
||||
cpp_controller_include_dir,
|
||||
controller_include_dir,
|
||||
]
|
||||
self.cpp_info.components["cpp_controller"].libdirs = [controller_lib_dir, *extra_libdirs]
|
||||
if self.settings.os == "Windows":
|
||||
self.cpp_info.components["cpp_controller"].bindirs = [controller_lib_dir, *extra_bindirs]
|
||||
else:
|
||||
self.cpp_info.components["controller"].includedirs = ["include/controller/c"]
|
||||
self.cpp_info.components["cpp_controller"].includedirs = ["include/controller/cpp", "include/controller/c"]
|
||||
|
||||
self.cpp_info.components["controller"].libs = ["Controller"]
|
||||
self.cpp_info.components["controller"].set_property("cmake_target_name", "Webots::Controller")
|
||||
self.cpp_info.components["cpp_controller"].libs = ["CppController"]
|
||||
self.cpp_info.components["cpp_controller"].set_property("cmake_target_name", "Webots::CppController")
|
||||
self.cpp_info.components["cpp_controller"].requires = ["controller"]
|
||||
cpp_controller = self.cpp_info.components["CppController"]
|
||||
cpp_controller.libs = ["webots_cpp_controller"]
|
||||
cpp_controller.includedirs = ["include", "include/controller/cpp", "include/controller/c"]
|
||||
cpp_controller.requires = ["Controller"]
|
||||
cpp_controller.set_property("cmake_target_name", "webots-controller::CppController")
|
||||
|
||||
if self.settings.os == "Linux":
|
||||
self.cpp_info.components["controller"].system_libs = ["m", "pthread", "dl", "rt"]
|
||||
controller.system_libs = ["m", "pthread", "rt"]
|
||||
if not bool(self.options.no_plugins):
|
||||
controller.system_libs.append("dl")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
diff --git a/motion.c b/motion.c
|
||||
index 02c5e62..3de3b2f 100644
|
||||
--- a/motion.c
|
||||
+++ b/motion.c
|
||||
@@ -45,7 +45,7 @@ typedef struct WbMotionStructPrivate {
|
||||
extern void wb_motor_set_position_no_mutex(WbDeviceTag, double);
|
||||
|
||||
static const int UNDEFINED_TIME = -1;
|
||||
-static const int MAX_LINE = 4096;
|
||||
+#define MAX_LINE 4096
|
||||
static const double UNDEFINED_POSITION = -9999999.9;
|
||||
static WbMotionRef head = NULL;
|
||||
static const char *HEADER = "#WEBOTS_MOTION";
|
||||
diff --git a/robot.c b/robot.c
|
||||
index 6bb2b81..4d4cb6b 100644
|
||||
--- a/robot.c
|
||||
+++ b/robot.c
|
||||
@@ -65,6 +65,10 @@
|
||||
#include "supervisor_private.h"
|
||||
#include "tcp_client.h"
|
||||
|
||||
+#ifdef _WIN32
|
||||
+#undef wb_robot_init
|
||||
+#endif
|
||||
+
|
||||
#ifdef _WIN32
|
||||
#include <windows.h> // GetCommandLine
|
||||
#else
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
add_subdirectory(c)
|
||||
add_subdirectory(cpp)
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
set(WEBOTS_HEADERS_ROOT "${WEBOTS_REPO_SOURCE_DIR}/include/controller/c")
|
||||
set(WEBOTS_INCLUDE_ROOT "${WEBOTS_REPO_SOURCE_DIR}/include")
|
||||
set(WEBOTS_STB_DIR "${WEBOTS_REPO_SOURCE_DIR}/src/stb")
|
||||
set(WEBOTS_CONTROLLER_C_SOURCE_DIR "${WEBOTS_REPO_SOURCE_DIR}/src/controller/c")
|
||||
|
||||
file(GLOB_RECURSE WEBOTS_CONTROLLER_C_PUBLIC_HEADERS CONFIGURE_DEPENDS
|
||||
"${WEBOTS_HEADERS_ROOT}/webots/*.h")
|
||||
file(GLOB_RECURSE WEBOTS_CONTROLLER_PLUGIN_PUBLIC_HEADERS CONFIGURE_DEPENDS
|
||||
"${WEBOTS_INCLUDE_ROOT}/plugins/*.h")
|
||||
|
||||
set(WEBOTS_CONTROLLER_C_CORE_SOURCES
|
||||
abstract_camera.c
|
||||
accelerometer.c
|
||||
altimeter.c
|
||||
ansi_codes.c
|
||||
base64.c
|
||||
brake.c
|
||||
camera.c
|
||||
compass.c
|
||||
connector.c
|
||||
console.c
|
||||
default_robot_window.c
|
||||
device.c
|
||||
display.c
|
||||
distance_sensor.c
|
||||
emitter.c
|
||||
file.c
|
||||
g_image.c
|
||||
g_pipe.c
|
||||
gps.c
|
||||
gyro.c
|
||||
image.c
|
||||
inertial_unit.c
|
||||
joystick.c
|
||||
keyboard.c
|
||||
led.c
|
||||
lidar.c
|
||||
light_sensor.c
|
||||
microphone.c
|
||||
motion.c
|
||||
motor.c
|
||||
mouse.c
|
||||
node.c
|
||||
pen.c
|
||||
percent.c
|
||||
position_sensor.c
|
||||
radar.c
|
||||
range_finder.c
|
||||
receiver.c
|
||||
request.c
|
||||
robot.c
|
||||
scheduler.c
|
||||
sha1.c
|
||||
skin.c
|
||||
speaker.c
|
||||
string.c
|
||||
supervisor.c
|
||||
system.c
|
||||
tcp_client.c
|
||||
touch_sensor.c
|
||||
vacuum_gripper.c)
|
||||
|
||||
set(WEBOTS_CONTROLLER_C_PLUGIN_SOURCES dynamic_library.c html_robot_window.c
|
||||
radio.c remote_control.c robot_window.c)
|
||||
|
||||
set(WEBOTS_CONTROLLER_C_SOURCES ${WEBOTS_CONTROLLER_C_CORE_SOURCES})
|
||||
list(APPEND WEBOTS_CONTROLLER_C_SOURCES ${WEBOTS_CONTROLLER_C_PLUGIN_SOURCES})
|
||||
|
||||
list(TRANSFORM WEBOTS_CONTROLLER_C_SOURCES PREPEND "${WEBOTS_CONTROLLER_C_SOURCE_DIR}/")
|
||||
|
||||
if(MSVC)
|
||||
find_package(Git REQUIRED)
|
||||
set(WEBOTS_CONTROLLER_MSVC_SOURCE_DIR
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/msvc-patched-source")
|
||||
file(REMOVE_RECURSE "${WEBOTS_CONTROLLER_MSVC_SOURCE_DIR}")
|
||||
file(COPY "${WEBOTS_CONTROLLER_C_SOURCE_DIR}/"
|
||||
DESTINATION "${WEBOTS_CONTROLLER_MSVC_SOURCE_DIR}")
|
||||
file(RELATIVE_PATH WEBOTS_CONTROLLER_MSVC_SOURCE_RELATIVE_DIR
|
||||
"${CMAKE_SOURCE_DIR}" "${WEBOTS_CONTROLLER_MSVC_SOURCE_DIR}")
|
||||
execute_process(
|
||||
COMMAND
|
||||
"${GIT_EXECUTABLE}" apply
|
||||
"--directory=${WEBOTS_CONTROLLER_MSVC_SOURCE_RELATIVE_DIR}"
|
||||
"${CMAKE_SOURCE_DIR}/patches/msvc-controller-c.patch"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
RESULT_VARIABLE WEBOTS_CONTROLLER_MSVC_PATCH_RESULT)
|
||||
if(NOT WEBOTS_CONTROLLER_MSVC_PATCH_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to apply MSVC controller C source patch")
|
||||
endif()
|
||||
|
||||
list(TRANSFORM WEBOTS_CONTROLLER_C_SOURCES
|
||||
REPLACE "^${WEBOTS_CONTROLLER_C_SOURCE_DIR}" "${WEBOTS_CONTROLLER_MSVC_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
add_library(webots_controller ${WEBOTS_CONTROLLER_C_SOURCES})
|
||||
add_library(webots-controller::webots_controller ALIAS webots_controller)
|
||||
add_library(webots-controller::Controller ALIAS webots_controller)
|
||||
|
||||
target_sources(
|
||||
webots_controller
|
||||
PUBLIC FILE_SET
|
||||
webots_c_headers
|
||||
TYPE
|
||||
HEADERS
|
||||
BASE_DIRS
|
||||
"${WEBOTS_HEADERS_ROOT}"
|
||||
FILES
|
||||
${WEBOTS_CONTROLLER_C_PUBLIC_HEADERS}
|
||||
FILE_SET
|
||||
webots_plugin_headers
|
||||
TYPE
|
||||
HEADERS
|
||||
BASE_DIRS
|
||||
"${WEBOTS_INCLUDE_ROOT}"
|
||||
FILES
|
||||
${WEBOTS_CONTROLLER_PLUGIN_PUBLIC_HEADERS})
|
||||
|
||||
if(WIN32)
|
||||
set_target_properties(webots_controller PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS
|
||||
ON)
|
||||
target_link_libraries(webots_controller PRIVATE ws2_32)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
target_sources(webots_controller
|
||||
PRIVATE "${libunistd_SOURCE_DIR}/unistd/clock_gettime.cpp")
|
||||
target_link_libraries(webots_controller
|
||||
PRIVATE webots_controller_msvc_unix_headers)
|
||||
target_compile_definitions(webots_controller PRIVATE _USE_MATH_DEFINES
|
||||
O_TEXT=_O_TEXT)
|
||||
target_compile_options(webots_controller PRIVATE /utf-8)
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
webots_controller
|
||||
PUBLIC $<BUILD_INTERFACE:${WEBOTS_INCLUDE_ROOT}>
|
||||
$<BUILD_INTERFACE:${WEBOTS_HEADERS_ROOT}> $<INSTALL_INTERFACE:include>
|
||||
$<INSTALL_INTERFACE:include/controller/c>
|
||||
PRIVATE ${WEBOTS_STB_DIR} ${WEBOTS_CONTROLLER_C_SOURCE_DIR}
|
||||
${WEBOTS_CONTROLLER_MSVC_SOURCE_DIR})
|
||||
|
||||
target_compile_definitions(
|
||||
webots_controller PRIVATE LIBCONTROLLER_VERSION="${LIBCONTROLLER_VERSION}")
|
||||
if(WEBOTS_CONTROLLER_NO_PLUGINS)
|
||||
target_compile_definitions(webots_controller
|
||||
PUBLIC WEBOTS_CONTROLLER_NO_PLUGINS=1)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
target_link_libraries(webots_controller PRIVATE m)
|
||||
if(NOT APPLE)
|
||||
target_link_libraries(webots_controller PRIVATE pthread rt)
|
||||
if(NOT WEBOTS_CONTROLLER_NO_PLUGINS)
|
||||
target_link_libraries(webots_controller PRIVATE dl)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS webots_controller
|
||||
RUNTIME DESTINATION "bin"
|
||||
LIBRARY DESTINATION "lib"
|
||||
ARCHIVE DESTINATION "lib"
|
||||
FILE_SET webots_c_headers
|
||||
DESTINATION "include/controller/c"
|
||||
FILE_SET webots_plugin_headers
|
||||
DESTINATION "include")
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
set(WEBOTS_CONTROLLER_CPP_SOURCE_DIR "${WEBOTS_REPO_SOURCE_DIR}/src/controller/cpp")
|
||||
|
||||
set(WEBOTS_CONTROLLER_CPP_SOURCES
|
||||
Accelerometer.cpp
|
||||
Altimeter.cpp
|
||||
Brake.cpp
|
||||
Camera.cpp
|
||||
Compass.cpp
|
||||
Connector.cpp
|
||||
Device.cpp
|
||||
Display.cpp
|
||||
DistanceSensor.cpp
|
||||
Emitter.cpp
|
||||
Field.cpp
|
||||
GPS.cpp
|
||||
Gyro.cpp
|
||||
InertialUnit.cpp
|
||||
Joystick.cpp
|
||||
Keyboard.cpp
|
||||
LED.cpp
|
||||
Lidar.cpp
|
||||
LightSensor.cpp
|
||||
Motion.cpp
|
||||
Motor.cpp
|
||||
Mouse.cpp
|
||||
Node.cpp
|
||||
Pen.cpp
|
||||
PositionSensor.cpp
|
||||
Proto.cpp
|
||||
Radar.cpp
|
||||
RangeFinder.cpp
|
||||
Receiver.cpp
|
||||
Robot.cpp
|
||||
Skin.cpp
|
||||
Speaker.cpp
|
||||
Supervisor.cpp
|
||||
TouchSensor.cpp
|
||||
VacuumGripper.cpp)
|
||||
|
||||
list(TRANSFORM WEBOTS_CONTROLLER_CPP_SOURCES PREPEND "${WEBOTS_CONTROLLER_CPP_SOURCE_DIR}/")
|
||||
|
||||
file(GLOB_RECURSE WEBOTS_CONTROLLER_CPP_PUBLIC_HEADERS CONFIGURE_DEPENDS
|
||||
"${WEBOTS_REPO_SOURCE_DIR}/include/controller/cpp/webots/*.hpp")
|
||||
|
||||
add_library(webots_cpp_controller ${WEBOTS_CONTROLLER_CPP_SOURCES})
|
||||
add_library(webots-controller::webots_cpp_controller ALIAS
|
||||
webots_cpp_controller)
|
||||
add_library(webots-controller::CppController ALIAS webots_cpp_controller)
|
||||
add_library(webots-controller::webots-controller ALIAS webots_cpp_controller)
|
||||
|
||||
target_sources(
|
||||
webots_cpp_controller
|
||||
PUBLIC FILE_SET
|
||||
webots_cpp_headers
|
||||
TYPE
|
||||
HEADERS
|
||||
BASE_DIRS
|
||||
"${WEBOTS_REPO_SOURCE_DIR}/include/controller/cpp"
|
||||
FILES
|
||||
${WEBOTS_CONTROLLER_CPP_PUBLIC_HEADERS})
|
||||
|
||||
if(WIN32)
|
||||
set_target_properties(webots_cpp_controller
|
||||
PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
webots_cpp_controller
|
||||
PUBLIC $<BUILD_INTERFACE:${WEBOTS_REPO_SOURCE_DIR}/include/controller/cpp>
|
||||
$<INSTALL_INTERFACE:include/controller/cpp>)
|
||||
|
||||
target_link_libraries(webots_cpp_controller PUBLIC webots_controller)
|
||||
|
||||
install(
|
||||
TARGETS webots_cpp_controller
|
||||
RUNTIME DESTINATION "bin"
|
||||
LIBRARY DESTINATION "lib"
|
||||
ARCHIVE DESTINATION "lib"
|
||||
FILE_SET webots_cpp_headers
|
||||
DESTINATION "include/controller/cpp")
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# Ignore everything
|
||||
*
|
||||
# But do not ignore files with extensions (like .c, .py, .md)
|
||||
!*.*
|
||||
# Do not ignore directories
|
||||
!*/
|
||||
*.dll
|
||||
*.exe
|
||||
build/
|
||||
*.pyc
|
||||
*.json
|
||||
|
|
@ -1,46 +1,58 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
project(test_package CXX)
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
project(test_package C CXX)
|
||||
|
||||
find_package(webots-controller REQUIRED CONFIG)
|
||||
|
||||
add_executable(test_package test_package.cpp)
|
||||
target_link_libraries(test_package PRIVATE Webots::CppController)
|
||||
target_link_libraries(test_package PRIVATE webots-controller::CppController)
|
||||
|
||||
add_executable(test_package_c test_package.c)
|
||||
target_link_libraries(test_package_c PRIVATE webots-controller::Controller)
|
||||
|
||||
if(POLICY CMP0207)
|
||||
cmake_policy(SET CMP0207 NEW)
|
||||
endif()
|
||||
|
||||
# Webots controllers rely on seeing shared deps in the same directory as the executable.
|
||||
install(TARGETS test_package
|
||||
RUNTIME_DEPENDENCY_SET test_package_runtime_deps
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib)
|
||||
set(_extra_runtime_dirs)
|
||||
if(CMAKE_PREFIX_PATH)
|
||||
foreach(prefix IN LISTS CMAKE_PREFIX_PATH)
|
||||
list(APPEND _extra_runtime_dirs "${prefix}/lib")
|
||||
endforeach()
|
||||
endif()
|
||||
if(WIN32 AND DEFINED ENV{MINGW_HOME})
|
||||
list(APPEND _extra_runtime_dirs "$ENV{MINGW_HOME}/bin")
|
||||
endif()
|
||||
|
||||
# Webots controllers rely on seeing shared deps in the same directory as the
|
||||
# executable. Destination therefore change to "."
|
||||
install(
|
||||
TARGETS test_package test_package_c RUNTIME_DEPENDENCY_SET
|
||||
test_package_runtime_deps
|
||||
RUNTIME DESTINATION .
|
||||
LIBRARY DESTINATION .
|
||||
ARCHIVE DESTINATION .)
|
||||
|
||||
if(WIN32)
|
||||
# for single-config generators.
|
||||
set(_runtime_dependency_directories)
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" _conan_build_type)
|
||||
set(_webots_bin_dirs_var "webots-controller_BIN_DIRS_${_conan_build_type}")
|
||||
if(DEFINED ${_webots_bin_dirs_var})
|
||||
list(APPEND _runtime_dependency_directories ${${_webots_bin_dirs_var}})
|
||||
endif()
|
||||
if(DEFINED ENV{MINGW_HOME})
|
||||
list(APPEND _runtime_dependency_directories "$ENV{MINGW_HOME}/bin")
|
||||
endif()
|
||||
install(
|
||||
RUNTIME_DEPENDENCY_SET test_package_runtime_deps
|
||||
DIRECTORIES ${_runtime_dependency_directories}
|
||||
PRE_EXCLUDE_REGEXES
|
||||
"^api-ms-win-.*"
|
||||
"^ext-ms-.*"
|
||||
POST_EXCLUDE_REGEXES
|
||||
".*/system32/.*"
|
||||
".*/Windows/.*"
|
||||
".*/SysWOW64/.*"
|
||||
DESTINATION bin)
|
||||
set(_runtime_dep_pre_excludes "^api-ms-win-.*" "^ext-ms-.*")
|
||||
set(_runtime_dep_post_excludes ".*/system32/.*" ".*/Windows/.*"
|
||||
".*/SysWOW64/.*")
|
||||
else()
|
||||
install(
|
||||
RUNTIME_DEPENDENCY_SET test_package_runtime_deps
|
||||
DESTINATION bin)
|
||||
set(_runtime_dep_pre_excludes
|
||||
[[libc\.so\..*]] [[libgcc_s\.so\..*]] [[libm\.so\..*]]
|
||||
[[libstdc\+\+\.so\..*]] [[ld-linux-x86-64\.so\..*]])
|
||||
set(_runtime_dep_post_excludes [[^/lib.*]] [[^/usr/lib.*]])
|
||||
endif()
|
||||
|
||||
install(
|
||||
RUNTIME_DEPENDENCY_SET
|
||||
test_package_runtime_deps
|
||||
PRE_EXCLUDE_REGEXES
|
||||
${_runtime_dep_pre_excludes}
|
||||
POST_EXCLUDE_REGEXES
|
||||
${_runtime_dep_post_excludes}
|
||||
DIRECTORIES
|
||||
${CONAN_RUNTIME_LIB_DIRS}
|
||||
${CMAKE_SYSROOT}/lib
|
||||
${_extra_runtime_dirs}
|
||||
DESTINATION
|
||||
.)
|
||||
|
|
|
|||
|
|
@ -21,8 +21,11 @@ class TestPackageConan(ConanFile):
|
|||
cmake.build()
|
||||
|
||||
def test(self):
|
||||
# check if RUNTIME_DEPENDENCY_SET work
|
||||
cmake = CMake(self)
|
||||
cmake.install()
|
||||
if can_run(self):
|
||||
exe = os.path.join(self.source_folder, "bin", "test_package")
|
||||
exe = os.path.join(self.source_folder, "test_package")
|
||||
self.run(exe, env="conanrun")
|
||||
exe = os.path.join(self.source_folder, "test_package_c")
|
||||
self.run(exe, env="conanrun")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
#include <webots/robot.h>
|
||||
|
||||
int main(void) {
|
||||
double (*c_symbol)(void) = &wb_robot_get_time;
|
||||
(void)c_symbol;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -9,4 +9,4 @@ int main() {
|
|||
(void)c_symbol;
|
||||
std::cout << "Success!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue