Operating System代写:COMP202 Make A Difference

代写一个类似Make的命令行工具,功能和Make完全一样,可以根据Makefile进行编译。

Introduction

Make is a system utility for building software. After editing a source file, the programmer runs make on the project. Make examines the modification date-time stamp of the source files and works out what commands need to be executed in order to bring the entire project up to date. Make is more efficient than a shell script that compiles everything, because make won’t recompile source files unnecessarily. However, make has some limitations that can, at times, be frustrating.

In this lab assignment, you will develop an implementation of make with a difference. Your make program will still have the basic functionality of make, but it will have some different capabilities that set it apart. Because it is an assignment to be completed in four weeks, there will also be some advanced features of make (particularly the advanced macros) that you do not implement.

However, perhaps one day some of the ideas in this lab may be incorporated into make - in that case, your work may help make a difference to make! Even if that never happens, you will learn about system calls, implement some interesting ideas and become an accomplished C systems programmer.

Because the program you will develop is a different make, we have named it dmake. When explaining the command line, we will use this name even though you can use any name you wish during your development and testing.

Overview and learning outcomes

The primary goal of this lab is for you to gain experience with Unix system calls. For this reason, we will in some cases specify that your program must use a particular system call or one of a group of related system calls. In other cases, we leave it to you to discover the relevant system calls. In all cases, we expect you to read the Unix manual pages as a primary source of information about the parameters and usage of the various system calls. You may access the manual pages on the Internet, but the definitive version for our system is on the system itself and is accessed through the man command. You are responsible to ensure that you are not misled by documentation that may refer to a different operating system.

The learning outcomes of this lab include the following:

  • Ability to write a significant systems program in C
  • Ability to understand Unix man pages and use them as an information source
  • Ability to choose systems calls appropriate to a task
  • Ability to employ systems calls and library calls to achieve a systems task

As with other labs in COMP202, there is an auto-marker for each lab stage that tests your submission, awards a mark and provides feedback. The lab command functions for this lab in the same way as it did for the first lab.

Incremental development

In this lab you are incrementally developing your implementation of dmake. The features that you develop for stage 1 should remain in your solution for later stages so that your final solution has all the capabilities of all the stages. Instead of having different programs for each stage, you will have one program that behaves differently depending on the command line options. You should periodically test your submissions for later stages as submissions for the earlier stages to ensure that you have not broken the earlier features.

Fetching your lab stage

Use the lab command to fetch sample test files for each stage. Refer to this lab specification for the requirements of each lab stage and also to the marking guide that is downloaded with each stage.

Stage 1: Reading and parsing the make file

The first task for dmake is to read the make input file and parse it into an internal representation that can be processed in later stages. To verify that you have parsed the input correctly, you are required to dump the parsed information in a specific debugging syntax.

We do not specify the internal representation that you should use, but we encourage good design. Specifically, we encourage simplicity, ease of programming, and ease of future extensions. It is likely that you will use familiar C constructs such as arrays, structs, character strings, and pointers. Your program should contain suitable comments describing the internal representation of the make file.

You should also consider Some Important Comments on Code Style and Systems Programming Style guidelines.

The system make command reads its input file from Makefile by default. We encourage you to use the system make command to manage your source compilations for this project, so we specify the default input file for dmake as Dmakefile to avoid confusion.

The input file is a text file. Some lines of the input file are empty, some are comments, and the remaining lines are (in this stage) rules. Rules commence with a rule header line that defines targets and dependencies. Each rule contains zero or more commands that are to be executed if the rule fires - i.e. if the targets need to be created or updated.

