This code should basically perform the actions of a makefile 
struct timespec parallel_evaluate(Rule *rule) {
  int len = dep_length(rule);
  int i = 0;
  struct timespec timestamps[len];
  Dependency *curr = rule->dependencies;
  while (curr != NULL) {
    timestamps[i] = parallel_evaluate(curr->rule);

    curr = curr->next_dep;
    i ++;
  }
  
  struct stat stats;
  char path[strlen(rule->target) + 3];
  strcpy(path, "./");
  strcat(path, rule->target);
  int err = stat(path, &stats);
  if (err == -1) {
    if (rule->actions != NULL) {
      // run the actions for this rule   
      run_actions_parallel(rule->actions);
      
      // call stat again and return the last modified time
      if (stat(path, &stats) == -1) {
        perror("stat");
        exit(1);
      }
      
    } else {
      perror("stat");
      exit(1);
    }
  } else {
    // compare the timestamp from stat to all other timestamps
    i = 0;
    int update = 0;
    while (i < len && update == 0) {
      if (timestamps[i].tv_nsec > stats.st_mtim.tv_nsec) {
        update = 1;
      }
      i ++;
    }

    if (update) {
      run_actions_parallel(rule->actions);
      if (stat(path, &stats) == -1) {
        perror("stat");
        exit(1);
      }
    }
  }
  
  return stats.st_mtim;
}


int dep_length(Rule *rule) {
  int size = 0;
  Dependency *curr = rule->dependencies;
  while (curr != NULL) {
    size ++;
    curr = curr->next_dep;
  }
  return size;
}


int arr_length(char **arr) {
  int i = 0;
  int len = 0;
  while (arr[i] != NULL) {
    len = len + strlen(arr[i]) + 1;
    i ++;
  }

  return len;
}

void run_actions_parallel(Action *actions) {
  Action *curr = actions;
  char *buffer;
  while (curr != NULL) {
    int len = arr_length(curr->args);
    buffer = malloc(len);
    if (buffer == NULL) {
      perror("malloc");
      exit(1);
    }

    args_to_string(curr->args, buffer, len);
    printf("%s\n", buffer);

    int r = fork();
    
    if (r == 0) {
      // child process, run the command
      execvp(curr->args[0], curr->args);

      perror("execvp");
      exit(1);

    } else if (r > 0) {
      // parent process, continue iterating
      curr = curr->next_act;

    } else {
      perror("fork");
      exit(1);
    }
  }
}

