From e5ffa017047525ed2e3ee41ea2294546ee64894c Mon Sep 17 00:00:00 2001 From: Stefan Vacek Date: Fri, 28 Aug 2015 16:59:52 +0200 Subject: Add C++ extension - header only implementation, uses variadic templates from C++ 11 - Enable installation and building tests with -DWITH_DLT_CXX11_EXT - allow logging in the form of DLT_LOG_CXX(context, level, param1, param2, param3), e.g. - allow logging of user types (if a function logToDlt for the given user-type is present), e.g. - Added pkg-config file automotive-dlt-c++.pc - Sample code is provided in tests/dlt-test-cpp-extension.cpp Signed-off-by: Stefan Vacek --- CMakeLists.txt | 7 ++ automotive-dlt-c++.pc.in | 9 ++ automotive-dlt.spec.in | 19 ++- include/dlt/CMakeLists.txt | 7 ++ include/dlt/dlt_cpp_extension.hpp | 238 ++++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 5 + tests/dlt-test-cpp-extension.cpp | 118 +++++++++++++++++++ 7 files changed, 401 insertions(+), 2 deletions(-) create mode 100644 automotive-dlt-c++.pc.in create mode 100644 include/dlt/dlt_cpp_extension.hpp create mode 100644 tests/dlt-test-cpp-extension.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a036676..8497dc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,7 @@ option(WITH_DLT_EXAMPLES "Set to ON to build src/examples binaries" option(WITH_DLT_SYSTEM "Set to ON to build src/system binaries" ON) option(WITH_DLT_DBUS "Set to ON to build src/dbus binaries" ON) option(WITH_DLT_TESTS "Set to ON to build src/test binaries" ON) +option(WITH_DLT_CXX11_EXT "Set to ON to build C++11 extensions" ON) # RPM settings set( GENIVI_RPM_RELEASE "1")#${DLT_REVISION}") set( LICENSE "Mozilla Public License Version 2.0" ) @@ -120,6 +121,11 @@ configure_file(${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.spec.in ${PROJECT_BINARY_DIR} configure_file(${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.pc.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.pc @ONLY) install(FILES ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT devel) +if(${WITH_DLT_CXX11_EXT}) + configure_file(${CMAKE_SOURCE_DIR}/${PROJECT_NAME}-c++.pc.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-c++.pc @ONLY) + install(FILES ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-c++.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT devel) +endif() + IF(${CMAKE_INSTALL_PREFIX} STREQUAL "/usr") set(CONFIGURATION_FILES_DIR "/etc") ELSE() @@ -172,6 +178,7 @@ message( STATUS "WITH_DLT_DBUS = ${WITH_DLT_DBUS}") message( STATUS "WITH_DLT_TESTS = ${WITH_DLT_TESTS}") message( STATUS "WITH_DLT_SHM_ENABLE = ${WITH_DLT_SHM_ENABLE}" ) message( STATUS "WITH_DLTTEST = ${WITH_DLTTEST}" ) +message( STATUS "WITH_DLT_CXX11_EXT = ${WITH_DLT_CXX11_EXT}" ) message( STATUS "WITH_CHECK_CONFIG_FILE = ${WITH_CHECK_CONFIG_FILE}" ) message( STATUS "WITH_TESTSCRIPTS = ${WITH_TESTSCRIPTS}" ) message( STATUS "WITH_GPROF = ${WITH_GPROF}" ) diff --git a/automotive-dlt-c++.pc.in b/automotive-dlt-c++.pc.in new file mode 100644 index 0000000..3e950ae --- /dev/null +++ b/automotive-dlt-c++.pc.in @@ -0,0 +1,9 @@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +includedir=${exec_prefix}/include + +Name: DLT C++ +Description: Diagnostic Log and Trace C++ extensions +Version: @DLTCPP_VERSION@ +Requires: automotive-dlt +Cflags: -std=c++11 + diff --git a/automotive-dlt.spec.in b/automotive-dlt.spec.in index eeb7221..ec5fe53 100644 --- a/automotive-dlt.spec.in +++ b/automotive-dlt.spec.in @@ -24,7 +24,8 @@ Vendor: BMW Group AG License: @LICENSE@ Source0: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root -Requires: %{name} = %{version}-%{release}, pkgconfig +BuildRequires: pkg-configure +BuildRequires: cmake %description This component provides a standardised log and trace interface, based on the @@ -50,11 +51,21 @@ This component provides the documentation for %{name}. %package devel Summary: %{name} - Diagnostic Log and Trace: Development files Group: Development/Libraries -Requires: %{name} = %{version}-%{release}, pkgconfig +Requires: %{name} = %{version}-%{release} +Provides: pkgconfig(%{name}) %description devel This component provides the development libraries and includes for %{name}. +%package c++-devel +Summary: %{name} - Diagnostic Log and Trace: Development files +Group: Development/Libraries +Requires: %{name} = %{version}-%{release}-devel +Provides: pkgconfig(%{name}-c++) + +%description c++devel +This component adds a C++ extension for %{name}. + %prep %setup -q @@ -135,3 +146,7 @@ rm -rf $RPM_BUILD_ROOT %files devel %{_includedir}/dlt/*.h %{_libdir}/pkgconfig/@PROJECT_NAME@.pc + +%files c++-devel +%{_includedir}/dlt/*.hpp +%{_libdir}/pkgconfig/@PROJECT_NAME@-c++.pc diff --git a/include/dlt/CMakeLists.txt b/include/dlt/CMakeLists.txt index a137206..057af1f 100644 --- a/include/dlt/CMakeLists.txt +++ b/include/dlt/CMakeLists.txt @@ -18,3 +18,10 @@ install(FILES dlt.h dlt_user.h dlt_user_macros.h dlt_client.h dlt_protocol.h dlt_common.h dlt_types.h dlt_version.h dlt_shm.h dlt_offline_trace.h dlt_filetransfer.h dlt_common_api.h DESTINATION include/dlt COMPONENT devel) + + +if(${WITH_DLT_CXX11_EXT}) + install(FILES dlt_cpp_extension.hpp + DESTINATION include/dlt + COMPONENT devel) +endif() \ No newline at end of file diff --git a/include/dlt/dlt_cpp_extension.hpp b/include/dlt/dlt_cpp_extension.hpp new file mode 100644 index 0000000..8949658 --- /dev/null +++ b/include/dlt/dlt_cpp_extension.hpp @@ -0,0 +1,238 @@ +/** + * @licence app begin@ + * Copyright (C) 2015 Intel Corporation + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * Contributions are licensed to the GENIVI Alliance under one or more + * Contribution License Agreements. + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \file dlt_cpp_extension.hpp + * For further information see http://www.genivi.org/. + * @licence end@ + */ + + +#ifndef DLT_CPP_EXTENSION_HPP +#define DLT_CPP_EXTENSION_HPP + +#include +#include +#include +#include +#include + + +template +int32_t logToDlt(DltContextData &log, T const &value) = delete; + + +template<> +inline int32_t logToDlt(DltContextData &log, int8_t const &value) +{ + return dlt_user_log_write_int8(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, int16_t const &value) +{ + return dlt_user_log_write_int16(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, int32_t const &value) +{ + return dlt_user_log_write_int32(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, int64_t const &value) +{ + return dlt_user_log_write_int64(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, uint8_t const &value) +{ + return dlt_user_log_write_uint8(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, uint16_t const &value) +{ + return dlt_user_log_write_uint16(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, uint32_t const &value) +{ + return dlt_user_log_write_uint32(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, uint64_t const &value) +{ + return dlt_user_log_write_uint64(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, float32_t const &value) +{ + return dlt_user_log_write_float32(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, double const &value) +{ + return dlt_user_log_write_float64(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, bool const &value) +{ + return dlt_user_log_write_bool(&log, value); +} + +static inline int32_t logToDlt(DltContextData &log, char const * const value) +{ + return dlt_user_log_write_utf8_string(&log, value); +} + +static inline int32_t logToDlt(DltContextData &log, char * const value) +{ + return dlt_user_log_write_utf8_string(&log, value); +} + +template<> +inline int32_t logToDlt(DltContextData &log, std::string const &value) +{ + return dlt_user_log_write_utf8_string(&log, value.c_str()); +} + + +/* stl types */ +template<> +int32_t logToDlt(DltContextData &log, std::string const &value); + +template> +static inline int32_t logToDlt(DltContextData &log, std::vector<_Tp, _Alloc > const & value) +{ + int result = 0; + + for (auto elem: value) + { + result += logToDlt(log, elem); + } + + if (result != 0) + { + result = -1; + } + return result; +} + +template> +static inline int32_t logToDlt(DltContextData &log, std::list<_Tp, _Alloc > const & value) +{ + int result = 0; + + for (auto elem: value) + { + result += logToDlt(log, elem); + } + + if (result != 0) + { + result = -1; + } + return result; +} + +template, + typename _Alloc = std::allocator >> +static inline int32_t logToDlt(DltContextData &log, std::map<_Key, _Tp, _Compare, _Alloc > const & value) +{ + int result = 0; + + for (auto elem: value) + { + result += logToDlt(log, elem.first); + result += logToDlt(log, elem.second); + } + + if (result != 0) + { + result = -1; + } + return result; +} + + +//variadic functions using C11 standard +template +static inline int32_t logToDltVariadic(DltContextData &log, First const &valueA) +{ + return logToDlt(log, valueA); +} + +template +static inline int32_t logToDltVariadic(DltContextData &log, First const &valueA, const Rest&... valueB) +{ + int result = logToDlt(log, valueA) + logToDltVariadic(log, valueB...); + if ( result != 0 ) + { + result = -1; + } + return result; +} + + +/** + * @brief macro to write a log message with variable number of arguments and without the need to specify the type of log data + * + * The macro can be used with any type that provides a logToDlt function. + * + * Example: + * DLT_LOG_CXX(dltContext, DLT_LV_X, "text", valueA, valueB, ...) + */ +#define DLT_LOG_CXX(CONTEXT, LOGLEVEL, ...)\ + do{ \ + DltContextData log; \ + if (dlt_user_log_write_start(&CONTEXT,&log,LOGLEVEL)>0) \ + { \ + logToDltVariadic(log, ##__VA_ARGS__); \ + dlt_user_log_write_finish(&log); \ + } \ + } while(0) + +/** + * @brief macro to write a log message with variable number of arguments and without the need to specify the type of log data. + * + * The macro can be used with any type that provides a logToDlt function. + * This includes all the types that are code generated. + * + * This macro is similar to \c DLT_LOG_CXX. However, it adds the current function name as the first log argument. + * + * Example: + * DLT_LOG_FCN_CXX(dltContext, DLT_LV_X, "text", valueA, valueB, ...) + */ +#define DLT_LOG_FCN_CXX(CONTEXT, LOGLEVEL, ...) \ + do { \ + DltContextData log; \ + if (dlt_user_log_write_start(&CONTEXT, &log, LOGLEVEL) > 0) \ + { \ + dlt_user_log_write_string(&log, __PRETTY_FUNCTION__); \ + logToDltVariadic(log, ##__VA_ARGS__); \ + dlt_user_log_write_finish(&log); \ + } \ + } while(0) + + +#endif /* DLT_CPP_EXTENSION_HPP */ + + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6cc1006..5ce6945 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,3 +21,8 @@ target_link_libraries(dlt_test_receiver dlt) target_link_libraries(dlt_env_ll_unit_test gtest gtest_main dlt) target_link_libraries(dlt-test-preregister-context gtest gtest_main dlt) +if(${WITH_DLT_CXX11_EXT}) + add_executable(dlt-test-cpp-extension dlt-test-cpp-extension.cpp) + set_target_properties(dlt-test-cpp-extension PROPERTIES COMPILE_FLAGS "-std=c++11") + target_link_libraries(dlt-test-cpp-extension gtest gtest_main dlt) +endif() \ No newline at end of file diff --git a/tests/dlt-test-cpp-extension.cpp b/tests/dlt-test-cpp-extension.cpp new file mode 100644 index 0000000..ce9f1db --- /dev/null +++ b/tests/dlt-test-cpp-extension.cpp @@ -0,0 +1,118 @@ +/** + * @licence app begin@ + * Copyright (C) 2015 Intel Corporation + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * Contributions are licensed to the GENIVI Alliance under one or more + * Contribution License Agreements. + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \file dlt-test-cpp-extension.cpp + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +#include "dlt_cpp_extension.hpp" +#include +#include + + +struct MyStruct +{ + int64_t uuid; + int32_t interfaceId; + int32_t registrationState; +}; + + +template<> +inline int logToDlt(DltContextData & log, MyStruct const & value) +{ + int result = 0; + + result += dlt_user_log_write_string(&log, "("); + result += logToDlt(log, value.uuid); + result += dlt_user_log_write_string(&log, ","); + result += logToDlt(log, value.interfaceId); + result += dlt_user_log_write_string(&log, ","); + result += logToDlt(log, value.registrationState); + result += dlt_user_log_write_string(&log, ")"); + + if (result != 0) + { + result = -1; + } + + return result; +} + + +/** + * Sample code to show usage of the cpp-extension + * mainly the variadic templates + */ +int main() +{ + if (dlt_register_app("TCPP", "Test cpp extension") < 0) + { + printf("Failed to register application\n"); + return -1; + } + + DltContext ctx; + if (dlt_register_context_ll_ts(&ctx, "TCPP", "Test cpp extension", DLT_LOG_INFO, DLT_TRACE_STATUS_OFF) < 0) + { + printf("Failed to register context\n"); + return -1; + } + + dlt_enable_local_print(); + dlt_verbose_mode(); + + DLT_LOG(ctx, DLT_LOG_WARN, DLT_STRING("a message")); /* the classic way to go */ + + int an_int = 42; + float a_float = 22.7; + DLT_LOG_FCN_CXX(ctx, DLT_LOG_WARN, "Testing DLT_LOG_CXX_FCN", an_int, a_float); + DLT_LOG_CXX(ctx, DLT_LOG_WARN, 1.0, 65); + + /* Example for logging user-defined types */ + MyStruct myData = { 1u, 2u, 3u}; + DLT_LOG_CXX(ctx, DLT_LOG_WARN, "MyStruct myData", myData); + + char * non_const_string = (char *)malloc(17); + memcpy(non_const_string, "non_const_string", 16); + non_const_string[16] = 0; + DLT_LOG_CXX(ctx, DLT_LOG_WARN, "char *", non_const_string); + + std::string aString = "std::string"; + DLT_LOG_CXX(ctx, DLT_LOG_WARN, "std::string", aString); + + std::vector intVector; + intVector.push_back(0); + intVector.push_back(1); + intVector.push_back(2); + DLT_LOG_CXX(ctx, DLT_LOG_WARN, "vector", intVector); + + std::vector doubleList; + doubleList.push_back(10.); + doubleList.push_back(11.); + doubleList.push_back(12.); + DLT_LOG_CXX(ctx, DLT_LOG_WARN, "list", doubleList); + + std::map testMap; + testMap["apple"] = 100; + testMap["plum"] = 200; + testMap["orange"] = 300; + DLT_LOG_CXX(ctx, DLT_LOG_WARN, "map", testMap); + + dlt_unregister_context(&ctx); + dlt_unregister_app(); + + return 0; +} -- cgit v1.2.1