void generate_parsingtree(target_t *node, pid_t *child_pid) { if(node == NULL) return; int ndep = 0; pid_t cpid[node->nDependencyCount]; int status[node->nDependencyCount]; memset(status, 0, node->nDependencyCount); while(ndep < node->nDependencyCount) { generate_parsingtree(find_target(node->szDependencies[ndep]), cpid+ndep); ndep++; } // Wait for all the children to execute ndep=0; while(ndep < node->nDependencyCount) { cpid[ndep] = waitpid( cpid[ndep], status+ndep, 0); ndep++; } // Execute the code if the dependencies are modified; ndep=0; int virginity = 1; while(ndep < node->nDependencyCount) { int temp = compare_modification_time(node->szTarget, node->szDependencies[ndep]); if(temp!=1) virginity = -1; ndep++; } if(virginity ==-1) { /* virginity is lost. */ *child_pid = fork(); if(*child_pid==0) { system(node->szCommand); printf("\n%s\t%d", node->szCommand, getpid()); exit(0); } } else { /* virginity is maintained. */ printf("\n no need of %s", node->szCommand); } }
int main(int argc, char **argv) { // Declarations for getopt extern int optind; extern char * optarg; int ch; char * format = "f:hnBm:"; // Default makefile name will be Makefile char szMakefile[64] = "Makefile"; char szTarget[64]; char szLog[64]; // boolean flags for each option. int b = 0; int n = 0; int m = 0; int f = 0; int file; // keep track of stdout so we can return to default output int stdOutClone = dup(1); while((ch = getopt(argc, argv, format)) != -1) { switch(ch) { case 'f': strcpy(szMakefile, strdup(optarg)); f = 1; break; case 'n': n = 1; break; case 'B': b = 1; break; case 'm': m = 1; strcpy(szLog, strdup(optarg)); fprintf(stderr,"log name: %s\n",szLog); file = open(szLog, O_APPEND|O_RDWR|O_CREAT, 0777); dup2(file, 1); break; case 'h': show_error_message(argv[0]); exit(1); default: show_error_message(argv[0]); exit(1); } } argc -= optind; argv += optind; // at this point, what is left in argv is the targets that were // specified on the command line. argc has the number of them. // If getopt is still really confusing, // try printing out what's in argv right here, then just running // with various command-line arguments. if(argc > 1) { show_error_message(argv[0]); return EXIT_FAILURE; } // build a target_t array of all targets found in the specified Makefile. int parseResult = parse(szMakefile); // Parse graph file or die if(parseResult == -1) { return EXIT_FAILURE; } // target provided. if(argc == 1) { strcpy(szTarget,argv[0]); } // If no target provided, use the first one found in the Makefile. else { strcpy(szTarget,targets[0].szTarget); //fprintf(stderr, "szTarget: %s\n", szTarget); } int i; int j; // how many children to wait for. int waits = 0; for(i = 0; i < 10; i++) { // look for target in the targets array. if(strcmp(szTarget,targets[i].szTarget) == 0) { targets[i].nStatus = 0; targets[i].pid = 1; for(j = 0; j < targets[i].nDependencyCount; j++) { // if the dependency's associated file exists and needs to be updated (or b flag is set) make a child with it as the target. if(is_file_exist(targets[i].szDependencies[j]) != -1){ if(b || compare_modification_time(targets[i].szTarget,targets[i].szDependencies[j]) == 2) { if(targets[i].szDependencies[j][strlen(targets[i].szDependencies[j])-1] == 'c'){ break; } else { targets[i].pid = fork(); if(targets[i].pid == 0) { break; } else { // increment waits for each child created for a given adult. waits++; } } } // if the dependency's associated file does not exist, make a child with it as the target. } else { targets[i].pid = fork(); if(targets[i].pid == 0) { break; // increment waits for each child created for a given adult. } else { waits++; } } } if(targets[i].pid > 0){ int k; // wait for ALL children to finish. for(k = 0; k < waits; k++) { wait(NULL); } // echo commands if n if(n) { char* echoCommand = (char*) calloc(100, 1); strcat(echoCommand, "echo '"); char* command = &targets[i].szCommand[0]; strcat(echoCommand,command); strcat(echoCommand,"'"); system(echoCommand); } // else execute them else { system(targets[i].szCommand); } // debugging code /* echoCommand = (char*) calloc(100, 1); strcat(echoCommand, "echo 'command: "); command = &targets[i].szCommand[0]; strcat(echoCommand,command); strcat(echoCommand," is complete.'"); system(echoCommand); */ } else if (targets[i].pid == 0){ /* this is clunky, but we were up against the clock * so after making a *char[] and having it not work * we just copied that array into a char** */ char* nextArgs[7]; int k; for(k = 0; k < 7; k++){ nextArgs[k] = (char*) calloc(64, 1); } int ind = 1; strcpy(nextArgs[0],"./make4061"); if(f){ strcpy(nextArgs[ind], "-f"); ind++; char* makeFile = (char *) calloc(64, 1); strcpy(makeFile, &szMakefile[0]); strcpy(nextArgs[ind], makeFile); ind++; } if(n) { strcpy(nextArgs[ind], "-n"); ind++; } if(b) { strcpy(nextArgs[ind], "-B"); ind++; } if(m) { strcpy(nextArgs[ind], "-m"); ind++; char* logFile = (char *) calloc(64, 1); strcpy(logFile, &szLog[0]); strcpy(nextArgs[ind], logFile); ind++; } strcpy(nextArgs[ind], &targets[i].szDependencies[j][0]); k = 0; while(nextArgs[k][0] != 0) { k++; } char** realNextArgs = (char**) calloc(i,sizeof(char*)); int j; for(j= 0; j < k; j++){ realNextArgs[j] = (char*) calloc(64, 1); strcpy(realNextArgs[j], nextArgs[j]); } // it doesn't work without this line, but for some reason // this corrupts the third spot in the copy array (it's writing to the 6th). realNextArgs[j] = NULL; //debug /*m = 0; while(m != k){ fprintf(stderr,"Arg %d: %s\n", m, realNextArgs[m]); m++; }*/ execvp(realNextArgs[0], realNextArgs); // child failed if execvp returns. fprintf(stderr, "Not execvp\n"); exit(-1); } else { perror("bad forking"); exit(-1); } break; } } // close the file if writing to log, and reset stdout. if (m == 1) { close(file); dup2(stdOutClone,1); } return EXIT_SUCCESS; }
//Handles all forking and exec'ing of commands. Execs the commands (if there are //any) for the processes with zero dependencies that have not been built. //Decriments the number of dependencies for parents. Also handles timestamps. int forkExec(Node **toBeExeced, int numElements){ int i; int k = 0; int comp; if(strcmp(targ, "clean")==0) commands[1] = 1; for(i=0;i<numElements;i++){ char **execargv; pid_t childpid; int execargc; int status; int recompile = 1; //if recompile is 1, then build //-n flag set if(commands[1] == 0){ recompile = 1; for(k = 0;k<toBeExeced[i]->sizeDepends;k++){ comp = compare_modification_time(toBeExeced[i]->dependencies[k],toBeExeced[i]->target); int child_timestamp = get_file_modification_time(toBeExeced[i]->dependencies[k]); int parent_timestamp = get_file_modification_time(toBeExeced[i]->target); //if the timestamp for one doesn't exist, or the timestamp of the child is greater (newer) than the parent if(comp < 2 || (parent_timestamp == -1)){ recompile = 1; } } } //if child is older than the parent, don't rebuild if(recompile == 0 && commands[0] != 1){ continue; } if (strcmp (toBeExeced[i]->command, " ") != 0){ if(commands[0] == 1){ printf("%s\n", toBeExeced[i]->command); if (toBeExeced[i]->toParent != NULL){ toBeExeced[i]->toParent->numTargetDep--; } continue; } execargc = makeargv (toBeExeced[i]->command," ",&execargv); toBeExeced[i]->pid = childpid = fork(); }else { continue; } if (childpid == -1){ perror("Failed to Fork\n"); return -1; } if(childpid ==0){ execvp(execargv[0],&execargv[0]); perror("Child failed to Exec \n"); return -1; } if(childpid > 0){ wait(&status); if(toBeExeced[i]->toParent != NULL){ toBeExeced[i]->toParent->numTargetDep--; } } freemakeargv(execargv); } return 1; }