Duplicate inference rules - makefile

There are several inference rules in my makefile as follows:
%.ml: %.mll
$(OCAMLLEX) $*.mll
%.ml %.mli: %.mly
$(OCAMLYACC) $*.mly
%.cmo: %.ml %.cmi
$(OCAMLC) $(OCAMLFLAGS) -c $*.ml
%.cmx: %.ml %.cmi
$(OCAMLOPT) $(OCAMLFLAGS) -c $*.ml
%.cmi: %.mli
$(OCAMLC) $(OCAMLFLAGS) -c $*.mli
%.cmo: %.ml
$(OCAMLC) $(OCAMLFLAGS) -c $*.ml
%.cmx: %.ml
$(OCAMLOPT) $(OCAMLFLAGS) -c $*.ml
I am just wondering if there are duplicates over there. For example, there are two rules for %.cmx, which rule counts? Should .cmx depends on .cmi?

I'm not an expert in make, but as far as I understand, if make finds a rule with all prerequisite satisfied, it will use it. So your rule with cmi will not be taken at all.
As for ocaml part of the question, cmx, should depend on cmi if there exists an mli, if it doesn't then it is not a failure, and ocaml will not check the module interface. And it is not an easy task, to express this in make language.
I would suggest you either to use an existing Makefile solution, or use ocamlbuild, or even oasis. I actually have a strong opinion against reinventing the build system. First of all you're spending your precious time on a task, that is already solved. Second, your solution will stil lag behind the existing one, mostly due to the lack of testing and total effort. There are so many wrongly packed ocaml packages, and all of the use their custom and bugy build system. Don't reinvent a bicycle, just learn how to ride :)

Related

Missing dependency in Makefile

