SlideShare a Scribd company logo
CSE 380 C++ Boot Camp
Part 2/2
You
You
C++
C++
Subtle and
Subtle and
annoying things
annoying things
Now what?
●
Last week: The language
●
This week: The tools
●
Compiling and linking code
●
Box2D, specifically
●
You will be using it for your course project
●
Splitting classes into headers and source files
●
What that means and why you must do it
●
Overview of popular C++ libraries and tools
●
Tips about the course
Static vs. Dynamic Libraries

.a or .lib extension
(varies by compiler)

Resolved at link-time and
included in the binary

Must recompile to update
the library

Unused or duplicated
library code can be
removed

.dylib, .dll, or .so
extension (varies by OS)

Resolved at run-time and
included in program
directory or system folders

Can swap out different
versions at will

Only loaded to RAM once
if multiple programs use
the same dynamic library
at the same time
Compiling
moe.cpp
<cmath> “Yours.hpp”
<string>
larry.cpp curly.cpp
moe.obj
moe.obj larry.obj
larry.obj curly.obj
curly.obj
Symbol Tables
moe.obj
moe.obj
Have: stooges::slap
Have: std::vector<float>
Seeking: stooges::poke
Seeking: std::sin

Multiple gaps seeking one symbol: Perfectly normal

Multiple tabs declaring one symbol: multiple definition of
symbol symbol_name

Gap without a tab filling it: unresolved external symbol
symbol_name

Tab not assigned to a gap: Unused symbol (can be stripped)
Linking
moe.obj
moe.obj larry.obj
larry.obj
Static
Static
Libraries
Libraries
Have: stooges::slap Seeking: stooges::slap
curly.obj
curly.obj
stooges.exe
Installing Box2D

I assume you've downloaded Visual Studio already

Download Box2D now
– And 7-Zip to open the archive

Extract the Box2D_v2.3.0/Box2D folder to wherever you want to keep
your libraries
 I use C:/Users/<name>/Libraries
All of your libraries should go
here (with a folder for each)
Does this
contain these?
Compiling Box2D

Projects contain related code

Solutions contain related projects

Open Build/vs2012/Box2D.sln
#include that
in your game
For testing
and demos

Right-click Box2D → Build
 You just built a static library!
Compiling Box2D

Do the same with Testbed

Note that its dependencies are compiled

See Solution 'Box2D' → Properties → Project Dependencies

Testbed → Debug → Start New Instance
Play around with this over the weekend
What did you just build?

Box2D → Properties
The most
important
stuff
Change options depending on build type and platform
Macros have different values
depending on config or build
environment
Release Builds

Run the Testbed, go to Tiles demo, tick the Profile box

Look at step [ave] (max); note these numbers

previous [average] (longest time) for one physics step in milliseconds

Do it again in Release mode
WOW!
Debug build Release build
Creating a Solution

Your solution will have multiple projects

Your game + any supporting libraries

File → New → New Project
Create a new solution
Let's Compile Something

Source Files → Add New Item → C++ File
#include <iostream>
#include <cstdlib>
using std::cout;
using std::endl;
using std::system;
int main() {
cout << "Hello world!" << endl;
system("PAUSE");
}
Headers and Classes

Declare classes, global functions, etc. in header files
(.hpp extension)

Define them in a corresponding source file (.cpp
extension)

Exception: templated classes, functions, or methods
must be defined in headers
Headers and Classes

Reduces the number of files to build

Header changes? All .cpp files that use it
must be recompiled

Source changes? Only that file must be
recompiled

