60

Let's say I have 10 *.hpp and *.cpp files that I need to compile a code. I know that I will need those same files for many different codes. Can I create a "package" with those files that would allow me to simply write:

#include <mypackage>

instead of:

#include "file1.hpp"
#include "file2.hpp"
...
#include "file10.hpp"

I wouldn't then need to write a makefile every time I need this "package".

To be more precise, I use Linux.

0

7 Answers 7

98

A collection of CPP sources (H files and CPP files) can be compiled together in to a "library," which can then be used in other programs and libraries. The specifics of how to do this are platform- and toolchain-specific, so I leave it to you to discover the details. However, I'll provide a couple links that you can have a read of:

Creating a shared and static library with the gnu compiler [gcc]

Walkthrough: Creating and Using a Dynamic Link Library (C++)

Libraries can be seperated in to two types: source code libraries, and binary libraries. There can also be hybrids of these two types -- a library can be both a source and binary library. Source code libraries are simply that: a collection of code distributed as just source code; typically header files. Most of the Boost libraries are of this type. Binary libraries are compiled in to a package that is runtime-loadable by a client program.

Even in the case of binary libraries (and obviously in the case of source libraries), a header file (or multiple header files) must be provided to the user of the library. This tells the compiler of the client program what functions etc to look for in the library. What is often done by library writers is a single, master header file is composed with declarations of everything that is exported by the library, and the client will #include that header. Later, in the case of binary libraries, the client program will "link" to the library, and this resolves all the names mentioned in the header to executable addresses.

When composing the client-side header file, keep complexity in mind. There may be many cases where some of your clients only want to use some few parts of your library. If you compose one master header file that includes everything from your library, your clients compilation times will be needlessly increased.

A common way of dealing with this problem is to provide individual header files for correlated parts of your library. If you think of all of Boost a single library, then Boost is an example of this. Boost is an enormous library, but if all you want is the regex functionality, you can only #include the regex-related header(s) to get that functionality. You don't have to include all of Boost if all you want is the regex stuff.

Under both Windows and Linux, binary libraries can be further subdivided in to two types: dynamic and static. In the case of static libraries, the code of the library is actually "imported" (for lack of a better term) in to the executable of the client program. A static library is distributed by you, but this is only needed by the client during the compilation step. This is handy when you do not want to force your client to have to distribute additional files with their program. It also helps to avoid Dependancy Hell. A Dynamic library, on the other hand, is not "imported" in to the client program directly, it is dynamically loaded by the client program when it executes. This both reduces the size of the client program and potentially the disc footprint in cases where multiple programs use the same dynamic library, but the library binary must be distributed & installed with the client program.

2
  • 1
    Very good, I’d hoped somebody would post a tutorial, you even posted two. Commented May 22, 2013 at 13:59
  • What if I have a library of only template functions? They can't be dealt with like regular functions, definitions must be in the header file. So if I distribute the binary static library, I'd basically by sending away the source code itself... Is there a way to hide the source code of template functions from the client? Commented Sep 18, 2017 at 14:41
6

On Linux:

g++ FLAGS -shared -Wl,-soname,libLIBNAME.so.1 -o libLIBNAME.VERSION OBJECT_FILES

where

FLAGS: typical flags (e.g., -g, -Wall, -Wextra, etc.)

LIBNAME: name of your library

OBJECT_FILES: objects files resulting from compiling cpp files

VERSION: version of your library

2

