1 / 57

Poject1

Mymake, a simplified Make Program. Poject1. Overview. How does a make work? what does a makefile contain? How to implement make program? How to implement commands in a make program?. Make – the working mechanism.

cassia
Download Presentation

Poject1

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Mymake, a simplified Make Program Poject1

  2. Overview • How does a make work? • what does a makefile contain? • How to implement make program? • How to implement commands in a make program?

  3. Make – the working mechanism • Update a program automatically by checking dependency relationships among different pieces of the program according to the rules specified in a makefile • Work in two phases • Read makefiles to build dependency graph of all targets and their prerequisites • Use the dependency graph to determine what targets will need to be update and carry out corresponding commands • Default target for make is the first target specified in a makefile • Rules related to the to be made target will be invoked, others will not be processed

  4. Makefile – its components • Five kinds : explicit rules, implicit rules, variables, directives, and comment • In this project, only explicit rules and comment will be considered. (making life easier) • Rules take the following format: • Target : Prerequisite … • Tab Command • … • All prerequisites must be processed before the target could be made

  5. Implement Make- Phase1 • Scan/read makefile line by line • Remove comments • Save information of all targets • Save information of all prerequisites information • Build the dependency graph • Adjacent matrix (small or very dense graph) • Adjacent list (sparse graph) • Static array Don't need worry about possible memory leakage problems

  6. Implement Make - Graph Representation Adjacent list 3 1 2 1 2 Adjacent matrix-list 3 2 2 3 1 Adjacent matrix 2 3 2 3 1 2 1 1 1 3 2 3

  7. Implement Make - Phase2 • Invoke rules and carry out commands • Target is made after all its prerequisites • Make recursively checks a target's all prerequisites # Makefile Case 1 : Using explict rules main: main.o f1.o f2.o gcc -o main main.o f1.o f2.o main.o: main.c f1.h f2.h gcc -c main.c -o main.o f1.o: f1.c f1.h gcc -c f1.c -o f1.o f2.o: f2.c f2.h gcc -c f2.c -o f2.o clean: rm *.o main main f1.o f2.o main.o f1.c f2.c f1.h f2.h main.c

  8. Implement Make – Traverse dependency graph • Depth First traversal (DFS) • Breadth First traversal (BFS) • DFS should be used in this case. Recursive version ---------------------------------------------------------- DFS(u): Mark u as “Explored” and add u to R For each edge (u,v) incident to u If v is not marked “Explored” then Recursively invoke DFS(v) Endif Endfor Non-Recursive Stack version ---------------------------------------------------------- DFS(u): Initialize S to be a stack with one elements While S is not empty Take a node u from S If Explored[u] = false then Set Explored[u] = true For each edge (u,v) incident to u Add v to the stack S Endfor Endif Endwhile

  9. Implement Make – Modify DFS graph traversal • A cycle must be handled correctly to avoid infinite loop. • A target may not always carry out commands associated with it. Recursive version ---------------------------------------------------------- DFS(u): Mark u as “Made” For each edge (u,v) incident to u If v is not marked “Made” Recursively invoke DFS(v) Endif Endfor If u is need to be made then Carry out the commands associated with u Endif

  10. Implement Make – Cases that a target is needed to be updated • A target does not exist (it is a file). • A target exists and one of its prerequisite is newer than it. (check st_ctime field)

  11. Implement Make – Emulate GNU make • Try to follow the behavior of the GNU make. • Print out error information to indicate what kind of error it might be. • If there are some cases that your make program can not handle, you must make sure it will not crash your make program. (or report as bugs in your README for the project)

  12. Commands to be supported • A simple command with/without arguments • Multiple commands with/without arguments separated by ';' • The 'cd' command (making sense in multiple commands) • Multiple piped commands: cmd1 | cmd2 | cmd3 | cmd4 • A command to be executed in background ('&') • A command with redirected I/O ('>' and '<') • No need to handle combinations of the forms  • Support an environment variable MYMAKEPATH storing the paths to search for the commands.

  13. System Calls • fork() • exec() • Overwrites current process with a new one • 6 different versions • http://www.opengroup.org/onlinepubs/000095399/functions/exec.html • We use execv()‏ • int execv(const char *path, char *const argv[])‏ • path is full path to the file • argv[] is a list of arguments • First arg is the name of the executable • Last arg is a null pointer • wait(), waitpid()

  14. Simple Command int simplecmd(char *argv[]) { int ret = 0 ; if ((pid = fork()) == 0) { if (execv(argv[0], argv) == -1) { perror(“execv”); exit(-1); } } if (pid == -1) { perror(“fork”); ret = -1; } if ( waitpid(pid, &stat, 0) == -1) { perror(“waitpid”); ret = -1; } return ret; }

  15. Background Command • Difference between background and foreground command. Parent process Child process wait() fork() Parent process Child process fork()

  16. cd Command • Two ways to implement this command • chdir(const char *path) • Change the current work directory • Maintain a variable to store a relative path used for searching for files, cd will change the value of this variable • cd's behavior in GNU make • Considering the following case: • all : • cd bak; ls -l • ls -l • Only the first “ls -l” will be influence by the “cd bak” • Whenever you change the current directory using chdir, you need to change it back.

  17. I/O redirection • Everything in UNIX is a file, and I/O streams are no exception • I/O streams are written and read like files • Each I/O stream has a file descriptor associated with it • I/O redirection is handled through file descriptors • By default each process is created with 3 file descriptors • 0 stdin, 1 stdout, 2 stderr • To redirect I/O means to replace them with files • dup(fd) • Copies a fd and insert it into the first empty file descriptor slot

  18. fork()‏ file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 stdout 2 stderr shell Input Redirection shell

  19. open(input_file, O_RDONLY)‏ file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 stdout 2 stderr Input Redirection shell shell

  20. open(input_file, O_RDONLY)‏ file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 stdout 2 stderr 3 input_file Input Redirection shell shell

  21. file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 stdout 2 stderr 3 input_file Input Redirection close(0)‏ shell shell

  22. dup(3)‏ file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 input_file 1 stdout 2 stderr 3 input_file Input Redirection shell shell

  23. file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 input_file 1 stdout 2 stderr 3 input_file Input Redirection close(3)‏ shell shell

  24. fork()‏ file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 stdout 2 stderr shell Output Redirection shell

  25. open(output_file, O_RDWR | O_CREAT | O_TRUC)‏ file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 stdout 2 stderr Output Redirection shell shell

  26. open(output_file, O_RDWR | O_CREAT | O_TRUC)‏ file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 stdout 2 stderr 3 output_file Output Redirection shell shell

  27. file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 stdout 2 stderr 3 output_file Output Redirection shell shell close(1)‏

  28. dup(3)‏ file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 2 stderr 3 output_file Output Redirection shell shell

  29. file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 output_file 2 stderr 3 output_file Output Redirection dup(3)‏ shell shell

  30. file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 output_file 2 stderr 3 output_file Output Redirection close(3)‏ shell shell

  31. I/O redirection (“>” “<”) • More < 123 fd = open(123, o_rdonly) close(0) dup(fd) close(fd) • ls > 123 fd = open(123, O_RDWR | O_CREAT | O_TRUC) close(1) dup‏(fd) close(fd)

  32. Multipile Piped Commands • Pipes are for Interprocess Communication IPC • ps aux | more • Output of ps is the input of more • int pipe(int filedes[2]); • Creates a pair of file descriptors • File descriptors actually refer to a kernel FIFO data structure • Filedes[1] is for writing • Filedes[0] is for reading • Data written to filedes[1] can be read from filedes [0]

  33. file descriptors 0 stdin 1 stdout 2 stderr Pipe int p1_to_p2[2]; pipe(p1_to_p2); shell

  34. file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] Pipe int p1_to_p2[2]; pipe(p1_to_p2); shell

  35. fork()‏ int p1_to_p2[2]; pipe(p1_to_p2); file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] shell Pipe int p1_to_p2[2]; pipe(p1_to_p2); shell

  36. fork()‏ int p1_to_p2[2]; pipe(p1_to_p2); file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] shell Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell

  37. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  38. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] dup(4)‏ Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  39. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] dup(4)‏ Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  40. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  41. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  42. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr execvp(bin_path, argv)‏ 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  43. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr execvp(bin_path, argv)‏ 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  44. file descriptors file descriptors file descriptors dup(3)‏ 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr execvp(bin_path, argv)‏ 0 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  45. file descriptors file descriptors file descriptors dup(3)‏ 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr execvp(bin_path, argv)‏ 0 p1_to_p2[0] 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  46. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr execvp(bin_path, argv)‏ 0 p1_to_p2[0] 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  47. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr execvp(bin_path, argv)‏ 0 p1_to_p2[0] 1 stdout 2 stderr Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  48. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr execvp(bin_path, argv)‏ 0 p1_to_p2[0] 1 stdout 2 stderr execvp(bin_path, argv)‏ Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  49. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 3 p1_to_p2[0] 4 p1_to_p2[1] 0 stdin 1 p1_to_p2[1] 2 stderr execvp(bin_path, argv)‏ 0 p1_to_p2[0] 1 stdout 2 stderr execvp(bin_path, argv)‏ Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

  50. file descriptors file descriptors file descriptors 0 stdin 1 stdout 2 stderr 0 stdin 1 p1_to_p2[1] 2 stderr execvp(bin_path, argv)‏ 0 p1_to_p2[0] 1 stdout 2 stderr execvp(bin_path, argv)‏ Pipe int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); int p1_to_p2[2]; pipe(p1_to_p2); shell shell shell

More Related