The syntax of each type of line is as follows. The syntax for dmake is similar to make, but is not the same.

  • Continuation of a line is indicated by a backslash () as the last character. Continuation means that the following line is joined to the end of the current line after removing the backslash, and then the result is treated as a single line. There may be multiple lines of continuation. Continuation may be applied to any type of line: command, header or command.

  • Empty lines contain only zero or more white-space characters - tabs and/or spaces. Empty lines are ignored completely. However, an empty line after a continuation becomes part of the previous line.

  • Comment lines have the character ‘#’ as the first non-white-space character on the line. (White-space characters are tab and space). Comment lines are completely ignored by the parser.

  • Rule header lines commence with a non-white-space character (other than ‘#’) in the first position of the line, and they have a colon (‘:’) somewhere in the line. The contents of dependency lines are file names. The file name(s) appearing before the colon are target(s) - they are the file(s) that the dmake rule is designed to create. The file names appearing after the colon are the dependencies - the files that are required in order to execute the command(s) that create the target(s).

  • Command lines commence with one or more white-space characters (tab or space). Each command line indicates a Unix command that is to be executed. The leading white space should be removed from the command.

For example, consider the following Dmakefile:

# This is a comment
project: project.c defs.h
    gcc -o project project.c

In this simple dmake input file, there is a single comment line and an empty line - both are ignored by the parser. There is also one rule. The rule header indicates that the file project is the target and it depends on project.c and defs.h. The command line provides a gcc command that could be used to create or update the file project from the files project.c and defs.h. In general, rules may have one or more targets, zero or more dependencies and zero or more commands.

It is useful for a systems program such as dmake to have a debug option that reports the internal operation of the program. Indeed, the Linux make command has such an option. However, dmake’s debug option (-z) will behave differently. The debug output from dmake will be appropriate to the lab stage specified in the option and specific to the operation of dmake.

The download for stage 1 includes several sample dmake folders, and corresponding stage 1 debug output. The dmake files are each in their own subdirectory test1, test2, test3, …; the corresponding debug output files are test1.out, test2.out, test3.out, … and the error files are test1.err, test2.err, test3.err, …. The dmake command for each test case is available as test1.cmd, test2.cmd, test3.cmd, … - a this shows you the command-line options for each test case. Note that test9 is the case where the Dmakefile is missing and an error response is required.

Please note the following requirements:

  1. Use getopt(3) (i.e. getopt as described in section 3 of the Unix manual) to parse the dmake command line.
  2. The dmake debug option -z accepts a parameter which is the stage number. So, for stage 1 debug output the option is either “-z1” or “-z 1”, because getopt permits both forms. Clearly, this is different than the debug option for the Unix make command. With this option, dmake should print the stage 1 debug output and then exit without error.
  3. The dmake file name option -f accepts a parameter which is the input file name. Without this option, dmake will read Dmakefile. This option is convenient for testing dmake with several different input files. Your program will be tested both with and without the -f option.
  4. Your program output needs to match the sample output files except for differences in white spacing (see below). The syntax of the debug output is intended to be simple, but should require your program to parse the input file and accurately report the information that has been extracted. The sample output captures both standard output and standard error.
  5. It is required that your program parses the input file and produces an internal data structure representing the dmake rules. A program that produces the correct output but does not fully parse the input is not considered a correct solution and will hinder your progress in the future lab stages. Fully parsing the input means: separating the target file names, separating the dependency file names, and removing leading white space from the commands.cd stages/stage1
  6. Syntax errors in the dmake file should be detected and reported to standard error. The error messages are captured in the appropriate sample output files.
  7. You may read the dmake file using stdio facilities (such as fopen, fgetc, fgets, etc) but you should handle arbitrarily long lines and arbitrarily large files.

Examples:

$ dmake -z1

This command reads Dmakefile and prints out the stage 1 debug report for that input file.

$ dmake -f Dmakefile2 -z1

This command reads Dmakefile2 and prints out the stage 1 debug report for that input file.

Marking

The auto-marker will test your submission for this stage with the test files provided to you and with additional hidden test files. Some tests will be performed using the -f option and some will be performed by using an input file with the name Dmakefile. Therefore, your program must support both modes of operation. You may assume that the hidden test files have similar features as the test files that are provided to you - for example, instances of comments, of rules with and without commands, and both small and large files, and errors. While there are additional features that are introduced in later stages, your program will never be auto-marked using the -z1 option with those additional features. This means that, in later stages, you can add those features to the -z1 debug output (if you wish) without being concerned about failing the stage 1 tests because those features will not be tested with the -z1 option.

When your dmake program is executed with the -z1 option, it should print out the -z1 debugging output and then terminate. It should not continue with stage 2 or other additional processing.

A detailed marking guide is provided to you when you download the stage. Please note the following:

  • Most marks are awarded for correctly passing the test cases that are supplied to you.
  • A significant number of marks are awarded for correctly passing the hidden test cases.
  • Some marks are awarded for meeting specific programming requirements. In particular, you are expected to use relevant system calls and library routines to assist with the parsing of the input file. Also, you are expected to dynamically allocate memory to store the information that you read from the input file, and the amount of memory used will vary depending on the size of the input file.

Stage 2: Determining the commands to be executed

Each rule header specifies one or more target files and zero or more dependencies. The meaning is the same as in make: If the target file does not exist or if it is older than any of the dependency files then the rule should fire. When the rule fires, the commands in the rule are executed. After executing the commands, the targets will have been updated and this may lead to additional rules firing.

Stage 3: Executing commands

The primary task of dmake is to execute the commands that will create or update the targets. In this stage you will implement this feature.

Stage 4: The difference

One of the annoying features of make is that small edits can cause the entire project to be rebuilt. For example, if you edit a comment in a C source file, then that file’s modification time is updated so the file itself is recompiled, then everything that depends on the recompiled object file is also rebuilt even though the object file is actually unchanged. Of course, this behaviour is not incorrect - it merely wastes some time rebuilding parts of the project unnecessarily. For small projects, the impact is not noticeable, but for large projects (such as an OS kernel) it may take a long time to rebuild everything that is potentially affected by the edited file.

The difference in dmake is that it is intended to detect trivial changes and suppress unnecessary execution of other rules. This means comparing a new file with the original file, looking for differences and deciding whether to fire other rules based not only on the timestamp but also on the file content differences.