Assuming your "file1.hpp" and "file2.hpp" etc are closely related and (nearly) always used together, then making one "mypacakge.h" that contains the includes of the other components is a good idea (it doesn't in and of itself make it into a library - that is a different process altogether).

If they are NOT closely related and/or used together, then you shouldn't have such a "mega include", because it just drags in a bunch of things that aren't needed.

To make a library involves building your code once, and either generating a .lib file or a shared librar (.dll or .so file). The exact steps to do this depends on what system you are using, and it's a little too complicated for me to explain here.

Edit: To explain further: All of the C++ library is actually one library file or shared library file [along with a number of header files that contain some of the code and the declarations needed to use the code in the library]. But you include <iostream> and <vector> separately - it would become pretty awful to include EVERYTHING from all the different C++ library headers in one <allcpplibrary>, even if it was a lot less typing involved. It is split into sections that do one thing per headerfile. So you get a "complete" set from one header file, but not a too much other things you don't actually need.

1
  • okay, I understand the idea : don't put everything together if it's not useful and if the components are not closely related. I will build my own .so library. thx
    – PinkFloyd
    Commented May 22, 2013 at 14:03
2

Yes and no.

You can write an include-all header so that #include "myLib.h" is sufficient, because you include all those headers through the single header. However, that does not mean that the single include is enough to have the content of the 10 '.cpp' files linked to your project automagically. You will have to compile them into a library and link that single library (instead of all the object files) to the projects that use "myLib.h". Library binaries come as static and dynamic libraries, the files are typically named .lib and .dll (windows) and .a and .so (linux) for static and dynamic libraries, respectively.

How to build and link such libraries depends on your build system, you might want to loke those terms up on the net.

One alternative is to get rid of the .cpp files by defininig all the functions in the headers. That way you won't have to link the additional library, but it comes at the cost of increased build times, because the compiler will have to process all those functions every time you include the header directly or indirectly into one of your translation units.

1
  • 1
    "One alternative is to get rid of the .cpp files by defininig all the functions in the headers." The ISO recommends against this practice; headerfiles should be for declarations only, never for implementations. Commented Jan 5, 2020 at 5:16
1

If a client needs all ten headers to actually make use of your "package" (library), that's pretty bad interface design.

If a client needs only some headers, depending on which parts of your library are being used, let the client include the appropriate headers, so only a minimal set of identifiers are introduced. This helps scope, modularization, and compilation times.

If all else fails, you can make an "interface header" for external use, which is different from the ones you use internally for actually compiling your library. This would be the one that gets installed, and consists of the necessary contents from the other headers. (I still don't think you would need everything from every header in your lib.)

I would discourage Salgar's solution. You either have individual headers, or a monolithic one. Providing individual headers plus a central one that simply includes the others strikes me as pretty poor layout.

What I do not understand is inhowfar Makefiles play into this. Header dependencies should be resolved automatically by your Makefile / build system, i.e. it shouldn't matter here how your header files are layed out.

2
  • thx, to answer to your makefile question, i just meant that if i include a iostream for instance, I don't have to add it in my makefile... I wondered if it could be the same for my own library
    – PinkFloyd
    Commented May 22, 2013 at 13:58
  • @user2110463: I am seriously confused. I am not sure I want to ask what your Makefiles look like...
    – DevSolar
    Commented May 22, 2013 at 14:18
1

simply all you'd have to do is create a .h or .hpp file that has

#ifndef MAIN_LIB_H
#define MAIN_LIB_H

#include "file1.hpp"
#include "file2.hpp"
#include "file3.hpp"
...
#include "file10.hpp"

#endif

make the file called whatever I would choose main_lib.h because of the ifndef, and just

#include "DIRECTORY PATH IF THERE IS ONE/main_lib.h"

in the main file. No need for anything else if you were using visual studios. Just build then press CTRL + F5.

0

This method works for both C++ and C.

Say you want to use the function hello defined in the file hello.cpp, and you want to use it via a library.

//file hello.cpp 
#include <iostream>
void hello(void) { 
    std::cout<<"hi"<<std::endl;
}

First of all you need to create another file hello.h and declare the functions (and variables, if any), for hello.cpp. In C and C++ definition is different from declaration. The rule is define once and declare as many times as you want, and declaration shall precede usage.

//file hello.h
#ifndef HELLO  // C macro guard to prevent this file being included more than once
#define HELLO  // you can ignore them
void hello(void);
#endif  // end of guard

Here is main.cpp

//file main.cpp
#include "hello.h" 
int main () {
    hello();
    return 0;
}

So this is your file structure:

src
|- main.cpp
|- hello.cpp
|- hello.h

Now there are two options, building and linking with static library and dynamic library.

Option 1: Static library

g++ hello.cpp -c -o hello.o // compile to object file 
g++ main.cpp -c -o main.o   // compile main.cpp to object file
g++ main.o hello.o -o a.out // linked object file and produce executable

Now you may execute the executable a.out.

Dynamic(Shared) Library

Dynamic library ends in so. The convention is to name it as libCUSTOMNAME.so. When linking, pass the flag -lCUSTOMNAME instead of the file name.

g++ -fPIC hello.cpp -o hello.o // -fPIC produces position independent code. 
g++ -shared -Wl,-soname,libhello.so hello.o -o libhello.so // produce the dynamic library file 
g++ main.cpp -L$(pwd) -lhello -Wl,-rpath=$(pwd) // compile and link main file

In the last line of the code, $(pwd) is shell code substitution for path of current directory. -L specifies the location of the dynamic library file, -Wl,rpath= specifies run time path.

Remarks

As you can see, building C and C++ source code is troublesome, as you have to manually compile and linking all the libraries. This job is turning even more compilicated for large projects. For quick reference, the Linux Kernel has over 10000 lines of makefile and a custom build system, Kbuild, for building kernel source code. Other project, such as chromium and firefox, are similar.

Many tools are developed to solve this problem, such as gnu make, cmake, gmake, ninga, meson, etc. But in some opinions these tools are not very helpful, as they tries to solve a complicated problem by introducing more complications and idiosyncrasies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.