From 252a9b0c1774790fb9c25735d5a09c27dba895db Mon Sep 17 00:00:00 2001 From: Karsten Sperling Date: Tue, 11 Jun 2024 15:58:15 +1200 Subject: [PATCH] libubus: Make UBUS_* macros work cleanly in C++ C++ is picky about initializer order, and (depending on flags) missing fields. This fix makes UBUS_METHOD_* and UBUS_OBJECT_TYPE initialize all fields of the respective structs in the correct order. Also replace BIT(x) with an explicit expression since BIT() may not be defined. Signed-off-by: Karsten Sperling --- CMakeLists.txt | 9 +++++---- libubus.h | 41 +++++++++++++++++++++------------------- tests/CMakeLists.txt | 11 +++++++++++ tests/test-cplusplus.cpp | 34 +++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 23 deletions(-) create mode 100644 tests/test-cplusplus.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ae853b..03c3012 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,12 +2,13 @@ cmake_minimum_required(VERSION 3.13) PROJECT(ubus C) -ADD_DEFINITIONS(-Wall -Werror) +ADD_COMPILE_OPTIONS(-Wall -Werror) IF(CMAKE_C_COMPILER_VERSION VERSION_GREATER 6) - ADD_DEFINITIONS(-Wextra -Werror=implicit-function-declaration) - ADD_DEFINITIONS(-Wformat -Werror=format-security -Werror=format-nonliteral) + ADD_COMPILE_OPTIONS(-Wextra -Wformat -Werror=format-security -Werror=format-nonliteral) + ADD_COMPILE_OPTIONS($<$:-Werror=implicit-function-declaration>) ENDIF() -ADD_DEFINITIONS(-Os -std=gnu99 -g3 -Wmissing-declarations -Wno-unused-parameter) +ADD_COMPILE_OPTIONS(-Os -g3 -Wmissing-declarations -Wno-unused-parameter) +ADD_COMPILE_OPTIONS($<$:-std=gnu99>) OPTION(BUILD_LUA "build Lua plugin" ON) OPTION(BUILD_EXAMPLES "build examples" ON) diff --git a/libubus.h b/libubus.h index b74a823..fcf62c8 100644 --- a/libubus.h +++ b/libubus.h @@ -69,41 +69,44 @@ typedef bool (*ubus_new_object_handler_t)(struct ubus_context *ctx, struct ubus_ { \ .name = _name, \ .id = 0, \ - .n_methods = ARRAY_SIZE(_methods), \ - .methods = _methods \ + .methods = _methods, \ + .n_methods = ARRAY_SIZE(_methods) \ } -#define __UBUS_METHOD_NOARG(_name, _handler, _tags) \ - .name = _name, \ - .handler = _handler, \ +#define __UBUS_METHOD_BASE(_name, _handler, _mask, _tags) \ + .name = _name, \ + .handler = _handler, \ + .mask = _mask, \ .tags = _tags -#define __UBUS_METHOD(_name, _handler, _policy, _tags) \ - __UBUS_METHOD_NOARG(_name, _handler, _tags), \ - .policy = _policy, \ +#define __UBUS_METHOD_NOARG(_name, _handler, _mask, _tags) \ + __UBUS_METHOD_BASE(_name, _handler, _mask, _tags), \ + .policy = NULL, \ + .n_policy = 0 + +#define __UBUS_METHOD(_name, _handler, _mask, _policy, _tags) \ + __UBUS_METHOD_BASE(_name, _handler, _mask, _tags), \ + .policy = _policy, \ .n_policy = ARRAY_SIZE(_policy) #define UBUS_METHOD(_name, _handler, _policy) \ - { __UBUS_METHOD(_name, _handler, _policy, 0) } + { __UBUS_METHOD(_name, _handler, 0, _policy, 0) } #define UBUS_METHOD_TAG(_name, _handler, _policy, _tags)\ - { __UBUS_METHOD(_name, _handler, _policy, _tags) } + { __UBUS_METHOD(_name, _handler, 0, _policy, _tags) } #define UBUS_METHOD_MASK(_name, _handler, _policy, _mask) \ - { \ - __UBUS_METHOD(_name, _handler, _policy, 0),\ - .mask = _mask \ - } + { __UBUS_METHOD(_name, _handler, _mask, _policy, 0) } #define UBUS_METHOD_NOARG(_name, _handler) \ - { __UBUS_METHOD_NOARG(_name, _handler, 0) } + { __UBUS_METHOD_NOARG(_name, _handler, 0, 0) } #define UBUS_METHOD_TAG_NOARG(_name, _handler, _tags) \ - { __UBUS_METHOD_NOARG(_name, _handler, _tags) } + { __UBUS_METHOD_NOARG(_name, _handler, 0, _tags) } -#define UBUS_TAG_STATUS BIT(0) -#define UBUS_TAG_ADMIN BIT(1) -#define UBUS_TAG_PRIVATE BIT(2) +#define UBUS_TAG_STATUS (1ul << 0) +#define UBUS_TAG_ADMIN (1ul << 1) +#define UBUS_TAG_PRIVATE (1ul << 2) struct ubus_method { const char *name; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0cb3342..5549a40 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,6 +6,12 @@ MACRO(ADD_UNIT_TEST name) TARGET_INCLUDE_DIRECTORIES(${name} PRIVATE ${PROJECT_SOURCE_DIR}) ENDMACRO(ADD_UNIT_TEST) +MACRO(ADD_UNIT_TEST_CPP name) + ADD_EXECUTABLE(${name} ${name}.cpp) + TARGET_LINK_LIBRARIES(${name} ubox blobmsg_json json_script ${json}) + TARGET_INCLUDE_DIRECTORIES(${name} PRIVATE ${PROJECT_SOURCE_DIR}) +ENDMACRO(ADD_UNIT_TEST_CPP) + FILE(GLOB test_cases "test-*.c") FOREACH(test_case ${test_cases}) GET_FILENAME_COMPONENT(test_case ${test_case} NAME_WE) @@ -13,6 +19,11 @@ FOREACH(test_case ${test_cases}) ADD_UNIT_TEST_SAN(${test_case}) ENDFOREACH(test_case) +ENABLE_LANGUAGE(CXX) +ADD_COMPILE_OPTIONS($<$:-std=gnu++11>) +ADD_UNIT_TEST_CPP(test-cplusplus) +ADD_TEST(NAME cplusplus COMMAND test-cplusplus) + IF(CMAKE_C_COMPILER_ID STREQUAL "Clang") ADD_SUBDIRECTORY(fuzz) ENDIF() diff --git a/tests/test-cplusplus.cpp b/tests/test-cplusplus.cpp new file mode 100644 index 0000000..89c5ffb --- /dev/null +++ b/tests/test-cplusplus.cpp @@ -0,0 +1,34 @@ +#include "libubus.h" + +// Ensure UBUS_* macros can be used from C++ + +static int handler(ubus_context *, ubus_object *, ubus_request_data *, const char *, blob_attr *) +{ + return 0; +} + +enum { + HELLO_ID, + HELLO_MSG, +}; + +constexpr blobmsg_policy hello_policy[] = { + [HELLO_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 }, + [HELLO_MSG] = { .name = "msg", .type = BLOBMSG_TYPE_STRING }, +}; + +constexpr ubus_method test_methods[] = { + UBUS_METHOD("hello1", handler, hello_policy), + UBUS_METHOD_TAG("hello2", handler, hello_policy, UBUS_TAG_ADMIN | UBUS_TAG_PRIVATE), + UBUS_METHOD_MASK("hello3", handler, hello_policy, 0), + UBUS_METHOD_NOARG("hello4", handler), + UBUS_METHOD_TAG_NOARG("hello5", handler, UBUS_TAG_STATUS), +}; + +constexpr ubus_object_type test_object_type = UBUS_OBJECT_TYPE("test", test_methods); + +int main() +{ + (void) test_object_type; + return 0; +} -- 2.30.2