Prevent linker errors, too
You Should See These
// Vector2.hpp
#pragma once
class Vector2
{
public:
Vector2();
~Vector2();
};
// Vector2.cpp
#include "Vector2.hpp"
Vector2::Vector2()
{
}
Vector2::~Vector2()
{
}
Provides symbols Provides code
More (.hpp)
// Vector2.hpp
#pragma once
namespace cse380 {
class Vector2
{
public:
Vector2();
Vector2(const float, const float);
// Can omit names in declaration
float x, y;
Vector2& operator+=(const Vector2&);
Vector2& operator*=(const float);
};
Vector2 operator+(const Vector2&, const Vector2&);
Vector2 operator*(const Vector2&, const float);
}
More (.cpp)
// Vector2.cpp
#include "Vector2.hpp"
namespace cse380 {
Vector2::Vector2() : Vector2(0, 0) {}
Vector2::Vector2(const float x, const float y) : x(x), y(y) {}
Vector2& Vector2::operator+=(const Vector2& other) {
this->x += other.x;
this->y += other.y;
return *this;
}
Vector2& Vector2::operator*=(const float scale) {
this->x *= scale;
this->y *= scale;
return *this;
}
Vector2 operator+(const Vector2& a, const Vector2& b) {
return Vector2(a.x + b.x, a.y + b.y);
}
Vector2 operator*(const Vector2& v, const float scale) {
return Vector2(v.x * scale, v.y * scale);
}
}
Let's Make a 3D Vector (.hpp)
// Vector3.hpp
#pragma once
#include "Vector2.hpp"
namespace cse380 {
class Vector3
{
public:
Vector3();
Vector3(const float, const float, const float);
float x, y, z;
Vector3& operator+=(const Vector3&);
Vector3& operator*=(const float);
explicit operator Vector2() const;
};
Vector3 operator+(const Vector3&, const Vector3&);
Vector3 operator*(const Vector3&, const float);
}
Let's Make a 3D Vector (.cpp)
// Vector3.cpp
#include "Vector3.hpp"
namespace cse380 {
Vector3::Vector3(const float x, const float y, const float z) : x(x), y(y), z(z) {}
Vector3::Vector3() : Vector3(0, 0, 0) {}
Vector3& Vector3::operator+=(const Vector3& v) {
this->x += v.x;
this->y += v.y;
this->z += v.z;
return *this;
}
Vector3& Vector3::operator*=(const float scale) {
this->x *= scale;
this->y *= scale;
this->z *= scale;
return *this;
}
Vector3::operator Vector2() const { return Vector2(this->x, this->y); }
Vector3 operator+(const Vector3& a, const Vector3& b) { return Vector3(a) += b; }
Vector3 operator*(const Vector3& v, const float scale) { return Vector3(v) *= scale; }
}
Now Add a Conversion Operator
// Vector2.hpp
#pragma once
#include
#include "Vector3.hpp"
"Vector3.hpp"
namespace cse380 {
class Vector2
{
public:
// Omitted for brevity
explicit
explicit operator
operator Vector3
Vector3()
() const
const;
;
};
// Omitted for brevity
}
// Vector2.cpp
#include "Vector2.hpp"
namespace cse380 {
// Omitted for brevity
Vector2
Vector2::
::operator
operator cse380::
cse380::Vector3
Vector3()
() const
const {
{
return
return Vector3
Vector3(
(this
this->x,
->x, this
this->y, 0);
->y, 0);
}
}
// Omitted for brevity
}

You just tried a circular #include!

Won't compile; incomplete type
What to Do
// Vector2.hpp
#pragma once
#include "Vector3.hpp"
namespace cse380 {
class
class Vector3
Vector3;
;
// Omitted for brevity
}
// Vector3.hpp
#pragma once
#include "Vector2.hpp"
namespace cse380 {
class
class Vector2
Vector2;
;
// Omitted for brevity
}
// Vector3.cpp
#include "Vector3.hpp"
#include
#include "Vector2.hpp"
"Vector2.hpp"
namespace cse380 {
// Omitted for brevity
}
// Vector2.cpp
#include "Vector2.hpp"
#include
#include "Vector3.hpp"
"Vector3.hpp"
namespace cse380 {
// Omitted for brevity
}

Forward-declare a class when you only need its name

This is why we split classes into .hpp/.cpp

#include its header when you need anything else (including sizeof)

i.e. in dependent .cpp files or templates in headers

Two classes can't be members of each other