I have these recipes in my Makefile. They generate cross-compiled objects for ARM architecture and link them into an elf binary:
%.ao: %.c
$(ARM_CC) $(ARM_CPPFLAGS) $(ARM_FLAGS) $(CFLAGS) -c -o $# $<
%.elf: %.ao startup_stm32f0xx.ao system_stm32f0xx.ao
$(ARM_CC) $(ARM_FLAGS) $other_arguments -o $# $^
This works fine from a clean build.
Contrary to my expectation, if I then say touch foo.c; make foo.elf, gmake responds with
make: 'foo.elf' is up to date.
If I try to make foo.ao, gmake says that it, too , is up to date.
What am I missing?
Edit after reading the comments:
TLDR: I did have multiple rules matching the same target, as John Bollinger alluded and HardcoreHenry said specifically.
In addition to the rules above, there's a rule for assembly sources so I can use those vendor files:
%.ao: %.s
$(ARM_CC) $(ARM_CPPFLAGS) $(ARM_FLAGS) $(CFLAGS) -c -o $# $<
I had been debugging some macros, and used -save-temps to look at preprocessor output. This option also writes .s files. So after I'd run make foo.elf, I'd have the following in my directory:
foo.c
foo.i
foo.s
foo.ao
foo.elf
I can touch foo.c, but make sees that there's a foo.s which is older than foo.ao, and produces the output that it does. On a clean build, there is no foo.s, so make finds the %.c:%.ao rule and the build proceeds from foo.c.
(BTW, .ao stands for ARM object. In addition to cross-compiling for AMR, I compile many of the sources to run unit tests on the host, using the built-in .o:.c rule)
I'm not a fan of pattern rules.
Make can make very strange decisions on which rules apply depending on whatever is lying around on your hard disks.
It's all a bit arbitrary.
Much better IMHO to tell make exactly what files you need for a target.
It's pretty easy too.
Just prefix your pattern rule with the list of targets you actually want it to apply to.
This makes it a Static Pattern Rule.
objects := main.ao tools.ao devices.ao# etc
${objects}: %.ao: %.c
$(ARM_CC) $(ARM_CPPFLAGS) $(ARM_FLAGS) $(CFLAGS) -c -o $# $<
%.elf: ${objects} startup_stm32f0xx.ao system_stm32f0xx.ao
$(ARM_CC) $(ARM_FLAGS) $other_arguments -o $# $^
As an added bonus, make now won't try to create the pre-existing startup_stm32f0xx.ao and system_stm32f0xx.ao.
Usually I find it nicer to list the source files, but YMMV:
sources := main.c tools.c devices.c
objects := $(patsubst $.c,%.ao,${sources})
(P.S. Using a Static Pattern Rule doesn't really give you any advantage over a normal rule in this noddy case. I just wanted to show a small tweak that would make your makefiles much more consistent in their behaviour.)
I know it's bad form to use an answer to respond to another answer, but I ran out of space in a comment to #bobbogo's answer.
Sorry but I can't agree with your assessment of pattern rules. It's not true that you will get "strange decisions" based on "whatever is lying around on your harddisks", and it's certainly not arbitrary.
There is one advantage of static pattern rules over pattern rules, and that is also its downside: a static pattern rule is a shorthand for creating an explicit rule, so that rule will always be used to build that target. A pattern rule, on the other hand, is just one possible way to build a target: if the prerequisites of a pattern rule don't exist and can't be made, then make keeps going and looks for other pattern rules that might be able to build that target.
So if you have multiple possible ways you can build a target then an explicit rule cannot be used for that.
The problem with pattern rules is that if NO pattern rule applies then make just assumes there is no rule to build that target. If the target exists then make simply says "up to date" (as we see in the question) since there's no rule to build it. That can be confusing to users.
If you use an explicit rule (including a static pattern rule) and some prerequisite doesn't exist and can't be created, then make will exit with an error, which can make it easier to figure out what went wrong.

What is targets in a makefile implicit commands

Can any one tell me what is targets in the below make file with some implicit rules. I have searched in net alot, but haven't found anything helpful. It will be pleasure if anyone explains what is targets, construction commands, dependencies, and macros in a makefile.
COBJECTS = menu.o users.o resellers.o propspects.o
HFILES = menu.h
leads: $(COBJECTS)
gcc -o leads $(COBJECTS)
menu.o users.o resellers.o prospects.o: $(HFILES)
In this rule:
leads: $(COBJECTS)
gcc -o leads $(COBJECTS)
the target is leads, the prerequisites are $(COBJECTS), the command is gcc -o leads $(COBJECTS).
In this rule:
menu.o users.o resellers.o prospects.o: $(HFILES)
the targets are menu.o users.o resellers.o prospects.o and the prerequisite is $(HFILES). It has no commands.
The only really meaningful target defined in that makefile is leads. That also happens to be the default target so make and make leads will do the same thing.
There are other targets that exist as part of the rules necessary to build the leads target but those are all internal make defaults and not very interesting to run by hand.
Among the list of other possible targets (and among the more interesting out of the entirely uninteresting bunch) are:
menu.o
users.o
resellers.o
prospects.o

Library Linking

I am trying to learn to C programing using Zed Shaw's Learn C the hard way. I have been working on ex26 where we create a program "devpkg" used to install software. This exercise requires installing Apache Portable Runtime library. After writing the code for this exercise I could not get program to compile using the following makefile:
PREFIX?=/user/local
CFLAGS=-g -Wall -I${PREFIX}/apr/include/apr-1 -I{PREFIX}/apr/include/apr-util-1
LDFLAGS=-L${PREFIX}/apr/lib -lapr-1 -pthread -laprutil-1
all: devpkg
install: all
install -d${DESTDIR}/${PREFIX}/bin/
install devpkg ${DESTDIR}/${PREFIX}/bin/
clean:
rm -f *.o
rm -f devpkg
rm -f *.dSYM
This makefile did not seem to work as when I used "$make devpkg" not all of the APR library functions were declared. As a side note I am running this on a Ubuntu virtual machine. A solution given in the text says to alter a config file and then "run ldconfig" to help the linker find the appropriate library.
I do not understand the man page for ldconfig well enough to correctly utilize the function. How do run ldconfig correctly?
Also after some digging I found a reference that using "LDLIBS" instead of "LDFLAGS" in the makefile fixed the problem. I altered the makefile and the program compiled.
What is the difference between "LDFLAGS" and "LDLIBS" that allowed the C compiler to correctly link to the APR library? Is there a handy list of commands somewhere that can help me better understand how a makefile is correctly generated?
Thanks for your time.
From the GNU Make Manual, section 10.2 Catalogue of Implicit Rules:
Linking a single object file
n is made automatically from n.o by running the linker (usually called ld) via the C compiler. The precise recipe used is '$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)'.
As you can see, LDFLAGS comes before your object file and LDLIBS after. Sometimes that order can matter - apparently it does in your case.
Editorial note: While it might sometimes be convenient to use make's implicit rule support, it almost always ends up more confusing down the road. I'd urge you to write a complete makefile - it'll help you understand what's going on better and hopefully avoid this sort of problem in the future.
I just wanted to add this answer as an alternative to changing "LDFLAGS" to "LDLIBS". The above solution did work in my case but I found an alternative (though less direct) solution before I saw this thread which others may find useful or interesting. When compiling I was seeing lots of "undefined reference" errors e.g.:
/MyCode/LCTHW/devpkg/devpkg.c:18: undefined reference to `apr_pool_initialize'
After much trial and error, I changed the makefile thus (still using LDFLAGS):
CC=gcc
PREFIX?=/usr/local
CFLAGS=-g -Wall -I$(PREFIX)/apr/include/apr-1 -I$(PREFIX)/apr/include/apr-util-1
LDFLAGS=-L$(PREFIX)/apr/lib -lapr-1 -laprutil-1 -pthread
OBJECTS=bstrlib.o db.o shell.o commands.o devpkg.o
all: devpkg
devpkg: $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) -o devpkg $(LDFLAGS)
install: all
install -d $(DESTDIR)/$(PREFIX)/bin/
install devpkg $(DESTDIR)/$(PREFIX)/bin/
clean:
rm -f *.o
rm -f devpkg
rm -rf *.dSYM
I then had to add a .conf file to /etc/ld.so.conf.d containing the path to the apr libraries, namely
/usr/local/apr/lib
And then run
sudo ldconfig
so the system would pick up the new .conf file and so know where to find the library. From what I have read, it seems this last step was necessary because the library wasn't stored in /usr/local/lib. If I remove the .conf file and re-run ldconfig to update, the program compiles but then fails to find the libraries at run-time (whether compiled with my makefile or OP's).
While I don't fully understand my solution, it at least allowed me to compile and run the program with no errors. Hopefully this solution will be of interest to others, and maybe somebody more knowledgeable will be able to explain in more detail why it works.

Best practice to write reusable code

What is a best practice to writing reusable code in Makefiles?
Suppose I have a Makefile:
.PHONY: all task01-all task01-clean task01-run task02-all task02-clean task02-run
all: task01-all task02-all
###############################################################################
task01-all: task01-clean task01 task01-run
task01-clean:
rm task01 task01.{exi,o} -f
task01:
compiler task01.ext -O2 --make
task01-run:
./task01
###############################################################################
task02-all: task02-clean task02 task02-run
task02-clean:
rm task02 task02.{exi,o} -f
task02:
compiler task02.ext -O2 --make
task02-run:
./task02
Now I want to add new family of tasks (task03), and I need to copypaste whole section, make s/02/03/ for it and add them to .PHONY section - it's noisy, disgusting and just not right.
How can I avoid that? Could I redefine all tasks with templates somehow to have nice mechanism for adding new task group in one line?
Since the question is about writing re-usable code in Makefiles, I'll give an example of how to use pattern rules in GNU Make (it looks like that's what you're using since you mention the .PHONY target). However, if you're not using any of Make's dependency checking, it may be simpler to do this with a shell script--something like:
#!/bin/sh
TASKS="task01 task02 task03"
for i in $TASKS; do
rm $i $i.ext $i.o -f;
compiler $i.ext -O2 --make;
./$i;
done
But, to expand the principle to Make, we have another issue to tackle. Lines of the form:
task01-all: task01-clean task01 task01-run
don't tell Make in what order to build the pre-requisites--just that they all need to be done before task01-all gets built. Instead, each step to run should depend on the step before it. Something like this:
TASKS=task01-run task02-run task03-run
.PHONY: all $(TASKS) $(TASKS:run=clean)
all: $(TASKS)
$(TASKS:run=clean): %-clean:
rm $* $*.ext $*.o -f
%: %.ext | %-clean
compiler $< -O2 --make
$(TASKS): %-run: %
./$<
The rules with % are called "pattern rules", and they're a great tool to avoid re-writing the same rule multiple times for different targets. One caveat is that Make doesn't normally check pattern rules for a .PHONY target; we tell Make to do this explicitly by prefixing those rules with the list of targets and a second colon (e.g., $(TASKS):).
Since task01-run needs task01 in order to work, we make %-run targets depend on %. Also, your Makefile shows that you want to run clean every time, so we make % depend on %-clean. Since %-clean doesn't actually produce any output, we make this an "order only" dependency--Make won't look for a time-stamp or anything, it will just run the %-clean rule first any time it needs to run the % rule. "Order only" dependencies are placed after a |:
%: %.ext | %-clean
It's worth mentioning that one of Make's greatest strengths is that it can save time by not repeating work that doesn't need to be repeated--i.e., it only runs a rule if the dependencies are newer than the target. So, you could leave off the dependency on %-clean, which would cause make to only run compiler $< -O2 --make if %.ext is newer than %:
%: %.ext
compiler $< -O2 --make
You could then add a rule just to run all of the %-clean targets:
.PHONY: all $(TASKS) $(TASKS:run=clean) clean
clean: $(TASKS:run=clean)
Last thing: I use some special variables in the recipes. $# stands for the target being built. $< stands for the first dependency. $* stands for the "stem" of a pattern rule (i.e., the part matched by the %).
Looks like what I am looking for:
ALLS=task01-all task02-all
BUILDS=${ALLS:-all=-build}
CLEANS=${ALLS:-all=-clean}
RUNS=${ALLS:-all=-run}
.PHONY: all $(ALLS) $(CLEANS) $(BUILDS) $(RUNS)
all: $(ALLS)
###############################################################################
$(ALLS): $(CLEANS) $(BUILDS) $(RUNS)
$(CLEANS):
rm ${#:-clean=} ${#:-clean=}.{ext,o} -f
$(BUILDS):
compiler ${#:-build=}.ext -O2 --make
$(RUNS):
./${#:-run=}

Portable make clean rule

I am writing a smallish C program for fun. I decided to just use MinGW (only C), make and Notepad++ as an exercise in not using fancy IDEs for a change. So far so good and fun.
(MinGW == I am working on Windows.)
Now since the program compiles against vanilla C I thought of making it fully portable. MinGW make and gcc is smart enough create a program from the rule:
myprog: myprog.o other.o
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $#
Obviously, since I am on windows the compiler creates myprog.exe. This is quite smart and makes the entire thing quite portable.
As far as standard targets go I want to at least implement clean since I actually use that rule. Now the clean target, that actually works on Windows looks like this:
clean:
rm myprog.exe *.o
This rule will definitely not work in a POSIX environment, because programs don't have extensions there. (PSOIX: think GNU/Linux)
Is there a portable way implement a clean without to much make fu?
So far I have not found any really useful documentation around this issue. If you look at how autoconf and automake tackle the issue, they introduce the pattern #EXEEXT#. But that relies on lengthy configure code testing the environment.
Define the binary name as a variable (optionally deduce it from the name of the source file defining "main()" with a simple egrep command):
EXE_EXT_LINUX:=
EXE_EXT_WINDOWS:=exe
EXE_EXT:=$(EXE_EXT_$(PLATF))
BINARY_NAME:=$(notdir $(basename $(shell egrep -r -l --include=*.cpp '^[ \t]*?int[ \t]*?main[ \t]*?\(') ) )$(EXE_EXT)
And use this macro instead of hardcoded name
If solved it the following way:
UNAME = $(shell uname -o)
ifeq ($(UNAME), Msys)
EXEEXT = .exe
endif
clean:
rm *.o myprog$(EXEEXT)
It solved the issue quite nicely. Although it is not totally 100% portable it works most common cases.

Resources