libubus: Make UBUS_* macros work cleanly in C++ master
authorKarsten Sperling <ksperling@apple.com>
Tue, 11 Jun 2024 03:58:15 +0000 (15:58 +1200)
committerKarsten Sperling <ksperling@apple.com>
Tue, 11 Jun 2024 03:58:15 +0000 (15:58 +1200)
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 <ksperling@apple.com>
CMakeLists.txt
libubus.h
tests/CMakeLists.txt
tests/test-cplusplus.cpp [new file with mode: 0644]

index 8ae853bd4a86c56f677440f41ebd897a7c52db5a..03c30129030d70413d843cf8e1dfcc012dfc50be 100644 (file)
@@ -2,12 +2,13 @@ cmake_minimum_required(VERSION 3.13)
 
 PROJECT(ubus C)
 
 
 PROJECT(ubus C)
 
-ADD_DEFINITIONS(-Wall -Werror)
+ADD_COMPILE_OPTIONS(-Wall -Werror)
 IF(CMAKE_C_COMPILER_VERSION VERSION_GREATER 6)
 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()
 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)
 
 OPTION(BUILD_LUA "build Lua plugin" ON)
 OPTION(BUILD_EXAMPLES "build examples" ON)
index b74a82348e6c5fedb02805db626cfdce406cb060..fcf62c86fc7918fb2c5869a05b9e17687ba52922 100644 (file)
--- 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,                                \
        {                                               \
                .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
 
        .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)          \
        .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)\
 
 #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) \
 
 #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)             \
 
 #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)  \
 
 #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;
 
 struct ubus_method {
        const char *name;
index 0cb33427e45a5c5e24c5eb99893563e0fe42979e..5549a4079f1e90404983503c8d5fb6007fd59f36 100644 (file)
@@ -6,6 +6,12 @@ MACRO(ADD_UNIT_TEST name)
   TARGET_INCLUDE_DIRECTORIES(${name} PRIVATE ${PROJECT_SOURCE_DIR})
 ENDMACRO(ADD_UNIT_TEST)
 
   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)
 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)
 
   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()
 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 (file)
index 0000000..89c5ffb
--- /dev/null
@@ -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;
+}