In C language Code Structure This exercise contains the following important folders: include: This is where we keep C he
Posted: Thu Jul 14, 2022 2:18 pm
In C language
Code Structure
This exercise contains the following important folders:
include: This is where we keep C header files. Header files are used in C to share definitions across many C source files. That said, for this project, this directory will not be used.
input: This is where any input files that you need to work with will be stored. All input files will have a .in extension.
lib: This is where we keep any libraries that we might use. It will often be empty.
obj: This folder is used for object files that are generated from the C compilation process. This folder is initially empty until you compile your code. You may actually make use of this folder in this project.
output: This is where any output files generated will be stored. All output files need to have a .out extension. This folder will need to be created by your Makefile (mkdir output).
src: This is the source folder where all source code resides. For this project, you won’t be changing anything in this folder.
copysome.c: This is the sole source file for the program that you will need to compile.
test: This is the test folder where you can find all of the public unit tests - if any are given.
test.cpp: This file contains all the public google tests. Technically, this file is written in C++, but you can edit it as though it were C, since the content of this class is fundamental enough to largely be in the intersection of C and C++. This exists for your use, use it as you wish for more formal/automated testing. That said, it probably won’t be much use for this project, and you would need to compile it yourself or add a rule to the Makefile. Since it stands alone, the command gcc test/test.cpp -o make_makefile_test -lstdc++ -lgtest -lgtest_main -lpthread should do the trick (probably even contains more flags than necessary).
Makefile - this is a “build” file. This file is used to compile your code. This time, THIS is where all your work goes. And this is what you submit to the auto-grader.
Testing The Makefile
The natural way to casually test the Makefile is to just run make and see if it compiles copysome.c and generates the executable copysome. You can also check the output directory and see if all the files are generated with the correct number of lines copied.
You will similarly want to test make -e NUMLINES=20 or something (that’ll make more sense after reading the instructions).
You should also test the individual targets, obj/copysome.o, copysome, output, and clean.
TODO
Requirements
So the only thing you need to do is write the Makefile, but this makefile needs to do a number of things by default (make) or if given certain specific targets. See the skeleton Makefile for detailed guidance. Also, we encourage you to go through the makefile examples linked from the Moodle section for this module.
It will be helpful to know that copysome takes arguments in the form ./copysome [-n num_lines] [in_file] [out_file]
Tips/Specific Points
TABS! For the love of all that is good, beware the fact that Makefiles need tabs (not spaces). We highly recommend you try and make whitespace characters visible in the editor of your choice.
Also, beware that a Makefile must be named exactly Makefile with no extension. Some systems “helpfully” add a .txt if you don’t watch out for it. A way around this can be to zip Makefile into a zip file when moving it around.
The Makefile should be placed in the top directory of the project (not in src).
When referring to input files, don’t forget the leading input/ and that output files similarly need output/. This is because the Makefile resides in the folder above input and output.
We want to emphasise the simplicity and power of the makefile rule structure. The basic rules are of the form:
(Notice that tab before [commands]!)
This is generally seen in the form of compiling files, such as:
(Where you could have the all rule claim challenge_test as a dependency, or invoke make challenge_test directly.)
But commands in Makefiles are not restricted to compilation commands. An example is a clean rule:
(So make clean will not recursively consider any dependencies, but will invoke the rm commands.)
In addition to rules that list specific files, make supports pattern rules, which have the form:
where output_pattern and input_pattern have a % in them. For example, to build a .xyz file from a .abc file:
While the challenge does not require any regular pattern rules, you will find use for a static pattern rule, which restricts a pattern rule to apply to specific targets:
Your Makefile should not assume any specific .in files exist. Rather, it should process every .in file in the input directory. The wildcard make function will be helpful for discovering the input files, and the patsubst function can help create the names of the corresponding output files. Our presention described how to describe a dependency for each file in a set of files determined by previous variable settings in the Makefile (static pattern rule), which will also be helpful. Other commands that may be useful include mkdir -p for guaranteeing the existence of a directory, rm -f for deleting a file that may or may not exist in a clean rule, and likewise rm -rf for deleting a directory that may or may not exist and everything in it.
Good Makefile style suggests that each rule should take care of only one kind of action, but may have dependencies than can ultimately cause other things to happen. Consider, for example, what is needed in order to run copysome - it needs to exist, and its output directory also needs to exist. That is what suggested the dependencies for the rule to run copysome, etc.
A final reminder. A Makefile is not procedural, i.e., not something that executes top to bottom. Rules can appear in any order, with the one exception that the first rule is the default rule (most commonly with the target all, meaning “make everything”).
However, variables are built up in the order they appear, and it is generally a good idea to put variable definitions befire rules. The skeleton we provide suggests this.
In sum, you don’t need a lot of lines of Makefile “code”, but (as in any programming) they need to be the right lines!
This skeleton will guide you in preparing a suitable Makefile
# for this challenge.
#
#
# Define your Makefile variables here. They should include:
#
# INPUTS: The names of the input files, as seen from this folder,
# e.g., input/file.in (etc.). The make function "wildcard" will
# be useful for this.
#
# OUTPUTS: The names of the corresponding output files, e.g.,
# output/file.out. These can be constructed from INPUTS using
# the make function "patsubst". Note that patsubst can find and
# copy over a match in the middle of a string, not just at the ends.
# For example, $(patsubst a%b,c%d,axyzb afoob) will produce cxyzd cfood.
#
# NUMLINES: This should be set to the default number of lines for
# copysome to copy.
#
# You may define additional variables as you see fit, but no more are
# necessary for this challenge.
#
#
# Define your rules here. You will need rules for these targets
# (which the auto-grader will check!):
#
# all: This should be the first rule, and should have the output files
# as its prerequisites.
#
# A static pattern rule for building the output files: The first part
# should restrict the rule to apply to only the output files. The target will
# be a pattern that matches an output file, and the first prerequisite will be
# the pattern for the corresponding input file. Other prerequisites are
# copysome (the program), since you need it built before you can run it, and
# output (that is, the output directory), since that directory needs to exist
# for receiving the output files. The recipe should run copysome on the first
# prerequisite (the make automatic variable $< is a way to name that) to build
# the target (the make automatic variable $@ is a way to name that). Don't
# forget to mention NUMLINES as appropriate in the command to run copysome.
#
# obj/copysome.o: A rule to build this from src/copysome.c
#
# copysome: A rule to build this from obj/copysome.o
#
# output: A rule to create the output directory. This has no prerequisites.
# For the recipe, mkdir -p will be helpful.
#
# clean: This has no prerequisites and should remove the output directory and
# all of its contents. It should also remove copysome and obj/copysome.o.
Code Structure
This exercise contains the following important folders:
include: This is where we keep C header files. Header files are used in C to share definitions across many C source files. That said, for this project, this directory will not be used.
input: This is where any input files that you need to work with will be stored. All input files will have a .in extension.
lib: This is where we keep any libraries that we might use. It will often be empty.
obj: This folder is used for object files that are generated from the C compilation process. This folder is initially empty until you compile your code. You may actually make use of this folder in this project.
output: This is where any output files generated will be stored. All output files need to have a .out extension. This folder will need to be created by your Makefile (mkdir output).
src: This is the source folder where all source code resides. For this project, you won’t be changing anything in this folder.
copysome.c: This is the sole source file for the program that you will need to compile.
test: This is the test folder where you can find all of the public unit tests - if any are given.
test.cpp: This file contains all the public google tests. Technically, this file is written in C++, but you can edit it as though it were C, since the content of this class is fundamental enough to largely be in the intersection of C and C++. This exists for your use, use it as you wish for more formal/automated testing. That said, it probably won’t be much use for this project, and you would need to compile it yourself or add a rule to the Makefile. Since it stands alone, the command gcc test/test.cpp -o make_makefile_test -lstdc++ -lgtest -lgtest_main -lpthread should do the trick (probably even contains more flags than necessary).
Makefile - this is a “build” file. This file is used to compile your code. This time, THIS is where all your work goes. And this is what you submit to the auto-grader.
Testing The Makefile
The natural way to casually test the Makefile is to just run make and see if it compiles copysome.c and generates the executable copysome. You can also check the output directory and see if all the files are generated with the correct number of lines copied.
You will similarly want to test make -e NUMLINES=20 or something (that’ll make more sense after reading the instructions).
You should also test the individual targets, obj/copysome.o, copysome, output, and clean.
TODO
Requirements
So the only thing you need to do is write the Makefile, but this makefile needs to do a number of things by default (make) or if given certain specific targets. See the skeleton Makefile for detailed guidance. Also, we encourage you to go through the makefile examples linked from the Moodle section for this module.
It will be helpful to know that copysome takes arguments in the form ./copysome [-n num_lines] [in_file] [out_file]
Tips/Specific Points
TABS! For the love of all that is good, beware the fact that Makefiles need tabs (not spaces). We highly recommend you try and make whitespace characters visible in the editor of your choice.
Also, beware that a Makefile must be named exactly Makefile with no extension. Some systems “helpfully” add a .txt if you don’t watch out for it. A way around this can be to zip Makefile into a zip file when moving it around.
The Makefile should be placed in the top directory of the project (not in src).
When referring to input files, don’t forget the leading input/ and that output files similarly need output/. This is because the Makefile resides in the folder above input and output.
We want to emphasise the simplicity and power of the makefile rule structure. The basic rules are of the form:
(Notice that tab before [commands]!)
This is generally seen in the form of compiling files, such as:
(Where you could have the all rule claim challenge_test as a dependency, or invoke make challenge_test directly.)
But commands in Makefiles are not restricted to compilation commands. An example is a clean rule:
(So make clean will not recursively consider any dependencies, but will invoke the rm commands.)
In addition to rules that list specific files, make supports pattern rules, which have the form:
where output_pattern and input_pattern have a % in them. For example, to build a .xyz file from a .abc file:
While the challenge does not require any regular pattern rules, you will find use for a static pattern rule, which restricts a pattern rule to apply to specific targets:
Your Makefile should not assume any specific .in files exist. Rather, it should process every .in file in the input directory. The wildcard make function will be helpful for discovering the input files, and the patsubst function can help create the names of the corresponding output files. Our presention described how to describe a dependency for each file in a set of files determined by previous variable settings in the Makefile (static pattern rule), which will also be helpful. Other commands that may be useful include mkdir -p for guaranteeing the existence of a directory, rm -f for deleting a file that may or may not exist in a clean rule, and likewise rm -rf for deleting a directory that may or may not exist and everything in it.
Good Makefile style suggests that each rule should take care of only one kind of action, but may have dependencies than can ultimately cause other things to happen. Consider, for example, what is needed in order to run copysome - it needs to exist, and its output directory also needs to exist. That is what suggested the dependencies for the rule to run copysome, etc.
A final reminder. A Makefile is not procedural, i.e., not something that executes top to bottom. Rules can appear in any order, with the one exception that the first rule is the default rule (most commonly with the target all, meaning “make everything”).
However, variables are built up in the order they appear, and it is generally a good idea to put variable definitions befire rules. The skeleton we provide suggests this.
In sum, you don’t need a lot of lines of Makefile “code”, but (as in any programming) they need to be the right lines!
This skeleton will guide you in preparing a suitable Makefile
# for this challenge.
#
#
# Define your Makefile variables here. They should include:
#
# INPUTS: The names of the input files, as seen from this folder,
# e.g., input/file.in (etc.). The make function "wildcard" will
# be useful for this.
#
# OUTPUTS: The names of the corresponding output files, e.g.,
# output/file.out. These can be constructed from INPUTS using
# the make function "patsubst". Note that patsubst can find and
# copy over a match in the middle of a string, not just at the ends.
# For example, $(patsubst a%b,c%d,axyzb afoob) will produce cxyzd cfood.
#
# NUMLINES: This should be set to the default number of lines for
# copysome to copy.
#
# You may define additional variables as you see fit, but no more are
# necessary for this challenge.
#
#
# Define your rules here. You will need rules for these targets
# (which the auto-grader will check!):
#
# all: This should be the first rule, and should have the output files
# as its prerequisites.
#
# A static pattern rule for building the output files: The first part
# should restrict the rule to apply to only the output files. The target will
# be a pattern that matches an output file, and the first prerequisite will be
# the pattern for the corresponding input file. Other prerequisites are
# copysome (the program), since you need it built before you can run it, and
# output (that is, the output directory), since that directory needs to exist
# for receiving the output files. The recipe should run copysome on the first
# prerequisite (the make automatic variable $< is a way to name that) to build
# the target (the make automatic variable $@ is a way to name that). Don't
# forget to mention NUMLINES as appropriate in the command to run copysome.
#
# obj/copysome.o: A rule to build this from src/copysome.c
#
# copysome: A rule to build this from obj/copysome.o
#
# output: A rule to create the output directory. This has no prerequisites.
# For the recipe, mkdir -p will be helpful.
#
# clean: This has no prerequisites and should remove the output directory and
# all of its contents. It should also remove copysome and obj/copysome.o.