docs: def build(self):
          '''Connect nodes according to status of targets'''
          # right now we do not worry about status of nodes
          # connecting the output to the input of other nodes
          #
          # NOTE: This is implemented in the least efficient way just for
          # testing. It has to be re-implemented.
          #
          # refer to http://stackoverflow.com/questions/33494376/networkx-add-edges-to-graph-from-node-attributes
          #
          # several cases triggers dependency.
          if 'DAG' in env.config['SOS_DEBUG'] or 'ALL' in env.config['SOS_DEBUG']:
              env.log_to_file('DAG', 'build DAG')
          for wf in range(self._forward_workflow_id + 1):
              indexed = [x for x in self.nodes() if x._wf_index == wf]
              indexed.sort(key=lambda x: x._node_index)
  
              for idx, node in enumerate(indexed):
                  # 1. if a node changes context (using option alias), all later steps
                  # has to rely on it.
                  if node._context['__changed_vars__']:
                      for later_node in indexed[idx + 1:]:
                          if node._context['__changed_vars__'] & (
                                  later_node._context['__signature_vars__']
                                  | later_node._context['__environ_vars__']):
                              self.add_edge(node, later_node)
  
                  # 2. if the input of a step is undetermined, it has to be executed
                  # after all its previous steps.
                  if not node._input_targets.valid() and idx > 0:
                      # if there is some input specified, it does not use default
                      # input, so the relationship can be further looked before
                      if node._input_targets.undetermined():
                          # if the input is dynamic, has to rely on previous step...
                          if 'dynamic' in node._context['__environ_vars__']:
                              self.add_edge(indexed[idx - 1], node)
                          else:
                              # otherwise let us look back.
                              for prev_node in indexed[idx - 1::-1]:
                                  if node._context[
                                          '__environ_vars__'] & prev_node._context[
                                              '__changed_vars__']:
                                      self.add_edge(prev_node, node)
                      else:
                          self.add_edge(indexed[idx - 1], node)
          #
          # 3. if the input of a step depends on the output of another step
          for target, in_node in self._all_depends_files.items():
              if target not in self._all_output_files:
                  continue
              # it is possible that multiple nodes satisfy the same target
              out_node = self._all_output_files[target]
              for i in in_node:
                  for j in out_node:
                      if j != i:
                          self.add_edge(j, i)
          self.mark_dirty()