Makefile target inside conditional - linux

Sorry if this is a simple question, but most resources I've been able to find for Makefile tutorials cover only the extreme basics.
I'm attempting to interpret a Makefile that has a target inside a conditional ifneq. Additionally, said target is never declared as .PHONY but is called "all default". See below:
ifneq ($(SOME_VARIABLE)$(ANOTHER_VARIABLE,)
all default: check_a check_b
$(MAKE) ARCH=somearch CROSS_COMPILE=archcompiler -C $(KDIR) M=$(PWD) modules
else
obj-m += ...
endif
This is a simplified version, but hopefully gets the point across. My question is essentially:
Why isn't 'all default' declared as .PHONY? Is definitely isn't making a file called 'all default'.
Does a Makefile execute top-to-bottom like normal code? How could you even execute anything above a target?
This Makefile is building a linux kernel (or just kernel modules?), which I'm guessing is why I'm so confused. Can anyone recommend resources to help me begin to understand how all of this works? I don't even know where to start.

This isn't defining a rule to build a target called all default.
It's defining two rules to build two different targets, one called all and one called default. Multiple targets separated by spaces in an explicit rule define that same rule for each target.
Also note, that declaring a target .PHONY is not mandatory. Usually make will work the same way regardless of whether or not the target is explicitly marked .PHONY.
Marking a target .PHONY has these benefits: it's slightly more efficient (but hardly noticeable), and if you happen to create some file or directory with the same name as your target then it will continue to work.
In other words, as long as you don't create a file or directory named all or default, then your makefile will work properly even if these targets are not declared .PHONY.
As for your second question: no, makefiles are not processed procedurally, like programs or shell scripts.
The way it works is that make parses all the makefiles, included makefiles, etc. first and constructs an internal graph of all the targets and their prerequisites. Then after that's done, it chooses a starting node in the graph (either ones you asked for on the command line or else the first one in the makefile) and starts to walk the graph, building things that are out of date.

Related

NMake inference rules with both c and cpp files

I have a project with both c and cpp files, and I've been using NMake to build. My problem is that if I have two inferences rules, one for each file type,
{$(dirSrc)}.c{$(dirObj)}.obj:
cl /nologo /c /EHsc /Fo$(dirObj)\ $<
{$(dirSrc)}.cpp{$(dirObj)}.obj:
cl /nologo /c /EHsc /Fo$(dirObj)\ $<
$(binPath): $(dirObj)\*.obj
link /nologo /dll /out:$(binPath) $(dirObj)\*.obj
only the c files get compiled, presumably because the .c extension is first in the .SUFFIXES list.
I could of course simply change the extensions on the c files to cpp, but I was wondering if anyone knows of a way to have both rules invoked.
Well, to answer my own question, the best I could think of was to compile to 2 separate directories, then point to both when running the linker.
{$(dirSrc)}.c{$(dirObj)\c}.obj:
cl /nologo /c /EHsc /Fo$(dirObj)\c\ $<
{$(dirSrc)}.cpp{$(dirObj)\cpp}.obj:
cl /nologo /c /EHsc /Fo$(dirObj)\cpp\ $<
$(binPath): $(dirObj)\c\*.obj $(dirObj)\cpp\*.obj
link /nologo /dll /out:$(binPath) $(dirObj)\c\*.obj $(dirObj)\cpp\*.obj
(As a reference for others in the same boat) the problem is the *.obj wildcard.
That, together with the fact that if there are multiple (inference) rules for a target, only one can be reasonably applied to create/update it.
Now, the build logic from a clean state is the following (simplified):
Need to build $(binPath), let's see what it depends on...
There's that *.obj, so let't look closer...
Doesn't match any existing files; check if we could build it somehow...
Cool, an inference rule says .obj can be built from .c (or .cpp, it really doesn't matter, which one is found first, see below! BTW, it's not the .SUFFIXES order, but the ordering of the rules in the makefile that matters here)...
So, execute the compiler in the rule to create *.obj from its matching source, which is the non-expandable, literal *.c:
→ cl /c /Fo($outdir) *.c
Great, *.obj is now ready, go ahead to linking...
OK, final target, and (even though the linking may now fail for undefined externals) that's all we could do, so let's call it a day.
Notice, how the alternative rule never even came into the picture!
Now, for updates, assuming the broken (incomplete) target isn't there, but the object files built above are, and there're even some updates, both to some .c and .cpp files:
Need to build the missing $(binPath), let's see what it depends on...
There's *.obj, again, which can now match existing files, so let's check them (one by one) if they need updating...
Then, there's the same inference rule again (whichever; there can be only one for an item, let's stick with .c) matching the .obj target in question, so check for changes in the corresponding .c sources...
They are found, so "run compiler", but this time NMAKE is smart enough to only supply the updated C sources via the $< macro:
→ cl /c /Fo($outdir) some.c other.c
(Note: it's even smart enough (apparently, with VS 2019 here) to go ahead and use batch-mode by default, even if it's not explicitly a batch rule.)
OK, *.obj is now up-to-date again, proceed to linking...
Final target, same as before, end of job, celebrate! (Let's assume now that the link has succeeded, just for the sake of the remaining examples below.)
Again: the other rule was never needed/used for anything.
Now, curiously, you can even start deleting .obj files one by one (as long as some remain), and leave NMAKE unfazed:
'test.dll' is up-to-date
What?! Why aren't the missing ones rebuilt?
You know what? Let's delete all of them... And, just for the fun of it, replace them with a single fake one, by copying some random file there (from anywhere), renaming it to fake.obj.
'test.dll' is up-to-date
Jesus! This makes no sense!
OK, let's end this. Create a brand new .c file then. That'll sure trigger a rebuild!
'test.dll' is up-to-date
No way! :-o What the hell's going on?! Maybe adding a new .cpp then...
'test.dll' is up-to-date
OMG!... Such a piece of junk! Incredible, this NMAKE thing... Right?
Well... First of all, for fake.obj, for which there's no source with a matching name, neither rule applies: NMAKE can't "invent" a source for that, so it'll be never rebuilt, it's just sitting there, as a time-bomb, until the next linking round, where the linker would eventually pick it up and find out about it, ending all the fun. :)
To all the other "anomaly":
Any existing .obj file will satisfy the dependency of *.obj (for the lib), so as long as there's at least one, NMAKE will be happy, and never even know that it's not the complete list!
That is why nothing is ever done for any new .c or .cpp added to the project, so using a wildcard this way is shooting oneself in the foot. (Which doesn't mean there aren't any perfectly legitimate cases for wildcards in build scripts, BTW.)
And (to recap), for rebuilding a missing object, NMAKE (just like gmake etc.) has to pick a winner, and ignore the rest, if there are multiple matching rules.
(FYI, gmake even has a page specifically about this wildcard pitfall. And, to mitigate the risks, unlike NMAKE, it seems to refuse building the initial "complete" set of objects for a *.o wildcard, knowing that it'll become incomplete the minute we start adding sources — i.e. by the very act the wildcard was hoped to support! ;) )

automake Adding all c files in a directory

In automake's Makefile.am , the sources of a program is listed like
bin_PROGRAMS = os345v1
os345v1_SOURCES = os345.c os345interrupts.c os345semaphores.c
Instead of specifying individual files, How to add all c files in a specific directory and subdirectory ?
it's usually a bad idea to do use wildcards in automake.
for one thing, your automake project might be processed used with a non-GNU make implementation (which might not be able to use GNU-make extensions such as $(wildcard *.c)).
One of the strengts of autotools/automake is that it is agnostic of the target systems and their tool-chains.
More importantly, automake might need to actually know exactly which source files you want to be build.
This is important for instance when you want to make out-of-source-tree builds (e.g. with the source-code on read-only media, and the builds being "somewhere else): this is a common use-case for distributions (e.g. Debian) that allow to easily build multiple flavours (with different configure flags) from the same source in a single run.
And finally, not using wildcards protects your build against stray source code. E.g. having "foo.c" and a backup-file "foo_old.c" (e.g. because you are re-implementing "foo" and want to have check with the old implementation and want your editor to automatically enable syntax-highlighting) lying around in the same folder, might accidentally build both files resulting in multiple-definitions of the same symbols.
See also the automake documentation why automake does not support wildcards

If there are multiple directories in LDFLAGS, how does the linker know where to look first?

If I have two libraries with the same library name but stored in different directories (and they may contain different code) and I list both directories in the LDFLAGS variable in a makefile, how does the linker know where to look first and which library to use?
LDFLAGS+= \
-L${INSTALL_DIR}/lib\
-L${EVO_INSTALL_DIR}/lib\
Will it look in the INSTALL_DIR path first or in the EVO_INSTALL_DIR path?
INSTALL_DIR. It will look in the order they are listed.
By the way, it's your linker (probably the same program as your compiler) that's making this choice, not the Makefile. Make (which is reading your Makefile) only runs the build tools.

Is there a makefile option to delete the obj files only but leaving the targets intact?

I am short of disk space while trying to compare different releases of Android (each of them takes about 6-7G after building).
I thought there is an option for make (similar to make clean) that it will delete all the intermediate .obj files and leaves the target(s) alone. But I couldn't remember what it is; or is there an option like that?!
A makefile will do whatever it's written to do. The clean target is a convention for makefiles, not a feature of Make. A makefile need not have a clean rule; if there is a clean rule, and if it is written well it will clean out the files you wanted cleaned out, if it is written badly there's no limit to how badly it can mess things up.
If you are writing (or editing) a makefile, you can put in a rule for removing object files. If you are using a makefile written by someone else, either it has such a rule or it doesn't.
Maybe the .INTERMEDIATE directive will help. From the GNU Make documentation (10.4 Chains of Implicit Rules):
The second difference is that if make' _does_ create B in order to
update something else, it deletes B later on after it is no longer
needed. Therefore, an intermediate file which did not exist before
make' also does not exist after make'.make' reports the deletion
to you by printing a `rm -f' command showing which file it is
deleting.
Ordinarily, a file cannot be intermediate if it is mentioned in the
makefile as a target or prerequisite. However, you can explicitly
mark a file as intermediate by listing it as a prerequisite of the
special target `.INTERMEDIATE'. This takes effect even if the file is
mentioned explicitly in some other way.

How to convert a makefile into readable code?

I downloaded a set of source code for a program in a book and I got a makefile.
I am quite new to Linux, and I want to know whether there is any way I can see the actual source code written in C?
Or what exactly am I to do with it?
It sounds like you may not have downloaded the complete source code from the book web site. As mentioned previously, a Makefile is only the instructions for building the source code, and the source code is normally found in additional files with names ending in .c and .h. Perhaps you could look around the book web site for more files to download?
Or, since presumably the book web site is public, let us know which one it is and somebody will be happy to point you in the right direction.
A Makefile does not contain any source itself. It is simply a list of instructions in a special format which specifies what commands should be run, and in what order, to build your program. If you want to see where the source is, your Makefile will likely contain many "filename.c"'s and "filename.h"'s. You can use grep to find all the instances of ".c" and ".h" in the file, which should correspond to the C source and header files in the project. The following command should do the trick:
grep -e '\.[ch]' Makefile
To use the Makefile to build your project, simply typing make should do something reasonable. If that doesn't do what you want, look for unindented lines ending in a colon; these are target names, and represent different arguments you can specify after "make" to build a particular part of your project, or build it in a certain way. For instance, make install, make all, and make debug are common targets.
You probably have GNU Make on your system; much more information on Makefiles can be found here.
It looks like you also need to download the SB-AllSource.zip file. Then use make (with the Makefile that you've already downloaded) to build.

Resources