lab00 : Review of C++ basics, Makefiles, submit.cs

num ready? description assigned due
lab00 true Review of C++ basics, Makefiles, submit.cs Wed 04/12 03:30PM Mon 04/17 11:59PM

https://ucsb-cs32-s17.github.io/lab/lab00/

Goals

By the time you have finished this lab, you should have demonstrated your ability to:

Step by Step

Step 0: Getting Started

Step 0a: Make sure you have a CSIL account and know how to use it

Ideally, before this lab begins, you will have been instructed to visit the link below, and create your “College of Engineering” computer account:

You should already know the following from CS16 / CS24. If not, alert your TA/instructor immediately:

Q: Can I work on my own computer? A: MAYBE. MAYBE NOT.

It MIGHT, SOMETIMES, be possible to do SOME of the course work on your own computer that is connected to the Internet. In lecture, I will give VERY brief demonstrations of how to access the CSIL machines over the internet using Windows, Mac, and Linux.

But for some of the assignment, using CSIL is required. You might be able to access CSIL over the internet from your own machine rather than coming to CSIl in person.

At the links below, we a “best effort” introduction to “how to do work on your own computer”, and then YOU ARE ON YOUR OWN.

So, please be aware:

If you are working from your own computer at home or in your dorm, i.e. in not in Phelps 3525, or the CSIL Lab, you may need information on:

Step 0b: Decide: Working solo or pair?

Pair programming is MANDATORY for this lab.

If working in a pair (yes you are): Choose who will be the first driver and who will start as navigator, and then remember to switch (at least once) during the lab. But you should probably know the long-term goal too: each partner should participate in both roles in approximately equal parts over the course of the quarter. We realize it is not possible to equally split time in every lab, but it’s worth trying, and it is possible to make up for unequal splits in future labs. We trust you will try to meet this goal. Thanks!

Also: don’t share passwords. Instead, use scp or email to share files with each other at the end of each work session.

Step 0c: Register on submit.cs for this course, and register pair if working in a pair

  1. Go to https://submit.cs.ucsb.edu
  2. Log in with your umail address as your username. If you don’t already have an account, click “Create Account” and follow the instruction.
  3. Once you are logged in, click on the Join CS32_s17 button.
  4. Go to the page for Lab 00 and click on Join Group.
  5. Enter the email address of your pair partner.
  6. Your pair partner now should log on to submit.cs, join the class, and accept the invitation.

Step 0d: Create your ~/cs32/lab00 directory

Create a ~/cs32/lab00 directory and make it your current directory. You should already know how to do this from previous courses, but in case you need a reminder:

mkdir ~/cs32
mkdir ~/cs32/lab00
cd ~/cs32/lab00

You are responsible for knowing the mkdir and cd commands—though these should be review, so they will not be covered in detail. Questions about their use, however, appear on any exam in this course. So if, up to this point, you’ve just “followed the instructions” without really understanding what you are doing, the time for that has passed.

You are responsible for knowing the the “shell” is the program that you type Unix commands into—commands such as mkdir, cd, etc.

You are also responsible for knowing that the tilde symbol (~) stands for “the user’s home directory”, but only in the shell. There are many contexts where you cannot use the ~ symbol—in fact, almost everywhere other than the Unix command line that a filename is needed, you actually CANNOT use the tilde.

Step 1: Copying some programs

Visit the following web link—you may want to use “right click” (or “control-click” on Mac) to bring up a window where you can open this in a new window or tab: http://www.cs.ucsb.edu/~aduncan/cs32/s17/labs/lab00/ You should see a listing of several C++ programs. We are going to copy those into your ~/cs32/lab00 directory all at once with the following command:

