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 2020/11/10 19:05:29 UTC

[celix] 01/01: Initial refactoring to add a build() call support for the dependency manager (dm, components, service provide and service dependencies)

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

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

commit d820c9edb5da0262bb7c93d4142a2a0a408d5a56
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Tue Nov 10 20:05:07 2020 +0100

    Initial refactoring to add a build() call support for the dependency manager (dm, components, service provide and service dependencies)
---
 libs/framework/gtest/src/dm_tests.cpp              |  30 +++++
 libs/framework/include/celix/dm/Component.h        |  37 ++++--
 libs/framework/include/celix/dm/Component_Impl.h   | 127 ++++++++++++---------
 .../framework/include/celix/dm/DependencyManager.h |   6 +-
 .../include/celix/dm/DependencyManager_Impl.h      |  13 ++-
 .../framework/include/celix/dm/ServiceDependency.h |  27 ++++-
 .../include/celix/dm/ServiceDependency_Impl.h      |  81 ++++++++-----
 7 files changed, 218 insertions(+), 103 deletions(-)

diff --git a/libs/framework/gtest/src/dm_tests.cpp b/libs/framework/gtest/src/dm_tests.cpp
index 18ed4e1..893ed14 100644
--- a/libs/framework/gtest/src/dm_tests.cpp
+++ b/libs/framework/gtest/src/dm_tests.cpp
@@ -75,3 +75,33 @@ TEST_F(DepenencyManagerTests, TestCheckActive) {
     celix_dependencyManager_add(mng, cmp);
     ASSERT_FALSE(celix_dependencyManager_areComponentsActive(mng));
 }
+
+class TestComponent {
+
+};
+
+TEST_F(DepenencyManagerTests, OnlyActiveAfterBuildCheck) {
+    celix::dm::DependencyManager dm{ctx};
+    EXPECT_EQ(0, dm.getNrOfComponents());
+
+    auto& cmp = dm.createComponent<TestComponent>(std::make_shared<TestComponent>(), "test1");
+    EXPECT_EQ(0, dm.getNrOfComponents()); //dm not started yet / comp not build yet
+    EXPECT_TRUE(cmp.isValid());
+
+    cmp.build();
+    EXPECT_EQ(1, dm.getNrOfComponents()); //cmp "build", so active
+}
+
+TEST_F(DepenencyManagerTests, StartDmWillBuildCmp) {
+    celix::dm::DependencyManager dm{ctx};
+    EXPECT_EQ(0, dm.getNrOfComponents());
+
+    auto& cmp = dm.createComponent<TestComponent>(std::make_shared<TestComponent>(), "test1");
+    EXPECT_EQ(0, dm.getNrOfComponents()); //dm not started yet / comp not build yet
+    EXPECT_TRUE(cmp.isValid());
+
+    dm.start();
+    EXPECT_EQ(1, dm.getNrOfComponents()); //cmp "build", so active
+}
+
+//TODO add test where not all svc dependency are active and active them by a build call
diff --git a/libs/framework/include/celix/dm/Component.h b/libs/framework/include/celix/dm/Component.h
index 57b7959..a4eefab 100644
--- a/libs/framework/include/celix/dm/Component.h
+++ b/libs/framework/include/celix/dm/Component.h
@@ -26,15 +26,13 @@
 #include <map>
 #include <string>
 #include <vector>
