Advertisement

Why do you need the .h .cpp AND .lib files?

Started by June 16, 2015 06:26 AM
10 comments, last by Glass_Knife 9 years, 6 months ago

I found a project online and wanted to compile and run it. To do this I needed a YAML parser, which had to be built with CMAKE. There is something I don't understand though, the project needed the original YAML source code .h and .cpp files, and it also needed the built library file "libyaml-cppmd.lib" to be added to Additional Dependencies.

Why does it need both the .h and .cpp source files and the lib? Don't the source files tell it everything it needs to know (what the functions will do etc)? Doesn't it create the .lib file from the source files?

Appreciate any clarification on my confusion.

Thanks

For a static library, the .lib file contains all the code and data for the library. The linker then identifies the bits it needs and puts them in the final executable.

For a dynamic library, the .lib file contains a list of the exported functions and data elements from the library, and information about which DLL they came from. When the linker builds the final executable then if any of the functions or data elements from the library are used then the linker adds a reference to the DLL (causing it to be automatically loaded by Windows), and adds entries to the executable's import table so that a call to the function is redirected into that DLL.

Think of both like this (Disclaimer: this is a really high-level analogy ;) ..

  • The header is a phone number you can call, while...
  • ...the library is the actual person you can reach there!

It's the fundamental difference between "interface" and "implementation"; the interface (header) tells you how to call some functionality (without knowing how it works), while the implementation (library) is the actual functionality.

Note: The concept is so fundamental, because it allows you flexibility: you can have the same header for different libraries (i.e. the functionality is exactly called in the same way), and each library mayimplement the functionality in a different way. By keeping the same interface, you can replace the libraries without changing your code.

And: you can change the implementation of the library without breaking the calling code!

"Don't gain the world and lose your soul. Wisdom is better than silver or gold." - Bob Marley

Advertisement

^ Thanks, i (think) i understand some what of that.

but what I am confused is about the fact that it has both the header and cpp files? In your analogy, isint the .h file the phone number and the .cpp file the actual person? I cant understand the difference between a .lib and a .cpp implementation file...

Let's explain it low level. You can have all of this in a single cpp file. But if you would do that, you would get a huge file filled with code and not that easy to read and understand. If you split that cpp in headers and .cpp files wouldn't it be more easy to manage?
Let's say you wrote few math functions and few sorting functions and you use it in your code. If you wanted to use the same functions in another project you have to go there and copy-paste it. But if you put these functions in a header, you can just simply get that .h/hpp file and use all the function. Project management, code reuse and a clean code policy are the most important factors. Among many others.

"Don't gain the world and lose your soul. Wisdom is better than silver or gold." - Bob Marley

Let's explain it low level. You can have all of this in a single cpp file. But if you would do that, you would get a huge file filled with code and not that easy to read and understand. If you split that cpp in headers and .cpp files wouldn't it be more easy to manage?
Let's say you wrote few math functions and few sorting functions and you use it in your code. If you wanted to use the same functions in another project you have to go there and copy-paste it. But if you put these functions in a header, you can just simply get that .h/hpp file and use all the function. Project management, code reuse and a clean code policy are the most important factors. Among many others.

Thanks, yes I think I understand the use of .h and .cpp for code reause and maintainability...