cp ~aduncan/public_html/cs32/s17/labs/lab00/* ~/cs32/lab00

Note: If you get the error message:

cp: target '/cs/student/youruserid/cs32/lab00' is not a directory

then it probably means you didn’t create a ~/cs32/lab00 directory yet. So do that first. The * symbol in this command is a “wildcard”—it means that we want all of the files from the source directory copy be copied into the destination directory namely ~/cs32/lab00. After doing this command, if you cd into ~/cs32/lab00 and use the ls command, you should see several files in your ~/cs32/lab00 directory—the same ones that you see if you visit the link http://www.cs.ucsb.edu/~aduncan/cs32/s17/labs/lab00/ If so, you are ready to move on to the next step. If you don’t see those files, go back through the instructions and make sure you didn’t miss a step. If you still have trouble, ask your TA for assistance.

Step 2: Learn how to learn about some basic Linux commands

The man program can be used to find out details about commands, programs, standard library functions, and anything else for which a man page has been created. You just used mkdir and cd without any options, so why not learn more about those commands right now. First type:

man mkdir

With man, the space key moves to the next page, and q quits. Notice that mkdir is a utility (program) to create directories, and it has three options available:

Try making a directory tree without specifying the -p option, for example:

bash-4.2$ mkdir one/two/three
mkdir: cannot create directory `one/two/three': No such file or directory

Oops. Let’s try it again with -p, and also use the -v option to hear the details:

bash-4.2$ mkdir -p -v one/two/three
mkdir: created directory `one'
mkdir: created directory `one/two'
mkdir: created directory `one/two/three'

Aaah … much better, and so informative!

Now learn some more about cd as follows:

man cd

Uh oh … it seems that cd is a built-in shell command, not a program, and it does not have its own man page. If you spacebar down a ways though, you will find a section that starts out as follows:

cd [-L|-P] [dir]
       Change  the  current directory to dir. ...

That’s all you really need to know in this case, which is a good thing since the rest of the text for this command is not very helpful (-L and -P both relate to symbolic links). Some built-in commands do have their own pages though, and so man is usually a good place to start looking for information. By the way, before going to Step 3, learn more about man as follows:

man man

Step 3: Reviewing Makefiles

We are now going to create a Makefile.

In many previous labs in CS16 and CS24, you may have copied your Makefile from the instructors directory. However, for this lab, you are going to make it yourself from scratch. This is because now that you are in CS32, it is finally time, if you haven’t yet, to learn completely how a Makefile works—every single part of it—and to be able to create, modify and debug your own Makefiles as needed.

Step 3a: Specifying which C++ compiler to use

The first thing we should do is edit our Makefile using emacs or vim, or whatever text editor you prefer. For example:

On the first line of the file, put this, substituting your name (and that of your pair partner(s) if applicable, for YOUR NAME(S) HERE, as appropriate:

# Makefile for lab00, YOUR NAME(S) HERE, CS32, S17

Then, leave a blank line, and add the following two lines shown here, so that you end up with this as the first four lines of your Makefile:

# Makefile for lab00, YOUR NAME(S) HERE, CS32, S17

CXX=clang++
# CXX=g++

What is a toolchain

A toolchain refers to a set of tools that you use in some programming environment to get your work done. It typically includes a compiler, but may also include:

  • an editor
  • a linker for creating executables
  • a tool for creating libraries (combining compiled code from multiple files into a single file)
  • when compiling on one system and running on another (e.g. development for the Arduino, Android, iPhone, etc.), a tool to transfer the compiled software to the target device.
  • a debugger
  • a profiler (tool to help find where your program is spending most of its cpu time (“hotspots”), or to find memory leaks).

Both GNU and LLVM provide toolchains for working with C++ on Unix. The iOS products (iPhone/iPad/iPod) have their own toolchain, as do platforms such as Android and Arduino.

There are at least four important concepts about Makefiles to take away here:

  1. The pound sign (#) is used to start a comment in a Makefile. That comment extends from the pound sign to the end of the line.
  2. Anytime you have VARIABLE_NAME=value in a Makefile, you are defining a variable.
  3. The variable CXX is special—it is the variable that by default, indicates which compiler should be used for compiling C++ programs.
  4. There are two commonly used C++ compilers that you should be aware of: g++ (the C++ compiler from the GNU toolchain) and clang++ (the C++ compiler that is part of the LLVM toolchain). For more information on what a toolchain is, see the discussion at the right hand side of the page.

So what these lines of code do is this:

Makefile code Explanation
# Makefile for lab00... comment documenting what the Makefile is for
CXX=clang++ The clang++ compiler will be used to compile C++ programs
# CXX=g++ If you want to switch to the g++ compiler for some reason, you can uncomment this line and comment out the CXX=clang++ line.

In the step of this lab where you copied files into your directory, one of the files you copied in was a simple HelloWorld.cpp program. Take a moment to look at the source code of that program, using the Unix more command:

-bash-4.2$ more helloWorld.cpp

The only reason this simple program is here is so we can practice setting up a rule in the Makefile, from scratch, to compile a simple program. Here is what that rule will look like. Add it below the lines we already have, as shown here.

Two important things:

# Makefile for lab00, YOUR NAME(S) HERE, CS32, F15

CXX=clang++
# CXX=g++

helloWorld: helloWorld.o
        ${CXX} helloWorld.o -o helloWorld

What do these two lines mean?

Step 3c: Adding a rule to compile helloWorld.cpp to helloWorld.o

Now it turns out that helloWorld.o is a file we do not have in our directory at the moment. The following rule is one that will create that, so add this to our Makefile next. Remember that you need to use a TAB character on the indented lines, not spaces; so copying and pasting this WILL NOT WORK.

Leave a blank line after your rule for the helloWorld target, and add these two lines to your Makefile:

helloWorld.o: helloWorld.cpp
        ${CXX} -c helloWorld.cpp

Now we are ready to test this all out. That’s what we’ll do in the next step.

Step 3d: Testing our Makefile so far

To test what we have so far:

(1) Save your Makefile, and return to the Unix prompt.

(2) At the Unix prompt, type make helloWorld and you should see output like the following:

-bash-4.2$ make helloWorld
clang++ -c helloWorld.cpp
clang++ helloWorld.o -o helloWorld
-bash-4.2$ 

(3) You can now run the helloWorld program by typing ./helloWorld as we have done all along throughout CS16 and CS24. Try that now:

-bash-4.2$ ./helloWorld
Hello, World!
-bash-4.2$ 

(4) Now, if type make helloWorld again, we should see the following output. Do that now. Notice it is different from before:

-bash-4.2$ make helloWorld
make: `helloWorld' is up to date.
-bash-4.2$ 

(5) Now, edit your helloWorld.cpp program, changing the program by adding a comment with your name(s) between the first two comments:

// helloWorld.cpp  P. Conrad for UCSB CS32 F15
// Edited by: YOUR NAME(S) HERE
// minimal Hello World! program for testing Makefiles

Save the change.

(6) Although this change doesn’t really affect the program, it is enough for the Make utility to see that the file has been changed. If we now type make helloWorld again, we’ll see that the program is recompiled:

-bash-4.2$ make helloWorld
clang++ -c helloWorld.cpp
clang++ helloWorld.o -o helloWorld
-bash-4.2$ 

(7) Here is what you need to understand, both to work with make, and for your exams in this course:

So, based on the rules:

helloWorld: helloWorld.o
        ${CXX} helloWorld.o -o helloWorld

helloWorld.o: helloWorld.cpp
        ${CXX} -c helloWorld.cpp

We have this chain of dependencies: helloWorld.cpphelloWorld.ohelloWorld.

After constructing the dependencies, the make program then looks to see which files already exist (or not), and what the time stamps are, and executes the necessary commands in the order needed.

That is why the result, when we make a change to helloWorld.cpp is that the rules are done in this order:

what we see explanation
-bash-4.2$ make helloWorld we type make helloWorld to make the executable, and make constructs the dependency chain helloWorld.cpphelloWorld.ohelloWorld
clang++ -c helloWorld.cpp From the dependency chain, this is the first thing that must be done. It must be done because helloWorld.cpp is “newer” than helloWorld.o. The command recompiles helloWorld.cpp into helloWorld.o—the -c flag indicates “compile only; do not link”, so we get a helloWorld.o file as the result.
clang++ helloWorld.o -o helloWorld This is the link step. It is done because NOW helloWorld.o, which is newly remade from the previous step, is NOW newer than the executable helloWorld. The command relinks the helloWorld.o code (the machine language version of ONLY the code from the helloWorld.cpp file) with the machine language versions of the code in the standard libaries (e.g. the code for the iostream library that provides cout, endl, among other things.) The result of this command is a new version of the executable file helloWorld
-bash-4.2$ The bash prompt indicates that the command is complete and the shell is ready for our next command.

So what should you know from this for your exams? These items suggest a few of things you might be asked about.

Step 3e: Adding a rule for make clean

Sometimes we may want to remove all of the executable and .o files from our directory. As you may recall from Makefiles that were supplied to you in CS16 and CS24, that is traditionally done with a clean target that allows us to type make clean.

Here are some examples of when that is appropriate:

A clean rule looks like this, and is typically at or near the end of your Makefile. Add this to your Makefile now. Note that the second line starts with a tab, and that there should be a blank line after your rule.

clean: 
        /bin/rm -f *.o helloWorld

make clean almost always runs the clean rule. In general, any Makefile target with no files specified after the colon is always run when it is invoked. Technically, there is one exception: when there is a file that has exactly the same name as the rule in the file. So it is best to avoid having any executable or other file with the exact name clean. In such a case, the make clean rule would never be invoked. That’s what we call a corner case—it rarely happens in practice, but is possible in theory, so its good to keep in mind.)

The fact that this rule has clean: as the first line with nothing after the colon (:) means that clean does not depend on anything. That has a special meaning in a Makefile—it means that every time we invoke make clean, the commands following the first line of the rule will always be executed. (Well, almost always. See the note at right for an exception.)

So make clean always results in the command /bin/rm -f *.o helloWorld being executed, which removes all .o files (the * being a wildcard that matches any filename.

Why/bin/rm -f rather than just rm?

Step 3f: Testing the make clean rule

-bash-4.2$ make clean
/bin/rm -f *.o helloWorld
-bash-4.2$ make helloWorld
clang++ -c helloWorld.cpp
clang++ helloWorld.o -o helloWorld
-bash-4.2$ make helloWorld
make: `helloWorld' is up to date.
-bash-4.2$ 

Now let’s test it out. Run make clean, then run make helloWorld twice.

Your output should look like what you see at right.

Be able to predict how typing make clean will affect what happens when make commands are invoked, and be able to explain why.

Step 4: Adding rules to support separate compilation

Now that we have practiced a bit on some simple Makefile rules for a “Hello, World!” progam, we are ready to put in some Makefile rules for something a bit more complex. In this weeks program, we are working with some code that is basically review from CS16, but will set us up for some of the advanced material we’ll be covering in CS32. This code deals with simple arrays in C++, finding min and max, and differentiating between index and value. So, nothing too complicated.

The code is in the following source files:

+-----------------------+-----------------------+-----------------------+
| Filename              | Purpose               | Do I need\            |
|                       |                       | to modify\            |
|                       |                       | this file?            |
+=======================+=======================+=======================+
|                       | Function definitions  | YES                   |
|                       | for five functions.   |                       |
|   arrayFuncs.cpp      | Two are complete,     |                       |
|                       | three are stubs\      |                       |
|                       | <b>Your job in this   |                       |
|                       | lab is to replace the |                       |
|                       | stubs with working    |                       |
|                       | code</b>              |                       |
+-----------------------+-----------------------+-----------------------+
|                       | function prototypes   | NO                    |
|    arrayFuncs.h       | for five functions    |                       |
|                       | defined in            |                       |
|                       | arrayFuncs.cpp        |                       |
+-----------------------+-----------------------+-----------------------+
|                       | test cases for        | NO                    |
|                       | functions defined in  |                       |
|                       | arrayFuncs.cpp\       |                       |
|    lab00Test.cpp      | <b>This is the only   |                       |
|                       | file in this lab with |                       |
|                       | a main()              |                       |
|                       | function</b>\         |                       |
|                       | (other than           |                       |
|                       | helloWorld.cpp)       |                       |
+-----------------------+-----------------------+-----------------------+
|                       | definitions for       | NO                    |
|                       | functions that        |                       |
|     tddFuncs.cpp      | support test-driven   |                       |
|                       | development:\         |                       |
|                       | assertEquals,         |                       |
|                       | assertTrue, etc.      |                       |
+-----------------------+-----------------------+-----------------------+
|                       | function prototypes   | NO                    |
|    tddFuncs.h         | for functions defined |                       |
|                       | in tddFuncs.cpp       |                       |
+-----------------------+-----------------------+-----------------------+

The file lab00Test.cpp is the one with a main function in it. So that is the one that we make an executable from.

We make an executable from it by linking its .o version together with the .o versions of the other .cpp files. The first line of the rule looks like this:

lab00Test: lab00Test.o tddFuncs.o arrayFuncs.o

That says that the executable for lab00Test depends on the .o files lab00Test.o, tddFuncs.o and arrayFuncs.o, which are in turn, the compiled machine code versions of lab00Test.cpp, tddFuncs.cpp and arrayFuncs.cpp.

The line that follows this one is the command to link these .o files into the executable. Remember that the second line here MUST START WITH A TAB, not with spaces. You CANNOT JUST COPY AND PASTE FROM THIS WEB PAGE.

lab00Test: lab00Test.o tddFuncs.o arrayFuncs.o
        ${CXX} lab00Test.o tddFuncs.o arrayFuncs.o -o lab00Test

Put that in your Makefile, and then try running make lab00Test

Now, you might think that we need to create a rule such as this one next:

lab00Test.o: lab00Test.cpp
        ${CXX} -c lab00Test.cpp 

That is what we would do to tell the make utility how to create lab00Test.o from lab00Test.cpp, with the -c flag (compile only; don’t link). The output file is automatically named by removing the .cpp and replacing it with .o. BUT WE DON’T HAVE TO DO THAT. (See the tip below for an explanation as to why)

Instead, just try typing make lab00Test and it should work:

-bash-4.2$ make lab00Test
clang++    -c -o lab00Test.o lab00Test.cpp
clang++    -c -o arrayFuncs.o arrayFuncs.cpp
clang++    -c -o tddFuncs.o tddFuncs.cpp
clang++ lab00Test.o arrayFuncs.o tddFuncs.o -o lab00Test
-bash-4.2$ 

So read the tip now to understand why we didn’t need those extra rules:

We can actually omit the rules for lab00Test.o, etc.

The reason we can omit this rule is that it follows the pattern of an implicit rule that the Make utility already has in place. That default rule looks like this—it is NOT important (at this point in the course) for you to fully understand all the symbols in this default rule—it is only important that you understand the idea that it replaces the specific rule for helloWorld.o. Later in the course, we will cover the meaning of the various symbols (%, $<, $@).

%.o : %.cpp
        $(CXX) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

Implicit rules are explained more in this section of the GNU Make documentation

As it turns out, we didn’t need the rule for helloWorld.o either. Try commenting it out, and doing a make clean, then a make helloWorld and you’ll see that everything still works just fine. We typically DO needs rules for the linking steps, because Make cannot guess which .o files need to be linked together to create an executable. But we often do NOT need the rules for compiling, if our compile is following the normal naming conventions.

Step 4b: Adjusting the clean rule

So now, we are almost ready to run our ./lab00Test program and start working on getting test cases to pass. BUT FIRST, we need to adjust our make clean rule.

Here’s how it looks now:

clean: 
        /bin/rm -f *.o helloWorld

Here is how it needs to look instead:

clean: 
        /bin/rm -f *.o helloWorld lab00Test

We need to add the lab00Test executable to the make clean rule. In a future lab, we’ll see how we can factor out parts of this to make keeping a Makefile up to date less tedious.

Step 5: Make your the code in arrayFuncs.cpp pass its tests

Here you need to follow the instructions inside the file arrayFuncs.cpp to replace the stubs with working code.

The instructions there should be self-explanatory, and the assignment should be super easy—this is essentially review from CS16, laying a foundation for a discussion of sorting algorithms.

We need to be sure we understand how to find the index of a minimum and maximum element, and how to swap two elements in an array.

With those concepts down, we are ready (next week) to move on to both selection sort and insertion sort.

When your code passes the tests, you are ready to try submitting it to submit.cs

Step 6: Checking your work before submitting

When you are finished, you should be able to type make clean and then make lab00Test then ./lab00Test and see the following output:

-bash-4.2$ ./lab00Test
arrayToString(a,sizeA)={3,14,15,92,65,35,89}
PASSED: arrayToString(a,sizeA)
PASSED: indexOfMin(a,sizeA)
PASSED: indexOfMax(a,sizeA)
PASSED: arrayToString(a,sizeA); after swap(a,0,1)
PASSED: arrayToString(a,sizeA); after swap(a,0,2)
arrayToString(b,sizeB)={79,32,38,46}
PASSED: arrayToString(b,sizeB)
PASSED: indexOfMin(b,sizeB)
PASSED: indexOfMax(b,sizeB)
PASSED: arrayToString(b,sizeB); after swap(b,1,3)
PASSED: arrayToString(b,sizeB); after swap(b,0,2)
arrayToString(c,sizeC)={40,30,20,10}
PASSED: arrayToString(c,sizeC)
PASSED: indexOfMin(c,sizeC)
PASSED: indexOfMax(c,sizeC)
arrayToString(d,sizeD)={11,21,22,23}
PASSED: arrayToString(d,sizeD)
PASSED: indexOfMin(d,sizeD)
PASSED: indexOfMax(d,sizeD)
arrayToString(e,sizeE)={79,32,32,38,46}
PASSED: arrayToString(e,sizeE)
PASSED: indexOfMin(e,sizeE)
PASSED: indexOfMax(e,sizeE)
arrayToString(f,sizeF)={5,32,32,31,6,4,4}
PASSED: arrayToString(f,sizeF)
PASSED: indexOfMin(f,sizeF)
PASSED: indexOfMax(f,sizeF)
arrayToString(g,sizeG)={32,32,38,46,46,4,4}
PASSED: arrayToString(g,sizeG)
PASSED: indexOfMin(g,sizeG)
PASSED: indexOfMax(g,sizeG)
-bash-4.2$

At that point, you are ready to try submitting on the submit.cs system.

An important word about academic honesty and the submit.cs system

We will test your code against other data files too—not just these. So while you might be able to pass the tests on submit.cs now by just doing a hard-coded “cout” of the expected output, that will NOT receive credit.

To be very clear, code like this will pass on submit.cs, BUT REPRESENTS A FORM OF ACADEMIC DISHONESTY since it is an attempt to just “game the system”, i.e. to get the tests to pass without really solving the problem.

I would hope this would be obvious, but I have to say it so that there is no ambiguity: hard coding your output is a form of cheating, i.e. a form of “academic dishonesty”. Submitting a program of this kind would be subject not only to a reduced grade, but to possible disciplinary penalties. If there is any doubt about this fact, please ask your TA and/or your instructor for clarification.

Step 7: Submitting via submit.cs

The command to submit this weeks lab is this one:

Here is the command to submit this week’s labs:

~submit/submit -p 697 Makefile arrayFuncs.cpp

Grading Rubric

This lab is based entirely on the grade assigned by submit.cs. There WILL be labs this quarter where code style is assessed, but this is not one of those labs.

submit.cs automated

Acknowledgements

Some material in this lab is based on work originally written by Mike Costanzo and edited by Phill Conrad. Other parts are original work of Phill Conrad.