Banner: ZumGuy Publications and Network

ZumGuy Publications and Network

Making C++ libraries

Posted by Sean on Monday, 2nd October 2017 21:19
If you use C++, you have almost certainly already used a library of some kind. Even the classic "Hello world" program requires one:
#include <iostream> // include the iostream library

int main() {
	std::cout << "Hello world!";
	return 0;
}
But what if we wanted to write our own? This has several advantages. First of all, if we have a function (or many) we want to use in several projects, we can wrap it (or them) in a neat library, and use it time and time again, without tedious copy/pasting. Secondly, if you're working on a big project, it gets messy if you have everything crammed into one.cppfile! We can use libraries to break our functionality up into simpler, more manageable chunks. And last but not least, if we have lots and lots of code, this can take a long time to compile, and this can get wasteful if we're only working on a small part of our project. A library is precompiled, and can save us lots of development time!


Creating the library source code



Let's create a simple library to wrap one function, calledsquare, which takes two numbers and squares them. First off, we want to create our function file,square.cpp:
//square.cpp

#include "square.h"

double square(double x) {
	return x*x;
}
Pretty straightforward. You can already see that we are including another file,square.h. So we'll create this too:
// square.h

double square(double);
This is what is called a header file. It contains only the declaration of our functionsquare.
Before we move on to the next step, we want to make a small improvement to our file, with what is called a header guard:
//square.h

#ifndef SQUARE_H
#define SQUARE_H

double square(double);

#endif
This uses preprocessor directives to prevent declaring our functions twice, in casesquare.his somehow included twice. What happens is that the code between the lines#ifndef SQUARE_Hand#endifis only executed if the preprocessor constantSQUARE_His undefined. If that is the case, define that constant and declare all our functions (just one in this case) - this way declarations will only happen once, because ifsquare.his included a second time,SQUARE_Hwill be defined and the declarations will be skipped.

Now that we have our little library source code ready, let's place it in a folder calledlib/. It could be called anything - in fact it's not even necessary to create it at all - but this name is a popular choice, and it keeps our files nice and tidy.

Let's create a filemain.cppoutside oflib/to use our library:
//main.cpp
#include <iostream>
#include "lib/square.h"

int main() {
	std::cout << square(5);
	return 0;
}
As far as the source is concerned, that's it! Now we have to compile our files to make an executable.


Compiling a file with the library



If we attempt to simply compile our filemain.cppwe will get an error:
$ g++ main.cpp -o main
/tmp/cc0V8dkz.o: In function
main':
main.cpp:(.text+0x1c): undefined reference to
square(double)'
collect2: error: ld returned 1 exit status
turing@Turing:~/pt17/pt17-exercises/tests$
g++can't find the definition ofsquare. What we must do is compile the files separately but without linking them. Linking is the final step in the compilation process, in which all binary files of the various libraries are crammed into one executable. Here's how:
$ g++ -c main.cpp -o  main.o
$ g++ -c lib/square.cpp -o lib/square.o
These two commands will compile the filesmain.oandsquare.o, without linking them. Note that this also prevents the compiler from complaining aboutsquare.cppnot having amainfunction!
Then we need to line the files manually:$ g++ main.o lib/square.o -o mainNow we can execute ourmainfile with./mainand it will behave as expected!

Making a proper library



But what if we have many files we would like to include? This compilation process takes multiple steps and gets very tedious very quickly. We can group many*.ofiles into one as follows:
ar ruc lib/libsquare.a lib/square.o lib/file2.o [...]
ranlib lib/libsquare.a
ranlibwill create an index for the library and is not required by all systems. The file must be calledlib.ain order for it to work.

Finally, we can compile ourmain.cppfile using our library:g++ main.cpp -Ilib -Llib -lsquare -o mainHere,-Ispecifies the drectory where the header filesquare.his located,-Lthe location where the library is located, and-lspecifies to look for the library.
Of course, this entire process can be automated withmake!
Posted by Andrew on Wednesday, 4th October 2017 08:53

This will help me a lot. Thank you!

You must be logged in to post messages.

Quote of the day...


ZumGuy Internet Promotions