A static library is just an ar
archive (like zip but ancient) of object files. An object file is the source code that has been compiled to machine code, but hasn't been linked yet. You can make a static library like this (on Linux/OSX):
# Create a source file containing the single function in our library.
echo "int answer() { return 42; }" > answer.cpp
# Compile it to machine code.
c++ -c answer.cpp -o answer.o
# Compress it into an ar archive.
ar -r libanswer.a answer.o
That's it. The ar
format isn't specific to static libraries at all. You can use it like Zip if you want (but nobody does because it is old and rubbish). There is also one slight improvement you can make which is to add an index to all the symbols in the library which can give a performance improvement when linking. Like this:
ar -rs libanswer.a answer.o
That's all ranlib
does if you've ever wondered.
Anyway - the point about Link Time Optimisation is that it doesn't create a "real" object file, in the sense that it doesn't compile to machine code. Take a look:
$ c++ -c answer.cpp -o answer.o
$ c++ -c answer.cpp -flto -o answer_lto.o
$ file answer.o
answer.o: Mach-O 64-bit object x86_64
$ file answer_lto.o
answer_lto.o: LLVM bitcode, wrapper x86_64
answer.o
is a native Mach-O object file (because I am on Mac; on Linux it will be ELF). But answer_lto.o
is not! It's LLVM bitcode. That hasn't been compiled to machine code.
You can put this in an ar
archive if you want:
ar -r libanswer_lto.a answer_lto.o
But this isn't a real static library, and no tools (except Clang) will be able to link with it. GCC could link with libanswer.a
but not with libanswer_lto.a
.
I guess you could call libanswer_lto.a
a "static library" if you wanted (definitions can change etc.) but if you said "here is a static library" and gave them libanswer_lto.a
most people would say "what, no it isn't".
I would call it an LLVM bitcode library or something like that.
Libraries and dependencies are like persons and relatives: One is just an entity (something), the other is a relational entity.
I am a person. My niece is also a person. But to her, I'm a relative. You cannot simply be a relative by nature; you're always a relative of someone else.
Similarly, a code library becomes a dependency only when another project uses it, and then it's a dependency of that project and not of another. Even though a code library is invented specifically for other projects to use, it's not a dependency until this actually happens.
Best Answer
The main difference between a device driver and a library is that the purpose of a device driver is to control some hardware component.
Device drivers can either directly control I/O pins of the processor (like the SPI driver in your example is likely doing), or they can use the services of a lower-layer device driver to communicate over a communication channel with their device (like the MCP2515 driver).
What sets the latter kind of device driver apart from a library that implements a communication protocol is that the communication partner is a hardware chip that can only perform some dedicated function and that the communication protocol is very low level.