Relationship between sources and binaries in Makefile - makefile

I have source code tree that contains about 300 Makefiles. These Makefiles compile sources to object files and object files to several firmware images.
What I want is to get a listing like this:
<firmware image name> : <list of object files> : <list of source files>
Is there any tool for that?

Well, if what you are shooting for is getting a list of images that will be built, you could try playing around with the -n and -W flags.
-n tells make to do a dry-run. It will print out all the commands it would have executed, but won't really execute them. If you do this after a make clean it might give you the information you want. Perhaps not in exactly the form you want, but that's what sed and awk are for.
-W file tells make to pretend that file was modified, and do its thing. This might be helpful if a make clean would be excessive.

Not by magic. Make doesn't know what are sources and what are objects. It just knows that there are all targets with various dependency relationships between them. You could try post-processing -p.

Related

The difference between .mk file and Makefile

I've just begun to study Porting Android. And I come across a new type of file which is .mk file. It's is an extension of Makefile but I don't know what it is different from a Makefile ? So, can somebody help you clarify them. Thanks very much !
A make file can have any name. The -f option of make is used to specify which file to use:
make -f foobar
You can even use -f several times:
make -f foo -f bar
In which case make processes the files in order (or, equivalently, concatenates the files and processes the result).
makefile and Makefile are special names because if make is called without the -f option it automatically searches for them, in this order, and use the first it finds. Note that GNU make also considers GNUmakefile, and prefers it over makefile and Makefile. Other make implementations can have other default names.
The .mk extension is a more or less standard extension for make files that have other names than the defaults. It is a reasonable extension if you want humans to quickly understand what these files are: convert.mk is more informative than foobar. Some editors use this extension to identify the file type and apply syntax coloring. They usually apply the same syntax coloring to makefile and Makefile.

Detect if make command target is a path or a phony