Raw pointers (not smart pointers) to each other okay
Visualized
Vector2.obj
Vector2.obj Vector3.obj
Vector3.obj
main.obj
main.obj
Have:
main
...
MSVCP
MSVCPXX.DLL
.DLL
Seeking:
std@cout
std@system
...
Have:
cse380@Vector2@$ctor
cse380@Vector2@x
...
Have:
std@cout
std@system
...
Seeking:
cse380@Vector2@$ctor
cse380@Vector2@$ctor
...
Seeking:
cse380@Vector3@$ctor
cse380@Vector3@$opcse380@Vector2
...
Seeking:
cse380@Vector2@$ctor
cse380@Vector2@$opcse380@Vector3
...
Have:
cse380@Vector3@$ctor
cse380@Vector3@$op*=@f
...
(Remember, symbol names
are implementation-defined)
#pragma once

Include at the top of each .hpp

Otherwise the same class is effectively
defined multiple times
#include "Vector2.hpp"
#pragma once
// Contents of Vector2.hpp
<nothing>
First time this file
was #included?
Yes
No
With
#pragma once
Without
#pragma once
#pragma once
// France.hpp
// Spain.hpp
#include "France.hpp"
// Before
#include "France.hpp"
#include "Spain.hpp"
int main() {
// Etc.
}
// France.hpp
#pragma once
// Spain.hpp
#pragma once
#include "France.hpp"
// Hooray!
// France.hpp
// Spain.hpp
int main() {
// It works!
}
// Uh-oh
// France.hpp
// Spain.hpp
// France.hpp
int main() {
// Multiple
// definition error
}
Library/Include Install
Conventions
Linux
●
/usr/include and /usr/lib for
package managers
●
/usr/local/include and
/usr/local/lib for everything
else
Mac
●
/Library/Frameworks
Project-Specific
●
Enforce a location
●
“Use your home folder”
●
Include in your source tree
●
Recommended for this course
●
Submodules
Windows
●
None
●
God help you
Importing Box2D

Right-click Solution → Add → Existing Project

Ensure your CSE380Example project depends on
Box2D
– Solution → Properties
Importing Box2D
●
Still gotta add the include/library paths
●
Project → VC++ Directories
●
If you and your team aren't consistent, you
will lose lots of sleep
The important stuff
Importing Box2D
●
Add <RootBox2DDir>Box2D
to includes
●
Change your main to this:
Expands to these
Nice and easy
Filter by macro name
#include <iostream>
#include <cstdlib>
#include
#include "Vector2.hpp"
"Vector2.hpp"
#include
#include "Vector3.hpp"
"Vector3.hpp"
#include
#include <Box2DBox2D.h>
<Box2DBox2D.h>
using std::cout;
using std::endl;
using std::system;
using
using namespace
namespace cse380;
cse380;
int main() {
b2World
b2World world(b2Vec2_zero);
world(b2Vec2_zero);
Vector2
Vector2 a(2, 3);
a(2, 3);
Vector3
Vector3 b;
b;
cout << "Hello world!" << endl;
system("PAUSE");
}
// Not done yet; you'll get a linker error!
Importing Box2D
●
Consider changing Box2D's output directory
●
Then add Box2D.lib as a linker input
Importing Box2D
●
Success!
Using the Debugger
Nothing really new here
Just make sure you're using a Debug
build (and libraries, too)
Doxygen

De facto C++
documentation tool

Similar tags and
syntax to Javadoc

More powerful
Boost

Massive utility library
 Pain to install, though

Calendar math

Geometry

File system manipulation

Graphs

Networking

Unit testing

Lots, lots more
Popular Cross-Platform
GUI Libraries

Smaller, simpler

Uses its own
rendering

FLUID editor

Huge, lots of utilities
(plus an IDE)

Native OS
appearance

Qt Creator editor
Popular Cross-Platform
Game/Media Frameworks

Low-level (C)

Uses native API

High-level (C++)

Uses OpenGL

Thor/TGUI
extensions

Fewer features

My personal
favorite

Low-level (C)

Wraps native API
Other Compilers

Popular on Mac

gcc-compatible

Good luck using it
on Windows

Popular on Linux

Available for
Windows via
MinGW
Other Build Systems

Simple

UNIX-centric
 Need MinGW for
Windows

Universal

Generates
build/IDE files
 Including for Visual
