From d13836eb1e1919f483ab72e33251611e28170238 Mon Sep 17 00:00:00 2001 From: Mara Bos <m-ou.se@m-ou.se> Date: Sun, 18 Nov 2018 19:05:08 +0100 Subject: [PATCH] Add dynamic modules on Posix. You can now add `DYNAMIC` as an option to `px4_add_module`, which will cause that module to no longer be compiled into the px4 executable, but instead produce a separate shared library file, which can be loaded and executed with the new `dyn` command: pxh> dyn ./hello.px4mod start This will load the shared object file `hello.px4mod` if it wasn't already loaded, and execute its main function with the given arguments. --- cmake/common/px4_base.cmake | 25 +++++-- cmake/configs/posix_rpi_common.cmake | 1 + cmake/configs/posix_sitl_default.cmake | 1 + platforms/posix/cmake/px4_impl_os.cmake | 5 ++ src/systemcmds/dyn/CMakeLists.txt | 8 +++ src/systemcmds/dyn/dyn.cpp | 91 +++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 src/systemcmds/dyn/CMakeLists.txt create mode 100644 src/systemcmds/dyn/dyn.cpp diff --git a/cmake/common/px4_base.cmake b/cmake/common/px4_base.cmake index 60703be25a..58ed8fe3c6 100644 --- a/cmake/common/px4_base.cmake +++ b/cmake/common/px4_base.cmake @@ -163,6 +163,7 @@ endfunction() # [ SRCS <list> ] # [ MODULE_CONFIG <list> ] # [ EXTERNAL ] +# [ DYNAMIC ] # ) # # Input: @@ -178,10 +179,12 @@ endfunction() # INCLUDES : include directories # DEPENDS : targets which this module depends on # EXTERNAL : flag to indicate that this module is out-of-tree +# DYNAMIC : don't compile into the px4 binary, but build a separate dynamically loadable module (posix) # UNITY_BUILD : merge all source files and build this module as a single compilation unit # # Output: # Static library with name matching MODULE. +# (Or a shared library when DYNAMIC is specified.) # # Example: # px4_add_module(MODULE test @@ -198,7 +201,7 @@ function(px4_add_module) NAME px4_add_module ONE_VALUE MODULE MAIN STACK STACK_MAIN STACK_MAX PRIORITY MULTI_VALUE COMPILE_FLAGS LINK_FLAGS SRCS INCLUDES DEPENDS MODULE_CONFIG - OPTIONS EXTERNAL UNITY_BUILD + OPTIONS EXTERNAL DYNAMIC UNITY_BUILD REQUIRED MODULE MAIN ARGN ${ARGN}) @@ -226,16 +229,30 @@ function(px4_add_module) add_library(${MODULE} STATIC EXCLUDE_FROM_ALL ${CMAKE_CURRENT_BINARY_DIR}/${MODULE}_unity.cpp) target_include_directories(${MODULE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + elseif(DYNAMIC AND MAIN AND (${OS} STREQUAL "posix")) + add_library(${MODULE} SHARED ${SRCS}) + target_compile_definitions(${MODULE} PRIVATE ${MAIN}_main=px4_module_main) + set_target_properties(${MODULE} PROPERTIES + PREFIX "" + SUFFIX ".px4mod" + ) + target_link_libraries(${MODULE} PRIVATE px4) + if(APPLE) + # Postpone resolving symbols until loading time, which is the default on most systems, but not Mac. + set_target_properties(${MODULE} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") + endif() else() add_library(${MODULE} STATIC EXCLUDE_FROM_ALL ${SRCS}) endif() # all modules can potentially use parameters and uORB add_dependencies(${MODULE} uorb_headers) - target_link_libraries(${MODULE} PRIVATE prebuild_targets parameters_interface platforms__common px4_layer systemlib) - set_property(GLOBAL APPEND PROPERTY PX4_MODULE_LIBRARIES ${MODULE}) - set_property(GLOBAL APPEND PROPERTY PX4_MODULE_PATHS ${CMAKE_CURRENT_SOURCE_DIR}) + if(NOT DYNAMIC) + target_link_libraries(${MODULE} PRIVATE prebuild_targets parameters_interface platforms__common px4_layer systemlib) + set_property(GLOBAL APPEND PROPERTY PX4_MODULE_LIBRARIES ${MODULE}) + set_property(GLOBAL APPEND PROPERTY PX4_MODULE_PATHS ${CMAKE_CURRENT_SOURCE_DIR}) + endif() px4_add_optimization_flags_for_target(${MODULE}) diff --git a/cmake/configs/posix_rpi_common.cmake b/cmake/configs/posix_rpi_common.cmake index 0bba4a1cfe..2b8968b793 100644 --- a/cmake/configs/posix_rpi_common.cmake +++ b/cmake/configs/posix_rpi_common.cmake @@ -34,6 +34,7 @@ set(config_module_list # System commands # systemcmds/param + systemcmds/dyn systemcmds/led_control systemcmds/mixer systemcmds/ver diff --git a/cmake/configs/posix_sitl_default.cmake b/cmake/configs/posix_sitl_default.cmake index ca43114198..a8a5cdbb96 100644 --- a/cmake/configs/posix_sitl_default.cmake +++ b/cmake/configs/posix_sitl_default.cmake @@ -24,6 +24,7 @@ set(config_module_list #systemcmds/bl_update #systemcmds/config #systemcmds/dumpfile + systemcmds/dyn systemcmds/esc_calib systemcmds/led_control systemcmds/mixer diff --git a/platforms/posix/cmake/px4_impl_os.cmake b/platforms/posix/cmake/px4_impl_os.cmake index ed29e8347a..d21bccd3fc 100644 --- a/platforms/posix/cmake/px4_impl_os.cmake +++ b/platforms/posix/cmake/px4_impl_os.cmake @@ -48,6 +48,11 @@ include(common/px4_base) list(APPEND CMAKE_MODULE_PATH ${PX4_SOURCE_DIR}/cmake/posix) +# This makes it possible to dynamically load code which depends on symbols +# inside the px4 executable. +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_ENABLE_EXPORTS ON) + #============================================================================= # # px4_posix_generate_builtin_commands diff --git a/src/systemcmds/dyn/CMakeLists.txt b/src/systemcmds/dyn/CMakeLists.txt new file mode 100644 index 0000000000..1d2ec09f5f --- /dev/null +++ b/src/systemcmds/dyn/CMakeLists.txt @@ -0,0 +1,8 @@ +px4_add_module( + MODULE systemcmds__dyn + MAIN dyn + SRCS + dyn.cpp + ) + +target_link_libraries(systemcmds__dyn PUBLIC dl) diff --git a/src/systemcmds/dyn/dyn.cpp b/src/systemcmds/dyn/dyn.cpp new file mode 100644 index 0000000000..150d42f146 --- /dev/null +++ b/src/systemcmds/dyn/dyn.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** + * + * Copyright (C) 2018 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name PX4 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 OWNER 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. + * + ****************************************************************************/ + +/** + * @file dyn.cpp + * + * @author Mara Bos <m-ou.se@m-ou.se> + */ + +#include <dlfcn.h> + +#include <px4_module.h> +#include <px4_log.h> + +static void usage(); + +extern "C" { + __EXPORT int dyn_main(int argc, char *argv[]); +} + +static void usage() +{ + PRINT_MODULE_DESCRIPTION( + R"( +### Description +Load and run a dynamic PX4 module, which was not compiled into the PX4 binary. + +### Example +$ dyn ./hello.px4mod start + +)"); + PRINT_MODULE_USAGE_NAME_SIMPLE("dyn", "command"); + PRINT_MODULE_USAGE_ARG("<file>", "File containing the module", false); + PRINT_MODULE_USAGE_ARG("arguments...", "Arguments to the module", true); +} + +int dyn_main(int argc, char *argv[]) { + if (argc < 2) { + usage(); + return 1; + } + + void *handle = dlopen(argv[1], RTLD_NOW); + + if (!handle) { + PX4_ERR("%s", dlerror()); + return 1; + } + + void *main_address = dlsym(handle, "px4_module_main"); + + if (!main_address) { + PX4_ERR("%s", dlerror()); + dlclose(handle); + return 1; + } + + auto main_function = (int (*)(int, char **))main_address; + + return main_function(argc - 1, argv + 1); +} -- GitLab