CS 312 - Week 2.2 Class
CS 312 Audio Programming Winter 2020
Table of Contents
2.2 Class
I've graded and returned all homework in the Hand In folder that was there at 8:00am Wed Jan 15.
Graded homework is found in the Return folder.
I will no longer empty the the Hand In folder after today.
Requests
Review your homework in the the Return folder.
Copy it to your CMC /Accounts/home folder or other storage device.
Delete it from the Return folder.
Delete it from the Hand In folder.
Boilerplate
Boilerplate is meant to be copied to the top of every homework file you turn in. Here's an example.
/*************************************************************** hw111_hello.cpp Copyright (c) Carleton College CS312 free open source Assignment: hw111 Duck Donald dduck@carleton.edu Mouse Minny mmouse@carleton.edu DATE: 2019-12-15 TIME: 14:46:25 ****************************************************************/ #include <iostream> int main() { std::cout << "hello, world" << std::endl; }
When you complete the hw211_boilerplate homework you'll be able to execute boilerplate with two parameters and paste the result directly into your source code. No more editing.
# boilerplate <assignment> <filename> | pbcopy #example boilerplate hw111 hw111_hello.cpp | pbcopy # Paste directly into your source code
hw22 Setup
Mount your course folder using the Go menu in Mac Finder
smb://courses.ads.carleton.edu/COURSES/cs312-00-w20
Execute in Mac Terminal
setup312 <your_carleton_email_name>
Folder structure
After you've mounted your cs312 course folder the mount point is
/Volumes/cs312-00-w20/StuWork/email_name $HOME312 = /Volumes/cs312-00-w20/StuWork/email_name (same as above) Inside $HOME312 are these folders bin common cs312 googletest (the big download from class 3.2) # anything else is ignored in assignment setups
Execute in Mac Terminal.
## JE TESTING cd $HOME312/cs312 mkdir hw22 cd hw22 mkdir c221_argc_argv cd c221_argc_argv touch c221_argc_argv.cpp cd .. mkdir hw221_boilerplate #empty for now mkdir hw222_CMidiPacket cd hw222_CMidiPacket cp $HOME312/cs312/hw21/hw212_CMidiPacket/hw212_CMidiPacket.h ./hw222_CMidiPacket.h cp $HOME312/cs312/hw21/hw212_CMidiPacket/hw212_CMidiPacket.cpp ./hw222_CMidiPacket.cpp cp $HOME312/cs312/hw21/hw212_CMidiPacket/hw212_main.cpp ./hw222_main.cpp touch hw222_test_CMidiPacket.h touch hw222_test_CMidiPacket.cpp for file in hw222*; do sed -i '' 's/HW212/HW222/g' $file; sed -i '' 's/hw212/hw222/g' $file; sed -i '' 's/CMP21/CMP22/g' $file; done ls -lR $HOME312/cs312/hw22 # minus ell R
Folder structure
$HOME312/cs312/hw22 ├── c221_argc_argv │ └── c221_argc_argv.cpp ├── hw221_boilerplate (empty) └── hw222_CMidiPacket ├── hw222_CMidiPacket.cpp ├── hw222_CMidiPacket.h ├── hw222_main.cpp ├── hw222_test_CMidiPacket.cpp └── hw222_test_CMidiPacket.h
c221_argc_argv
This section will help you complete hw221_boilerplate.cpp. This c221_argc_argv section does not have to be turned in but hw221_boilerplate.cpp dies.
Quit vsCode if it is open.
Execute these commands in Mac Terminal. You do not have to type the comments.
# make sure you're in the correct directory cd $HOME/cs312/hw22 mkdir c221_argc_argv # change the working directory to $HOME/cs312/hw22/c22_argc_argv cd c221_argc_argv # create a new file argc_argv.cpp touch argc_argv.cpp code .
What's this argc_argv stuff anyway?
Open argc_argv.cpp and type main. After a very slight pause the Snippet popup will appear and the line for main is highlighted.
Type Enter and you should see this.
This is the original C main(…) function carried over into C++.
Note the white dot in the filename tab that indicates the file is not saved.
argc and argv[] describe additional parameters that are passed on the command line into into the main() function.
The shell interprets these parameters using argc and the array argv[ ].
- int argc
- The number of parameters passed in.
- char const *argv[ ]
- An array of strings from argv[0] to argv[argc]
argv[0] is the name of the command
argv[1] is the first parameter
…
argv[argc] is the final parameter
Parameters are parsed by white space.
If any parameter contains white space it must be quoted.
- What does char const *argv[ ] mean?
- It basically means you cannot change the parameters in main().
Replace/copy/paste
// argc_argv.cpp #include <iostream> int main(int argc, char const *argv[]) { std::cout << "argc\t\t" << argc << std::endl; for (int ix = 0; ix < argc; ++ix) std::cout << "argv[" << ix << "]\t" << argv[ix] << std::endl; return 0; }
Compile
# compile cl argc_argv.cpp
Run
./a.out
Output
argc 1 argv[0] ./a.out
- Notes
- argc: There is one parameter, the name of the program. argv[0]: is always the program name.
Run again
This time with eight parameters.
./a.out 1 2 "buckle my shoe" 3 4 shut the door
Output
argc 9 argv[0] ./a.out argv[1] 1 argv[2] 2 argv[3] buckle my shoe argv[4] 3 argv[5] 4 argv[6] shut argv[7] the argv[8] door
Note: argc is always one more than the number of parameters because arg[0] is the command name.
hw222_CMidiPacket
Overview
In this assignment we're going to learn about three different build systems for C++ projects.
- command line
- This is the one we've been using. It's best suited for quick tests and projects with a very small number of files. It's not efficient for large projects because you, the programmer, have to keep track of which files need to be recompiled in addition to all files that depend on those files. You generally recompile everything.
- make and Makefile
- The make tool and the Makefile text file are available on virtually every platform with a C or C++ compiler. Make was included with early versions of Unix in the late 1970's and is still being used today. Makefiles have a specific language syntax that specifes dependencies between header files and source files and between object files and executable files.It became the de facto build system for almost 4 decades because it sped up the build-run-test cycle by only recompiling files that were changed and those affected by the change.
- CMake and CMakeLists.txt
- CMake appeared in 2000 and has become the modern standard for large software projects. CMake uses a CMakeLists.txt file to build a Makefile that is then used to build the program. CMake can do its work in separate build directory so your source directory stays clean. While cmake can become complex, it is very flexible. The CMakeLists.txt syntax is clearer than the Makefile. CMake will become our build tool of choice for the next several weeks and is the build system of many major open source projects.
Compile / Link
The compiler compiles source files and outputs machine code object files having a .o extension. The linker combines the .o files along with any needed libraries to produce the program output. The clang++ tool does both the compile and link steps. The output object could be an application, a command line tool, or a library.
Copy paste this content into your corresponding files
Build 1 - Command Line
We'll begin with the command line compile. We need to compile three .cpp files. If these are the only .cpp files in the current directory you can use this short form to compile the project. However, if there were other .cpp files in other directory you'd need to specify the files needed.
Build and run
cl hw222_CMidiPacket.cpp hw222_test_CMidiPacket.cpp hw222_main.cpp && ./a.out
Output
The compile must be successful and produce output.
The output will depend on the the progress made in your hw212_CMidiPacket homework.
This is the output you want to see.
0 80 0 0 # length 3 0 c0 11 # length 2 0 90 67 100 # length 3 900 80 67 0 # length 3 1000 90 76 100 # length 3 1900 80 76 0 # length 3 2000 90 72 100 # length 3 2900 80 72 0 # length 3 # 0xFn status not processed # length 0
Build 2 - Make
The make command gets its instructions from a plain text file named Makefile. If Makefile exists in the project directory you can compile your project with a simple make commad. Makefile must begin with capital M and does not have a file extension. You can name the makefile something else like make-osx but then you'll need to use the command make -f make-osx to specify the makefile name.
As part of the compile phase the compiler produces intermediate object files with the extension .o.
As part of the link phase the compiler combines the .o files into the application.
The make file has to specify
- the object files needed by the application
- the .cpp and .h files needed by each object file
Example project files
This hypothetical example contains five files.
- Two header files
- file1.h
- file2.h
- Three source files
- file1.cpp
- file2.cpp
- main.cpp
The contents of the files are not important.
It's the #include dependencies between header and source files that matter.
file1.h
// file1.h ...
file1.cpp
// file1.cpp #include "file1.h" ...
file2.h
// file2.h ...
file2.cpp
// file2.cpp #include "file2.h" #include "file1.h" ...
main.cpp
// main.cpp #include "file2.h" ...
In order to write a Makefile you need to know:
- the object/source/header file dependencies for the compile phase
- the object file dependencies for the link phase.
Compile phase dependencies
Dependencies travel left to right.
OBJECT FILE | DEPENDS ON SOURCE | DEPENDS ON HEADER |
---|---|---|
file1.o | file1.cpp | file1.h |
file2.o | file2.cpp | file2.h, file1.h |
main.o | main.cpp | file2.h |
Link phase dependencies
EXECUTABLE | DEPENDS ON OBJECT FILES |
---|---|
myapp | file1.o, file2.o, main.o |
Makefile syntax rules
- Non indented lines are dependency rules.
- Indented lines are commands.
- Indented lines must begin with a tab character
- # is a comment.
- variables are defined like this APPNAME=this_app_name_is_very_very_long
- defined variables appear like this: $(APPNAME)
This Makefile describes these dependencies.
# Define application name APPNAME=myapp # define the compiler to use CC=clang++ #define the compiler parameters CFLAGS=-c -std=c++17 -Wall # the variables $(CC) $(CFLAGS) expand to clang++ -c -std-c++17 -Wall # -c Only run preprocess, compile, and assemble steps but do not link # define the make command parameter option all, as in: make all all: $(APPNAME) # line 1: cmp221 depends on all three object files # line 2: single TAB followed by linker command, no $(CFLAGS) $(APPNAME): main.o file2.o file1.o $(CC) -g -o $(APPNAME) main.o file2.o file1.o # line 1: main.o depends on file2.h # line 2: single TAB followed by compile command main.o: main.cpp file2.h $(CC) $(CFLAGS) main.cpp # line 1: file2.o depends on file2.h and 1.h # line 2: single TAB followed by compile command file2.o: file2.cpp file2.h file1.h $(CC) $(CFLAGS) file2.cpp # line 1: file1.o depends on file1.h # line 2: single TAB followed by compile command file1.o: file1.cpp file1.h $(CC) $(CFLAGS) file1.cpp # define make command option clean, as in: make clean # removes all the .o object files clean: rm *.o rm ${APPNAME}
Create the Makefile for hw222_CMidiPacket
It's no coincidence that the Makefile we need has the same dependencies as the example Makefile above.
Setup
In vsCode create a new file called Makefile.
Copy/paste the Makefile example above into Makefile.
Makefile is very picky about syntax. A common error is not using a tab character for the indented lines. To view invisible characters in vsCode choose Render Whitespace from the View menu.
You'll need to check for tabs after you've pasted the text. VSCode displays spaces as dots, "tab stops" as vertical bars, and tabs as right pointing arrows.
If you see vertical bars and and the tab arrow as the first character in all indented lines you have tab indentation. Skip to the Find and Replace section below.
If you see vertical bars and dots between beginning each indented line you'll need to convert the spaces to tabs following these steps.
Choose Command Palette… from the View menu.
Shortcut: Shift-Cmd-P
Type the word tab in the text entry box and choose Convert Indentation to Tabs.
You should now see the tab arrow as the the first character in all indented lines. In the picture below one tab equals two spaces. It's a Preference setting in vsCode. Your setting may be different.
Important:
In a Makefile, all indented lines must begin with a tab character.
Save.
Find and Replace
The next task is to change the example names to the CMidiPacket names using Find/Replace.
Example name | CMidiPacket name |
file1 | hw222_CMidiPacket |
file2 | hw222_test_CMidiPacket |
main | hw222_main |
myapp | cmp22 |
Use the vsCode Find/Replace panel.
Shortcut: Opt-Cmd-F
Find: file1
Replace: hw222_CMidiPacket
Click the Replace All icon.
All file1's have been changed.
Replace All: file2 with hw222_test_CmidiPacket
Replace All: main with hw222_main
Replace All: myapp with cmp22
compile
make and run
make && ./cmp22
You should see the same output you saw in the Build 1 - Command Line section.
make clean
A side effect of running make leaves the .o object files in the project directory.
Once the program is working the .o object files are no longer needed you can remove them with the make clean command.
If you do not want to remove the executable along comment the rm ${APPNAME} line.
clean: rm *.o # rm $(APPNAME)
This is my working Makefile. It had tabs when I saved it but they often get changed to spaces when copying and pasting from a web page. You may have to convert spaces to tabs again.
# Define application name APPNAME=cmp22 # define the compiler to use CC=clang++ #define the compiler parameters CFLAGS=-c -std=c++17 -Wall # the variables $(CC) $(CFLAGS) expand to clang++ -c -std-c++17 -Wall # -c Only run preprocess, compile, and assemble steps but do not link # define the make command parameter option all, as in: make all all: $(APPNAME) # line 1: cmp221 depends on all three object files # line 2: single TAB followed by linker command, no $(CFLAGS) $(APPNAME): hw222_main.o hw222_test_CMidiPacket.o hw222_CMidiPacket.o $(CC) -g -o $(APPNAME) hw222_main.o hw222_test_CMidiPacket.o hw222_CMidiPacket.o # line 1: hw222_main.o depends on hw222_test_CMidiPacket.h # line 2: single TAB followed by compile command hw222_main.o: hw222_main.cpp hw222_test_CMidiPacket.h $(CC) $(CFLAGS) hw222_main.cpp # line 1: hw222_test_CMidiPacket.o depends on hw222_test_CMidiPacket.h and 1.h # line 2: single TAB followed by compile command hw222_test_CMidiPacket.o: hw222_test_CMidiPacket.cpp hw222_test_CMidiPacket.h hw222_CMidiPacket.h $(CC) $(CFLAGS) hw222_test_CMidiPacket.cpp # line 1: hw222_CMidiPacket.o depends on hw222_CMidiPacket.h # line 2: single TAB followed by compile command hw222_CMidiPacket.o: hw222_CMidiPacket.cpp hw222_CMidiPacket.h $(CC) $(CFLAGS) hw222_CMidiPacket.cpp # define make command option clean, as in: make clean # removes all the .o object files clean: rm *.o rm ${APPNAME}
Output
Same as in Build 1
Use sed for Find/Replace
I wanted you to have practice with the Find/Replace panel in vsCode but it's quicker to use sed (stream editor). Admittedly the time it takes to create the sed command might take longer than the vsCode approach but I think it's more fun.
Replace the contents of the Makefile you just created with the earlier example Makefile that used file1 and file2.
Convert spaces to tabs and save.
Now you can make the changes to the Makefile and make and run the program with these two commands.
sed -i '' 's/file1/hw222_CMidiPacket/g s/file2/hw222_test_CMidiPacket/g s/main/hw222_main/g s/myapp/cmp22/g' ./Makefile make && ./cmp22
Build 3 - CMake
CMake generates makefiles along with project files for Xcode and Visual Studio and many others. You can view a list of the 20+ generators at
https://cmake.org/cmake/help/v3.0/manual/cmake-generators.7.html
The CMakeLists.txt syntax is clearer and cleaner than the Makefile. We'll be using cmake in a basic way. It will become our build tool of choice for the next several weeks and is the build system that is used by many open source projects.
The CMakeLists.txt file provides source file names (.cpp) and compiler flags to the cmake command. The cmake command scans the listed source files and figures out the dependency relationships for you.
In large projects there are often separate CMakeLists.txt files project subdirectories. In CS 312 our needs are simple and we'll use a single top level CMakeLists.txt file.
CMake projects require two additional items in your project source directory.
- a CMakeLists.txt file
- a build directory
Create them now.
# cd $HOME312/cs312/hw12/hw222_CMidiPacket mkdir build touch CMakeLists.txt
CMakeLists.txt
Copy/paste.
cmake_minimum_required(VERSION 2.8) set(APPNAME cmp22) project(${APPNAME}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall") set( SOURCE_FILES hw222_CMidiPacket.cpp hw222_test_CMidiPacket.cpp hw222_main.cpp ) add_executable(${APPNAME} ${SOURCE_FILES})
CMakeLists.txt syntax
- parameters are enclosed in parentheses ( )
- individual parameters within parentheses are separated by white space
- parameters containing white space must be quoted
- variables are defined with set as in set(VAR_NAME what_it_represents)
- variables when used are prefixed with $ and enclosed in curly braces { } as in ${VAR_NAME}
Here's additional explanation for each of the lines in CMakeLists.txt.
- 1 cmake_minimum_required(VERSION 2.8)
- This first line is required for all CMake projects in the top level CMakeLists.txt file. CS312 labs are version 3.15+
- 2 set(APPNAME cmp22)
- The name of the executable.
- 3 project(${APPNAME})
- The project name is the same as the executable name but doesn't have to be.
- 4 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall"}
- set the C++ flags (parameters). They're the same parameters we used in the .bash_aliases file in week1_1.
alias cl "clang++ -std/c++17 -Wall " - 5-10 set(SOURCE_FILES…)
- Define the variable SOURCE_FILES. When used as ${SOURCE_FILES} it expands to the three .cpp files needed to compile the project. Note the opening parenthesis after the word set, and the closing parenthesis after all files have been listed.
- 11 add_executable(${APPNAME} ${SOURCE_FILES})
- The executable cmp22 depends on ${SOURCE_FILES}
CMake build and run
Run these commands
- cd build
- move to the build directory
so the .o object files and other cmake intermediate files don't pollute the source file directory - cmake ..
- ../ refers to the parent directory where CMakeLists.txt is located.
cmake reads the CMakeLists.txt file and generates a Makefile. - make
- Execute the Makefile cmake generated.
- ./cmp22
- Run the application produced by make.
If you're in the build directory this can be done on one line if there are no errors to fix.
cmake .. && make && ./cmp22
Output
Same as in Build 1
You should always run cmake from a folder inside your source code folder. It's normally called build. If you run cmake directly from your source code folder you'll end up with lots of files polluting your source code folder.
cd build
ls -R build
If you want to do a fresh recompile you'll need to empty the build folder before running cmake. We'll write a script to do it.
emptyBuildFolder.sh
Setup
cd $HOME312/bin touch emptyBuildFolder.sh # make it executable chmod 755 emptyBuildFolder.sh # open in vsCode code emptyBuildFolder.sh
Copy/paste this code int emptyBuildFolder.sh. Read the comments to see how it works.
#!/bin/bash # `pwd` in backquotes represents the output of the command pwd # if true it then execute rm -fR build/* # if the command had said rm -fR build without the /* it would have removed the build folder and its contents # the /* removes contents of build but does not remove build if [ -d "`pwd`/build" ] # -d is a test whether the build folder exists # if you were already in the build folder the above command would return false # unless you had a build folder inside your build folder then # -f = force, R = recursive to delete everything inside build. rm -fR build/* elif [ -d ../build ] # this -d checks for a build folder in the parent folder of the working directory # if you're in the the source folder then you'll have a build folder then rm -fR ../build/* elif [ -d "`pwd`/build-debug" ] # later classes will use build for release version and build-debug for debug version then rm -fR build-debug/* elif [ -d ../build-debug ] then rm -fR ../build-debug/* else echo "no build or build-debug folder found" fi exit 0
CMake produces a very complex Makefile. You can find it in the build directory.
Test emptyBuildFolder.sh
Display the contents of the build folder in vsCode EXPLORER.
Execute emptyBuildFolder.sh in vsCode Terminal.
Watch the files disappear.
CMake Documentation
These commands provide built in help for CMake.
cmake --help #shorter man cmake #longer
The CMake web page https://cmake.org/ has extensive documentation.
If you still have time in lab go to hw220_boilerplate.
Reading
There's quite a lot of reading/doing here. Most of it is aimed at making you more productive in Terminal and vsCode. Be sure to work through the entire vsCode section.
TCPP
16.2.4
16.2.5
16.2.8
16.2.9
16.2.11
Essential commands
Command help
Almost every command accepts parameters that modify the output of the command in different ways. Most commands support the -h or /–help option to display help for that command. If not try
Try this in Apple Terminal
clang++ --help
I got 376 lines of help. Use the scrollbar to navigate.
Try it again using this command.
clang++ --help | more
more is a text reader that displays one page of text at a time. You can navigate through the pages using these commands.
- Page forward: press space bar or type Ctrl-f
- Page backward: type Ctrl-b
- To quit: type q or Ctrl-c
less is another popular text reader with similar commands. Get it, more or less.
man pages
Extensive documentation is also available by typing man followed by the command name. Try this.
man bash
Navigation commands ::
- Page forward: press space bar or type Ctrl-f
- Page backward: type Ctrl-b
- To quit: type q= or =Ctrl-c
Deleting files and folders
Testing each of these commands assume that the folder ddd exists and contains the file delete_me.cpp. This folder and file will be deleted and recreated in following tests.
Delete file commands
- Terminal
- rm
- In 1.2 Lab you created a .bash_alias file that aliased rm= to run in Interactive mode (/rm/rm -i). This is a safety option that asks for a yes/no before removing the file.
# vsCode Terminal cd ddd rm delete_me.cpp # remove ddd/delete_me.cpp? # respond with y or yes ls # verify delete # recreate for next test touch delete_me.cpp ls # verify it's back
- rm -f
- The -f option force removes the file without asking. This can be useful when you're trying to remove many files at once.
# vsCode Terminal cd ddd rm -f delete_me.cpp ls # verify delete # recreate for next test touch delete_me.cpp ls #verify it's back
Delete folder commands
- Terminal
- rm
- rm is for files with one exception you'll see later
# vsCode Terminal pwd # you need to be in $HOME312/cs312/hw222_CMidiPacket rm ddd # rm: ddd: is a directory # doesn't work
- rmdir
- rmdir is for ReMove DIRectory (but it must be empty)
# vsCode Terminal pwd # you need to be in $HOME312/cs312/hw222_CMidiPacket rmdir ddd # rmdir: ddd: Directory not empty # remove delete_me.cpp rm ddd/delete_me.cpp # ddd is now empty rmdir ddd ls # verify # setup for next test mkdir ddd touch ddd/delete_me.cpp
- rm -fR
- DANGER DANGER!
-f= is force and =-fR is recursive. It will delete every file and subdirectory without asking.
# vsCode Terminal # you need to be in this directory cd $HOME312/cs312/hw222_CMidiPacket # verify ddd/delete_me.cpp exists ls ddd/delete_me.cpp # if not recreate ddd and delete_me.cpp using mkdir and touch rm -fR ddd ls # verify they're gone # setup for next test mkdir ddd touch ddd/delete_me.cpp
Visual Studio Code Tips
Your productivity as programmer in any language is directly related to your facility with and familiarity with the features supplied by your editor. Visual Studio Code comes out on top as the most popular editor in a 2019 survey:
https://insights.stackoverflow.com/survey/2019#development-environments-and-tools
VsCode is a very deep program. Browsing items in the Help menu on a regular basis will always lead to new insights.
vsCode cheat sheet
Make a link or even better print a copy of this page of keyboard shortcuts for the Mac.
https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf
Ignore the color differences between my screenshots and your monitor. My colors indicate the state of the file in the git repository and were taken during different git commits.
Create files/folders in EXPLORER
Click the New Folder icon.
Name the new folder atest and type Return.
The atest folder should appear and should be selected.
Click the New File icon.
Name the file please_dont_delete_me.cpp.
New files are created inside a selected folder.
Rename a file
Select please_dont_delete_me.cpp in the EXPLORER view.
Type Return.
The filename will change to enter text mode and is ready ready to be changed.
Rename the file.
Press Return
Move files/folders in EXPLORER
Drag the delete_me.cpp file name down and to the right. A small blue icon will tear off as you drag. Drag outside of the atest folder and release the mouse button.
A dialog will appear asking if you're sure you want to move delete_me.cpp. Click move. Note that you can click the "Do not ask me again" checkbox when you're comfortable with this approach.
You now have an empty atest folder and a delete_me.cpp file in the hw222_CMidiPacket folder
Delete a file
Right click the delete_me.cpp file.
Choose Delete from the popup menu that appears.
Shortcut: Cmd-Delete/Cmd-Backspace
A dialog will appear asking if you're sure you want to delete delete_me.cpp. Click move Move to Trash. Note that you can click the "Do not ask me again" checkbox when you're comfortable with this approach.
Use drag and drop to insert text into Terminal
In Mac OS X you can drag the icon of a file from Finder into Apple's Terminal window and the full path name will appear in Terminal when you release the mouse button. This also works in vsCode from EXPLORER into vsCode Terminal.
In vsCode Terminal type
# cd followed by space cd
Drag the build folder into vsCode Terminal. Release the mouse button when you reach the space after cd.
The full pathname for build should appear in the Terminal.
Copy full path names in EXPLORER
You can the same thing using a right click and choosing Copy Path and then paste it into Terminal.
Choosing Copy Relative Path copies just the filename.
vsCode Breadcrumbs
The term Breadcrumbs is used in the sense of following a trail.
Choose Toggle Breadcrumbs from the View Menu. The checkmark indicates its been activated. It's a toggle menu item. You may have to click the menu a second time to see if the checkmark is present.
The Breadcrumb line is the middle line in the picture below. The two small symbols on the right toggle popup menus.
The > symbol toggles a popup menu that lists all files in the current folder. Files can be selected and opened using this popup.
The … symbol toggles popup menu that lists the functions used in that file. It's a quick way to navigate to other functions.
Intellisense
Intellisense is a vsCode extension that should already be installed. It's a brilliant piece of code written by C++ experts to help mere mortals from making PEBCAC errors (Problem Exists Between Computer And Chair).
You can find out a lot more about Intellisense by clicking the Extensions icon on the left, selecting C/C++ Intellisense and reading about it.
Testing Intellisense
Create a new file named intellisense.cpp.
Copy this code into intellisense.cpp.
Save it.
We'll use it for practice.
// intellisense.cpp #ifndef C221_CMIDIPACKET_H #include "hw222_CMidiPacket.h" #endif #include <iostream> #include <string> void CreateMidiPacketString(std::string s) { uint16_t status uint16_t data1; uint16_t data2; uint16_t length; } int main() { CreateMidiPacketString("0\t90\t60\t100); CreateMidiPacketString("0\t80\t60\t0"); CreateMidiPacketString("0\t90\t62\t100") CreateMidiPacketString("0\t80\t62\t0"); CreateMidiPacketString("0\t90\t64\t100"); CreateMidiPacketString("0\t80\t64\t0"); }
Code Issues
The red squiggles you see under text indicate problems in the code. Open the vsCode Terminal and click PROBLEMS. You'll see the the problems you need to fix.
The two numbers in brackets may be different on your computer depending on the Tab key number of spaces setting.
The first number is the line number. I'm not sure what the second number refers to.
The line number is usually correct but sometimes refers to the previous line. In problem 1 the semicolon is missing at the end of line 11.
- Problem 1
- /expected a ';' [12,7]
A semicolon is missing at the end of line 11
Add the semicolon and Save.
You're now down to three problems. - Problem 2
- missing closing quote [19,26]
Line 19 (or maybe 18) is missing a closing quote (std::string must be quoted).
In fact it is line 19 where the std::string is missing the closing double quote. Add the closing double quote and Save.
You're now down to one problem. - Last problem
- expected a ';' [22,7]
Similar to problem 1.
A semicolon is missing at the end of line 21. Add the semicolon and Save.
Problems gone.
Auto-completion
Still in intellisense.cpp.
Add a new line at the end of main(). Type Cr <slight pause> and a popup menu will appear giving options for any terms Intellisense has learned about. In this case the one we want is already selected.
Type Return and the full term will be entered automatically.
Type the opening parenthesis and the parameters of the function will be displayed.
Type ESC and delete line 24.
Multiple Cursors
Still in intellisense.cpp.
Copy/Paste lines 18-23 into a block comment section starting at line 26.
We'll use this as our playground.
We're going to convert lines 26-31 into valid MIDIDisplay_DLS formatted MIDI messages.
This is the complete set of keyboard shortcuts for Multiple Cursors. The funny looking symbol is the =Alt/Option/ key.
Let's try a few.
Modifier Keys + Arrow Keys
Click just before Create in line 26.
Hold down Opt-Cmd and type the down arrow five times
Hold down Shift-Opt and type the right arrow once.
Release Opt.= Hold down =Shift and type the right arrow twice.
Type delete
Remove the Tabs
Type right arrow three times
Type Delete twice and Tab once
Type the right arrow four times
Type Delete twice and Tab once
Type the right arrow four times
Type Delete twice and Tab once
Select lines 26-31
Type Shift-Opt-i to place a cursor at the end of each line.
Type Delete three times.
Click anywhere and we're done.
Replace all occurrences of a word
Double click the word "CreateMidiPacketString" in line 9 to select the whole word.
If you refer to the Keyboard Shortcut table above you will see that:
- Shift-Opt-L will select a strings matching the selection.
- Cmd-F2 will select all words matching the selection.
Either one will work here. The difference is that strings can contain spaces, words can't.
Type either command. All occurrences of that word will be selected.
Start typing the new word and all selections will change as you type.
Change all uint16_t= to =uint8_t
More Multi-Cursor information can by found by choosing Interactive Playground from the Help. When the playground window opens click the Multi-cursor Editing link and read it.
Indent/Outdent
Select lines 26-31.
Type Cmd-] to outdent the selection.
Type Cmd-[ to indent the selection.
Click at a random place within the selection.
Type Cmd-] to outdent the line with the cursor.
Type Cmd-[ to indent the line with the cursor.
Bracketed words
- Select any word by double clicking
- While it's selected type any one of these characters and that character and its matching end character will surround the word.
- '
- single quote
- "
- double quote
- (
- left parenthesis
- [
- left bracket
- {
- left curly brace
Eye Candy
Open a .cpp file.
Choose Preferences/Color Theme from the Code menu.
Shortcut: Cmd-K-T= (Hold =Cmd down and type k followed by t)
Use the Up/Down arrow keys to preview the theme.
I'm using the Dark+ (default dark) theme for all screenshots in these web pages. You're free to use any theme you like. There are hundreds available. You can view some more at:
https://vscodethemes.com/
Homework 2.2
hw221_boilerplate.cpp
- The only two items that ever change can be passed as parameters to boilerplate
- assignment
filename.ext - These items can be const std::string
- Copyright
LastFirst1 email
LastFirst2 email
The date and time are calculated in the code.
The c221_argc_argv.cpp section has the answers.
Assignment hw221
Rewrite boilerplate to accept two parameters, assignment and filename.
This command
boilerplate hw111 hw111_hello.cpp
would produce this output
/***************************************************************
hw111_hello.cpp
Copyright (c) Carleton College CS312 free open source
Assignment: hw111
<Last First> <email>
<Last First> <email>
DATE: 2020-01-13
TIME: 20:46:25
****************************************************************/
You must display a usage message if there are not exactly two parameters.
std::cout << "** Usage: " << "boilerplate <hwNNN> <filename.extension>\n";
Rename and copy to $HOME312/bin
When you're satisfied that a.out works rename it as boilerplate and move it to $HOME/bin/.
Both partners do this.
mv a.out $HOME312/bin/boilerplate
Execute in vsCode terminal and paste its output at the top of every homework assignment from now on. example
boilerplate hw11 hw11_hello.cpp | pbcopy
pbcopy is an Apple command that copies text to the clipboard ready to be pasted into your source code.
hw222_CMidiPacket
This homework assumes you've complete the hw222 section shown above in the class lab.
Quit vsCode.
Setup
In Mac Finder drag the $HOME312/cs312/hw22/hw222_CMidiPacket icon into the main window of vsCode.
Open vsCode and then open hw222_CMidiPacket.h.
Make these two changes.
Save and close all open hw222_CMidiPacket.h and any other open files.
Make sure you're in the hw222_CMidiPacket directory in vsCode Terminal.
Private class variables are often suffixed with an underscore.
Run these commands to change them.
# suffix private variables with underscore # https://stackoverflow.com/questions/1032023/sed-whole-word-search-and-replace cd $HOME312/cs312/hw22/hw222_CMidiPacket sed -i '' 's/[[:<:]]timestamp[[:>:]]/timestamp_/g s/[[:<:]]status[[:>:]]/status_/g s/[[:<:]]data1[[:>:]]/data1_/g s/[[:<:]]data2[[:>:]]/data2_/g s/[[:<:]]length[[:>:]]/length_/' hw222_CMidiPacket*
Assignment hw222
Because we made the class data variables private other classes will not be able to access them. The standard way to deal with that is to implement "getter" and "setter" functions to access the private data. This is a recommended practice called encapsulation or data hiding that prevents other classes from modifying the data directly.
hw222_CMidiPacket.h
Replace/copy/paste
// hw221_CMidiPacket.h #ifndef HW221_CMIDIPACKET_H_ #define HW221_CMIDIPACKET_H_ #include <iostream> #include <string> namespace CMP22 { class CMidiPacket { private: // not really needed because they're private by default // MidiPacket2 data uint32_t timestamp_; uint8_t status_; uint8_t data1_; uint8_t data2_; uint8_t length_; public: // from class snippet CMidiPacket(); // constructor ~CMidiPacket(); // destructor CMidiPacket(const CMidiPacket &) = default; // copy constructor CMidiPacket(CMidiPacket &&) = default; // move constructor CMidiPacket &operator=(const CMidiPacket &) = default; // assignment CMidiPacket &operator=(CMidiPacket &&) = default; // move assignment // three overlaoded constructors // construct a CMidiPacket for a one data byte message CMidiPacket(uint32_t ts, uint8_t st, uint8_t d1); // construct a CMidiPacket for a two data byte message CMidiPacket(uint32_t ts, uint8_t st, uint8_t d1, uint8_t d2); // construct a CMidiPacket from a valid MIDIDisplay string CMidiPacket(const std::string &str); // return a string from this CMidiPacket data std::string to_string() const; // print this CMidiPacket data to std::cout // in MIDIDisplay format accounting for message lengths of 2 or 3 void print() const; // getters uint32_t get_timestamp() const; uint8_t get_status() const; uint8_t get_data1() const; uint8_t get_data2() const; uint8_t get_length() const; uint8_t get_midi_channel() const; // setters void set_timestamp(const uint32_t &ts); // status determines the length void set_status(const uint8_t &st); // length cannot be set without knowing status void set_status_length(); void set_data1(const uint8_t &d1); void set_data2(const uint8_t &d2); void set_midi_channel(const uint8_t &chan); // Utility functions bool is_status_8n() const; bool is_status_9n() const; bool is_status_An() const; bool is_status_Bn() const; bool is_status_Cn() const; bool is_status_Dn() const; bool is_status_En() const; bool is_status_Fn() const; bool is_note_off() const; bool is_note_on() const; }; } // namespace CMP22 #endif // HW221_CMIDIPACKET_H
Added functions
// getters uint32_t get_timestamp() const; uint8_t get_status() const; uint8_t get_data1() const; uint8_t get_data2() const; uint8_t get_length() const; uint8_t get_midi_channel() const; // setters void set_timestamp(const uint32_t &ts); // status determines the length void set_status(const uint8_t &st); // length cannot be set without knowing status void set_status_length(); void set_data1(const uint8_t &d1); void set_data2(const uint8_t &d2); void set_midi_channel(const uint8_t &chan); // Utility functions bool is_status_8n() const; bool is_status_9n() const; bool is_status_An() const; bool is_status_Bn() const; bool is_status_Cn() const; bool is_status_Dn() const; bool is_status_En() const; bool is_status_Fn() const; bool is_note_off() const; bool is_note_on() const; }; } // namespace CMP22 #endif // HW221_CMIDIPACKET_H
hw222_CMidiPacket.cpp
Replace/copy/paste the print() function.
// Do not change print() // Send a MIDIDisplay string to std::cout using toString() void CMidiPacket::print() const { std::cout << to_string() << std::endl; }
Note:
You'll have to implement the getter, setter, and utility functions in hw222_CMidiPacket.cpp.
hw222_test_CMidiPacket.h
Replace/copy/paste
// hw222_test_CMidiPacket.h #ifndef HW222_TEST_CMIDIPACKET_H_ #define HW222_TEST_CMIDIPACKET_H_ void run_CMidiPacket_tests(); #endif // HW222_TESTCMIDIPACKET_H_
hw222_test_CMidiPacket.cpp
Replace/copy/paste
// hw222_test_CMidiPacket.cpp #ifndef HW222_TEST_CMidiPacket_H_ #include "hw222_test_CMidiPacket.h" #endif #ifndef HW222_CMidiPacket_H_ #include "hw222_CMidiPacket.h" #endif #include <iostream> #include <sstream> #include <string> using namespace CMP22; void print_main_message(const std::string &msg, CMidiPacket mp) { std::cout << "\n===> " << msg << std::endl; mp.print(); } void print_sub_message(const std::string &msg, CMidiPacket mp) { std::cout << "----\n" << msg << std::endl; mp.print(); } void print_length_message(const std::string &msg, CMidiPacket mp) { std::cout << "----\n" << msg << std::endl; std::cout << +mp.get_length() << std::endl; } void test_default_constructor() { CMidiPacket mp; print_main_message("test_default_constructor()\n(0, 80, 0, 0)", mp); } void test_constructor_one_data_byte() { CMidiPacket mp{100, 0xc0, 11}; print_main_message("test_constructor_one_data_byte\n(100, 0xc0, 11)", mp); CMidiPacket mp1{100, 0xF2, 11}; print_sub_message("(100, 0xF2, 11)", mp1); } void test_constructor_two_data_bytes() { CMidiPacket mp{1001, 0x91, 61, 101}; print_main_message("test_constructor_ts_two_data_bytes\n(1001, 0x91, 61, 101)", mp); CMidiPacket mp1{100, 0xB4, 11, 0}; print_sub_message("(100, 0xB4, 11, 0)", mp1); } void test_constructor_string() { CMidiPacket mp("100\tc0\t11"); print_main_message("test_constructor_string\n(100\tc0\t11)", mp); CMidiPacket mp1("1001\t91\t61\t101"); print_sub_message("(1001\t91\t61\t101)", mp1); CMidiPacket mp2("1002 B2 7 102"); print_sub_message("NO TABS: (1002 B2 7 102)", mp2); } void test_to_string() { CMidiPacket mp(100, 0xC0, 11); print_main_message("test_to_string\n(100, 0xC0, 11)", mp); CMidiPacket mp1(1001, 0x91, 60, 101); print_sub_message("(1001, 91, 60, 101)", mp1); CMidiPacket mp2(2002, 0xB2, 7, 102); print_sub_message("(2002, 0xB2, 7, 102)", mp2); } void test_print() { CMidiPacket mp(100, 0xC0, 11); print_main_message("test_print\n(100, 0xC0, 11)", mp); CMidiPacket mp1(1001, 0x91, 60, 101); print_sub_message("(1001, 91, 60, 101)", mp1); CMidiPacket mp2(2002, 0xB2, 7, 102); print_sub_message("(2002, B2, 7, 102)", mp2); } // getters void test_get_timestamp() { CMidiPacket mp1(1001, 0x91, 60, 101); print_main_message("test_get_timestamp(1001, 91, 60, 101)", mp1); } void test_get_status() { CMidiPacket mp1(1001, 0x91, 60, 101); print_main_message("test_get_status(1001, 91, 60, 101)", mp1); } void test_get_data1() { CMidiPacket mp1(1001, 0x91, 60, 101); print_main_message("test_get_data1(1001, 91, 60, 101)", mp1); } void test_get_data2() { CMidiPacket mp1(1001, 0x91, 60, 101); print_main_message("test_get_data2(1001, 91, 60, 101)", mp1); } void test_get_length() { CMidiPacket mp1(1001, 0x91, 60, 101); print_main_message("test_get_length(1001, 91, 60, 101)", mp1); } // setters void test_set_timestamp() { CMidiPacket mp1(1001, 0x91, 60, 101); mp1.set_timestamp(999); print_main_message("test_set_timestamp(999)", mp1); } void test_set_status_length() { CMidiPacket mp1(1001, 0x91, 60, 101); mp1.set_status_length(); print_main_message("test_set_status_length(1001, 0x91, 60, 101)", mp1); print_length_message("length(1001, 0x91, 60, 101)", mp1); CMidiPacket mp2(1001, 0xC1, 60, 100); mp2.set_status_length(); print_sub_message("USING BAD INPUT: test_set_status_length(1001, 0xC1, 60, 100)", mp2); print_length_message("USING BAD INPUT: length(1001, 0xC1, 60, 100)", mp2); } void test_set_data1() { CMidiPacket mp1(1001, 0x91, 60, 101); mp1.set_data1(99); print_main_message("test_set_data1(1001, 0x91, 60, 101) -> 99", mp1); } void test_set_data2() { CMidiPacket mp1(1001, 0x91, 60, 101); mp1.set_data2(99); print_main_message("test_set_data2(1001, 0x91, 60, 101) -> 99", mp1); } // Utility functions void test_is_status_8n() { std::cout << "\n===> test_is_status_8n" << std::endl; CMidiPacket mp1(1001, 0x81, 60, 101); std::cout << std::boolalpha << mp1.is_status_8n() << std::endl; mp1.print(); CMidiPacket mp2(1001, 0x91, 60, 101); std::cout << std::boolalpha << mp2.is_status_8n() << std::endl; mp2.print(); } void test_is_status_9n() { std::cout << "\n===> test_is_status_9n" << std::endl; CMidiPacket mp1(1001, 0x91, 60, 101); std::cout << std::boolalpha << mp1.is_status_9n() << std::endl; mp1.print(); CMidiPacket mp2(1001, 0x81, 60, 101); std::cout << std::boolalpha << mp2.is_status_9n() << std::endl; mp2.print(); } void test_is_status_An() { std::cout << "\n===> test_is_status_An" << std::endl; CMidiPacket mp1(1001, 0xA1, 60); std::cout << std::boolalpha << mp1.is_status_An() << std::endl; mp1.print(); CMidiPacket mp2(1001, 0x91, 60, 101); std::cout << std::boolalpha << mp2.is_status_An() << std::endl; mp2.print(); } void test_is_status_Bn() { std::cout << "\n===> test_is_status_Bn" << std::endl; CMidiPacket mp1(1001, 0xB1, 60, 101); std::cout << std::boolalpha << mp1.is_status_Bn() << std::endl; mp1.print(); CMidiPacket mp2(1001, 0x91, 60, 101); std::cout << std::boolalpha << mp2.is_status_Bn() << std::endl; mp2.print(); } void test_is_status_Cn() { std::cout << "\n===> test_is_status_Cn" << std::endl; CMidiPacket mp1(1001, 0xC1, 60); std::cout << std::boolalpha << mp1.is_status_Cn() << std::endl; mp1.print(); CMidiPacket mp2(1001, 0x91, 60, 101); std::cout << std::boolalpha << mp2.is_status_Cn() << std::endl; mp2.print(); } void test_is_status_Dn() { std::cout << "\n===> test_is_status_Dn" << std::endl; CMidiPacket mp1(1001, 0xD1, 60, 101); std::cout << std::boolalpha << mp1.is_status_Dn() << std::endl; mp1.print(); CMidiPacket mp2(1001, 0x91, 60, 101); std::cout << std::boolalpha << mp2.is_status_Dn() << std::endl; mp2.print(); } void test_is_status_En() { std::cout << "\n===> test_is_status_En" << std::endl; CMidiPacket mp1(1001, 0xE1, 60, 101); std::cout << std::boolalpha << mp1.is_status_En() << std::endl; mp1.print(); CMidiPacket mp2(1001, 0x91, 60, 101); std::cout << std::boolalpha << mp2.is_status_En() << std::endl; mp2.print(); } void test_is_status_Fn() { std::cout << "\n===> test_is_status_Fn" << std::endl; CMidiPacket mp1(1001, 0xF1, 60, 101); std::cout << std::boolalpha << mp1.is_status_Fn() << std::endl; mp1.print(); } void test_is_note_off() { std::cout << "\n===> test_is_note_off" << std::endl; CMidiPacket mp1(1001, 0x81, 60, 101); std::cout << std::boolalpha << mp1.is_note_off() << std::endl; mp1.print(); CMidiPacket mp2(1001, 0x92, 60, 0); std::cout << std::boolalpha << mp2.is_note_off() << std::endl; mp2.print(); CMidiPacket mp3(1001, 0x93, 60, 101); std::cout << std::boolalpha << mp3.is_note_off() << std::endl; mp3.print(); CMidiPacket mp4(1001, 0xA3, 60, 101); std::cout << std::boolalpha << mp4.is_note_off() << std::endl; mp4.print(); } void test_is_note_on() { std::cout << "\n===> test_is_note_on" << std::endl; CMidiPacket mp1(1001, 0x92, 60, 101); std::cout << std::boolalpha << mp1.is_note_on() << std::endl; mp1.print(); CMidiPacket mp2(1001, 0x92, 60, 0); std::cout << std::boolalpha << mp2.is_note_on() << std::endl; mp2.print(); CMidiPacket mp3(1001, 0xB3, 60, 101); std::cout << std::boolalpha << mp3.is_note_on() << std::endl; mp3.print(); } void run_CMidiPacket_tests() { test_default_constructor(); test_constructor_one_data_byte(); test_constructor_two_data_bytes(); test_constructor_string(); test_to_string(); test_print(); test_get_timestamp(); test_get_length(); test_get_status(); test_get_data1(); test_get_data2(); test_set_timestamp(); test_set_status_length(); test_set_data1(); test_set_data2(); test_is_status_8n(); test_is_status_9n(); test_is_status_An(); test_is_status_Bn(); test_is_status_Cn(); test_is_status_Dn(); test_is_status_En(); test_is_status_Fn(); test_is_note_off(); test_is_note_on(); }
hw222_main.cpp
Replace/copy/paste
// hw222_main.cpp #ifndef HW222_CMIDIPACKET_H_ #include "hw222_CMidiPacket.h" #endif #ifndef HW222_TEST_CMidiPacket_H_ #include "hw222_test_CMidiPacket.h" #endif using namespace CMP22; int main() { run_CMidiPacket_tests(); }
CMake, Make, Run
# build, make, and run cd build cmake .. && make && ./cmp22
Fix any errors.
My output is shown below.
Function parameters are shown in ( ).
Function output is the following line with numbers separated by tabs.
Carefully read through the output looking for errors in output.
===> test_default_constructor() (0, 80, 0, 0) 0 80 0 0 ===> test_constructor_one_data_byte (100, 0xc0, 11) 100 c0 11 ---- (100, 0xF2, 11) # 0xFn status_ not processed ===> test_constructor_ts_two_data_bytes (1001, 0x91, 61, 101) 1001 91 61 101 ---- (100, 0xB4, 11, 0) 100 b4 11 0 ===> test_constructor_string (100 c0 11) 100 c0 11 ---- (1001 91 61 101) 1001 91 61 101 ---- NO TABS: (1002 B2 7 102) 1002 b2 7 102 ===> test_to_string (100, 0xC0, 11) 100 c0 11 ---- (1001, 91, 60, 101) 1001 91 60 101 ---- (2002, 0xB2, 7, 102) 2002 b2 7 102 ===> test_print (100, 0xC0, 11) 100 c0 11 ---- (1001, 91, 60, 101) 1001 91 60 101 ---- (2002, B2, 7, 102) 2002 b2 7 102 ===> test_get_timestamp(1001, 91, 60, 101) 1001 91 60 101 ===> test_get_length(1001, 91, 60, 101) 1001 91 60 101 ===> test_get_status(1001, 91, 60, 101) 1001 91 60 101 ===> test_get_data1(1001, 91, 60, 101) 1001 91 60 101 ===> test_get_data2(1001, 91, 60, 101) 1001 91 60 101 ===> test_set_timestamp(999) 999 91 60 101 ===> test_set_status_length(1001, 0x91, 60, 101) 1001 91 60 101 ---- length(1001, 0x91, 60, 101) 3 ---- USING BAD INPUT: test_set_status_length(1001, 0xC1, 60, 100) 1001 c1 60 ---- USING BAD INPUT: length(1001, 0xC1, 60, 100) 2 ===> test_set_data1(1001, 0x91, 60, 101) -> 99 1001 91 99 101 ===> test_set_data2(1001, 0x91, 60, 101) -> 99 1001 91 60 99 ===> test_is_status_8n true 1001 81 60 101 false 1001 91 60 101 ===> test_is_status_9n true 1001 91 60 101 false 1001 81 60 101 ===> test_is_status_An true 1001 a1 60 false 1001 91 60 101 ===> test_is_status_Bn true 1001 b1 60 101 false 1001 91 60 101 ===> test_is_status_Cn true 1001 c1 60 false 1001 91 60 101 ===> test_is_status_Dn true 1001 d1 60 101 false 1001 91 60 101 ===> test_is_status_En true 1001 e1 60 101 false 1001 91 60 101 ===> test_is_status_Fn # 0xFn status_ not processed true # 0xFn status_ not processed ===> test_is_note_off true 1001 81 60 101 true 1001 92 60 0 false 1001 93 60 101 false 1001 a3 60 101 ===> test_is_note_on true 1001 92 60 101 false 1001 92 60 0 false 1001 b3 60 101
Submission Format
Feel free to email jellinge@carleton.edu on any part of the homework that is unclear to you. Chances are if you have questions other students do too. I will answer those questions by email to everyone in the class. The original sender will remain anonymous. I have tried to provide clues to the homework in the web pages, reading assignments, and labs. Sometimes what seems obvious to me is not obvious to students just learning C++.
Create a folder named hwNN_LastnameFirstname1_LastnameFirstname2.
Substitute your name and your partner's name for LastnameFirstname1_LastnameFirstname2.
Remember
- Boilerplate header at top of every file.
- Make sure your program compiles before submitting.
- Programs that compile and produce partially correct output will be graded.
- You can send notes to me in your homework files by enclosing them in block comments.
- Programs that do not compile get an automatic F (59%).
- Each partner must submit identical homework folders to the course Hand-in folder.
- If only one partner submits the homework send me an email explaining why.
- Empty your build or build-debug folders using the command emptyBuildFolder.sh
- Only include .h, .cpp, Makefiles, CMakeLists.txt
- Do not include these folders/files
.git
.vscode Double check for the above two folders using this command
ls -a hwNN_LastnameFirstname1_LastnameFirstname2 # if either .git or .vscode exist in the folder you're submitting remove them with # rm -fR .git # rm -fR .vscode
hw22_LastnameFirstname_LastnameFirstname