Separate Compilation
To create truly reusable functions, their implementations need to be written
in a separate file that does not contain a main function. This approach, known
as separate compilation, allows you to organize your project into multiple
files, making it easier to manage, test, and reuse your code. By combining a
makefile, header files, source files, and a driver, you can build modular
and scalable C++ projects.
Header File
Section titled “Header File”A header file (.h) is used to declare function prototypes, class definitions,
and other shared components, allowing them to be included in multiple C++ files.
By placing your function prototypes in a header file, you enable other source
files to access and use those functions without redefining them.
Key Points
Section titled “Key Points”-
Reusable Prototypes: Placing function prototypes in a header file makes them accessible to multiple source files within a project.
-
Header Guards: To prevent multiple inclusions of the same header file, use header guards. These ensure that the contents of the header file are included only once during compilation:
// Copyright 2024 CSCE240#ifndef PROJECT_PATH_FILENAME_H_#define PROJECT_PATH_FILENAME_H_
// Function prototypes hereint aFunction(int, int);void anotherFunction();
#endifSource File
Section titled “Source File”A source file (.cc) contains the actual implementation of your functions and
includes the corresponding header file for the function prototypes. This
structure allows for clean separation of declarations and implementations,
enhancing modularity and reusability in your code.
Key Points
Section titled “Key Points”- Including the Header File: The source file begins by including the header file that declares the function prototypes. This ensures that the implementation matches the declarations.
// Copyright 2024 CSCE240#include "header.h"
int aFunction(int x, int y) { // Do something}
void anotherFunction() { // Do something}- Compiling the Source File: Use the
g++ -ccommand to compile the source file into an object file (.o). For example, the following would generate asource.ofile:
g++ -Wall -std=c++17 -c source.cc- Linking Object Files: The object code can be linked with other object files and a driver file to create an executable. For example:
g++ -Wall -std=c++17 source.o driver.o -o executableExample
Section titled “Example”Lets take the previous Calculator program from the Writing and Using page and properly separate it into different files.
Header File
Section titled “Header File”Create a file called calculator.h and add the function prototypes:
// Copyright 2024 CSCE240
#ifndef CALCULATOR_H_#define CALCULATOR_H_
void Greet();void FrontEnd();int Add(int x, int y);int Subtract(int x, int y);int Multiply(int x, int y);double Divide(double num, double denom);int Square(int x);
#endifChecking the file with cpplint will throw the following error:
cpplint calculator.hcalculator.h:3: #ifndef header guard has wrong style, please use: FILE_PATH [build/header_guard] [5]calculator.h:14: #endif line should be "#endif // FILE_PATH" [build/header_guard] [5]Source File
Section titled “Source File”Now create a file called calculator.cc and add the implementation for each function:
// Copyright 2024 CSCE2024
#include "calculator.h"
#include <iostream>
using std::cin;using std::cout;using std::endl;
void Greet() { cout << "------------------------------------" << endl; cout << "Welcome to the CSCE240 Calculator!!!" << endl; cout << "------------------------------------\n" << endl;}
void FrontEnd() { cout << "Enter 1: To Add" << endl; cout << "Enter 2: To Subtract" << endl; cout << "Enter 3: To Multiply" << endl; cout << "Enter 4: To Divide" << endl; cout << "Enter 5: To Square" << endl; cout << "Enter 0: To Quit" << endl;}
int Add(int x, int y) { return x + y; }
int Subtract(int x, int y) { return x - y; }
int Multiply(int x, int y) { return x * y; }
double Divide(double num, double denom) { if (num == 0 || denom == 0) { return 0; } else { return num / denom; }}
int Square(int x) { return x * x; }Again, running cpplint will throw the following error:
cpplint calculator.cccalculator.cc:3: Include the directory when naming header files [build/include_subdir] [4]Driver File
Section titled “Driver File”The Driver will contain our main function so create a file called driver.cc and add what your program does:
// Copyright 2024 CSCE240
#include <iostream>
#include "calculator.h"
using std::cin;using std::cout;using std::endl;
int main() { Greet();
bool run_program = true;
while (run_program) { FrontEnd();
int input; cin >> input;
switch (input) { case 0: run_program = false; break; case 1: // Add cout << "Enter the first integer to add: " << endl; int first_add; cin >> first_add;
cout << "Enter the second integer to add: " << endl; int second_add; cin >> second_add;
cout << first_add << " + " << second_add << " = " << Add(first_add, second_add) << "\n" << endl; break; case 2: // Subtract cout << "Enter the first integer to subtract: " << endl; int first_sub; cin >> first_sub;
cout << "Enter the second integer to subtract: " << endl; int second_sub; cin >> second_sub;
cout << first_sub << " - " << second_sub << " = " << Subtract(first_sub, second_sub) << "\n" << endl; break; case 3: // Multiply cout << "Enter the first integer to multiply: " << endl; int first_mul; cin >> first_mul;
cout << "Enter the second integer to multiply: " << endl; int second_mul; cin >> second_mul;
cout << first_mul << " * " << second_mul << " = " << Multiply(first_mul, second_mul) << "\n" << endl; break; case 4: // Divide cout << "Enter the numerator: " << endl; int num; cin >> num;
cout << "Enter the denominator: " << endl; int denom; cin >> denom;
cout << num << " / " << denom << " = " << Divide(num, denom) << "\n" << endl; break; case 5: // Square cout << "Enter the integer you would like to square: " << endl; int square; cin >> square;
cout << square << "^2 = " << Square(square) << "\n" << endl; break; default: cout << "Please enter an integer for the available options\n" << endl; } }
cout << "Calculator powering off..." << endl;
return 0;}Makefile
Section titled “Makefile”The final file to create is a makefile. Not using one becomes incredibly tedious as we would have to compile and
link various files. Add the following code to your makefile:
# Variablescompiler = g++flags = -Wall -std=c++17compile = $(compiler) $(flags) -clink = $(compiler) $(flags)
# Compilecalculator.o : calculator.cc calculator.h $(compile) $<
# Compiledriver.o : driver.cc calculator.h $(compile) $<
# Link and Executedriver : driver.o calculator.o $(link) $^ ./a.out
# Clean Folderclean : rm *.o helloCompile, Link, & Run
Section titled “Compile, Link, & Run”Now that we created a makefile we can compile, link, and run our calculator program. Though the makefile shows many
commands, we only have to run the driver script to accomplish everything!
make driverg++ -Wall -std=c++17 -c driver.ccg++ -Wall -std=c++17 -c calculator.ccg++ -Wall -std=c++17 driver.o calculator.o./a.out------------------------------------Welcome to the CSCE240 Calculator!!!------------------------------------
Enter 1: To AddEnter 2: To SubtractEnter 3: To MultiplyEnter 4: To DivideEnter 5: To SquareEnter 0: To Quit1Enter the first integer to add:2Enter the second integer to add:22 + 2 = 4
Enter 1: To AddEnter 2: To SubtractEnter 3: To MultiplyEnter 4: To DivideEnter 5: To SquareEnter 0: To Quit0Calculator powering off...