[PATCH] libubus: Make UBUS_* macros work cleanly in C++
Karsten Sperling
ksperling at apple.com
Tue Aug 13 22:26:13 PDT 2024
Note: I’ve also submitted this patch as a GitHub PR (https://github.com/openwrt/ubus/pull/3) but I’m not sure anyone actually looks there for contributions, so I’m submitting it as a patch here as well.
-- >8 --
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, making those macros usable from C++.
Also replace BIT(x) with an explicit expression since BIT() may not be defined.
Signed-off-by: Karsten Sperling <ksperling at apple.com>
---
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($<$<COMPILE_LANGUAGE:C>:-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($<$<COMPILE_LANGUAGE:C>:-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($<$<COMPILE_LANGUAGE:CXX>:-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.39.2
More information about the openwrt-devel
mailing list