You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2022/10/31 22:02:25 UTC

[celix] branch feature/cxx14_framework_support created (now 82cc3ffc)

This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a change to branch feature/cxx14_framework_support
in repository https://gitbox.apache.org/repos/asf/celix.git


      at 82cc3ffc Refactor Celix utils and framework C++ headers for C++14 support

This branch includes the following new commits:

     new 82cc3ffc Refactor Celix utils and framework C++ headers for C++14 support

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[celix] 01/01: Refactor Celix utils and framework C++ headers for C++14 support

Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/cxx14_framework_support
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 82cc3ffcd5ba7f5cf17a33c9211cdd7690c79881
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Mon Oct 31 23:01:50 2022 +0100

    Refactor Celix utils and framework C++ headers for C++14 support
---
 .github/workflows/macos-nightly.yml                |   3 +
 .github/workflows/macos.yml                        |   2 +
 .github/workflows/ubuntu-nightly.yml               |   4 +
 .github/workflows/ubuntu.yml                       |   2 +
 CMakeLists.txt                                     |   2 +
 README.md                                          |   4 +-
 libs/framework/gtest/CMakeLists.txt                |  92 ++++++---
 .../gtest/src/CxxBundleContextTestSuite.cc         |   3 +-
 libs/framework/include/celix/Bundle.h              |  32 +++-
 libs/framework/include/celix/BundleActivator.h     |   8 +-
 libs/framework/include/celix/BundleContext.h       | 143 ++++++++++++--
 libs/framework/include/celix/ServiceRegistration.h | 128 ++++++++-----
 .../include/celix/ServiceRegistrationBuilder.h     |  15 +-
 libs/framework/include/celix/TrackerBuilders.h     |  13 +-
 libs/framework/include/celix/Trackers.h            | 210 ++++++++++++++-------
 libs/framework/include/celix/UseServiceBuilder.h   |  11 +-
 libs/utils/gtest/CMakeLists.txt                    |  29 +--
 libs/utils/gtest/src/CxxUtilsTestSuite.cc          |  18 +-
 libs/utils/include/celix/Filter.h                  |  44 ++++-
 libs/utils/include/celix/Properties.h              |  21 ++-
 libs/utils/include/celix/Utils.h                   |  40 ++--
 21 files changed, 590 insertions(+), 234 deletions(-)

diff --git a/.github/workflows/macos-nightly.yml b/.github/workflows/macos-nightly.yml
index 8fdd6b98..6ca4191e 100644
--- a/.github/workflows/macos-nightly.yml
+++ b/.github/workflows/macos-nightly.yml
@@ -27,6 +27,9 @@ jobs:
         BUILD_OPTIONS: |
           -DENABLE_TESTING=ON
           -DENABLE_ADDRESS_SANITIZER=ON
+          -DBUILD_CXX_REMOTE_SERVICE_ADMIN=ON
+          -DCELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11=ON
+          -DCELIX_TEST_FOR_CXX14=ON
       run: |
         mkdir build install
         cd build
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index 0517e80a..b14634ee 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -26,6 +26,8 @@ jobs:
           -DENABLE_TESTING=ON
           -DENABLE_ADDRESS_SANITIZER=ON
           -DBUILD_CXX_REMOTE_SERVICE_ADMIN=ON
+          -DCELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11=ON
+          -DCELIX_TEST_FOR_CXX14=ON
       run: |
         mkdir build install
         cd build
diff --git a/.github/workflows/ubuntu-nightly.yml b/.github/workflows/ubuntu-nightly.yml
index 6ce46e73..8a66c85d 100644
--- a/.github/workflows/ubuntu-nightly.yml
+++ b/.github/workflows/ubuntu-nightly.yml
@@ -56,6 +56,10 @@ jobs:
         CXX: ${{ matrix.cxx_compiler }}
         BUILD_OPTIONS: |
           -DENABLE_TESTING=ON
+          -DBUILD_EXPERIMENTAL=ON
+          -DBUILD_CXX_REMOTE_SERVICE_ADMIN=ON
+          -DCELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11=ON
+          -DCELIX_TEST_FOR_CXX14=ON
         BUILD_OPTIONS_SANITIZER: |
           -DENABLE_ADDRESS_SANITIZER=ON
         BUILD_OPTIONS_V3_API: |
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index b95e44e4..7b78569f 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -56,6 +56,8 @@ jobs:
           -DENABLE_TESTING=ON
           -DBUILD_EXPERIMENTAL=ON
           -DBUILD_CXX_REMOTE_SERVICE_ADMIN=ON
+          -DCELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11=ON
+          -DCELIX_TEST_FOR_CXX14=ON
         BUILD_OPTIONS_SANITIZER: |
           -DENABLE_ADDRESS_SANITIZER=ON
         BUILD_OPTIONS_V3_API: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 42b3097f..575c43e1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -187,6 +187,8 @@ endif ()
 option(CELIX_USE_ZIP_INSTEAD_OF_JAR "Default Celix cmake command will use jar to package bundle (if found). This option enforces Celix to use zip instead." OFF)
 
 option(CELIX_CXX "Build C++ libraries and bundles. Note for tests C++ is always used." ON)
+option(CELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11 "Test the Dependency Manager for C++11 support" OFF)
+option(CELIX_TEST_FOR_CXX14 "Test celix utils and framework C++ header for C++14 support" OFF)
 
 #Libraries and Launcher
 add_subdirectory(libs)
