We live in a time where software makes software development so much faster and simpler. Writing a simple hello world program in C++ is as simple as installing an IDE (integrated development environment), write a cout statement and then press build. The IDE makes the process nice and simple, but can you do the same thing without the help of an IDE?
Many developers today become too reliant on IDE that they do not actually know what happens behind the scene. I am not saying you need to know everything that happens when you build a massive code project — there is a lot going on! What I am saying is that you should at least know what happens to something like a hello world program when you press build. Better yet, be able to manually build that hello world program.
So, why exactly am I telling you this? Well, it is because you will not always have the luxury of an IDE. Sometimes, you might have a computer terminal and that is all. In such a situation, you would need to know some essential details on working with your compiler (g++ in this case) through the terminal.
Compiling Code by Command Line
The very least you should know is how to compile your program by command line. For example, you should know how to compile a hello world program with g++ from the terminal. In case, you don’t here is an example.
#include <iostream> int main (int argc, char* argv[]) { std::cout << "Hello World" << std::endl; return 0; }
$ g++ hello_world.cc $ ./a.out Hello World
Know Important Flags to Pass to the Compiler
Compilers tend to have many functionalities that are not enabled by default. They can be accessed through passing flags into the command line when compiling your code. Some functionalities are awesome to have. For example, did you know g++ has an optimization feature that makes your code run faster without you needing to do anything to your code?
Here are a few flags that I think is important for you to know when it comes to g++.
Defining a Macro
If you take advantage of defining a macro during compile time, you can write your code just once and have it behave differently based on the macros defined. This means, instead of changing the code, you just have to rebuild the application with a different set of macros defined.
Here is an example.
#include <iostream> int main() { #ifdef DEBUG std::cout << "Debug mode running" << std::endl; #else std::cout << "Release mode running" << std::endl; #endif return 0; }
$ g++ macro_example.cc -o macro_example $ ./macro_example Release mode running $ g++ -DDEBUG macro_example.cc -o macro_example $ ./macro_exampler Debug mode running
Optimization
The optimization flag tells the compiler to try to optimize your code if possible. This means you can get a free speed up without changing your code. Optimization is not always about speed, so you can also optimize for size if you really need to.
# optimize for runtime $ g++ -O2 macro_example.cc -o macro_example # optimize for size $ g++ -Os macro_example.cc -o macro_example
Include Directories
Sometimes you are writing your own libraries and want to keep it nice and organize. The problem is that it becomes a hassle to include the files in your code. Other times, the compiler can’t find the files and fails to compile. The include directories flag can solve this problem by allowing you to add directories into the compiler’s search path.
#include "Helper.h" #include <string> int main () { std::string hi = "hi"; std::vector<std::string> array_of_words; array_of_words.push_back("Hello World"); array_of_words.push_back("Good bye"); Helper helper; helper.print(hi); helper.print(array_of_words); return 0; }
$ g++ -I./mylib ./mylib/Helper.cc include_example.cc -o include_example $ ./include_example hi Hello World Good bye
Include Shared Libraries
If you are building your own shared libraries or using a publicly available shared library, you might want to have them place within your project. That means they will not be in the compiler’s search path. Using the include shared library flags, you can tell the compiler where and what to look for.
$ g++ -I./mylib -L./ ./include_example.cc -o include_example -lhelper
The “-L” flag specifies which directory to search for the shared library. The “-l” flag specify the name of the shared library.
Debugging Features with the Compiler
Isn’t it nice when you use an IDE to build a program and when something goes wrong you see callbacks to where the problem happened? You can do that too by passing in the correct flags to g++. A debugger that g++ works with is gdb and all you need to do is include the flag when compiling your program. The compiler fills your program with debugging information. Then instead of running your program through the command line, you pass it to gdb.
#include <vector> void causeSegFault() { std::vector<int> v; int first_value = v[0]; } int main() { causeSegFault(); return 0; }
$ g++ -g seg_fault_ex.cc -o seg_fault_example $ gdb seg_fault_example (gdb) run Program received signal SIGSEGV, Segmentation fault. 0x000000000040079a in causeSegFault () at seg_fault_ex.cc:6 6 int first_value = v[0];
I hope you found this post helpful to you. If so, share it with others so they can benefit too.
Was there a time you found yourself without an IDE and need to do things purely by command line? Was it something you find yourself able to easily adapt to?
To stay in touch, follow me on Twitter, leave a comment, or send me an email at steven@brightdevelopers.com.