+#include <atomic>
 
 namespace celix { namespace dm {
 
     class BaseComponent {
-    private:
-        celix_bundle_context_t *context {nullptr};
-        celix_dm_component_t *cCmp {nullptr};
     public:
-        BaseComponent(celix_bundle_context_t *con, const std::string &name) : context{con}, cCmp{nullptr} {
+        BaseComponent(celix_bundle_context_t *con, celix_dependency_manager_t* cdm, const std::string &name) : context{con}, cDepMan{cdm}, cCmp{nullptr} {
             this->cCmp = celix_dmComponent_create(this->context, name.c_str());
             celix_dmComponent_setImplementation(this->cCmp, this);
         }
@@ -52,6 +50,22 @@ namespace celix { namespace dm {
          * Returns the C bundle context
          */
         celix_bundle_context_t* bundleContext() const { return this->context; }
+
+        void runBuild();
+    protected:
+        std::vector<std::shared_ptr<BaseServiceDependency>> dependencies{};
+
+        // 0 = service name
+        // 1 = service version
+        // 2 = properties
+        // 3 = is C++ service (true -> C++, false -> C)
+        // 4 = service pointer
+        std::vector<std::tuple<std::string, std::string, Properties, bool, void*>> inactiveProvidedServices{};
+    private:
+        celix_bundle_context_t* context;
+        celix_dependency_manager_t* cDepMan;
+        celix_dm_component_t *cCmp;
+        std::atomic<bool> cmpAddedToDepMan{false};
     };
 
 
@@ -62,7 +76,6 @@ namespace celix { namespace dm {
         std::unique_ptr<T> instance {nullptr};
         std::shared_ptr<T> sharedInstance {nullptr};
         std::vector<T> valInstance {};
-        std::vector<std::shared_ptr<BaseServiceDependency>> dependencies {};
 
         void (T::*initFp)() = {};
         void (T::*startFp)() = {};
@@ -74,7 +87,7 @@ namespace celix { namespace dm {
         int (T::*stopFpNoExc)() = {};
         int (T::*deinitFpNoExc)() = {};
     public:
-        Component(celix_bundle_context_t *context, const std::string &name);
+        Component(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, const std::string &name);
         ~Component() override;
 
         /**
@@ -83,14 +96,14 @@ namespace celix { namespace dm {
          * Will use new(nothrow) if exceptions are disabled.
          * @return newly created DM Component or nullptr
          */
-        static Component<T>* create(celix_bundle_context_t*, const std::string &name);
+        static Component<T>* create(celix_bundle_context_t*, celix_dependency_manager_t* cDepMan, const std::string &name);
 
         /**
          * Creates a Component using the provided bundle context.
          * Will use new(nothrow) if exceptions are disabled.
          * @return newly created DM Component or nullptr
          */
-        static Component<T>* create(celix_bundle_context_t*);
+        static Component<T>* create(celix_bundle_context_t*, celix_dependency_manager_t* cDepMan);
 
         /**
          * Whether the component is valid. Invalid component can occurs when no new components can be created and
@@ -243,6 +256,14 @@ namespace celix { namespace dm {
          * @return the DM Component reference for chaining (fluent API)
          */
         Component<T>& removeCallbacks();
+
+        /**
+         * 'Build' the component.
+         *  build all the inactive service dependencies.
+         *
+         *  Inactive service dependencies are service dependencies where the `build()` is not yet called.
+         */
+         Component<T>& build();
     };
 }}
 
diff --git a/libs/framework/include/celix/dm/Component_Impl.h b/libs/framework/include/celix/dm/Component_Impl.h
index 484c4d2..37110fa 100644
--- a/libs/framework/include/celix/dm/Component_Impl.h
+++ b/libs/framework/include/celix/dm/Component_Impl.h
@@ -29,31 +29,55 @@
 
 using namespace celix::dm;
 
-template<class T>
-Component<T>::Component(celix_bundle_context_t *context, const std::string &name) : BaseComponent(context, name) {}
+inline void BaseComponent::runBuild() {
+    if (context == nullptr || cDepMan == nullptr) {
+        return;
+    }
 
-template<class T>
-Component<T>::~Component() {
-    this->dependencies.clear();
-}
+    for (auto& provideInfo : inactiveProvidedServices) {
+        std::string& serviceName = std::get<0>(provideInfo);
+        std::string& serviceVersion = std::get<1>(provideInfo);
+        Properties& props = std::get<2>(provideInfo);
+        bool isCppService = std::get<3>(provideInfo);
+        void* intfPtr = std::get<4>(provideInfo);
 
-template<class T>
-template<class I>
-Component<T>& Component<T>::addInterfaceWithName(const std::string &serviceName, const std::string &version, const Properties &properties) {
-    if (!serviceName.empty()) {
         //setup c properties
         celix_properties_t *cProperties = properties_create();
-        properties_set(cProperties, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_CXX_LANGUAGE);
-        for (const auto& pair : properties) {
+        properties_set(cProperties, CELIX_FRAMEWORK_SERVICE_LANGUAGE, isCppService ? CELIX_FRAMEWORK_SERVICE_CXX_LANGUAGE : CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
+        for (const auto& pair : props) {
             properties_set(cProperties, pair.first.c_str(), pair.second.c_str());
         }
 
+        const char *cVersion = serviceVersion.empty() ? nullptr : serviceVersion.c_str();
+        celix_dmComponent_addInterface(this->cComponent(), serviceName.c_str(), cVersion, intfPtr, cProperties);
+    }
+    inactiveProvidedServices.clear();
+
+    for (auto &dep : dependencies) {
+        dep->runBuild();
+    }
+
+    bool alreadyAdded = cmpAddedToDepMan.exchange(true);
+    if (!alreadyAdded) {
+        celix_dependencyManager_add(cDepMan, cCmp);
+    }
+}
+
+template<class T>
+inline Component<T>::Component(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, const std::string &name) : BaseComponent(context, cDepMan, name) {}
+
+template<class T>
+inline Component<T>::~Component() = default;
+
+template<class T>
+template<class I>
+inline Component<T>& Component<T>::addInterfaceWithName(const std::string &serviceName, const std::string &version, const Properties &properties) {
+    if (!serviceName.empty()) {
         T* cmpPtr = &this->getInstance();
         I* intfPtr = static_cast<I*>(cmpPtr); //NOTE T should implement I
+        void* ptr = static_cast<void*>(intfPtr);
 
-        const char *cVersion = version.empty() ? nullptr : version.c_str();
-        celix_dmComponent_addInterface(this->cComponent(), serviceName.c_str(), cVersion,
-                                       intfPtr, cProperties);
+        inactiveProvidedServices.emplace_back(serviceName, version, properties, true, ptr);
     } else {
         std::cerr << "Cannot add interface with a empty name\n";
     }
@@ -63,7 +87,7 @@ Component<T>& Component<T>::addInterfaceWithName(const std::string &serviceName,
 
 template<class T>
 template<class I>
-Component<T>& Component<T>::addInterface(const std::string &version, const Properties &properties) {
+inline Component<T>& Component<T>::addInterface(const std::string &version, const Properties &properties) {
     //get name if not provided
     static_assert(std::is_base_of<I,T>::value, "Component T must implement Interface I");
     std::string serviceName = typeName<I>();
@@ -76,23 +100,16 @@ Component<T>& Component<T>::addInterface(const std::string &version, const Prope
 
 template<class T>
 template<class I>
-Component<T>& Component<T>::addCInterface(const I* svc, const std::string &serviceName, const std::string &version, const Properties &properties) {
-    static_assert(std::is_standard_layout<I>::value, "Service I must be an object with a standard layout");
-    celix_properties_t *cProperties = properties_create();
-    properties_set(cProperties, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
-    for (const auto& pair : properties) {
-        properties_set(cProperties, pair.first.c_str(), pair.second.c_str());
-    }
-
-    const char *cVersion = version.empty() ? nullptr : version.c_str();
-    celix_dmComponent_addInterface(this->cComponent(), serviceName.c_str(), cVersion, svc, cProperties);
-
+inline Component<T>& Component<T>::addCInterface(const I* svc, const std::string &serviceName, const std::string &version, const Properties &properties) {
+    const void* constPtr = static_cast<const void*>(svc);
+    void* ptr = const_cast<void*>(constPtr);
+    inactiveProvidedServices.emplace_back(serviceName, version, properties, false, ptr);
     return *this;
 }
 
 template<class T>
 template<class I>
-Component<T>& Component<T>::removeCInterface(const I* svc){
+inline Component<T>& Component<T>::removeCInterface(const I* svc){
     static_assert(std::is_standard_layout<I>::value, "Service I must be an object with a standard layout");
     celix_dmComponent_removeInterface(this->cComponent(), svc);
     return *this;
@@ -100,21 +117,20 @@ Component<T>& Component<T>::removeCInterface(const I* svc){
 
 template<class T>
 template<class I>
-ServiceDependency<T,I>& Component<T>::createServiceDependency(const std::string &name) {
-    static ServiceDependency<T,I> invalidDep{std::string{}, false};
-    auto dep = std::shared_ptr<ServiceDependency<T,I>> {new ServiceDependency<T,I>(name)};
+inline ServiceDependency<T,I>& Component<T>::createServiceDependency(const std::string &name) {
+    static ServiceDependency<T,I> invalidDep{cComponent(), std::string{}, false};
+    auto dep = std::shared_ptr<ServiceDependency<T,I>> {new ServiceDependency<T,I>(cComponent(), name)};
     if (dep == nullptr) {
         return invalidDep;
     }
-    this->dependencies.push_back(dep);
-    celix_dmComponent_addServiceDependency(cComponent(), dep->cServiceDependency());
+    dependencies.push_back(dep);
     dep->setComponentInstance(&getInstance());
     return *dep;
 }
 
 template<class T>
 template<class I>
-Component<T>& Component<T>::remove(ServiceDependency<T,I>& dep) {
+inline Component<T>& Component<T>::remove(ServiceDependency<T,I>& dep) {
     celix_component_removeServiceDependency(cComponent(), dep.cServiceDependency());
     this->dependencies.erase(std::remove(this->dependencies.begin(), this->dependencies.end(), dep));
     return *this;
@@ -122,36 +138,35 @@ Component<T>& Component<T>::remove(ServiceDependency<T,I>& dep) {
 
 template<class T>
 template<typename I>
-CServiceDependency<T,I>& Component<T>::createCServiceDependency(const std::string &name) {
-    static CServiceDependency<T,I> invalidDep{std::string{}, false};
-    auto dep = std::shared_ptr<CServiceDependency<T,I>> {new CServiceDependency<T,I>(name)};
+inline CServiceDependency<T,I>& Component<T>::createCServiceDependency(const std::string &name) {
+    static CServiceDependency<T,I> invalidDep{cComponent(), std::string{}, false};
+    auto dep = std::shared_ptr<CServiceDependency<T,I>> {new CServiceDependency<T,I>(cComponent(), name)};
     if (dep == nullptr) {
         return invalidDep;
     }
-    this->dependencies.push_back(dep);
-    celix_dmComponent_addServiceDependency(cComponent(), dep->cServiceDependency());
+    dependencies.push_back(dep);
     dep->setComponentInstance(&getInstance());
     return *dep;
 }
 
 template<class T>
 template<typename I>
-Component<T>& Component<T>::remove(CServiceDependency<T,I>& dep) {
+inline Component<T>& Component<T>::remove(CServiceDependency<T,I>& dep) {
     celix_component_removeServiceDependency(cComponent(), dep.cServiceDependency());
     this->dependencies.erase(std::remove(this->dependencies.begin(), this->dependencies.end(), dep));
     return *this;
 }
 
 template<class T>
-Component<T>* Component<T>::create(celix_bundle_context_t *context) {
+inline Component<T>* Component<T>::create(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan) {
     std::string name = typeName<T>();
-    return Component<T>::create(context, name);
+    return Component<T>::create(context, cDepMan, name);
 }
 
 template<class T>
-Component<T>* Component<T>::create(celix_bundle_context_t *context, const std::string &name) {
-    static Component<T> invalid{nullptr, std::string{}};
-    Component<T>* cmp = new (std::nothrow) Component<T>(context, name);
+inline Component<T>* Component<T>::create(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, const std::string &name) {
+    static Component<T> invalid{nullptr, nullptr, std::string{}};
+    Component<T>* cmp = new (std::nothrow) Component<T>(context, cDepMan, name);
     if (cmp == nullptr) {
         cmp = &invalid;
     }
@@ -159,12 +174,12 @@ Component<T>* Component<T>::create(celix_bundle_context_t *context, const std::s
 }
 
 template<class T>
-bool Component<T>::isValid() const {
+inline bool Component<T>::isValid() const {
     return this->bundleContext() != nullptr;
 }
 
 template<class T>
-T& Component<T>::getInstance() {
+inline T& Component<T>::getInstance() {
     if (this->valInstance.size() == 1) {
         return valInstance.front();
     } else if (this->sharedInstance.get() != nullptr) {
@@ -178,7 +193,7 @@ T& Component<T>::getInstance() {
 }
 
 template<class T>
-Component<T>& Component<T>::setInstance(std::shared_ptr<T> inst) {
+inline Component<T>& Component<T>::setInstance(std::shared_ptr<T> inst) {
     this->valInstance.clear();
     this->instance = std::unique_ptr<T> {nullptr};
     this->sharedInstance = std::move(inst);
@@ -186,7 +201,7 @@ Component<T>& Component<T>::setInstance(std::shared_ptr<T> inst) {
 }
 
 template<class T>
-Component<T>& Component<T>::setInstance(std::unique_ptr<T>&& inst) {
+inline Component<T>& Component<T>::setInstance(std::unique_ptr<T>&& inst) {
     this->valInstance.clear();
     this->sharedInstance = std::shared_ptr<T> {nullptr};
     this->instance = std::move(inst);
@@ -194,7 +209,7 @@ Component<T>& Component<T>::setInstance(std::unique_ptr<T>&& inst) {
 }
 
 template<class T>
-Component<T>& Component<T>::setInstance(T&& inst) {
+inline Component<T>& Component<T>::setInstance(T&& inst) {
     this->instance = std::unique_ptr<T> {nullptr};
     this->sharedInstance = std::shared_ptr<T> {nullptr};
     this->valInstance.clear();
@@ -203,7 +218,7 @@ Component<T>& Component<T>::setInstance(T&& inst) {
 }
 
 template<class T>
-Component<T>& Component<T>::setCallbacks(
+inline Component<T>& Component<T>::setCallbacks(
         void (T::*init)(),
         void (T::*start)(),
         void (T::*stop)(),
@@ -257,7 +272,7 @@ Component<T>& Component<T>::setCallbacks(
 }
 
 template<class T>
-Component<T>& Component<T>::setCallbacks(
+inline Component<T>& Component<T>::setCallbacks(
         int (T::*init)(),
         int (T::*start)(),
         int (T::*stop)(),
@@ -311,10 +326,16 @@ Component<T>& Component<T>::setCallbacks(
 }
 
 template<class T>
-Component<T>& Component<T>::removeCallbacks() {
+inline Component<T>& Component<T>::removeCallbacks() {
 
     celix_dmComponent_setCallbacks(this->cComponent(), nullptr, nullptr, nullptr, nullptr);
 
     return *this;
 }
 
+template<typename T>
+inline Component<T>& Component<T>::build() {
+    runBuild();
+    return *this;
+}
+
diff --git a/libs/framework/include/celix/dm/DependencyManager.h b/libs/framework/include/celix/dm/DependencyManager.h
index 3e8b6c1..3a454cb 100644
--- a/libs/framework/include/celix/dm/DependencyManager.h
+++ b/libs/framework/include/celix/dm/DependencyManager.h
@@ -119,7 +119,7 @@ namespace celix { namespace dm {
                 }
                 for (auto it = toBeStartedComponents.begin(); it != toBeStartedComponents.end(); ++it) {
 
-                        celix_dependencyManager_add(cDepMan, (*it)->cComponent());
+                        (*it)->runBuild();
                         {
                                 std::lock_guard<std::recursive_mutex> lock(componentsMutex);
                                 startedComponents.push_back(std::move(*it));
@@ -150,6 +150,10 @@ namespace celix { namespace dm {
             clearStarted.clear();
             clearQueued.clear();
         }
+
+        std::size_t getNrOfComponents() const {
+            return celix_dependencyManager_nrOfComponents(cDepMan);
+        }
     private:
         celix_bundle_context_t *context {nullptr};
         std::vector<std::unique_ptr<BaseComponent>> queuedComponents {};
diff --git a/libs/framework/include/celix/dm/DependencyManager_Impl.h b/libs/framework/include/celix/dm/DependencyManager_Impl.h
index 716a296..13f2ebd 100644
--- a/libs/framework/include/celix/dm/DependencyManager_Impl.h
+++ b/libs/framework/include/celix/dm/DependencyManager_Impl.h
@@ -20,10 +20,10 @@
 using namespace celix::dm;
 
 template<class T>
-Component<T>& DependencyManager::createComponent(std::string name) {
+inline Component<T>& DependencyManager::createComponent(std::string name) {
     Component<T>* cmp = name.empty() ?
-                        Component<T>::create(this->context) :
-                        Component<T>::create(this->context, name);
+                        Component<T>::create(this->context, this->cDepMan) :
+                        Component<T>::create(this->context, this->cDepMan, name);
     if (cmp->isValid()) {
         std::lock_guard<std::recursive_mutex> lock(componentsMutex);
         this->queuedComponents.push_back(std::unique_ptr<BaseComponent> {cmp});
@@ -32,16 +32,17 @@ Component<T>& DependencyManager::createComponent(std::string name) {
 }
 
 template<class T>
-Component<T>& DependencyManager::createComponent(std::unique_ptr<T>&& rhs, std::string name) {
+inline Component<T>& DependencyManager::createComponent(std::unique_ptr<T>&& rhs, std::string name) {
     return this->createComponent<T>(name).setInstance(std::move(rhs));
 }
 
 template<class T>
-Component<T>& DependencyManager::createComponent(std::shared_ptr<T> rhs, std::string name) {
+inline Component<T>& DependencyManager::createComponent(std::shared_ptr<T> rhs, std::string name) {
     return this->createComponent<T>(name).setInstance(rhs);
 }
 
 template<class T>
-Component<T>& DependencyManager::createComponent(T rhs, std::string name) {
+inline Component<T>& DependencyManager::createComponent(T rhs, std::string name) {
     return this->createComponent<T>(name).setInstance(std::forward<T>(rhs));
 }
+
diff --git a/libs/framework/include/celix/dm/ServiceDependency.h b/libs/framework/include/celix/dm/ServiceDependency.h
index b9163f3..0045720 100644
--- a/libs/framework/include/celix/dm/ServiceDependency.h
+++ b/libs/framework/include/celix/dm/ServiceDependency.h
@@ -42,7 +42,9 @@ namespace celix { namespace dm {
 
     class BaseServiceDependency {
     private:
+        celix_dm_component_t* cCmp;
         bool valid;
+        std::atomic<bool> depAddedToCmp{false};
     protected:
         celix_dm_service_dependency_t *cServiceDep {nullptr};
 
@@ -59,7 +61,7 @@ namespace celix { namespace dm {
             }
         }
     public:
-        BaseServiceDependency(bool v)  : valid{v} {
+        BaseServiceDependency(celix_dm_component_t* c, bool v)  : cCmp{c}, valid{v} {
             if (this->valid) {
                 this->cServiceDep = celix_dmServiceDependency_create();
                 //NOTE using suspend as default strategy
@@ -83,6 +85,8 @@ namespace celix { namespace dm {
          * Returns the C DM service dependency
          */
         celix_dm_service_dependency_t *cServiceDependency() const { return cServiceDep; }
+
+        void runBuild();
     };
 
     template<class T>
@@ -91,7 +95,7 @@ namespace celix { namespace dm {
     protected:
         T* componentInstance {nullptr};
     public:
-        TypedServiceDependency(bool valid) : BaseServiceDependency(valid) {}
+        TypedServiceDependency(celix_dm_component_t* cCmp, bool valid) : BaseServiceDependency(cCmp, valid) {}
         ~TypedServiceDependency() override = default;
 
         TypedServiceDependency(const TypedServiceDependency&) = delete;
@@ -109,7 +113,7 @@ namespace celix { namespace dm {
     class CServiceDependency : public TypedServiceDependency<T> {
         using type = I;
     public:
-        CServiceDependency(const std::string &name, bool valid = true);
+        CServiceDependency(celix_dm_component_t* cCmp, const std::string &name, bool valid = true);
         ~CServiceDependency() override = default;
 
         CServiceDependency(const CServiceDependency&) = delete;
@@ -200,6 +204,13 @@ namespace celix { namespace dm {
          * For C service dependencies 'service.lang=C' will be added.
          */
         CServiceDependency<T,I>& setAddLanguageFilter(bool addLang);
+
+        /**
+         * "Build" the service dependency.
+         * A service dependency added to an active component will only become active if the build is called
+         * @return
+         */
+        CServiceDependency<T,I>& build();
     private:
         std::string name {};
         std::string filter {};
@@ -219,7 +230,7 @@ namespace celix { namespace dm {
     class ServiceDependency : public TypedServiceDependency<T> {
         using type = I;
     public:
-        ServiceDependency(const std::string &name = std::string{}, bool valid = true);
+        ServiceDependency(celix_dm_component_t* cCmp, const std::string &name, bool valid = true);
         ~ServiceDependency() override = default;
 
         ServiceDependency(const ServiceDependency&) = delete;
@@ -316,6 +327,14 @@ namespace celix { namespace dm {
          * Should be called before
          */
         ServiceDependency<T,I>& setAddLanguageFilter(bool addLang);
+
+
+        /**
+         * "Build" the service dependency.
+         * A service dependency added to an active component will only become active if the build is called
+         * @return
+         */
+        ServiceDependency<T,I>& build();
     private:
         bool addCxxLanguageFilter {true};
         std::string name {};
diff --git a/libs/framework/include/celix/dm/ServiceDependency_Impl.h b/libs/framework/include/celix/dm/ServiceDependency_Impl.h
index ea4a04a..6229fb6 100644
--- a/libs/framework/include/celix/dm/ServiceDependency_Impl.h
+++ b/libs/framework/include/celix/dm/ServiceDependency_Impl.h
@@ -25,28 +25,35 @@
 
 using namespace celix::dm;
 
+inline void BaseServiceDependency::runBuild() {
+    bool alreadyAdded = depAddedToCmp.exchange(true);
+    if (!alreadyAdded) {
+        celix_dmComponent_addServiceDependency(cCmp, cServiceDep);
+    }
+}
+
 template<class T, typename I>
-CServiceDependency<T,I>::CServiceDependency(const std::string &name, bool valid) : TypedServiceDependency<T>(valid) {
+inline CServiceDependency<T,I>::CServiceDependency(celix_dm_component_t* cCmp, const std::string &name, bool valid) : TypedServiceDependency<T>(cCmp, valid) {
     this->name = name;
     this->setupService();
 }
 
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setVersionRange(const std::string &serviceVersionRange) {
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setVersionRange(const std::string &serviceVersionRange) {
     this->versionRange = serviceVersionRange;
     this->setupService();
     return *this;
 }
 
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setFilter(const std::string &_filter) {
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setFilter(const std::string &_filter) {
     filter = _filter;
     this->setupService();
     return *this;
 }
 
 template<class T, typename I>
-void CServiceDependency<T,I>::setupService() {
+inline void CServiceDependency<T,I>::setupService() {
     if (!this->isValid()) {
         return;
     }
@@ -56,7 +63,7 @@ void CServiceDependency<T,I>::setupService() {
 }
 
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setAddLanguageFilter(bool addLang) {
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setAddLanguageFilter(bool addLang) {
 //    if (!this->isValid()) {
 //        *this;
 //    }
@@ -66,7 +73,7 @@ CServiceDependency<T,I>& CServiceDependency<T,I>::setAddLanguageFilter(bool addL
 }
 
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setRequired(bool req) {
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setRequired(bool req) {
     if (!this->isValid()) {
         return *this;
     }
@@ -75,7 +82,7 @@ CServiceDependency<T,I>& CServiceDependency<T,I>::setRequired(bool req) {
 }
 
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setStrategy(DependencyUpdateStrategy strategy) {
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setStrategy(DependencyUpdateStrategy strategy) {
     if (!this->isValid()) {
         return *this;
     }
@@ -85,7 +92,7 @@ CServiceDependency<T,I>& CServiceDependency<T,I>::setStrategy(DependencyUpdateSt
 
 //set callbacks
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(void (T::*set)(const I* service)) {
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(void (T::*set)(const I* service)) {
     this->setCallbacks([this, set](const I* service, [[gnu::unused]] Properties&& properties) {
         T *cmp = this->componentInstance;
         (cmp->*set)(service);
@@ -94,7 +101,7 @@ CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(void (T::*set)(co
 }
 
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(void (T::*set)(const I* service, Properties&& properties)) {
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(void (T::*set)(const I* service, Properties&& properties)) {
     this->setCallbacks([this, set](const I* service, Properties&& properties) {
         T *cmp = this->componentInstance;
         (cmp->*set)(service, std::move(properties));
@@ -103,7 +110,7 @@ CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(void (T::*set)(co
 }
 
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(std::function<void(const I* service, Properties&& properties)> set) {
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(std::function<void(const I* service, Properties&& properties)> set) {
     this->setFp = set;
     this->setupCallbacks();
     return *this;
@@ -111,7 +118,7 @@ CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(std::function<voi
 
 //add remove callbacks
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(
         void (T::*add)(const I* service),
         void (T::*remove)(const I* service)) {
     this->setCallbacks(
@@ -128,7 +135,7 @@ CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(
 }
 
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(
         void (T::*add)(const I* service, Properties&& properties),
         void (T::*remove)(const I* service, Properties&& properties)
 ) {
@@ -146,7 +153,7 @@ CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(
 }
 
 template<class T, typename I>
-CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(std::function<void(const I* service, Properties&& properties)> add, std::function<void(const I* service, Properties&& properties)> remove) {
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(std::function<void(const I* service, Properties&& properties)> add, std::function<void(const I* service, Properties&& properties)> remove) {
     this->addFp = add;
     this->removeFp = remove;
     this->setupCallbacks();
@@ -155,7 +162,7 @@ CServiceDependency<T,I>& CServiceDependency<T,I>::setCallbacks(std::function<voi
 
 
 template<class T, typename I>
-void CServiceDependency<T,I>::setupCallbacks() {
+inline void CServiceDependency<T,I>::setupCallbacks() {
     if (!this->isValid()) {
         return;
     }
@@ -192,7 +199,7 @@ void CServiceDependency<T,I>::setupCallbacks() {
 }
 
 template<class T, typename I>
-int CServiceDependency<T,I>::invokeCallback(std::function<void(const I*, Properties&&)> fp, const celix_properties_t *props, const void* service) {
+inline int CServiceDependency<T,I>::invokeCallback(std::function<void(const I*, Properties&&)> fp, const celix_properties_t *props, const void* service) {
     Properties properties {};
     const char* key {nullptr};
     const char* value {nullptr};
@@ -213,8 +220,14 @@ int CServiceDependency<T,I>::invokeCallback(std::function<void(const I*, Propert
     return 0;
 }
 
+
 template<class T, class I>
-ServiceDependency<T,I>::ServiceDependency(const std::string &name, bool valid) : TypedServiceDependency<T>(valid) {
+inline CServiceDependency<T,I>& CServiceDependency<T,I>::build() {
+    this->callBuildCallback();
+}
+
+template<class T, class I>
+inline ServiceDependency<T,I>::ServiceDependency(celix_dm_component_t* cCmp, const std::string &name, bool valid) : TypedServiceDependency<T>(cCmp, valid) {
     if (!name.empty()) {
         this->setName(name);
     } else {
@@ -223,7 +236,7 @@ ServiceDependency<T,I>::ServiceDependency(const std::string &name, bool valid) :
 }
 
 template<class T, class I>
-void ServiceDependency<T,I>::setupService() {
+inline void ServiceDependency<T,I>::setupService() {
     if (!this->isValid()) {
         return;
     }
@@ -276,21 +289,21 @@ void ServiceDependency<T,I>::setupService() {
 }
 
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setName(const std::string &_name) {
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setName(const std::string &_name) {
     name = _name;
     setupService();
     return *this;
 }
 
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setFilter(const std::string &_filter) {
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setFilter(const std::string &_filter) {
     filter = _filter;
     setupService();
     return *this;
 }
 
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setVersionRange(const std::string &_versionRange) {
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setVersionRange(const std::string &_versionRange) {
     versionRange = _versionRange;
     setupService();
     return *this;
@@ -298,7 +311,7 @@ ServiceDependency<T,I>& ServiceDependency<T,I>::setVersionRange(const std::strin
 
 
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setAddLanguageFilter(bool addLang) {
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setAddLanguageFilter(bool addLang) {
     this->addCxxLanguageFilter = addLang;
     setupService();
     return *this;
@@ -306,7 +319,7 @@ ServiceDependency<T,I>& ServiceDependency<T,I>::setAddLanguageFilter(bool addLan
 
 //set callbacks
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(void (T::*set)(I* service)) {
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(void (T::*set)(I* service)) {
     this->setCallbacks([this, set](I* srv, [[gnu::unused]] Properties&& props) {
         T *cmp = this->componentInstance;
         (cmp->*set)(srv);
@@ -315,7 +328,7 @@ ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(void (T::*set)(I* s
 }
 
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(void (T::*set)(I* service, Properties&& properties)) {
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(void (T::*set)(I* service, Properties&& properties)) {
     this->setCallbacks([this, set](I* srv, Properties&& props) {
         T *cmp = this->componentInstance;
         (cmp->*set)(srv, std::move(props));
@@ -324,7 +337,7 @@ ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(void (T::*set)(I* s
 }
 
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(std::function<void(I* service, Properties&& properties)> set) {
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(std::function<void(I* service, Properties&& properties)> set) {
     this->setFp = set;
     this->setupCallbacks();
     return *this;
@@ -332,7 +345,7 @@ ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(std::function<void(
 
 //add remove callbacks
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
         void (T::*add)(I* service),
         void (T::*remove)(I* service)) {
     this->setCallbacks(
@@ -349,7 +362,7 @@ ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
 }
 
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
         void (T::*add)(I* service, Properties&& properties),
         void (T::*remove)(I* service, Properties&& properties)
 ) {
@@ -367,7 +380,7 @@ ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
 }
 
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
         std::function<void(I* service, Properties&& properties)> add,
         std::function<void(I* service, Properties&& properties)> remove) {
     this->addFp = add;
@@ -377,19 +390,19 @@ ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
 }
 
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setRequired(bool req) {
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setRequired(bool req) {
     celix_dmServiceDependency_setRequired(this->cServiceDependency(), req);
     return *this;
 }
 
 template<class T, class I>
-ServiceDependency<T,I>& ServiceDependency<T,I>::setStrategy(DependencyUpdateStrategy strategy) {
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::setStrategy(DependencyUpdateStrategy strategy) {
     this->setDepStrategy(strategy);
     return *this;
 }
 
 template<class T, class I>
-int ServiceDependency<T,I>::invokeCallback(std::function<void(I*, Properties&&)> fp, const celix_properties_t *props, const void* service) {
+inline int ServiceDependency<T,I>::invokeCallback(std::function<void(I*, Properties&&)> fp, const celix_properties_t *props, const void* service) {
     I *svc = (I*)service;
 
     Properties properties {};
@@ -411,7 +424,7 @@ int ServiceDependency<T,I>::invokeCallback(std::function<void(I*, Properties&&)>
 }
 
 template<class T, class I>
-void ServiceDependency<T,I>::setupCallbacks() {
+inline void ServiceDependency<T,I>::setupCallbacks() {
     if (!this->isValid()) {
         return;
     }
@@ -447,3 +460,9 @@ void ServiceDependency<T,I>::setupCallbacks() {
     opts.removeWithProps = crem;
     celix_dmServiceDependency_setCallbacksWithOptions(this->cServiceDependency(), &opts);
 }
+
+template<class T, class I>
+inline ServiceDependency<T,I>& ServiceDependency<T,I>::build() {
+    this->runBuild();
+    return *this;
+}