diff --git a/README.md b/README.md
index 46e42d15..5024b23b 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ limitations under the License.
 [![codecov](https://codecov.io/gh/apache/celix/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/celix)
 [![Coverity Scan Build Status](https://scan.coverity.com/projects/6685/badge.svg)](https://scan.coverity.com/projects/6685)
 
-Apache Celix is an implementation of a dynamic service framework inspired by the OSGi specification and adapted to C 
-and C++ (C++17).
+Apache Celix is an implementation of a dynamic service framework inspired by the OSGi specification and adapted to C, 
+C++14 and C++17.
 It is a framework to develop dynamic modular software applications using component and in-process service-oriented 
 programming.
 
diff --git a/libs/framework/gtest/CMakeLists.txt b/libs/framework/gtest/CMakeLists.txt
index 9de0023a..977fcf99 100644
--- a/libs/framework/gtest/CMakeLists.txt
+++ b/libs/framework/gtest/CMakeLists.txt
@@ -38,16 +38,19 @@ if(NOT APPLE)
 endif()
 add_dependencies(unresolvable_bundle sublib)
 
-add_executable(test_framework
-        src/single_framework_test.cpp
-        src/multiple_frameworks_test.cpp
-        src/bundle_context_bundles_tests.cpp
-        src/bundle_context_services_test.cpp
-        src/DependencyManagerTestSuite.cc
-        src/CxxBundleContextTestSuite.cc
-        src/HelloWorldCxxActivator.cc
-        src/CxxFrameworkFactoryTestSuite.cc
-        src/CxxBundleActivatorTestSuite.cc)
+set(CELIX_FRAMEWORK_TEST_SOURCES
+    src/single_framework_test.cpp
+    src/multiple_frameworks_test.cpp
+    src/bundle_context_bundles_tests.cpp
+    src/bundle_context_services_test.cpp
+    src/DependencyManagerTestSuite.cc
+    src/CxxBundleContextTestSuite.cc
+    src/HelloWorldCxxActivator.cc
+    src/CxxFrameworkFactoryTestSuite.cc
+    src/CxxBundleActivatorTestSuite.cc
+)
+
+add_executable(test_framework ${CELIX_FRAMEWORK_TEST_SOURCES})
 target_link_libraries(test_framework PRIVATE Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
 add_celix_bundle_dependencies(test_framework
         simple_test_bundle1
@@ -93,21 +96,60 @@ target_compile_definitions(test_framework PRIVATE
 add_test(NAME test_framework COMMAND test_framework)
 setup_target_for_coverage(test_framework SCAN_DIR ..)
 
-#Setting standard to C++11 and testing C++ dependency manager to ensure that this still support C++11.
-#This ensure that the C++11 dependency manager is backwards compatible with Celix 2.2.1
-set(CMAKE_CXX_STANDARD 11)
-add_executable(test_dep_man_with_cxx11
-        src/DependencyManagerTestSuite.cc
-)
-target_link_libraries(test_dep_man_with_cxx11 PRIVATE Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
-target_compile_definitions(test_dep_man_with_cxx11 PRIVATE
-        SIMPLE_CXX_DEP_MAN_BUNDLE_LOC="${SIMPLE_CXX_DEP_MAN_BUNDLE_LOC}"
-)
-add_test(NAME test_dep_man_with_cxx11 COMMAND test_dep_man_with_cxx11)
-setup_target_for_coverage(test_dep_man_with_cxx11 SCAN_DIR ..)
+if (CELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11)
+    #Setting standard to C++11 and testing C++ dependency manager to ensure that this still support C++11.
+    #This ensure that the C++11 dependency manager is backwards compatible with Celix 2.2.1
+    set(CMAKE_CXX_STANDARD 11)
+    add_executable(test_dep_man_with_cxx11
+            src/DependencyManagerTestSuite.cc
+            )
+    target_link_libraries(test_dep_man_with_cxx11 PRIVATE Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
+    target_compile_definitions(test_dep_man_with_cxx11 PRIVATE
+            SIMPLE_CXX_DEP_MAN_BUNDLE_LOC="${SIMPLE_CXX_DEP_MAN_BUNDLE_LOC}"
+            )
+    add_test(NAME test_dep_man_with_cxx11 COMMAND test_dep_man_with_cxx11)
+    setup_target_for_coverage(test_dep_man_with_cxx11 SCAN_DIR ..)
+
+    #Also to ensure that CELIX_GEN_CXX_BUNDLE_ACTIVATOR still works for C++11 bundle activators with a
+    #dependency manager argument, the HelloWorldCxxActivatorWithDepMan will be used to create a C++11 bundle
+    add_celix_bundle(test_dep_man_bundle_activator_with_cxx11 SOURCES src/HelloWorldCxxActivatorWithDepMan.cc VERSION 1.0.0)
+endif ()
+
+if (CELIX_TEST_FOR_CXX14)
+    #Setting standard to C++14 and testing the C++ framework headers to ensure that C++14 is also supported.
+    set(CMAKE_CXX_STANDARD 14)
+
+    add_executable(test_framework_with_cxx14 ${CELIX_FRAMEWORK_TEST_SOURCES})
+    target_link_libraries(test_framework_with_cxx14 PRIVATE Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
+    add_celix_bundle_dependencies(test_framework_with_cxx14
+            simple_test_bundle1
+            simple_test_bundle2 simple_test_bundle3 simple_test_bundle4
+            simple_test_bundle5 bundle_with_exception unresolveable_bundle simple_cxx_bundle simple_cxx_dep_man_bundle cmp_test_bundle)
+    target_include_directories(test_framework_with_cxx14 PRIVATE ../src)
+
+    #Also to ensure that CELIX_GEN_CXX_BUNDLE_ACTIVATOR still for C++11.
+    add_celix_bundle(simple_cxx_bundle_with_cxx1 SOURCES src/HelloWorldCxxActivator.cc VERSION 1.0.0)
+    add_celix_bundle(simple_cxx_dep_man_bundle_with_cxx1 SOURCES src/HelloWorldCxxActivatorWithDepMan.cc VERSION 1.0.0)
+    add_celix_bundle_dependencies(test_framework_with_cxx14 simple_cxx_bundle_with_cxx1 simple_cxx_dep_man_bundle_with_cxx1)
 
-#Also to ensure that CELIX_GEN_CXX_BUNDLE_ACTIVATOR still works for C++11 bundle activators with a
-#dependency manager argument, the HelloWorldCxxActivatorWithDepMan will be used to create a C++11 bundle
+    celix_get_bundle_file(simple_cxx_bundle_with_cxx1 SIMPLE_CXX_BUNDLE_WITH_CXX11_LOC)
+    celix_get_bundle_file(simple_cxx_dep_man_bundle_with_cxx1 SIMPLE_CXX_DEP_MAN_WITH_CXX11_BUNDLE_LOC)
 
-add_celix_bundle(test_dep_man_bundle_activator_with_cxx11 SOURCES src/HelloWorldCxxActivatorWithDepMan.cc VERSION 1.0.0)
+    target_compile_definitions(test_framework_with_cxx14 PRIVATE
+            SIMPLE_TEST_BUNDLE1_LOCATION="${SIMPLE_TEST_BUNDLE1}"
+            SIMPLE_TEST_BUNDLE2_LOCATION="${SIMPLE_TEST_BUNDLE2}"
+            SIMPLE_TEST_BUNDLE3_LOCATION="${SIMPLE_TEST_BUNDLE3}"
+            SIMPLE_TEST_BUNDLE4_LOCATION="${SIMPLE_TEST_BUNDLE4_FILENAME}"
+            SIMPLE_TEST_BUNDLE5_LOCATION="${SIMPLE_TEST_BUNDLE5_FILENAME}"
+            TEST_BUNDLE_WITH_EXCEPTION_LOCATION="${BUNDLE_WITH_EXCEPTION}"
+            TEST_BUNDLE_UNRESOLVABLE_LOCATION="${UNRESOLVABLE_BUNDLE}"
+            SIMPLE_CXX_BUNDLE_LOC="${SIMPLE_CXX_BUNDLE_WITH_CXX11_LOC}"
+            CMP_TEST_BUNDLE_LOC="${CMP_TEST_BUNDLE_LOC}"
+            SIMPLE_CXX_DEP_MAN_BUNDLE_LOC="${SIMPLE_CXX_DEP_MAN_WITH_CXX11_BUNDLE_LOC}"
+            CMP_TEST_BUNDLE_LOC="${CMP_TEST_BUNDLE_LOC}"
+            INSTALL_AND_START_BUNDLES_CONFIG_PROPERTIES_FILE="${CMAKE_CURRENT_BINARY_DIR}/install_and_start_bundles.properties"
+    )
 
+    add_test(NAME test_framework_with_cxx14 COMMAND test_framework_with_cxx14)
+    setup_target_for_coverage(test_framework_with_cxx14 SCAN_DIR ..)
+endif ()
diff --git a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
index fe015185..dabc4288 100644
--- a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
+++ b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
@@ -715,6 +715,7 @@ TEST_F(CxxBundleContextTestSuite, GetBundleInformation) {
     EXPECT_TRUE(startCalled);
 }
 
+#if __cplusplus >= 201703L //C++17 or higher
 class TestInterfaceWithStaticInfo {
 public:
     static constexpr std::string_view NAME = "TestName";
@@ -727,7 +728,7 @@ TEST_F(CxxBundleContextTestSuite, RegisterServiceWithNameAndVersionInfo) {
     EXPECT_EQ(reg->getServiceName(), "TestName");
     EXPECT_EQ(reg->getServiceVersion(), "1.2.3");
 }
-
+#endif
 
 TEST_F(CxxBundleContextTestSuite, listBundles) {
     auto list = ctx->listBundleIds();
diff --git a/libs/framework/include/celix/Bundle.h b/libs/framework/include/celix/Bundle.h
index 90e31be4..4bc09ad8 100644
--- a/libs/framework/include/celix/Bundle.h
+++ b/libs/framework/include/celix/Bundle.h
@@ -64,25 +64,32 @@ namespace celix {
          * @param path The relative path to a bundle resource
          * @return The use-able entry path or an empty string if the entry is not found.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         [[nodiscard]] std::string getEntry(std::string_view path) const {
-            std::string result{};
-            char* entry = celix_bundle_getEntry(cBnd.get(), path.data());
-            if (entry != nullptr) {
-                result = std::string{entry};
-                free(entry);
-            }
-            return result;
+            return getEntryInternal(path.data());
+        }
+#else
+        std::string getEntry(const std::string& path) const {
+            return getEntryInternal(path.c_str());
         }
+#endif
 
         /**
          * @brief Get a manifest attribute value from the bundle manifest.
          * @param attribute The attribute to get the value from.
          * @return The attribute value or an empty string if the attribute is not present in the bundle manifest.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         [[nodiscard]] std::string getManifestValue(std::string_view attribute) const {
             const char* header = celix_bundle_getManifestValue(cBnd.get(), attribute.data());
             return header == nullptr ? std::string{} : std::string{header};
         }
+#else
+        [[nodiscard]] std::string getManifestValue(const std::string& attribute) const {
+            const char* header = celix_bundle_getManifestValue(cBnd.get(), attribute.c_str());
+            return header == nullptr ? std::string{} : std::string{header};
+        }
+#endif
 
         /**
          * @brief the symbolic name of the bundle.
@@ -143,6 +150,17 @@ namespace celix {
             return celix_bundle_isSystemBundle(cBnd.get());
         }
     private:
+        std::string getEntryInternal(const char* path) const {
+            std::string result{};
+            char* entry = celix_bundle_getEntry(cBnd.get(), path);
+            if (entry != nullptr) {
+                result = std::string{entry};
+                free(entry);
+            }
+            return result;
+        }
+
+
         const std::shared_ptr<celix_bundle_t> cBnd;
     };
 }
diff --git a/libs/framework/include/celix/BundleActivator.h b/libs/framework/include/celix/BundleActivator.h
index 267777c8..1656db26 100644
--- a/libs/framework/include/celix/BundleActivator.h
+++ b/libs/framework/include/celix/BundleActivator.h
@@ -24,10 +24,10 @@
 #include "celix/dm/DependencyManager.h"
 #include "celix_bundle_activator.h"
 
-#if __cplusplus >= 201703L //C++17 or higher
+#if __cplusplus >= 201402L //C++14 or higher
 #include "celix/BundleContext.h"
-
-namespace celix::impl {
+namespace celix {
+namespace impl {
     template<typename I>
     struct BundleActivatorData {
         long bndId{};
@@ -94,7 +94,7 @@ namespace celix::impl {
         waitForExpired(bndId, ctx, "celix::dm::DependencyManager", dm);
         return CELIX_SUCCESS;
     }
-}
+}}
 #else //C++11
 namespace celix {
 namespace impl {
diff --git a/libs/framework/include/celix/BundleContext.h b/libs/framework/include/celix/BundleContext.h
index bbbc8ffb..20af2000 100644
--- a/libs/framework/include/celix/BundleContext.h
+++ b/libs/framework/include/celix/BundleContext.h
@@ -78,11 +78,19 @@ namespace celix {
          * @param name The optional name of the service. If not provided celix::typeName<I> will be used to defer the service name.
          * @return A ServiceRegistrationBuilder object.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         template<typename I, typename Implementer>
         ServiceRegistrationBuilder<I> registerService(std::shared_ptr<Implementer> implementer, std::string_view name = {}) {
             std::shared_ptr<I> svc = implementer; //note Implement should be derived from I
             return ServiceRegistrationBuilder<I>{cCtx, std::move(svc), celix::typeName<I>(name)};
         }
+#else
+        template<typename I, typename Implementer>
+        ServiceRegistrationBuilder<I> registerService(std::shared_ptr<Implementer> implementer, const std::string& name = {}) {
+            std::shared_ptr<I> svc = implementer; //note Implement should be derived from I
+            return ServiceRegistrationBuilder<I>{cCtx, std::move(svc), celix::typeName<I>(name)};
+        }
+#endif
 
         /**
          * @brief Register a (unmanaged) service in the Celix framework using a fluent builder API.
@@ -94,11 +102,19 @@ namespace celix {
          * By default the service registration is configure to register the service async, but to unregister the
          * service sync (because the svc pointer is unmanaged).
          */
+#if __cplusplus >= 201703L //C++17 or higher
         template<typename I, typename Implementer>
         ServiceRegistrationBuilder<I> registerUnmanagedService(Implementer* svc, std::string_view name = {}) {
             auto unmanagedSvc = std::shared_ptr<I>{svc, [](I*){/*nop*/}};
             return ServiceRegistrationBuilder<I>{cCtx, std::move(unmanagedSvc), celix::typeName<I>(name), true, false};
         }
+#else
+        template<typename I, typename Implementer>
+        ServiceRegistrationBuilder<I> registerUnmanagedService(Implementer* svc, const std::string& name = {}) {
+            auto unmanagedSvc = std::shared_ptr<I>{svc, [](I*){/*nop*/}};
+            return ServiceRegistrationBuilder<I>{cCtx, std::move(unmanagedSvc), celix::typeName<I>(name), true, false};
+        }
+#endif
 
         //TODO registerServiceFactory<I>()
 
@@ -128,10 +144,17 @@ namespace celix {
          * @param name The optional service name to use. If not provided celix::typeName<I> will be used to defer the service name.
          * @return A UseServiceBuilder object.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         template<typename I>
         UseServiceBuilder<I> useService(std::string_view name = {}) {
             return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), true};
         }
+#else
+        template<typename I>
+        UseServiceBuilder<I> useService(const std::string& name = {}) {
+            return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), true};
+        }
+#endif
 
         /**
          * @brief Use services registered in the Celix framework using a fluent builder API.
@@ -156,10 +179,17 @@ namespace celix {
          * @param name The optional service name to use. If not provided celix::typeName<I> will be used to defer the service name.
          * @return A UseServiceBuilder object.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         template<typename I>
         UseServiceBuilder<I> useServices(std::string_view name = {}) {
             return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), false};
         }
+#else
+        template<typename I>
+        UseServiceBuilder<I> useServices(const std::string& name = {}) {
+            return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), false};
+        }
+#endif
 
         /**
          * @brief Finds the highest ranking service using the optional provided (LDAP) filter
@@ -172,10 +202,17 @@ namespace celix {
          * @param versionRange An optional version range.
          * @return The service id of the found service or -1 if the service was not found.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         template<typename I>
         long findService(std::string_view filter = {}, std::string_view versionRange = {}) {
             return findServiceWithName(celix::typeName<I>(), filter, versionRange);
         }
+#else
+        template<typename I>
+        long findService(const std::string& filter = {}, const std::string& versionRange = {}) {
+            return findServiceWithName(celix::typeName<I>(), filter, versionRange);
+        }
+#endif
 
         /**
          * @brief Finds the highest ranking service using the provided service name and
@@ -186,6 +223,7 @@ namespace celix {
          * @param versionRange An optional version range.
          * @return The service id of the found service or -1 if the service was not found.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         long findServiceWithName(std::string_view name, std::string_view filter = {}, std::string_view versionRange = {}) {
             waitIfAbleForEvents();
             celix_service_filter_options_t opts{};
@@ -194,6 +232,16 @@ namespace celix {
             opts.versionRange = versionRange.empty() ? nullptr : versionRange.data();
             return celix_bundleContext_findServiceWithOptions(cCtx.get(), &opts);
         }
+#else
+        long findServiceWithName(const std::string& name, const std::string& filter = {}, const std::string& versionRange = {}) {
+            waitIfAbleForEvents();
+            celix_service_filter_options_t opts{};
+            opts.serviceName = name.empty() ? nullptr : name.data();
+            opts.filter = filter.empty() ? nullptr : filter.data();
+            opts.versionRange = versionRange.empty() ? nullptr : versionRange.data();
+            return celix_bundleContext_findServiceWithOptions(cCtx.get(), &opts);
+        }
+#endif
 
         /**
          * @brief Finds all services matching the optional provided (LDAP) filter
@@ -206,10 +254,17 @@ namespace celix {
          * @param versionRange An optional version range.
          * @return A vector of service ids.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         template<typename I>
         std::vector<long> findServices(std::string_view filter = {}, std::string_view versionRange = {}) {
             return findServicesWithName(celix::typeName<I>(), filter, versionRange);
         }
+#else
+        template<typename I>
+        std::vector<long> findServices(const std::string& filter = {}, const std::string& versionRange = {}) {
+            return findServicesWithName(celix::typeName<I>(), filter, versionRange);
+        }
+#endif
 
         /**
          * @brief Finds all service matching the provided service name and the optional (LDAP) filter
@@ -220,22 +275,21 @@ namespace celix {
          * @param versionRange An optional version range.
          * @return A vector of service ids.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         std::vector<long> findServicesWithName(std::string_view name, std::string_view filter = {}, std::string_view versionRange = {}) {
-            waitIfAbleForEvents();
-            celix_service_filter_options_t opts{};
-            opts.serviceName = name.empty() ? nullptr : name.data();
-            opts.filter = filter.empty() ? nullptr : filter.data();
-            opts.versionRange = versionRange.empty() ? nullptr : versionRange.data();
-
-            std::vector<long> result{};
-            auto cList = celix_bundleContext_findServicesWithOptions(cCtx.get(), &opts);
-            for (int i = 0; i < celix_arrayList_size(cList); ++i) {
-                long svcId = celix_arrayList_getLong(cList, i);
-                result.push_back(svcId);
-            }
-            celix_arrayList_destroy(cList);
-            return result;
+            return findServicesWithNameInternal(
+                    name.empty() ? nullptr : name.data(),
+                    filter.empty() ? nullptr : filter.data(),
+                    versionRange.empty() ? nullptr : versionRange.data());
+        }
+#else
+        std::vector<long> findServicesWithName(const std::string& name, const std::string& filter = {}, const std::string& versionRange = {}) {
+            return findServicesWithNameInternal(
+                    name.empty() ? nullptr : name.c_str(),
+                    filter.empty() ? nullptr : filter.c_str(),
+                    versionRange.empty() ? nullptr : versionRange.c_str());
         }
+#endif
 
         /**
          * @brief Track services in the Celix framework using a fluent builder API.
@@ -257,10 +311,17 @@ namespace celix {
          * @param name The optional service name. If empty celix::typeName<I> will be used to defer the service name.
          * @return A ServiceTrackerBuilder object.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         template<typename I>
         ServiceTrackerBuilder<I> trackServices(std::string_view name = {}) {
             return ServiceTrackerBuilder<I>{cCtx, celix::typeName<I>(name)};
         }
+#else
+        template<typename I>
+        ServiceTrackerBuilder<I> trackServices(const std::string& name = {}) {
+            return ServiceTrackerBuilder<I>{cCtx, celix::typeName<I>(name)};
+        }
+#endif
 
         /**
          * @brief Track services in the Celix framework using a fluent builder API.
@@ -310,10 +371,17 @@ namespace celix {
          * @param name The optional service name. If empty celix::typeName<I> will be used to defer the service name.
          * @return A MetaTrackerBuilder object.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         template<typename I>
         MetaTrackerBuilder trackServiceTrackers(std::string_view name = {}) {
             return MetaTrackerBuilder(cCtx, celix::typeName<I>(name));
         }
+#else
+        template<typename I>
+        MetaTrackerBuilder trackServiceTrackers(const std::string& name = {}) {
+            return MetaTrackerBuilder(cCtx, celix::typeName<I>(name));
+        }
+#endif
 
         /**
          * @brief Track service trackers in the Celix framework using a fluent builder API.
@@ -333,9 +401,15 @@ namespace celix {
          * @param autoStart If the bundle should also be started.
          * @return the bundleId (>= 0) or < 0 if the bundle could not be installed and possibly started.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         long installBundle(std::string_view bndLocation, bool autoStart = true) {
             return celix_bundleContext_installBundle(cCtx.get(), bndLocation.data(), autoStart);
         }
+#else
+        long installBundle(const std::string& bndLocation, bool autoStart = true) {
+            return celix_bundleContext_installBundle(cCtx.get(), bndLocation.c_str(), autoStart);
+        }
+#endif
 
         /**
          * @brief Uninstall the bundle with the provided bundle id.
@@ -405,9 +479,15 @@ namespace celix {
          * @param defaultVal The default value to use if the property is not found.
          * @return The config property value for the provided key or the provided defaultValue is the name is not found.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         [[nodiscard]] std::string getConfigProperty(std::string_view name, std::string_view defaultValue) const {
             return std::string{celix_bundleContext_getProperty(cCtx.get(), name.data(), defaultValue.data())};
         }
+#else
+        std::string getConfigProperty(const std::string& name, const std::string& defaultValue) const {
+            return std::string{celix_bundleContext_getProperty(cCtx.get(), name.c_str(), defaultValue.c_str())};
+        }
+#endif
 
         /**
          * @brief Gets the config property for the provided name and returns it as a long.
@@ -421,9 +501,15 @@ namespace celix {
          * @return The config property value (as long) for the provided key or the provided defaultValue is the name
          * is not found or not a valid long.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         [[nodiscard]] long getConfigPropertyAsLong(std::string_view name, long defaultValue) const {
             return celix_bundleContext_getPropertyAsLong(cCtx.get(), name.data(), defaultValue);
         }
+#else
+        long getConfigPropertyAsLong(const std::string& name, long defaultValue) const {
+            return celix_bundleContext_getPropertyAsLong(cCtx.get(), name.c_str(), defaultValue);
+        }
+#endif
 
         /**
          * @brief Gets the config property for the provided name and returns it as a double.
@@ -437,9 +523,15 @@ namespace celix {
          * @return The config property value (as double) for the provided key or the provided defaultValue is the name
          * is not found or not a valid double.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         [[nodiscard]] double getConfigPropertyAsDouble(std::string_view name, double defaultValue) const {
             return celix_bundleContext_getPropertyAsDouble(cCtx.get(), name.data(), defaultValue);
         }
+#else
+        double getConfigPropertyAsDouble(const std::string& name, double defaultValue) const {
+            return celix_bundleContext_getPropertyAsDouble(cCtx.get(), name.c_str(), defaultValue);
+        }
+#endif
 
         /**
          * @brief Gets the config property for the provided name and returns it as a bool.
@@ -455,9 +547,15 @@ namespace celix {
          * @return The config property value (as boolean) for the provided key or the provided defaultValue is the name
          * is not found or not a valid boolean.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         [[nodiscard]] long getConfigPropertyAsBool(std::string_view name, bool defaultValue) const {
             return celix_bundleContext_getPropertyAsBool(cCtx.get(), name.data(), defaultValue);
         }
+#else
+        long getConfigPropertyAsBool(const std::string& name, bool defaultValue) const {
+            return celix_bundleContext_getPropertyAsBool(cCtx.get(), name.c_str(), defaultValue);
+        }
+#endif
 
         /**
          * @brief Get the bundle of this bundle context.
@@ -619,6 +717,23 @@ namespace celix {
             return result;
         }
 
+        std::vector<long> findServicesWithNameInternal(const char* name, const char* filter, const char* versionRange) {
+            waitIfAbleForEvents();
+            celix_service_filter_options_t opts{};
+            opts.serviceName = name;
+            opts.filter = filter;
+            opts.versionRange = versionRange;
+
+            std::vector<long> result{};
+            auto cList = celix_bundleContext_findServicesWithOptions(cCtx.get(), &opts);
+            for (int i = 0; i < celix_arrayList_size(cList); ++i) {
+                long svcId = celix_arrayList_getLong(cList, i);
+                result.push_back(svcId);
+            }
+            celix_arrayList_destroy(cList);
+            return result;
+        }
+
         const std::shared_ptr<celix_bundle_context_t> cCtx;
         const std::shared_ptr<celix::dm::DependencyManager> dm;
         const Bundle bnd;
diff --git a/libs/framework/include/celix/ServiceRegistration.h b/libs/framework/include/celix/ServiceRegistration.h
index 3b077365..6f7b4f0a 100644
--- a/libs/framework/include/celix/ServiceRegistration.h
+++ b/libs/framework/include/celix/ServiceRegistration.h
@@ -67,6 +67,7 @@ namespace celix {
          * @return The new ServiceRegistration object as shared ptr.
          * @throws celix::Exception
          */
+#if __cplusplus >= 201703L //C++17 or higher
         static std::shared_ptr<ServiceRegistration> create(std::shared_ptr<celix_bundle_context_t> cCtx,
                                                            std::shared_ptr<void> svc,
                                                            std::string_view name,
@@ -76,54 +77,25 @@ namespace celix {
                                                            bool unregisterAsync,
                                                            std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
                                                            std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
-            auto delCallback = [](ServiceRegistration* reg) {
-                if (reg->getState() == ServiceRegistrationState::UNREGISTERED) {
-                    delete reg;
-                } else {
-                    /*
-                     * if not registered/unregistering -> unregister() -> new event on the Celix event thread
-                     * if unregistering -> nop unregister() -> there is already a event on the Celix event thread to unregister
-                     */
-                    reg->unregister();
-
-                    /*
-                     * Creating event on the Event loop, this will be after the unregistration is done
-                     */
-                    auto* fw = celix_bundleContext_getFramework(reg->cCtx.get());
-                    auto* bnd = celix_bundleContext_getBundle(reg->cCtx.get());
-                    long bndId = celix_bundle_getId(bnd);
-                    celix_framework_fireGenericEvent(
-                            fw,
-                            -1,
-                            bndId,
-                            "celix::ServiceRegistration delete callback",
-                            reg,
-                            [](void *data) {
-                                auto* r = static_cast<ServiceRegistration*>(data);
-                                delete r;
-                            },
-                            nullptr,
-                            nullptr);
-                }
-            };
-
-            auto reg = std::shared_ptr<ServiceRegistration>{
-                new ServiceRegistration{
-                    std::move(cCtx),
-                    std::move(svc),
-                    name,
-                    version,
-                    std::move(properties),
-                    registerAsync,
-                    unregisterAsync,
-                    std::move(onRegisteredCallbacks),
-                    std::move(onUnregisteredCallbacks)},
-                delCallback
-            };
-            reg->setSelf(reg);
-            reg->registerService();
-            return reg;
+            return createInternal(std::move(cCtx), std::move(svc), name.data(),
+                                  version.data(), std::move(properties), registerAsync,
+                                  unregisterAsync, std::move(onRegisteredCallbacks), std::move(onUnregisteredCallbacks));
         }
+#else
+        static std::shared_ptr<ServiceRegistration> create(std::shared_ptr<celix_bundle_context_t> cCtx,
+                                                           std::shared_ptr<void> svc,
+                                                           const std::string& name,
+                                                           const std::string& version,
+                                                           celix::Properties properties,
+                                                           bool registerAsync,
+                                                           bool unregisterAsync,
+                                                           std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
+                                                           std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
+            return createInternal(std::move(cCtx), std::move(svc), name.c_str(),
+                                  version.c_str(), std::move(properties), registerAsync,
+                                  unregisterAsync, std::move(onRegisteredCallbacks), std::move(onUnregisteredCallbacks));
+        }
+#endif
 
         /**
          * @brief The service name for this service registration.
@@ -256,8 +228,8 @@ namespace celix {
         ServiceRegistration(
                 std::shared_ptr<celix_bundle_context_t> _cCtx,
                 std::shared_ptr<void> _svc,
-                std::string_view _name,
-                std::string_view _version,
+                const char* _name,
+                const char* _version,
                 celix::Properties _properties,
                 bool _registerAsync,
                 bool _unregisterAsync,
@@ -273,6 +245,64 @@ namespace celix {
                 onUnregisteredCallbacks{std::move(_onUnregisteredCallbacks)},
                 svc{std::move(_svc)} {}
 
+        static std::shared_ptr<ServiceRegistration> createInternal(
+                std::shared_ptr<celix_bundle_context_t> cCtx,
+                std::shared_ptr<void> svc,
+                const char* name,
+                const char* version,
+                celix::Properties properties,
+                bool registerAsync,
+                bool unregisterAsync,
+                std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
+        std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
+            auto delCallback = [](ServiceRegistration* reg) {
+                if (reg->getState() == ServiceRegistrationState::UNREGISTERED) {
+                    delete reg;
+                } else {
+                    /*
+                     * if not registered/unregistering -> unregister() -> new event on the Celix event thread
+                     * if unregistering -> nop unregister() -> there is already a event on the Celix event thread to unregister
+                     */
+                    reg->unregister();
+
+                    /*
+                     * Creating event on the Event loop, this will be after the unregistration is done
+                     */
+                    auto* fw = celix_bundleContext_getFramework(reg->cCtx.get());
+                    auto* bnd = celix_bundleContext_getBundle(reg->cCtx.get());
+                    long bndId = celix_bundle_getId(bnd);
+                    celix_framework_fireGenericEvent(
+                            fw,
+                            -1,
+                            bndId,
+                            "celix::ServiceRegistration delete callback",
+                            reg,
+                            [](void *data) {
+                                auto* r = static_cast<ServiceRegistration*>(data);
+                                delete r;
+                            },
+                            nullptr,
+                            nullptr);
+                }
+            };
+
+            auto reg = std::shared_ptr<ServiceRegistration>{
+                    new ServiceRegistration{
+                            std::move(cCtx),
+                            std::move(svc),
+                            name,
+                            version,
+                            std::move(properties),
+                            registerAsync,
+                            unregisterAsync,
+                            std::move(onRegisteredCallbacks),
+                            std::move(onUnregisteredCallbacks)},
+                    delCallback
+            };
+            reg->setSelf(reg);
+            reg->registerService();
+            return reg;
+        }
 
         /**
          * @brief Register service in the Celix framework.
diff --git a/libs/framework/include/celix/ServiceRegistrationBuilder.h b/libs/framework/include/celix/ServiceRegistrationBuilder.h
index 54bbd0e7..a05de383 100644
--- a/libs/framework/include/celix/ServiceRegistrationBuilder.h
+++ b/libs/framework/include/celix/ServiceRegistrationBuilder.h
@@ -45,15 +45,15 @@ namespace celix {
         ServiceRegistrationBuilder(
                 std::shared_ptr<celix_bundle_context_t> _cCtx,
                 std::shared_ptr<I> _svc,
-                std::string_view _name,
+                std::string _name,
                 bool _registerAsync = true,
                 bool _unregisterAsync = true) :
                 cCtx{std::move(_cCtx)},
                 svc{std::move(_svc)},
-                name{_name},
+                name{std::move(_name)},
                 version{celix::typeVersion<I>()},
                 registerAsync{_registerAsync},
-                unregisterAsync{_unregisterAsync}{}
+                unregisterAsync{_unregisterAsync} {}
 
         ServiceRegistrationBuilder& operator=(ServiceRegistrationBuilder&&) = delete;
         ServiceRegistrationBuilder(const ServiceRegistrationBuilder&) = delete;
@@ -64,15 +64,24 @@ namespace celix {
          *
          * This will lead to a 'service.version' service property.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         ServiceRegistrationBuilder& setVersion(std::string_view v) { version = v; return *this; }
+#else
+        ServiceRegistrationBuilder& setVersion(std::string v) { version = std::move(v); return *this; }
+#endif
 
         /**
          * @brief Add a property to the service properties.
          *
          * If a key is already present the value will be overridden.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         template<typename T>
         ServiceRegistrationBuilder& addProperty(std::string_view key, T&& value) { properties.template set(key, std::forward<T>(value)); return *this; }
+#else
+        template<typename T>
+        ServiceRegistrationBuilder& addProperty(const std::string& key, T&& value) { properties.template set(key, std::forward<T>(value)); return *this; }
+#endif
 
         /**
          * @brief Set the service properties.
diff --git a/libs/framework/include/celix/TrackerBuilders.h b/libs/framework/include/celix/TrackerBuilders.h
index bec73086..35883d82 100644
--- a/libs/framework/include/celix/TrackerBuilders.h
+++ b/libs/framework/include/celix/TrackerBuilders.h
@@ -42,9 +42,9 @@ namespace celix {
         //NOTE private to prevent move so that a build() call cannot be forgotten
         ServiceTrackerBuilder(ServiceTrackerBuilder&&) noexcept = default;
     public:
-        explicit ServiceTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string_view _name) :
+        explicit ServiceTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _name) :
                 cCtx{std::move(_cCtx)},
-                name{_name} {}
+                name{std::move(_name)} {}
 
         ServiceTrackerBuilder& operator=(ServiceTrackerBuilder&&) = delete;
         ServiceTrackerBuilder(const ServiceTrackerBuilder&) = delete;
@@ -57,7 +57,11 @@ namespace celix {
          * Example:
          *      "(property_key=value)"
          */
+#if __cplusplus >= 201703L //C++17 or higher
         ServiceTrackerBuilder& setFilter(std::string_view f) { filter = celix::Filter{f}; return *this; }
+#else
+        ServiceTrackerBuilder& setFilter(const std::string& f) { filter = celix::Filter{f}; return *this; }
+#endif
 
         /**
          * @brief Set filter to be used to matching services.
@@ -310,10 +314,9 @@ namespace celix {
         //NOTE private to prevent move so that a build() call cannot be forgotten
         MetaTrackerBuilder(MetaTrackerBuilder &&) = default;
     public:
-        explicit MetaTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string_view _serviceName) :
+        explicit MetaTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _serviceName) :
                 cCtx{std::move(_cCtx)},
-                serviceName{_serviceName}
-        {}
+                serviceName{std::move(_serviceName)} {}
 
         MetaTrackerBuilder &operator=(MetaTrackerBuilder &&) = delete;
         MetaTrackerBuilder(const MetaTrackerBuilder &) = delete;
diff --git a/libs/framework/include/celix/Trackers.h b/libs/framework/include/celix/Trackers.h
index 4a2b491e..cd99ecf3 100644
--- a/libs/framework/include/celix/Trackers.h
+++ b/libs/framework/include/celix/Trackers.h
@@ -217,18 +217,19 @@ namespace celix {
      */
     class GenericServiceTracker : public AbstractTracker {
     public:
+#if __cplusplus >= 201703L //C++17 or higher
         GenericServiceTracker(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string_view _svcName,
                               std::string_view _svcVersionRange, celix::Filter _filter) : AbstractTracker{std::move(_cCtx)}, svcName{_svcName},
                                                                                    svcVersionRange{_svcVersionRange}, filter{std::move(_filter)} {
-            opts.trackerCreatedCallbackData = this;
-            opts.trackerCreatedCallback = [](void *data) {
-                auto* trk = static_cast<GenericServiceTracker*>(data);
-                {
-                    std::lock_guard<std::mutex> callbackLock{trk->mutex};
-                    trk->state = TrackerState::OPEN;
-                }
-            };
+            setupServiceTrackerOptions();
+        }
+#else
+        GenericServiceTracker(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _svcName,
+                              std::string _svcVersionRange, celix::Filter _filter) : AbstractTracker{std::move(_cCtx)}, svcName{std::move(_svcName)},
+                                                                                   svcVersionRange{std::move(_svcVersionRange)}, filter{std::move(_filter)} {
+            setupServiceTrackerOptions();
         }
+#endif
 
         ~GenericServiceTracker() override = default;
 
@@ -278,6 +279,18 @@ namespace celix {
         const celix::Filter filter;
         celix_service_tracking_options opts{}; //note only set in the ctor
         std::atomic<size_t> svcCount{0};
+
+    private:
+        void setupServiceTrackerOptions() {
+            opts.trackerCreatedCallbackData = this;
+            opts.trackerCreatedCallback = [](void *data) {
+                auto* trk = static_cast<GenericServiceTracker*>(data);
+                {
+                    std::lock_guard<std::mutex> callbackLock{trk->mutex};
+                    trk->state = TrackerState::OPEN;
+                }
+            };
+        }
     };
 
     /**
@@ -307,6 +320,7 @@ namespace celix {
          * @return The new service tracker as shared ptr.
          * @throws celix::Exception
          */
+#if __cplusplus >= 201703L //C++17 or higher
         static std::shared_ptr<ServiceTracker<I>> create(
                 std::shared_ptr<celix_bundle_context_t> cCtx,
                 std::string_view svcName,
@@ -315,7 +329,6 @@ namespace celix {
                 std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> setCallbacks,
                 std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> addCallbacks,
                 std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> remCallbacks) {
-
             auto tracker = std::shared_ptr<ServiceTracker<I>>{
                 new ServiceTracker<I>{
                     std::move(cCtx),
@@ -329,6 +342,29 @@ namespace celix {
             tracker->open();
             return tracker;
         }
+#else
+        static std::shared_ptr<ServiceTracker<I>> create(
+                std::shared_ptr<celix_bundle_context_t> cCtx,
+                std::string svcName,
+                std::string svcVersionRange,
+                celix::Filter filter,
+                std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> setCallbacks,
+                std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> addCallbacks,
+                std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> remCallbacks) {
+            auto tracker = std::shared_ptr<ServiceTracker<I>>{
+                new ServiceTracker<I>{
+                    std::move(cCtx),
+                    std::move(svcName),
+                    std::move(svcVersionRange),
+                    std::move(filter),
+                    std::move(setCallbacks),
+                    std::move(addCallbacks),
+                    std::move(remCallbacks)},
+                AbstractTracker::delCallback<ServiceTracker<I>>()};
+            tracker->open();
+            return tracker;
+        }
+#endif
 
         /**
          * @brief Get the current highest ranking service tracked by this tracker.
@@ -382,6 +418,7 @@ namespace celix {
             std::shared_ptr<const celix::Bundle> owner;
         };
 
+#if __cplusplus >= 201703L //C++17 or higher
         ServiceTracker(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string_view _svcName,
                        std::string_view _svcVersionRange, celix::Filter _filter,
                        std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> _setCallbacks,
@@ -391,63 +428,21 @@ namespace celix {
                 setCallbacks{std::move(_setCallbacks)},
                 addCallbacks{std::move(_addCallbacks)},
                 remCallbacks{std::move(_remCallbacks)} {
-            opts.filter.serviceName = svcName.empty() ? nullptr : svcName.c_str();
-            opts.filter.versionRange = svcVersionRange.empty() ? nullptr : svcVersionRange.c_str();
-            opts.filter.filter = filter.empty() ? nullptr : filter.getFilterCString();
-            opts.callbackHandle = this;
-            opts.addWithOwner = [](void *handle, void *voidSvc, const celix_properties_t* cProps, const celix_bundle_t* cBnd) {
-                auto tracker = static_cast<ServiceTracker<I>*>(handle);
-                auto entry = createEntry(voidSvc, cProps, cBnd);
-                {
-                    std::lock_guard<std::mutex> lck{tracker->mutex};
-                    tracker->entries.insert(entry);
-                    tracker->cachedEntries[entry->svcId] = entry;
-                }
-                tracker->svcCount.fetch_add(1, std::memory_order_relaxed);
-                for (const auto& cb : tracker->addCallbacks) {
-                    cb(entry->svc, entry->properties, entry->owner);
-                }
-                tracker->invokeUpdateCallbacks();
-            };
-            opts.removeWithOwner = [](void *handle, void*, const celix_properties_t* cProps, const celix_bundle_t*) {
-                auto tracker = static_cast<ServiceTracker<I>*>(handle);
-                long svcId = celix_properties_getAsLong(cProps, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-                std::shared_ptr<SvcEntry> entry{};
-                {
-                    std::lock_guard<std::mutex> lck{tracker->mutex};
-                    auto it = tracker->cachedEntries.find(svcId);
-                    assert(it != tracker->cachedEntries.end()); //should not happen, added during add callback
-                    entry = it->second;
-                    tracker->cachedEntries.erase(it);
-                    tracker->entries.erase(entry);
-                }
-                for (const auto& cb : tracker->remCallbacks) {
-                    cb(entry->svc, entry->properties, entry->owner);
-                }
-                tracker->invokeUpdateCallbacks();
-                tracker->svcCount.fetch_sub(1, std::memory_order_relaxed);
-                tracker->waitForExpiredSvcEntry(entry);
-            };
-            opts.setWithOwner = [](void *handle, void *voidSvc, const celix_properties_t *cProps, const celix_bundle_t *cBnd) {
-                auto tracker = static_cast<ServiceTracker<I>*>(handle);
-                std::lock_guard<std::mutex> lck{tracker->mutex};
-                auto prevEntry = tracker->highestRankingServiceEntry;
-                if (voidSvc) {
-                    tracker->highestRankingServiceEntry = createEntry(voidSvc, cProps, cBnd);
-                } else {
-                    tracker->highestRankingServiceEntry = nullptr;
-                }
-                for (const auto& cb : tracker->setCallbacks) {
-                    if (tracker->highestRankingServiceEntry) {
-                        auto& e = tracker->highestRankingServiceEntry;
-                        cb(e->svc, e->properties, e->owner);
-                    } else /*"unset"*/ {
-                        cb(nullptr, nullptr, nullptr);
-                    }
-                }
-                tracker->waitForExpiredSvcEntry(prevEntry);
-            };
+            setupServiceTrackerOptions();
+        }
+#else
+        ServiceTracker(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _svcName,
+                       std::string _svcVersionRange, celix::Filter _filter,
+                       std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> _setCallbacks,
+                       std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> _addCallbacks,
+                       std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> _remCallbacks) :
+                GenericServiceTracker{std::move(_cCtx), std::move(_svcName), std::move(_svcVersionRange), std::move(_filter)},
+                setCallbacks{std::move(_setCallbacks)},
+                addCallbacks{std::move(_addCallbacks)},
+                remCallbacks{std::move(_remCallbacks)} {
+            setupServiceTrackerOptions();
         }
+#endif
 
         static std::shared_ptr<SvcEntry> createEntry(void* voidSvc, const celix_properties_t* cProps, const celix_bundle_t* cBnd) {
             long svcId = celix_properties_getAsLong(cProps, OSGI_FRAMEWORK_SERVICE_ID, -1L);
@@ -550,6 +545,66 @@ namespace celix {
         std::set<std::shared_ptr<SvcEntry>, SvcEntryCompare> entries{};
         std::unordered_map<long, std::shared_ptr<SvcEntry>> cachedEntries{};
         std::shared_ptr<SvcEntry> highestRankingServiceEntry{};
+
+    private:
+        void setupServiceTrackerOptions() {
+            opts.filter.serviceName = svcName.empty() ? nullptr : svcName.c_str();
+            opts.filter.versionRange = svcVersionRange.empty() ? nullptr : svcVersionRange.c_str();
+            opts.filter.filter = filter.empty() ? nullptr : filter.getFilterCString();
+            opts.callbackHandle = this;
+            opts.addWithOwner = [](void *handle, void *voidSvc, const celix_properties_t* cProps, const celix_bundle_t* cBnd) {
+                auto tracker = static_cast<ServiceTracker<I>*>(handle);
+                auto entry = createEntry(voidSvc, cProps, cBnd);
+                {
+                    std::lock_guard<std::mutex> lck{tracker->mutex};
+                    tracker->entries.insert(entry);
+                    tracker->cachedEntries[entry->svcId] = entry;
+                }
+                tracker->svcCount.fetch_add(1, std::memory_order_relaxed);
+                for (const auto& cb : tracker->addCallbacks) {
+                    cb(entry->svc, entry->properties, entry->owner);
+                }
+                tracker->invokeUpdateCallbacks();
+            };
+            opts.removeWithOwner = [](void *handle, void*, const celix_properties_t* cProps, const celix_bundle_t*) {
+                auto tracker = static_cast<ServiceTracker<I>*>(handle);
+                long svcId = celix_properties_getAsLong(cProps, OSGI_FRAMEWORK_SERVICE_ID, -1L);
+                std::shared_ptr<SvcEntry> entry{};
+                {
+                    std::lock_guard<std::mutex> lck{tracker->mutex};
+                    auto it = tracker->cachedEntries.find(svcId);
+                    assert(it != tracker->cachedEntries.end()); //should not happen, added during add callback
+                    entry = it->second;
+                    tracker->cachedEntries.erase(it);
+                    tracker->entries.erase(entry);
+                }
+                for (const auto& cb : tracker->remCallbacks) {
+                    cb(entry->svc, entry->properties, entry->owner);
+                }
+                tracker->invokeUpdateCallbacks();
+                tracker->svcCount.fetch_sub(1, std::memory_order_relaxed);
+                tracker->waitForExpiredSvcEntry(entry);
+            };
+            opts.setWithOwner = [](void *handle, void *voidSvc, const celix_properties_t *cProps, const celix_bundle_t *cBnd) {
+                auto tracker = static_cast<ServiceTracker<I>*>(handle);
+                std::lock_guard<std::mutex> lck{tracker->mutex};
+                auto prevEntry = tracker->highestRankingServiceEntry;
+                if (voidSvc) {
+                    tracker->highestRankingServiceEntry = createEntry(voidSvc, cProps, cBnd);
+                } else {
+                    tracker->highestRankingServiceEntry = nullptr;
+                }
+                for (const auto& cb : tracker->setCallbacks) {
+                    if (tracker->highestRankingServiceEntry) {
+                        auto& e = tracker->highestRankingServiceEntry;
+                        cb(e->svc, e->properties, e->owner);
+                    } else /*"unset"*/ {
+                        cb(nullptr, nullptr, nullptr);
+                    }
+                }
+                tracker->waitForExpiredSvcEntry(prevEntry);
+            };
+        }
     };
 
     /**
@@ -695,22 +750,39 @@ namespace celix {
          * @return The new meta tracker as shared ptr.
          * @throws celix::Exception.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         static std::shared_ptr<MetaTracker> create(
                 std::shared_ptr<celix_bundle_context_t> cCtx,
                 std::string_view serviceName,
                 std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerCreated,
                 std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerDestroyed) {
-
             auto tracker = std::shared_ptr<MetaTracker>{
                     new MetaTracker{
                             std::move(cCtx),
-                            serviceName,
+                            std::string{serviceName},
+                            std::move(onTrackerCreated),
+                            std::move(onTrackerDestroyed)},
+                    AbstractTracker::delCallback<MetaTracker>()};
+            tracker->open();
+            return tracker;
+        }
+#else
+        static std::shared_ptr<MetaTracker> create(
+                std::shared_ptr<celix_bundle_context_t> cCtx,
+                std::string serviceName,
+                std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerCreated,
+                std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerDestroyed) {
+            auto tracker = std::shared_ptr<MetaTracker>{
+                    new MetaTracker{
+                            std::move(cCtx),
+                            std::move(serviceName),
                             std::move(onTrackerCreated),
                             std::move(onTrackerDestroyed)},
                     AbstractTracker::delCallback<MetaTracker>()};
             tracker->open();
             return tracker;
         }
+#endif
 
         /**
          * @see AbstractTracker::open
@@ -756,11 +828,11 @@ namespace celix {
     private:
         MetaTracker(
                 std::shared_ptr<celix_bundle_context_t> _cCtx,
-                std::string_view _serviceName,
+                std::string _serviceName,
                 std::vector<std::function<void(const ServiceTrackerInfo&)>> _onTrackerCreated,
                 std::vector<std::function<void(const ServiceTrackerInfo&)>> _onTrackerDestroyed) :
                 AbstractTracker{std::move(_cCtx)},
-                serviceName{_serviceName},
+                serviceName{std::move(_serviceName)},
                 onTrackerCreated{std::move(_onTrackerCreated)},
                 onTrackerDestroyed{std::move(_onTrackerDestroyed)} {}
 
diff --git a/libs/framework/include/celix/UseServiceBuilder.h b/libs/framework/include/celix/UseServiceBuilder.h
index f6c6d11b..6aa8aa24 100644
--- a/libs/framework/include/celix/UseServiceBuilder.h
+++ b/libs/framework/include/celix/UseServiceBuilder.h
@@ -54,11 +54,10 @@ namespace celix {
         //NOTE private to prevent move so that a build() call cannot be forgotten
         UseServiceBuilder(UseServiceBuilder&&) noexcept = default;
     public:
-        explicit UseServiceBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string_view _name, bool _useSingleService = true) :
+        explicit UseServiceBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _name, bool _useSingleService = true) :
                 cCtx{std::move(_cCtx)},
-                name{_name},
-                useSingleService{_useSingleService} {
-        }
+                name{std::move(_name)},
+                useSingleService{_useSingleService} {}
 
         UseServiceBuilder& operator=(UseServiceBuilder&&) = delete;
         UseServiceBuilder(const UseServiceBuilder&) = delete;
@@ -71,7 +70,11 @@ namespace celix {
          * Example:
          *      "(property_key=value)"
          */
+#if __cplusplus >= 201703L //C++17 or higher
         UseServiceBuilder& setFilter(std::string_view f) { filter = celix::Filter{f}; return *this; }
+#else
+        UseServiceBuilder& setFilter(const std::string& f) { filter = celix::Filter{f}; return *this; }
+#endif
 
         /**
          * @brief Set filter to be used to matching services.
diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt
index b021b326..466002dc 100644
--- a/libs/utils/gtest/CMakeLists.txt
+++ b/libs/utils/gtest/CMakeLists.txt
@@ -15,6 +15,11 @@
 # specific language governing permissions and limitations
 # under the License.
 
+set(CELIX_UTIL_TEST_SOURCES_FOR_CXX_HEADERS
+        src/CxxUtilsTestSuite.cc
+        src/CxxPropertiesTestSuite.cc
+        src/CxxFilterTestSuite.cc
+)
 
 add_executable(test_utils
         src/LogUtilsTestSuite.cc
@@ -23,9 +28,7 @@ add_executable(test_utils
         src/HashMapTestSuite.cc
         src/ArrayListTestSuite.cc
         src/FileUtilsTestSuite.cc
-        src/CxxUtilsTestSuite.cc
-        src/CxxPropertiesTestSuite.cc
-        src/CxxFilterTestSuite.cc
+        ${CELIX_UTIL_TEST_SOURCES_FOR_CXX_HEADERS}
 )
 
 target_link_libraries(test_utils PRIVATE Celix::utils GTest::gtest GTest::gtest_main)
@@ -66,14 +69,14 @@ endif ()
 add_test(NAME test_utils COMMAND test_utils)
 setup_target_for_coverage(test_utils SCAN_DIR ..)
 
-
-#Setting standard to C++11 and testing C++ Properties to ensure that this still support C++11.
-#Note that celix Properties are used in the C++11 dependency manager and this be backwards compatible with Celix 2.2.1
-set(CMAKE_CXX_STANDARD 11)
-add_executable(test_properties_with_cxx11
-        src/CxxPropertiesTestSuite.cc
-)
-target_link_libraries(test_properties_with_cxx11 PRIVATE Celix::utils GTest::gtest GTest::gtest_main)
-add_test(NAME test_properties_with_cxx11 COMMAND test_properties_with_cxx11)
-setup_target_for_coverage(test_properties_with_cxx11 SCAN_DIR ..)
+if (CELIX_TEST_FOR_CXX14)
+    #Setting standard to C++14 and testing C++ Properties.h, Filter.h and Utils.h to ensure that C++14 is supported.
+    set(CMAKE_CXX_STANDARD 14)
+    add_executable(test_utils_cxx_headers_with_cxx14
+            ${CELIX_UTIL_TEST_SOURCES_FOR_CXX_HEADERS}
+    )
+    target_link_libraries(test_utils_cxx_headers_with_cxx14 PRIVATE Celix::utils GTest::gtest GTest::gtest_main)
+    add_test(NAME test_utils_cxx_headers_with_cxx14 COMMAND test_utils_cxx_headers_with_cxx14)
+    setup_target_for_coverage(test_utils_cxx_headers_with_cxx14 SCAN_DIR ..)
+endif ()
 
diff --git a/libs/utils/gtest/src/CxxUtilsTestSuite.cc b/libs/utils/gtest/src/CxxUtilsTestSuite.cc
index 11f21e99..4a051043 100644
--- a/libs/utils/gtest/src/CxxUtilsTestSuite.cc
+++ b/libs/utils/gtest/src/CxxUtilsTestSuite.cc
@@ -32,11 +32,13 @@ namespace example {
         std::string VERSION; //dummy non-static VERSION member, should not impact the typeVersion call
     };
 
+#if __cplusplus >= 201703L //C++17 or higher
     class TestType2 {
     public:
         static constexpr std::string_view NAME = "AnotherTestTypeName";
         static constexpr const char * const VERSION = "1.2.0";
     };
+#endif
 
     class TestType3 {
     public:
@@ -52,20 +54,24 @@ TEST_F(CxxUtilsTestSuite, testTypeName) {
     auto name = celix::typeName<example::TestType>();
     EXPECT_FALSE(name.empty());
 
+#if __cplusplus >= 201703L //C++17 or higher
     //When inferring a type name with no provided name, but the type has a NAME static member,
-    //the call should return the string value of the NAME static member
+    //the call should return the string value of the NAME static member (only support if C++17 is used).
     name = celix::typeName<example::TestType2>();
     EXPECT_EQ(std::string{name}, std::string{"AnotherTestTypeName"});
+#endif
 
     //When inferring a type name with a provided name and the type does not have a NAME static member,
     //the call should return the provided name.
     name = celix::typeName<example::TestType>("OverrideName");
     EXPECT_EQ(name, std::string{"OverrideName"});
 
+#if __cplusplus >= 201703L //C++17 or higher
     //When inferring a type name with a provided name and the type also has a NAME static member,
-    //the call should return the provided name.
+    //the call should return the provided name (only support if C++17 is used).
     name = celix::typeName<example::TestType2>("OverrideName");
     EXPECT_EQ(name, std::string{"OverrideName"});
+#endif
 
     //When inferring a type name, where there is a static NAME member but not of the right type (constructable from string),
     //the call should return an inferred name based on __PRETTY_FUNCTION__ (see celix::impl::extractTypeName)
@@ -80,20 +86,24 @@ TEST_F(CxxUtilsTestSuite, testTypeVersion) {
     auto version = celix::typeVersion<example::TestType>();
     EXPECT_TRUE(version.empty());
 
+#if __cplusplus >= 201703L //C++17 or higher
     //When inferring a type version with no provided version and the type has a VERSION static member,
-    //the call should return the value of the static member VERSION.
+    //the call should return the value of the static member VERSION (only support if C++17 is used).
     version = celix::typeVersion<example::TestType2>();
     EXPECT_EQ(std::string{version}, std::string{"1.2.0"});
+#endif
 
     //When inferring a type version with a provided version and the type does not have a VERSION static member,
     //the call should return the provided version.
     version = celix::typeVersion<example::TestType>("2.2.2");
     EXPECT_EQ(version, std::string{"2.2.2"});
 
+#if __cplusplus >= 201703L //C++17 or higher
     //When inferring a type version with a provided version and the type does have a VERSION static member,
-    //the call should return the provided version.
+    //the call should return the provided version (only support if C++17 is used).
     version = celix::typeVersion<example::TestType2>("2.2.2");
     EXPECT_EQ(version, std::string{"2.2.2"});
+#endif
 }
 
 TEST_F(CxxUtilsTestSuite, testSplit) {
diff --git a/libs/utils/include/celix/Filter.h b/libs/utils/include/celix/Filter.h
index ab00ec94..b92890d9 100644
--- a/libs/utils/include/celix/Filter.h
+++ b/libs/utils/include/celix/Filter.h
@@ -59,16 +59,21 @@ namespace celix {
     class Filter {
     public:
         Filter() : cFilter{createFilter("")} {}
-        explicit Filter(std::string_view filterStr) : cFilter{createFilter(filterStr)} {}
+#if __cplusplus >= 201703L //C++17 or higher
+        explicit Filter(std::string_view filterStr) : cFilter{createFilter(filterStr.data())} {}
+#else
+        explicit Filter(const std::string& filterStr) : cFilter{createFilter(filterStr.c_str())} {}
+#endif
+
 
         Filter(Filter&&) = default;
         Filter& operator=(Filter&&) = default;
 
-        Filter(const Filter& rhs) : cFilter{createFilter(rhs.getFilterString())} {}
+        Filter(const Filter& rhs) : cFilter{createFilter(rhs.getFilterString().c_str())} {}
 
         Filter& operator=(const Filter& rhs) {
             if (this != &rhs) {
-                cFilter = createFilter(rhs.getFilterString());
+                cFilter = createFilter(rhs.getFilterString().c_str());
             }
             return *this;
         }
@@ -107,17 +112,30 @@ namespace celix {
          * @brief Find the attribute based on the provided key.
          * @return The found attribute value or an empty string if the attribute was not found.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         [[nodiscard]] std::string findAttribute(std::string_view attributeKey) const {
             auto* cValue = celix_filter_findAttribute(cFilter.get(), attributeKey.data());
             return cValue == nullptr ? std::string{} : std::string{cValue};
         }
+#else
+        std::string findAttribute(const std::string& attributeKey) const {
+            auto* cValue = celix_filter_findAttribute(cFilter.get(), attributeKey.data());
+            return cValue == nullptr ? std::string{} : std::string{cValue};
+        }
+#endif
 
         /**
          * @brief Check whether the filter has a attribute with the provided attribute key.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         [[nodiscard]] bool hasAttribute(std::string_view attributeKey) const {
             return celix_filter_findAttribute(cFilter.get(), attributeKey.data()) != nullptr;
         }
+#else
+        bool hasAttribute(const std::string& attributeKey) const {
+            return celix_filter_findAttribute(cFilter.get(), attributeKey.data()) != nullptr;
+        }
+#endif
 
         /**
          * @brief Check whether the filter indicates the mandatory presence of an attribute with a specific value for the provided attribute key.
@@ -128,12 +146,18 @@ namespace celix {
          *   using this method for attribute key "key1" on filter "(key1>=value1)" yields false.
          *   using this method for attribute key "key1" on filter "(|(key1=value1)(key2=value2))" yields false.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         [[nodiscard]] bool hasMandatoryEqualsValueAttribute(std::string_view attributeKey) const {
              return celix_filter_hasMandatoryEqualsValueAttribute(cFilter.get(), attributeKey.data());
         }
+#else
+        bool hasMandatoryEqualsValueAttribute(const std::string& attributeKey) const {
+            return celix_filter_hasMandatoryEqualsValueAttribute(cFilter.get(), attributeKey.c_str());
+        }
+#endif
 
         /**
-         * @brief Chek whether the filter indicates the mandatory absence of an attribute, regardless of its value, for the provided attribute key.
+         * @brief Check whether the filter indicates the mandatory absence of an attribute, regardless of its value, for the provided attribute key.
          *
          * example:
          *   using this function for attribute key "key1" on the filter "(!(key1=*))" yields true.
@@ -141,9 +165,15 @@ namespace celix {
          *   using this function for attribute key "key1" on the filter "(key1=value)" yields false.
          *   using this function for attribute key "key1" on the filter "(|(!(key1=*))(key2=value2))" yields false.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         [[nodiscard]] bool hasMandatoryNegatedPresenceAttribute(std::string_view attributeKey) const {
             return celix_filter_hasMandatoryNegatedPresenceAttribute(cFilter.get(), attributeKey.data());
         }
+#else
+        bool hasMandatoryNegatedPresenceAttribute(const std::string& attributeKey) const {
+            return celix_filter_hasMandatoryNegatedPresenceAttribute(cFilter.get(), attributeKey.data());
+        }
+#endif
 
         /**
          * @brief Get the underlining C filter object.
@@ -163,11 +193,11 @@ namespace celix {
         }
 
     private:
-        static std::shared_ptr<celix_filter_t> createFilter(std::string_view filterStr) {
-            if (filterStr.empty()) {
+        static std::shared_ptr<celix_filter_t> createFilter(const char* filterStr) {
+            if (filterStr == nullptr || strnlen(filterStr, 1) == 0) {
                 return nullptr;
             }
-            auto* cf = celix_filter_create(filterStr.data());
+            auto* cf = celix_filter_create(filterStr);
             if (cf == nullptr) {
                 throw celix::FilterException{"Invalid LDAP filter '" + std::string{filterStr} + "'"};
             }
diff --git a/libs/utils/include/celix/Properties.h b/libs/utils/include/celix/Properties.h
index 1504dab0..6af04f82 100644
--- a/libs/utils/include/celix/Properties.h
+++ b/libs/utils/include/celix/Properties.h
@@ -296,6 +296,9 @@ namespace celix {
             return celix_properties_getAsBool(cProps.get(), key.data(), defaultValue);
         }
 
+        /**
+         * @brief Sets a T&& property. Will use (std::) to_string to convert the value to string.
+         */
         template<typename T>
         void set(std::string_view key, T&& value) {
             if constexpr (std::is_same_v<std::decay_t<T>, bool>) {
@@ -347,13 +350,6 @@ namespace celix {
             celix_properties_set(cProps.get(), key.c_str(), value.c_str());
         }
 
-        /**
-         * @brief Sets a property
-         */
-        void set(const std::string& key, const char* value) {
-            celix_properties_set(cProps.get(), key.c_str(), value);
-        }
-
         /**
          * @brief Sets a bool property
          */
@@ -362,13 +358,22 @@ namespace celix {
         }
 
         /**
-         * @brief Sets a T property. Will use std::to_string to convert the value to string.
+         * @brief Sets a T property. Will use (std::) to_string to convert the value to string.
          */
         template<typename T>
         void set(const std::string& key, T value) {
             using namespace std;
             celix_properties_set(cProps.get(), key.c_str(), to_string(value).c_str());
         }
+
+        /**
+         * @brief Sets a const char* property.
+         */
+        template<>
+        void set<const char*>(const std::string& key, const char* value) {
+            using namespace std;
+            celix_properties_set(cProps.get(), key.c_str(), value);
+        }
 #endif
 
         /**
diff --git a/libs/utils/include/celix/Utils.h b/libs/utils/include/celix/Utils.h
index 5a72e36a..8eb25f61 100644
--- a/libs/utils/include/celix/Utils.h
+++ b/libs/utils/include/celix/Utils.h
@@ -83,6 +83,27 @@ namespace impl {
 }
 }
 
+namespace celix {
+    /**
+     * @brief Splits a string using the provided delim.
+     *
+     * Also trims the entries from whitespaces.
+     * @param str The string to split
+     * @param delimiter The delimiter to use (default ",")
+     */
+    inline std::vector<std::string> split(const std::string& str, const std::string& delimiter = ",") {
+        std::vector<std::string> result{};
+        std::string delimiters = std::string{delimiter} + " \t";
+        size_t found;
+        size_t pos = 0;
+        while ((found = str.find_first_not_of(delimiters, pos)) != std::string::npos) {
+            pos = str.find_first_of(delimiters, found);
+            result.emplace_back(str.substr(found, pos - found));
+        }
+        return result;
+    }
+}
+
 #if __cplusplus >= 201703L //C++17 or higher
 namespace celix::impl {
 
@@ -194,25 +215,6 @@ namespace celix {
             return "";
         }
     }
-
-    /**
-     * @brief Splits a string using the provided delim.
-     *
-     * Also trims the entries from whitespaces.
-     * @param str The string to split
-     * @param delimiter The delimiter to use (default ",")
-     */
-     inline std::vector<std::string> split(std::string_view str, std::string_view delimiter = ",") {
-        std::vector<std::string> result{};
-        std::string delimiters = std::string{delimiter} + " \t";
-        size_t found;
-        size_t pos = 0;
-        while ((found = str.find_first_not_of(delimiters, pos)) != std::string::npos) {
-            pos = str.find_first_of(delimiters, found);
-            result.emplace_back(str.substr(found, pos - found));
-        }
-        return result;
-     }
 }
 
 #else //Assuming at least C++11