But I am confused about the actual difference of a .lib and a .cpp file. Since if I make a .h and .cpp file, and I want to include it into another project, I can just add the .h and .cpp file to it (I don't need multiple files, all my projects can link to the same .h and .cpp file), but where does the .lib come into play during all of this?

Others seem to have clarified a little how libraries work. Basically, each execution of your compiler, with various .cpp and .h files, can generate one or more .lib files. These are compiled code, but the compiled code has not yet been 'fixed' together into a complete executable file (this process is called linking).

Think of it like building a lego set. Your .cpp and .h files are raw plastic which the factory moulds into lego bricks (the .lib files). You then use the lego bricks (.lib files) to build the completed model (the executable). With a bit of glue you can build those different libs into different models by arranging them in a different order and calling them differently with different parameters.

You can keep your lib files around once compiled, or you can throw them away.

Technically, you don't need all three of the files. Which of the three you need, where and when are down to design and your own personal tastes.

There are header-only libraries such as stb, which do simplify development a whole lot. Managing build dependencies is a special kind of hell.

I tend to put the .lib files into the .gitignore of my project, which means they don't get committed to version control. They're pointless binaries, unless you plan to share your library with others without disclosing source - in which case you just send them the header and lib. Note though, that this is frought with problems as you have to consider which version of the runtime theyre built against in windows land. Did you use the visual studio 2013 runtime, or the 2012 runtime? Was it 64 bit, or was it 32? Was it the multi threaded or single threaded? Dynamic or static? Debug or release? So much to go wrong and so much headache.

Generally, every single possibility is bundled by people releasing their libraries in such a way, see for example the fmod low level api and the raft of bundled .lib files.

Have fun!

Advertisement
The lib is a collection of compiled object files for easier reuse, such that you dont need to recompile dozens of libraries with hundreds of cpp files each time you use them.
You could probably get the source files for the lib somewhere, its only for convenience.

To answer your questions, generally you would only have the .h and lib files. As you said the lib is the compiled .source code (.cpp), however you may also have three, maybe not all the source is compiled into the .lib, maybe you have a config .cpp file also for example.

Try removing the cpp file(s) and compiling and see if you get any errors. Make sure you link the lib file though in the IDE project settings.

I think this is one of those cases where analogies just aren't the best way to answer. Better to get your hands dirty. Please bear with me through the parts you are already familiar with.

Create three C files like so:
[source lang="C"]
// fun1.c
#include <stdio.h>

void fun1(void) {

puts("Running fun1.");

}

// fun2.c

#include <stdio.h>

void fun2(void) {

puts("Running fun2.");

}

// main.c

extern void fun1(void);

extern void fun2(void);

int main(int argc, char **argv) {

fun1();

fun2();

}
[/source]

You could put the prototypes of fun1 and fun2 in a header file and include it in main.c. Were you to do so, the C preprocessor would just replace the #include directive with the content of the header file anyway. The preprocessor is just an elaborate text substitution machine. Headers allow you to reuse the same declarations across multiple files without typing them over and over and over. Anyway, no need for one here.

Given a GCC compiler (I'm using the tdm64 distribution of MinGW on Windows), you can compile all three files into an executable with the following command line:


gcc main.c fun1.c fun2.c -odemo

Doing so results in an executable, but no intermediate files. The compiler has taken all three source files, translated them to the final output format, and passed everything directly to the linker to create the executable. This approach requires all of the source files. We can split it up, though, like this.


gcc -c fun1.c
gcc -c fun2.c
gcc main.c fun1.o fun2.o -odemo

The -c flag tells the compiler to compile the source file and store the output in an intermediate file (called an object file with a .o extension in this case), so the first two lines produce the files fun1.o and fun2.o. The third line creates the executable using the object files instead of the source files. Now, you can distribute fun1.o and fun2.o to other people (in which case you would want to create a header with the function prototypes) and they never need to see your original source.

Distributing two object files isn't a big deal, but if you've got several of them, then it can be a bit of an annoyance for the users of your project to have to pass all those object files to the compiler. So you can bundle them up into a library (or archive) to make it simpler. Given that you've already created fun1.o and fun2.o, you can then do this.


ar rcs libfuns.a fun1.o fun2.o

With this, ar (the GNU archiver, or librarian) takes the two object files and packs them together in a library file, much as you would add files to a zip archive (except they aren't compressed in this case). When you have dozens of object files, it's much more convenient to pack them into a library like this. Then the user can do the following.


gcc main.c libfuns.a -odemo.exe

Or, more commonly (given that a library is usually not in the same directory as the source)


gcc main.c -L. -lfuns -odemo.exe

-L tells the linker to search a specific directory, in this case the current directory (specified via the '.') for any libraries. The -l (lowercase L) in this case says to link with libfuns.a.

So, to directly answer your question, you don't need the YAML source to build your project, you only need the library and the YAML headers. However, to get the YAML library, you first have to compile the YAML source if it isn't available for download somewhere. Then you can link the library with your project. Alternatively, you could add the YAML source directly into your build system and compile it together, but then you have to worry about how to configure the source, which compiler options to use and so on. It's typically a much better choice to use the build system that ships with any library project to compile the library separately from your project, then link with the resulting binary. That way, you let the library maintainers worry about how best to configure the compiler output for the library and you can focus on configuring the output of your own project.

It was probably a mistake to post a question like this in "For Beginners". While well-meaning I fear the posters so far did not get the actual question you are asking and go into details which I believe from your post you already know.

To answer that: Usually you should not need to add implementation files if you are already linking the static library. In fact, that will result in linker errors because there are two definitions of the same function. What exactly goes wrong in your case, I cannot say. One possible scenario is that the project you downloaded was initially intended to build its own 'libyaml-cppmd.lib' and link it directly. Maybe you broke that configuration. Maybe it was already broken when you downloaded it. Maybe it relies on having a specific environment variable set or a path added to the global linker settings. Maybe the dependency between targets just got broken.

This topic is closed to new replies.

Advertisement