diff --git a/.gitignore b/.gitignore index 0ba1c63..b5a7db5 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,7 @@ vcpkg_installed/ # test output & cache Testing/ .cache/ + +# user +/CMakeUserPresets.json + diff --git a/CMakeLists.txt b/CMakeLists.txt index e69de29..2579c84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.21) +project(webots_controller VERSION 0.1.0 LANGUAGES C) + +option(WEBOTS_CONTROLLER_NO_PLUGINS "Disable runtime plugin loading (dlopen/LoadLibrary paths)." ON) + +add_subdirectory(src/controller) diff --git a/README.md b/README.md index eed3359..fd98b5f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ # webots-controller -Non official webots controller pack + +Unofficial Conan package for Webots controller sources. + +## Options + +- `no_plugins` (default: `True`): disables runtime plugin loading paths (`dlopen` / `LoadLibrary`) by compiling stub implementations for robot window and remote control plugin entry points. + +By default, headers are read from `./include/controller/c` and stb from `./src/stb`, matching this repo layout. + +## Example + +```bash +conan create . \ + -o webots-controller/*:no_plugins=True +``` diff --git a/conanfile.py b/conanfile.py index e69de29..4fa7566 100644 --- a/conanfile.py +++ b/conanfile.py @@ -0,0 +1,52 @@ +from conan import ConanFile +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.files import copy + + +class WebotsControllerConan(ConanFile): + name = "webots-controller" + version = "0.1.0" + package_type = "library" + + settings = "os", "arch", "compiler", "build_type" + 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/*", "LICENSE", "README.md" + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def layout(self): + cmake_layout(self) + + def generate(self): + deps = CMakeDeps(self) + deps.generate() + + tc = CMakeToolchain(self) + tc.variables["BUILD_SHARED_LIBS"] = bool(self.options.shared) + tc.variables["WEBOTS_CONTROLLER_NO_PLUGINS"] = bool(self.options.no_plugins) + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() + copy(self, "LICENSE", src=self.source_folder, dst=f"{self.package_folder}/licenses") + + def package_info(self): + self.cpp_info.libs = ["webots_controller"] diff --git a/src/controller/CMakeLists.txt b/src/controller/CMakeLists.txt new file mode 100644 index 0000000..20bc4cc --- /dev/null +++ b/src/controller/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(c) diff --git a/src/controller/c/CMakeLists.txt b/src/controller/c/CMakeLists.txt new file mode 100644 index 0000000..6a24c56 --- /dev/null +++ b/src/controller/c/CMakeLists.txt @@ -0,0 +1,116 @@ +set(WEBOTS_HEADERS_ROOT "${CMAKE_SOURCE_DIR}/include/controller/c") +set(WEBOTS_INCLUDE_ROOT "${CMAKE_SOURCE_DIR}/include") +set(WEBOTS_STB_DIR "${CMAKE_SOURCE_DIR}/src/stb") + +if(NOT EXISTS "${WEBOTS_HEADERS_ROOT}/webots") + message(FATAL_ERROR "Missing required repo path: ${WEBOTS_HEADERS_ROOT}/webots") +endif() + +if(NOT EXISTS "${WEBOTS_STB_DIR}/stb_image.h") + message(FATAL_ERROR "Missing required repo path: ${WEBOTS_STB_DIR}/stb_image.h") +endif() + +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_STUB_SOURCES + no_plugins_stubs.c +) + +set(WEBOTS_CONTROLLER_C_SOURCES ${WEBOTS_CONTROLLER_C_CORE_SOURCES}) +if(WEBOTS_CONTROLLER_NO_PLUGINS) + list(APPEND WEBOTS_CONTROLLER_C_SOURCES ${WEBOTS_CONTROLLER_C_STUB_SOURCES}) +else() + list(APPEND WEBOTS_CONTROLLER_C_SOURCES ${WEBOTS_CONTROLLER_C_PLUGIN_SOURCES}) +endif() + +# add_library without STATIC/SHARED follows BUILD_SHARED_LIBS automatically in cmake. +add_library(webots_controller ${WEBOTS_CONTROLLER_C_SOURCES}) +add_library(webots-controller::webots_controller ALIAS webots_controller) + +if(WIN32) + set_target_properties(webots_controller PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif() + +target_include_directories(webots_controller + PRIVATE + ${WEBOTS_HEADERS_ROOT} + ${WEBOTS_INCLUDE_ROOT} + ${WEBOTS_STB_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_compile_definitions(webots_controller PRIVATE LIBCONTROLLER_VERSION="custom") +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) diff --git a/src/controller/c/no_plugins_stubs.c b/src/controller/c/no_plugins_stubs.c new file mode 100644 index 0000000..f4ebfd0 --- /dev/null +++ b/src/controller/c/no_plugins_stubs.c @@ -0,0 +1,110 @@ +#include + +#include "html_robot_window_private.h" +#include "remote_control_private.h" +#include "robot_window_private.h" + +#include + +void robot_window_init(const char *library_name) { + (void)library_name; +} + +bool robot_window_is_initialized() { + return false; +} + +const char *robot_window_get_last_error() { + return "plugins disabled"; +} + +void robot_window_pre_update_gui() { +} + +void robot_window_update_gui() { +} + +void robot_window_read_sensors() { +} + +void robot_window_write_actuators() { +} + +void robot_window_cleanup() { +} + +void robot_window_show() { +} + +void *wb_robot_window_custom_function(void *args) { + (void)args; + return NULL; +} + +bool wb_robot_window_load_library(const char *name) { + (void)name; + return false; +} + +void html_robot_window_init() { +} + +void html_robot_window_step(int step) { + (void)step; +} + +void html_robot_window_cleanup() { +} + +void remote_control_init(const char *library_name) { + (void)library_name; +} + +void remote_control_cleanup() { +} + +bool remote_control_is_initialized() { + return false; +} + +const char *remote_control_get_last_error() { + return "plugins disabled"; +} + +bool remote_control_start(const char *args) { + (void)args; + return false; +} + +void remote_control_stop() { +} + +void remote_control_stop_actuators() { +} + +bool remote_control_has_failed() { + return false; +} + +void remote_control_step(int duration) { + (void)duration; +} + +WbRequest *remote_control_handle_messages(WbRequest *r) { + return r; +} + +void remote_control_handle_one_message(WbRequest *r, WbDeviceTag tag) { + (void)r; + (void)tag; +} + +bool remote_control_is_function_defined(const char *function_name) { + (void)function_name; + return false; +} + +void *wb_remote_control_custom_function(void *arg) { + (void)arg; + return NULL; +}