Purpose of nested archives - static-libraries

ar can create an .a file which includes another .a file, such that the output of ar -t whatever.a looks like:
someotherarchive.a
foo.o
bar.o
However, if this archive is then linked, the symbols from an .o in someotherarchive.a will not be accessible by foo.o. This can be resolved by flattening with the T switch to ar when creating, but that also creates a thin archive. Since there does not seem to be a flatten-but-don't-thin option, it's necessary to extract from someotherarchive.a first and then link the .os independently to create something that contains:
otherarchivememberA.o
otherarchivememberB.o
foo.o
bar.o
Raising the question, if putting one .a inside another .a makes it inaccessible, what's the purpose of doing so?

Presumably this is because ar was historically a general purpose archiving tool, like tar.
In other words, there is no purpose to inaccessibly nesting archives if you are creating static libraries.

Related

Why does a target archive behave like a .PHONY target in a Makefile?

I have a simple Makefile that builds an archive, libfoo.a, from a single object file, foo.o, like this:
CC=gcc
CFLAGS=-g -Wall
AR=ar
libfoo.a: libfoo.a(foo.o)
foo.o: foo.c
The first time I run make, it compiles the C file, then creates an archive with the object file:
$ make
gcc -g -Wall -c -o foo.o foo.c
ar rv libfoo.a foo.o
ar: creating libfoo.a
a - foo.o
However, if I run make again immediately (without touching foo.o), it still tries to update the archive with ar r (insert foo.o with replacement):
$ make
ar rv libfoo.a foo.o
r - foo.o
Why does Make do this when it shouldn't have to? (If another target depends on libfoo.a, that target will be rebuilt as well, etc.)
According to the output of make -d, it seems to be checking for the non-existent file named libfoo.a(foo.o), and apparently decides to rerun ar r because of that. But is this supposed to happen? Or am I missing something in my Makefile?
You are seeing this because the people who put together your Linux distribution (in particular the people that built the ar program you're using) made a silly decision.
An archive file like libfoo.a contains within it a manifest of the object files contained in the archive, along with the time that the object was added to the archive. That's how make can know if the object is out of date with respect to the archive (make works by comparing timestamps, it has no other way to know if a file is out of date).
In recent times it's become all the rage to have "deterministic builds", where after a build is complete you can do a byte-for-byte comparison between it and some previous build, to tell if anything has changed. When you want to perform deterministic builds it's obviously a non-starter to have your build outputs (like archive files) contain timestamps since these will never be the same.
So, the GNU binutils folks added a new option to ar, the -D option, to enable a "deterministic mode" where a timestamp of 0 is always put into the archive so that file comparisons will succeed. Obviously, doing this will break make's handling of archives since it will always assume the object is out of date.
That's all fine: if you want deterministic builds you add that extra -D option to ar, and you can't use the archive feature in make, and that's just the way it is.
But unfortunately, it went further than that. The GNU binutils developers unwisely (IMO) provided a configuration parameter that allowed the "deterministic mode" to be specified as the default mode, instead of requiring it to be specified via an extra flag.
Then the maintainers of some Linux distros made an even bigger mistake, by adding that configuration option when they built binutils for their distributions.
You are apparently the victim of one of these incorrect Linux distributions and that's why make's archive management doesn't work for your distribution.
You can fix it by adding the -U option, to force timestamps to be used in your archives, when you invoke ar:
ARFLAGS += -U
Or, you could get your Linux distribution to undo this bad mistake and remove that special configuration parameter from their binutils build. Or you could use a different distribution that doesn't have this mistake.
I have no problem with deterministic builds, I think they're a great thing. But it loses features and so it should be an opt-in capability, not an on-by-default capability.

How do I create a C++ program with each class in a different file

I want to create a class say PEN in one one c++ file and inherit it in another class that is in a separate file and finally run the program from a C++ file that has only the main function. I know this is a basic thing but I am new to C++. The program is a console program.
There's a few things here.
. Referencing
. Compling
. Linking
Referencing
You put your classes and main function in separate .cpp files.
Each file that references a class in another file needs to #include class.h where class.h is the headers that include the class declarations. You can have a single shared header for all the files, or a separate one for each. Usually there is a .h for each .cpp with the same name by convention.
Compiling
Then when you complie, you need to decide if you want a single binary blob (for you, this is my recommendation) or a library to link to.
Not sure exactly the cpp compile options but it will be something like: path/to/cpp-compiler main.cpp class.cpp
Order is important here, the classes main.cpp needs must be specified AFTER main.cpp on the command line.
Linking
If you chose to compile a separate library, you will need to do:
path/to/cpp-compiler
-c class.cpp
path/to/cpp-compiler -c main.cpp
separately, then do:
path/to/cpp-compiler -o a.out main.cpp class.o
to link.
You can also pack multiple .o files into a .so or dll if you like and link to that.
Linking can become quite complex and has many quirks so I think stick with compiling all you sources together for now until you get more familiar with it.
This is a good answer here: Using G++ to compile multiple .cpp and .h files
I suggest you do a little more research as there are bound to be heaps of other answers to this question.

Create library from several .c files and use it for linkin

I'm having problems creating a lib and using it to link a .c-file with a main-function.
I have e.g.
cfile1.c
cfile2.c
cfile3.c
program.c (with main-function)
I want to create a library from all the .c-files and use it to link the
program.c
What is the best way to do that?
I assume your program.c (which is main) need those *.c files(support) to make a new library. If is that so, may be you should compile all of them because your program.c need that (if there is a function on *.c files called on program.c files)
I think, you can take a look on this link below:
Including one C source file in another?
Hope it helps, CMIIW

What are the different types of files generated by the GCC compiler for?

When running make on one of my C projects I'm playing around with, I notice that gcc produces different file types at stages. I'm curious as to what these are, as I'm not too familiar with gcc.
The extensions I noticed are:
.o (I understand that these are compiled libraries)
.o.lst
.d
.a
I hope this is not a silly question, but I'm just trying to understand these files, and what they're used for.
.o is object file ie machine dependent output code
use gcc -c
.a is static library ... collection of several o files
ar -r
.d file is the dependency file that contain the dependency
.lst -If you want to see the C code together with the assembly it was converted to, use a command l
gcc -c -g -Wa,-a,-ad [other GCC options] foo.c > foo.lst

How to write rule to build object file when C files have different paths

I have bunch of C files, each with differnt path, so I have something like
SRC=/path1/path2/file1.c file2.c /usr/joe/files/file3.c
I want to build object file from each C file in build directory, so I did:
SRCBASE=$(notdir $(SRC))
OBJS= $(addprefix $(OBJDIR)/,$(SRCBASE:.c=.o))
This works fine, and I got the OBJS is build/file1.o build/file2.o build/file3.o
My question is how to write the implicit rule to build the object file, I tried to do:
build/%.o : %.c
gcc ....
But that seems now to work, since this rule did not catch the files with the full path.
I've tried to look at the gnu make, but did not find the answer there.
Many thanks.
You can use VPATH to locate files in other directories. Note that this does implicit searches, though, rather than using explicit paths. That is, you specify that you need file1.o through file3.o and that make should look first in ., then in /path1/path2, then in /usr/joe/files; so if . contains a file3.c you will get that one rather than the one in /usr/joe/files (or if not, but if there is one in /path1/path2, you will get that one).
It turns out that path searching is more often useful than explicit location anyway, so usually that's what you want. If you need to override something you just copy or symlink the "desired version" to the first place to be searched.

Resources