Static library built-in rule in GNU make - makefile

I'm a newbie in GNU make and I'm reading "Managing Projects with GNU make - O'Reilly" book.
In Chapter 2, Building library section, the book introduced 2 ways for updating an archive library (static - .a).
The first one:
libname.a: preq1.o preq2.o
$(AR) $(ARFLGS) $# $?
The second one:
libname.a(preq1.o): preq1.o
$(AR) $(ARFLGS) $# $<
How does libname.a(preq1.o) increase performance of updating a static library?
Also I guess that the second format may be overhead if the library has a lot of members (hundreds or thousands), is this right?
Is this the following built-in rule?
(%): %
# commands to execute (built-in):
$(AR) $(ARFLAGS) $# $<
Thanks in advance

I think I may be able to provide you with a slightly fuller answer based on my - also limited - knowledge of the GNU Make utility. The first form of the recipe merely specifies that 'libname.a' depends on the following list of object files. If any of those files are younger than the last-updated time of 'libname.a' - then 'libname.a' will, as MadScientist says, be recreated in its entirety from scratch. In this sense, 'libname.a' is no different from any other Make target. In the second form, the dependency itself is NOT 'libname.a' but the insertion timestamps of the subordinate object files within the archive. Here, 'libname.a' is not actually tested at all. The insertion timestamp of each object file is tested within the archive and any DEPENDENT files whose last-modified date is younger than the corresponding object member file then cause the object file to be rebuilt, the archive to be updated with the rebuilt object file AND the object file then to be deleted - which I personally think is brilliant. There are 2 caveats; The first is that 'libname.a' must already exist (even if it's just an empty file) before the make recipe will work UNLESS you specify the '-c' flag invoking make to force the initial creation of the archive. The second refers to thread safety. Rebuilding the entire archive member by member may result in several recipes being run in parallel. In this case, there is a high likelihood of the target archive being corrupted (due to the perennial problem associated with multiple file handles on the archive) unless the 'noparallel' directive is specified at the top of the makefile. To answer the thrust of your question, the second form is more efficient simply because only outdated archive component modules are rebuilt and re-inserted instead of the entire archive being rebuilt from the top down. Hope this helps - V.V.

Related

Makefile: how to detect changes within the makefile itself?

I'm aware of the idea of using recursive makefiles. Will the subsequent makefiles such as the following be called be updated solely on any changes to the subsequent makefiles themselves?
e.g.:
#parent makefile. no changes here.
subsystem:
cd subdir && $(MAKE)
If the makefile within subdir was changed such that the following does not hold (e.g. only a gcc flag was changed), then will the object files be updated?
The recompilation must be done if the source file, or any of the
header files named as dependencies, is more recent than the object
file, or if the object file does not exist.
The only reason that, as written, make even runs that rule at all is because subsystem and subdir do not match.
If a subsystem file or directory were ever to be created in that directory that rule would cease to function.
If .PHONY: subsystem1 were added that problem would be fixed and that rule would always be run when listed on the command line (i.e. make subsystem). (As indicated in the comments .PHONY is a GNU Make extension. The section following the linked section discusses a portable alternative. Though it is worth noting that they are not completely identical in that .PHONY has some extra benefits and some extra limitations.)
In neither of those cases is the subsystem target paying any attention to modification dates of anything (as it lists no prerequisites).
To have a target depend on changes to a makefile you need to list the makefile(s) as prerequisites like anything else (i.e. subsystem: subdir/Makefile). Listing it as .PHONY is likely more correct and more what you want.
No, nothing in make itself tracks non-prerequisites. So flag changes/etc. do not trigger rebuilds. There are ways to make that work for make however (they involve storing the used flags in files that themselves are prerequisites of the targets that use those flags, etc.). There are questions and answers on SO about doing that (I don't have them ready offhand though).
Other tools do handle flag changes automatically however. I believe Electric Cloud's tools do this. I believe CMake does as well. There might also be others.
Recursive makefiles are executed whether or not anything changed. This is exactly one of the objections pointed out by Paul Miller in his Recursive make considered harmful paper from almost 20 years ago.
With that said, a makefile is just like any other dependency and can be added to a production rule to trigger that rule if the makefile is altered.
You can include the makefile as a dependency, the same as any other file:
mytarget.o: mytarget.c Makefile

Writing a Makefile to be includable by other Makefiles

Background
I have a (large) project A and a (large) project B, such that A depends on B.
I would like to have two separate makefiles -- one for project A and one for project B -- for performance and maintainability.
Based on the comments to an earlier question, I have decided to entirely rewrite B's makefile such that A's makefile can include it. This will avoid the evils of recursive make: allow parallelism, not remake unnecessarily, improve performance, etc.
Current solution
I can find the directory of the currently executing makefile by including at the top (before any other includes).
TOP := $(dir $(lastword $(MAKEFILE_LIST)))
I am writing each target as
$(TOP)/some-target: $(TOP)/some-src
and making changes to any necessary shell commands, e.g. find dir to find $(TOP)/dir.
While this solves the problems it has a couple disadvantages:
Targets and rules are longer and a little less readable. (This is likely unavoidable. Modularity has a price).
Using gcc -M to auto-generate dependencies requires post-processing to add $(TOP) everywhere.
Is this the usual way to write makefiles that can be included by others?
If by "usual" you mean, "most common", then the answer is "no". The most common thing people do, is to improvise some changes to the includee so the names do not clash with the includer.
What you did, however, is "good design".
In fact, I take your design even futher.
I compute a stack of directories, if the inclusion is recursive, you need to keep the current directories on a stack as you parse the makefile tree. $D is the current directory - shorter for people to type than $(TOP)/,
and I prepend everything in the includee, with $D/, so you have variables:
$D/FOOBAR :=
and phony targets:
$D/phony:

Compilation order in make rule

I have a compilation rule as follows,
$(compiled_objs) : $(obj_dir)/%.o: $(src_base)/%.cpp
It creates .o dso objects from specific .cpp files in src_base and works fine.
Question:
My question is that is there a way in gnu Makefiles to sort the order in which %.cpp files are processed. For example, in each src_base, i have a file called xxxLast.cpp and i want to create the object for *Last.cpp after all other .cpp files from $src_dir directory has already been processed.
Use-Case:
My use case is not common but i want to embedd the md5sum of all other .o objects in xxxLast.cpp file for which i can add additional handling in my rule.
I haven't done much work on makefiles. Help will be highly appreciated and thanks in advance.
Somewhere else in your makefile you'll have a target that depends on $(compiled_objs):
all_objects: $(compiled_objs)
Make will build the prerequisites of any target in the order they are listed. So if you want a particular object to be built last, then you just put it at the end of the compiled_objs macro.
Be aware that during parallel builds make will still walk the commands to run in the same order, BUT due to parallelization effects they may actually run in a different order, or at least you can't know that the last one will be started after all the previous ones have completed.
For your situation I really don't recommend just stucking the last object at the end and hoping. You should define this relationship explicitly using make rules, so:
all_objects: xxxLast.o
xxxLast.o: $(compiled_objs-but-not-xxxLast.o)
...generate md5sums for $^...
xxxLast.o $(compiled_objs-but-not-xxxLast.o): $(obj_dir)/%.o: $(src_base)/%.cpp

How to make GCC debug dumps with Makefile projects?

The title says it pretty nicely. I have a huge project that uses Makefile. How do I do a project-wide debug dumps (say, -fdump-tree-gimple) with GCC?
You must pass -fdump-tree-gimple (actually put any pass-name instead of gimple, or even all to dump all tree passes) to compilation string for every compiler execution (i.e. every time, you are calling gcc on source files or with -c option). Dump in form filename.c.XXX.gimple for any source file name will appear (XXX is a pass number like 003, depends on gcc version) in a working directory (often it is build folder). Also you may want to specify -dumpdir to collect all dumps in a single dump directory, this may be handy to avoid mess.
How will you do it in you makefile -- up to you. You may add it to $CFLAGS (most common solution, because dumping is a part of compilation flags), or create special variable and pass it around, or hard-code it inside makefile.
If you are building your project with lto, you must pass those flag(s) also on second link stage (i.e. add to LDFLAGS or so).

how to have make targets for separate debug and release build directories?

I am looking for suggestions to properly handle separate debug and release build subdirectories, in a recursive makefile system that uses the $(SUBDIRS) target as documented in the gnumake manual to apply make targets to (source code) subdirectories.
Specifically, I'm interested in possible strategies to implement targets like 'all', 'clean', 'realclean' etc. that either assume one of the trees or should work on both trees are causing a problem.
Our current makefiles use a COMPILETYPE variable that gets set to Debug (default) or Release (the 'release' target), which properly does the builds, but cleaning up and make all only work on the default Debug tree. Passing down the COMPILETYPE variable gets clumsy, because whether and how to do this depends on the value of the actual target.
One option is to have specific targets in the subdirectories for each build type. So if you do a "make all" at the top level, it looks at COMPILETYPE and invokes "make all-debug" or "make all-release" as appropriate.
Alternatively, you could set a COMPILETYPE environment variable at the top level, and have each sub-Makefile deal with it.
The real solution is to not do a recursive make, but to include makefiles in subdirectories in the top level file. This will let you easily build in a different directory than the source lives in, so you can have build_debug and build_release directories. It also allows parallel make to work (make -j). See Recursive Make Considered Harmful for a full explanation.
If you are disciplined in your Makefiles about the use of your $(COMPILETYPE) variable to reference the appropriate build directory in all your rules, from rules that generate object files, to rules for clean/dist/etc, you should be fine.
In one project I've worked on, we had a $(BUILD) variable that was set to (the equivalent of) build-(COMPILETYPE) which made rules a little easier since all the rules could just refer to $(BUILD), e.g., clean would rm -rf $(BUILD).
As long as you are using $(MAKE) to invoke sub-makes (and using GNU make), you can automatically exporting the COMPILETYPE variable to all sub-makes without doing anything special. For more information, see the relevant section of the GNU make manual.
Some other options:
Force a re-build when compiler flags change, by adding a dependency for all objects on a meta-file that tracks the last used set of compiler flags. See, for example, how Git manages object files.
If you are using autoconf/automake, you can easily use a separate build out-of-place build directory for your different build types. e.g., cd /scratch/build/$COMPILETYPE && $srcdir/configure --mode=$COMPILETYPE && make which would take the build-type out of the Makefiles and into configure (where you'd have to add some support for specifying your desired build flags based on the value of --mode in your configure.ac)
If you give some more concrete examples of your actual rules, maybe you will get some more concrete suggestions.

Resources