Background
I am writing several books in Markdown. My files are structured as follows:
Description
writing/
Makefile 1. main Makefile (shown below)
book.template 2. pandoc template that uses TITLE
books/
current.txt 3. contains the current book name
book1/
meta.mk 4. sub-Makefile that defines TITLE
chapters/
01.md 5. actual text of book 1, chapter 1
02.md
...
book2/
meta.mk
chapters/
01.md
02.md
...
...
Here is the Makefile:
CURR_BOOK_NAME:=$(shell cat books/current.txt)
CURR_BOOK_DIR:=books/$(CURR_BOOK_NAME)/
CURR_CHAPTERS_DIR:=$(CURR_BOOK_DIR)chapters/
CURR_CHAPTERS:=$(wildcard $(CURR_CHAPTERS_DIR)*.pdf)
# suppose that each meta.mk defines the TITLE variable
include $(CURR_BOOK_DIR)/meta.mk
all: pdfs
...
pdfs: $(CURR_CHAPTERS)
%.pdf: %.md book.template
pandoc -o $# $< ... \
--template=book.template \
--variable=title:$(TITLE)
I usually work on only one book at a time. Thus, it was convenient to create a file current.txt with the name of the current book. Now I just type make to compile the current book to PDF by having the Makefile read in current.txt. Note that the PDF depends on a variable defined in the book-specific meta.mk.
Question
Occasionally, I want to make a small change to another book. How should I modify the Makefile so that I don’t have to update current.txt and then change it back each time? To be more precise, I would like to detect whether the arguments passed to make on the command line are phony targets or paths. For example, I would like the process to look like:
$ cat books/current.txt
book1
$ ls books/*/chapters/*
books/book1/chapters/01.md books/book1/chapters/02.md
books/book2/chapters/01.md books/book2/chapters/02.md
$ make
pandoc -o books/book1/chapters/01.pdf ... --variable=title:One
pandoc -o books/book1/chapters/02.pdf ... --variable=title:One
$ ls books/*/chapters/*
books/book1/chapters/01.md books/book1/chapters/02.md
books/book1/chapters/01.pdf books/book1/chapters/02.pdf
books/book2/chapters/01.md books/book2/chapters/02.md
$ make books/book2/chapters/01.pdf
pandoc -o books/book2/chapters/01.pdf ... --variable=title:Two
$ ls books/*/chapters/*
books/book1/chapters/01.md books/book1/chapters/02.md
books/book1/chapters/01.pdf books/book1/chapters/02.pdf
books/book2/chapters/01.md books/book2/chapters/02.md
books/book2/chapters/01.pdf
Possible solutions
It was suggested to override the variable on the command line:
make CURR_BOOK_NAME=book2 books/book2/chapters/01.pdf
However, I think this is too verbose and redundant, since it requires repeating the name of the book twice, and typing the name of the internal variable CURR_BOOK_NAME once.
Note
This is a simplified example. Please ask if you want to see the actual Makefile. Also, feel free to clarify the question title.
The following valuable answer was posted earlier, but after a short discussion of pros/cons in the comments, the answerer deleted it and left a downvote without opting to comment. I reproduce it here in case it helps other users. I am still looking for a “more complicated” solution that avoids the redundancy and allows building individual chapters.
A simple solution would be copy your Makefile to a new file, say book.mak and delete the first line CURR_BOOK_NAME:=$(shell cat books/current.txt). Then create new Makefile like this:
CURR_BOOK_NAME:=$(shell cat books/current.txt)
current:
$(MAKE) -f book.mak CURR_BOOK_NAME="$(CURR_BOOK_NAME)"
book1:
$(MAKE) -f book.mak CURR_BOOK_NAME="book1"
book2:
$(MAKE) -f book.mak CURR_BOOK_NAME="book2"
Then when you change something in book1 while book2 is current just type make book1. The makefile will figure out what's changed and update it.
If you really want to be able to type make books/book2/chapters/01.pdf then it's a fair bit more complicated.
I would restructure this so that your top-level Makefile is referenced from the top-level directory of each individual project. Think of it as a support library for each book project and manage it accordingly.
The individual Makefile can then be as simple as
include /usr/local/share/lib/bookmaker/main.mk
... assuming you call the library bookmaker and install it at this path. (It could live in a tree somewhere below your home directory just as well.)
I would think of this as a normalization of your de facto project structure, more than a new arrangement. Your individual books already depend on the bookmaker Makefile, but forcing them to live in physical subdirectories makes it harder to work on an experimental clone (assuming you manage each individual book as a separate Git project -- if not, switching to this model probably makes even more sense!). You can also get rid of the minor but pesky inconvenience of the "current" state file you will now obviously no longer need.

A make file for exporting all inkscape svg to pdf

I'm trying to write a make file that will create PDF from every inkscape SVG in a directory. From the make manual and various tutorials, it seems a pattern rule is the way to go, so I have
%.pdf : %.svg
inkscape -A $*.pdf $*.svg
I know the inkscape command works if I do it manually. When I invoke make though, I get
$ make
make: *** No targets. Stop.
Since the pdf files don't exist yet, I can't invoke make *.pdf and make *.svg won't match any targets. Also, I can't find a way to put an all target in that depends on the pattern.
One final problem; This is part of a large project, and I would like to invoke make in this directory recursively, but if make alone doesn't work, what target should I invoke recursively and how do I do this?
Your pattern is correct, but a pattern tells make how to build a target if you ask for one. You still have to ask for it, and since you haven't that's why you get the "no targets" message.
If you want to find all the SVG files and convert them, you can use the wildcard function:
SVGFILES := $(wildcard *.svg)
all: $(SVGFILES:%.svg=%.pdf)
%.pdf : %.svg
inkscape -A $*.pdf $*.svg
I don't quite understand your second question. Once you have the above you can just use normal $(MAKE) (always use this, never make) in a parent makefile to build these files.

Makefile: how to find out dependencies are no longer used in other rules

I have a somewhat complicated Makefile which runs perl scripts and other tools and generates some 1000 files. I would like to edit/modify some of those generated files after all files are generated. So I thought I can simply add a new rule to do so like this:
(phony new rule): $LIST_OF_FILES_TO_EDIT
file_modifier ...
however, the point here is some of those generated files which I'd like to edit ($LIST_OF_FILES_TO_EDIT) are used in the same make process to generate a long list of files. So I have to wait to make sure those files are no longer needed in the make process before I can go ahead and edit them. But I don't know how to do that. Not to mention that it is really hard to find out what files are generated by the help of $LIST_OF_FILES_TO_EDIT.
If it was possible to mention in the Makefile that this rule should be only run as the last rule, then my problem would be solved. but as far as I know this is not possible. So anyone has an idea?
Some points:
List of files to edit ($LIST_OF_FILES_TO_EDIT) is determined dynamically (not known before make process)
I am not sure I have picked a good title for this question. :)
1) If you're going to modify the files like that, it might behoove you to give the targets different names, like foo_unmodified and foo_modified, so that the Make's dependency handling will take care of this.
2) If your phony new rule is the one you invoke on the command line ("make phonyNewRule"), then Make will build whatever else it's going to build before executing the file_modifier command. If you want to build targets not on that list, you could do it this way:
(phony new rule): $(LIST_OF_FILES_TO_EDIT) $(OTHER_TARGETS)
file_modifier ...
3) If your dependencies are set up correctly, you can find out which targets depend on $(LIST_OF_FILES_TO_EDIT), but it's not very tidy. You could just touch one of the files, run make, see which targets it built, repeat for all files. You could save a little time by using Make arguments: "make -n -W foo1 -W foo2 -W foo3 ... -W foo99 all". This will print the commands Make would run-- I don't know of any way to get it to tell you which targets it would rebuild.

How do I use dependencies in a makefile without calling a target?

I'm using makefiles to convert an internal file format to an XML file which is sent to other colleagues. They would make changes to the XML file and send it back to us (Don't ask, this needs to be this way ;)). I'd like to use my makefile to update the internal files when this XML changes.
So I have these rules:
%.internal: $(DATAFILES)
# Read changes from XML if any
# Create internal representation here
%.xml: %.internal
# Convert to XML here
Now the XML could change because of the workflow described above. But since no data files have changed, make would tell me that file.internal is up-to-date. I would like to avoid making %.internal target phony and a circular dependency on %.xml obviously doesn't work.
Any other way I could force make to check for changes in the XML file and re-build %.internal?
You want to allow two different actions: making the xml file from the internal file, and making the internal file from the xml file. Since Make knows only the modification times, it knows which target is older but not whether it should be remade. So put in another file as a flag to record when either action was last taken, and make that your primary target; if either target is newer than the flag, it has been modified by something other than these actions, and make should rebuild the older target (and then touch the flag).
There are several ways to implement this. In some versions of Make (such as recent versions of GNUMake) you can write double-colon rules, so that Make will rebuild a target differently, based on which preq triggered it:
%.flag:: %.internal
# convert $*.internal to $*.xml
touch $#
%.flag:: %.xml
# rewrite $*.internal based on $*.xml
touch $#
A less elegant but more portable way is to look at $? and rebuild the other file:
%.flag: %.xml %.internal
ifeq ($?,$*.internal)
# convert $*.internal to $*.xml
else
# rewrite $*.internal based on $*.xml
endif
touch $#
I think you could do something like this:
all: .last-converted-xml .last-converted-internal
.last-converted-internal: *.internal
./internal-2-xml $?
touch $# .last-converted-xml
.last-converted-xml: *.xml
./xml-2-internal $?
touch $# .last-converted-internal
This runs "xml-convert" on any .xml files newer than an arbitrary marker file, ".last-converted". The $? should give you a list of all dependencies (*.xml) that are newer than the marker file.
Of course, the xml-convert program will have to be written to take a list of xml files and process each one.
I'm not sure from the question whether you actually need the .internal file, or if that was just an attempt to get the makefile working. So, either your "xml-convert" program can convert each .xml file in place, or it can also generate file.internal as well if you need it.
Use the -W option of make to have make think one of the data files has changed:
make -W somedatafile
This will cause make to think somedatafile has been modified without actually changing it's modification time.
Would it be possible to use different names for the XML file? The file you create from the internal format would have one name and the file your colleagues send you another? If they used different names there would be no circular dependency.

Resources