Studio and make
Other IDEs
UPX

Compress executables and
libraries

Output automatically
decompresses when run

Output may trigger virus
scanners
– They hate self-modifying code

Compressed DLLs cannot
be shared between
programs
Visual Studio Tips

Don't be afraid to customize it

Most of today's lessons are not specific to it

You can define tasks to run upon a
successful build (e.g. zipping up the
game/assets, copying over any DLLs, etc.)
Box2D Tips

Box2D has a lot of classes; most of these are only used
internally

I'll make a list of classes to care about later

There is an abstract b2Draw class you can extend for
drawing bodies, joints, etc.

USE IT USE IT USE IT USE IT USE IT

Don't use pixels as world units; pick a size (e.g. 64px = 1
meter) and use that

Otherwise it's hard to reason about world design
Next Week
No more C++ tutorials, I hate you all

More Related Content

C++ Boot Camp Part 2

  • 1. CSE 380 C++ Boot Camp Part 2/2 You You C++ C++ Subtle and Subtle and annoying things annoying things
  • 2. Now what? ● Last week: The language ● This week: The tools ● Compiling and linking code ● Box2D, specifically ● You will be using it for your course project ● Splitting classes into headers and source files ● What that means and why you must do it ● Overview of popular C++ libraries and tools ● Tips about the course
  • 3. Static vs. Dynamic Libraries  .a or .lib extension (varies by compiler)  Resolved at link-time and included in the binary  Must recompile to update the library  Unused or duplicated library code can be removed  .dylib, .dll, or .so extension (varies by OS)  Resolved at run-time and included in program directory or system folders  Can swap out different versions at will  Only loaded to RAM once if multiple programs use the same dynamic library at the same time
  • 5. Symbol Tables moe.obj moe.obj Have: stooges::slap Have: std::vector<float> Seeking: stooges::poke Seeking: std::sin  Multiple gaps seeking one symbol: Perfectly normal  Multiple tabs declaring one symbol: multiple definition of symbol symbol_name  Gap without a tab filling it: unresolved external symbol symbol_name  Tab not assigned to a gap: Unused symbol (can be stripped)
  • 7. Installing Box2D  I assume you've downloaded Visual Studio already  Download Box2D now – And 7-Zip to open the archive  Extract the Box2D_v2.3.0/Box2D folder to wherever you want to keep your libraries  I use C:/Users/<name>/Libraries All of your libraries should go here (with a folder for each) Does this contain these?
  • 8. Compiling Box2D  Projects contain related code  Solutions contain related projects  Open Build/vs2012/Box2D.sln #include that in your game For testing and demos  Right-click Box2D → Build  You just built a static library!
  • 9. Compiling Box2D  Do the same with Testbed  Note that its dependencies are compiled  See Solution 'Box2D' → Properties → Project Dependencies  Testbed → Debug → Start New Instance Play around with this over the weekend
  • 10. What did you just build?  Box2D → Properties The most important stuff Change options depending on build type and platform Macros have different values depending on config or build environment
  • 11. Release Builds  Run the Testbed, go to Tiles demo, tick the Profile box  Look at step [ave] (max); note these numbers  previous [average] (longest time) for one physics step in milliseconds  Do it again in Release mode WOW! Debug build Release build
  • 12. Creating a Solution  Your solution will have multiple projects  Your game + any supporting libraries  File → New → New Project Create a new solution
  • 13. Let's Compile Something  Source Files → Add New Item → C++ File #include <iostream> #include <cstdlib> using std::cout; using std::endl; using std::system; int main() { cout << "Hello world!" << endl; system("PAUSE"); }
  • 14. Headers and Classes  Declare classes, global functions, etc. in header files (.hpp extension)  Define them in a corresponding source file (.cpp extension)  Exception: templated classes, functions, or methods must be defined in headers
  • 15. Headers and Classes  Reduces the number of files to build  Header changes? All .cpp files that use it must be recompiled  Source changes? Only that file must be recompiled  Prevent linker errors, too
  • 16. You Should See These // Vector2.hpp #pragma once class Vector2 { public: Vector2(); ~Vector2(); }; // Vector2.cpp #include "Vector2.hpp" Vector2::Vector2() { } Vector2::~Vector2() { } Provides symbols Provides code
  • 17. More (.hpp) // Vector2.hpp #pragma once namespace cse380 { class Vector2 { public: Vector2(); Vector2(const float, const float); // Can omit names in declaration float x, y; Vector2& operator+=(const Vector2&); Vector2& operator*=(const float); }; Vector2 operator+(const Vector2&, const Vector2&); Vector2 operator*(const Vector2&, const float); }
  • 18. More (.cpp) // Vector2.cpp #include "Vector2.hpp" namespace cse380 { Vector2::Vector2() : Vector2(0, 0) {} Vector2::Vector2(const float x, const float y) : x(x), y(y) {} Vector2& Vector2::operator+=(const Vector2& other) { this->x += other.x; this->y += other.y; return *this; } Vector2& Vector2::operator*=(const float scale) { this->x *= scale; this->y *= scale; return *this; } Vector2 operator+(const Vector2& a, const Vector2& b) { return Vector2(a.x + b.x, a.y + b.y); } Vector2 operator*(const Vector2& v, const float scale) { return Vector2(v.x * scale, v.y * scale); } }
  • 19. Let's Make a 3D Vector (.hpp) // Vector3.hpp #pragma once #include "Vector2.hpp" namespace cse380 { class Vector3 { public: Vector3(); Vector3(const float, const float, const float); float x, y, z; Vector3& operator+=(const Vector3&); Vector3& operator*=(const float); explicit operator Vector2() const; }; Vector3 operator+(const Vector3&, const Vector3&); Vector3 operator*(const Vector3&, const float); }
  • 20. Let's Make a 3D Vector (.cpp) // Vector3.cpp #include "Vector3.hpp" namespace cse380 { Vector3::Vector3(const float x, const float y, const float z) : x(x), y(y), z(z) {} Vector3::Vector3() : Vector3(0, 0, 0) {} Vector3& Vector3::operator+=(const Vector3& v) { this->x += v.x; this->y += v.y; this->z += v.z; return *this; } Vector3& Vector3::operator*=(const float scale) { this->x *= scale; this->y *= scale; this->z *= scale; return *this; } Vector3::operator Vector2() const { return Vector2(this->x, this->y); } Vector3 operator+(const Vector3& a, const Vector3& b) { return Vector3(a) += b; } Vector3 operator*(const Vector3& v, const float scale) { return Vector3(v) *= scale; } }
  • 21. Now Add a Conversion Operator // Vector2.hpp #pragma once #include #include "Vector3.hpp" "Vector3.hpp" namespace cse380 { class Vector2 { public: // Omitted for brevity explicit explicit operator operator Vector3 Vector3() () const const; ; }; // Omitted for brevity } // Vector2.cpp #include "Vector2.hpp" namespace cse380 { // Omitted for brevity Vector2 Vector2:: ::operator operator cse380:: cse380::Vector3 Vector3() () const const { { return return Vector3 Vector3( (this this->x, ->x, this this->y, 0); ->y, 0); } } // Omitted for brevity }  You just tried a circular #include!  Won't compile; incomplete type
  • 22. What to Do // Vector2.hpp #pragma once #include "Vector3.hpp" namespace cse380 { class class Vector3 Vector3; ; // Omitted for brevity } // Vector3.hpp #pragma once #include "Vector2.hpp" namespace cse380 { class class Vector2 Vector2; ; // Omitted for brevity } // Vector3.cpp #include "Vector3.hpp" #include #include "Vector2.hpp" "Vector2.hpp" namespace cse380 { // Omitted for brevity } // Vector2.cpp #include "Vector2.hpp" #include #include "Vector3.hpp" "Vector3.hpp" namespace cse380 { // Omitted for brevity }  Forward-declare a class when you only need its name  This is why we split classes into .hpp/.cpp  #include its header when you need anything else (including sizeof)  i.e. in dependent .cpp files or templates in headers  Two classes can't be members of each other  Raw pointers (not smart pointers) to each other okay
  • 24. #pragma once  Include at the top of each .hpp  Otherwise the same class is effectively defined multiple times #include "Vector2.hpp" #pragma once // Contents of Vector2.hpp <nothing> First time this file was #included? Yes No
  • 25. With #pragma once Without #pragma once #pragma once // France.hpp // Spain.hpp #include "France.hpp" // Before #include "France.hpp" #include "Spain.hpp" int main() { // Etc. } // France.hpp #pragma once // Spain.hpp #pragma once #include "France.hpp" // Hooray! // France.hpp // Spain.hpp int main() { // It works! } // Uh-oh // France.hpp // Spain.hpp // France.hpp int main() { // Multiple // definition error }
  • 26. Library/Include Install Conventions Linux ● /usr/include and /usr/lib for package managers ● /usr/local/include and /usr/local/lib for everything else Mac ● /Library/Frameworks Project-Specific ● Enforce a location ● “Use your home folder” ● Include in your source tree ● Recommended for this course ● Submodules Windows ● None ● God help you
  • 27. Importing Box2D  Right-click Solution → Add → Existing Project  Ensure your CSE380Example project depends on Box2D – Solution → Properties
  • 28. Importing Box2D ● Still gotta add the include/library paths ● Project → VC++ Directories ● If you and your team aren't consistent, you will lose lots of sleep The important stuff
  • 29. Importing Box2D ● Add <RootBox2DDir>Box2D to includes ● Change your main to this: Expands to these Nice and easy Filter by macro name #include <iostream> #include <cstdlib> #include #include "Vector2.hpp" "Vector2.hpp" #include #include "Vector3.hpp" "Vector3.hpp" #include #include <Box2DBox2D.h> <Box2DBox2D.h> using std::cout; using std::endl; using std::system; using using namespace namespace cse380; cse380; int main() { b2World b2World world(b2Vec2_zero); world(b2Vec2_zero); Vector2 Vector2 a(2, 3); a(2, 3); Vector3 Vector3 b; b; cout << "Hello world!" << endl; system("PAUSE"); } // Not done yet; you'll get a linker error!
  • 30. Importing Box2D ● Consider changing Box2D's output directory ● Then add Box2D.lib as a linker input
  • 32. Using the Debugger Nothing really new here Just make sure you're using a Debug build (and libraries, too)
  • 33. Doxygen  De facto C++ documentation tool  Similar tags and syntax to Javadoc  More powerful
  • 34. Boost  Massive utility library  Pain to install, though  Calendar math  Geometry  File system manipulation  Graphs  Networking  Unit testing  Lots, lots more
  • 35. Popular Cross-Platform GUI Libraries  Smaller, simpler  Uses its own rendering  FLUID editor  Huge, lots of utilities (plus an IDE)  Native OS appearance  Qt Creator editor
  • 36. Popular Cross-Platform Game/Media Frameworks  Low-level (C)  Uses native API  High-level (C++)  Uses OpenGL  Thor/TGUI extensions  Fewer features  My personal favorite  Low-level (C)  Wraps native API
  • 37. Other Compilers  Popular on Mac  gcc-compatible  Good luck using it on Windows  Popular on Linux  Available for Windows via MinGW
  • 38. Other Build Systems  Simple  UNIX-centric  Need MinGW for Windows  Universal  Generates build/IDE files  Including for Visual Studio and make
  • 40. UPX  Compress executables and libraries  Output automatically decompresses when run  Output may trigger virus scanners – They hate self-modifying code  Compressed DLLs cannot be shared between programs
  • 41. Visual Studio Tips  Don't be afraid to customize it  Most of today's lessons are not specific to it  You can define tasks to run upon a successful build (e.g. zipping up the game/assets, copying over any DLLs, etc.)
  • 42. Box2D Tips  Box2D has a lot of classes; most of these are only used internally  I'll make a list of classes to care about later  There is an abstract b2Draw class you can extend for drawing bodies, joints, etc.  USE IT USE IT USE IT USE IT USE IT  Don't use pixels as world units; pick a size (e.g. 64px = 1 meter) and use that  Otherwise it's hard to reason about world design
  • 43. Next Week No more C++ tutorials, I hate you all