COMP2004
Programming Practice
2002 Summer School
Kevin Pulo
School of Information Technologies
University of Sydney
(page 1)
Development Tools
- Tools for editing code
- Tools for compiling code
- Tools for searching code
- Tools for debugging
- Tools for testing
(page 2)
Editing Code
- The ubiquitous text editor
- Invest time in learning a good editor
- Programmers use text editors a lot
- You want one that can
- Jump to a given line
- Run programs from within editor
- Search usefully
- Unix: vi (vim), emacs, nedit, xfte
- Windows: context, ultraedit, textpad
(page 3)
Compiling Code
- C++ uses separate compilation and linking
- Compile code to object files
- Link object files to produce executable
- g++ -c file1.cc
- compiles file1.cc to give file1.o
- g++ -c file2.cc
- compiles file2.cc to give file2.o
- g++ -o prog file1.o file2.o
- links objects files to produce prog
(page 4)
Benefits
- Imagine 100,000 lines of code in one .cc file
- Apart from other problems, compiling would take a long time
- Change one line of code -> recompile everything
- With separate .cc files, need only recompile the file(s) that have changed
- Still need to relink everything though
(page 5)
Automating compilation
- Tedious to always retype all or part of
g++ -c file1.cc
g++ -c file2.cc
...
g++ -o prog file1.o file2.o ...
- Can write a shell script which runs these commands for us
(page 6)
Shell scripts
- The shell is where you type commands
- Is actually a programming language
- Shell scripts are shell programs
- The first line must be #!/bin/sh or #!/gnu/usr/bin/bash
- This tells the computer to run the script using the shell
- The file must be executable
chmod +x filename
- We can then run it as a command
(page 7)
Compilation shell script
#!/gnu/usr/bin/bash
g++ -Wall -g -c file1.cc
g++ -Wall -g -c file2.cc
g++ -Wall -g -o prog file1.o file2.o
(page 8)
Compilation shell script
- What if we want to add -ansi -pedantic when compiling?
#!/gnu/usr/bin/bash
g++ -Wall -g -ansi -pedantic -c file1.cc
g++ -Wall -g -ansi -pedantic -c file2.cc
g++ -Wall -g -ansi -pedantic -o prog \
file1.o file2.o
(page 9)
Shell variables
- Use a shell variable called CXXFLAGS
#!/gnu/usr/bin/bash
CXXFLAGS="-Wall -g -ansi -pedantic"
g++ $CXXFLAGS -c file1.cc
g++ $CXXFLAGS -c file2.cc
g++ $CXXFLAGS -o prog file1.o file2.o
(page 10)
More shell variables
- What about adding -lm to link only?
#!/gnu/usr/bin/bash
CXXFLAGS="-Wall -g -ansi -pedantic"
LDFLAGS="-lm"
g++ $CXXFLAGS -c file1.cc
g++ $CXXFLAGS -c file2.cc
g++ $CXXFLAGS $LDFLAGS -o prog \
file1.o file2.o
(page 11)
Adding files
#!/gnu/usr/bin/bash
CXXFLAGS="-Wall -g -ansi -pedantic"
LDFLAGS="-lm"
FILES="file1 file2 file3 file4"
for file in $FILES; do
g++ $CXXFLAGS -c ${file}.cc
OBJS="$OBJS ${file}.o"
done
g++ $CXXFLAGS $LDFLAGS -o prog \
$OBJS
(page 12)
Environment variables
- Shell variables
- Only visible in the shell
- Environment variables
- Visible to programs run by the shell
- Convert shell variable to environment variable with export
CXXFLAGS="-Wall -g"
export CXXFLAGS
export CXXFLAGS="-Wall -g"
(page 13)
Environment variables in C++
- Use getenv() from #include
int main() {
string name = "CALENDAR_DATE";
char *c = getenv(name.c_str());
if (c) {
string s = c;
cout << "Today is: " <<
s.substr(0,3) << endl;
}
}
(page 14)
make
- Our shell script still compiles everything
- make is a tool to compile only what is needed
- Knows how to compile .cc to .o
- You can add rules for other things
- .java to .class for example
- To use make you need a Makefile
- You simply list dependencies
- And sometimes also commands
(page 15)
Makefile example
OBJS = main.o student.o course.o
CXXFLAGS = -Wall -g
LDFLAGS = -lm
all: prog
prog: $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) \
-o prog $(OBJS)
clean:
rm -f $(OBJS)
(page 16)
Using make
bash$ make cleanrm -f main.o student.o course.o
bash$ make OR make progg++ -Wall -g -c main.cc
g++ -Wall -g -c student.cc
g++ -Wall -g -c course.cc
g++ -Wall -g -lm -o prog main.o
student.o course.o
bash$
(page 17)
Example List Makefile
OBJS = main.o List.o
CXXFLAGS = -Wall -g
LDFLAGS = -lm
all: prog
prog: $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) \
-o prog $(OBJS)
List.o: List.h
test.o: List.h
(page 18)
makedepend
- Very useful for constructing dependencies
- Searches source code for #includes
- Adds dependency information to the Makefile
- Causes recompilation when headers change
(page 19)
Example makedepend usage
SRCS = main.cc List.cc
OBJS = main.o List.o
CXXFLAGS = -Wall -g
depend:
makedepend -- $(CXXFLAGS) -- \
$(SRCS)
- Then make depend to generate dependancies
(page 20)
GNU make
- Has some useful extensions
- Maintain only one list of files:
SRCS = main.cc List.cc
OBJS = $(SRCS:%.cc=%.o)
- Maintain no lists of files (use all .cc files in current directory):
SRCS = $(wildcard *.cc)
(page 21)
Searching Through Code
- As code grows you can't remember it
- So you need tools to search it
- Find where classes are used
- Find definitions
- Find where a message is output
(page 22)
grep
- A simple tool for searching files
- Prints all the lines that match a pattern
- Patterns are regular expressions
- Usage:
grep
- Most useful options:
- -nprint line numbers
- -vprint lines which don't match
- -icase insensitive
- -ccount number of lines
(page 23)
grep Regular Expressions
- . - matches any character
- * - matches zero or more of last item
- + - matches one or more of last item
- ^ - matches at start of line
- $ - matches at end of line
- [...] - matches any character inside
- [^...] - matches any character not inside
- \ - removes special meaning from next char
- For more info: man grep
(page 24)
grep Example
- Some people format their code to make grepping easy, eg:
int
convert42(int x) {
}
- Allows searching for function definition with:
grep -n '^ *convert[0-9]+(' *.cc
(page 25)
Debugging
- Frustrating and time consuming
- Debuggers can be a big help
- Can be hard to understand at first
- Allows viewing/modifying variables
- And stepping through source code
(page 26)
gdb
- The GNU debugger
- Command line interface
- Reasonably complicated
- A little knowledge provides a lot of benefit
(page 27)
gdb example
- Compiled with -g
- Crashed with
Segmentation fault (core dumped)
- Run: gdb prog core
- Common commands
- bt
- Get a stack backtrace
- Shows where the crash happened
- p head
- Print value of variable head
(page 28)
ddd and insight
- ddd is a GUI wrapper around gdb
- insight is a GUI version of gdb
- Easier to learn
- Less flexible
- ~sholden/pub/ddd/bin/ddd
- ~sholden/pub/insight/bin/gdb
(page 29)
Testing
- Testing is a difficult task
- There are many types of testing
- We'll look at input-output tests
- Often used for regression testing
- Have a collection of tests
- All tests rerun at every change
- Tests added when bugs fixed
- Prevents bugs from reappearing
(page 30)
How We Test
- Run the program with known input
- Compare the output with correct output
- Fail the test if they differ
- Pass the test if they are the same
- This is how machine marking is done
(page 31)
Run With Known Input
- The shell makes this easy
- Input data is in a file (say test.in)
- Program to be tested named prog
- ./prog < test.in
- Contents of test.in will be read from std::cin by prog
(page 32)
Saving the Output
- The shell makes this easy too
- ./prog < test.in > outfile
- Now the output from std::cout will be in outfile
- Saving std::cerr is possible too
- ./prog < test.in 2> errfile
- ./prog < test.in > outfile 2> errfile
- ./prog < test.in 1> outfile 2> errfile
- ./prog < test.in > outfile 2>&1
- ./prog > outfile 2> errfile
(page 33)
Comparing Output
- A utility named cmp compares files
- A utility named diff does also
- No output will be produced if the files are the same
- If correct output is in test.out then
- cmp test.out outfile
- No output if the test is passed
- diff test.out outfile
- Gives more detailed output if the test is failed
(page 34)