variable in Makefile not recognized by make correctly - makefile

Here is the related rules for the variable:
LIBAD = libadard.a
install: $(CRSLIB)/$(LIBAD)
$(CRSLIB)/$(LIBAD): $(LIBAD)
$(LIBAD): $(OBJECTS1)
OBJECTS1 = $(LIBAD)(libadardV.o)\
$(LIBAD)(a_delbb.o) $(LIBAD)(a_getbkm.o)\
...
$(LIBAD)(a_getbkm.o): a_getbkm.p \
$(KINCDIR)/dbug.h \
$(PRIMINC)/systypes.h \
$(PRIMINC)/externs.h \
$(PRIMINC)/reserrs.h \
$(KINCDIR)/ltypes.h \
$(KINCDIR)/except.h \
$(PRIMINC)/u_pr_bkmsg.h \
$(CRSINC)/sqlerrs.h \
$(PDBINC)/systypes.th \
$(PRIMINC)/u_pr_bkmsg.th \
$(INFORMINC)/sqlca.h
if i run "make install", here's what i got:
make: *** No rule to make target `/sqlca.h', needed by `libadard.a(a_getbkm.o)'. Stop.
For testing purpose, i added this rule in the makefile just to check the value of this variable $(INFORMINC):
PHONY: all
all: ; #echo $(INFORMINC)
And the output is correct:
mtang#rv02 release>make all
/informix-rv02_1/incl/esql
i also checked under the directory "/informix-rv02_1/incl/esql", the file sqlca.h is there. So what went wrong?
UPDATE:
variable $(INFORMINC) is not defined in this makefile. It is defined in a Makerules file sitting at the root level, and that Makerules is included by this Makefile:
include ../../Makerules
UPDATE 2:
Problem solved. Thanks #Roland Illig for the clue. In Makerules, INFORMINC is defined as:
INFORMIXDIR := $(MY_INFORMIXDIR)
INFORMIX := $(INFORMIXDIR)
INFORMINC := $(INFORMIX)/incl/esql
I just copied that last line where INFORMINC is defined and paste it in the makefile. And it worked. I am not sure if i totally understand the reason behind this, but that certainly gives me some experience to deal with similar problems in the future.

In BSD Make (and I think in many other implementations, too), the dependency lines are evaluated eagerly, at the time of parsing. So when you define the INFORMINC variable at a later point, it will not influence the dependency rule.
The shell command in the all target is evaluated lazily, just before executing it. Therefore you see its value.
See also https://mail-index.netbsd.org/tech-pkg/2016/05/26/msg016900.html, where I explained this topic a litle more verbosely.

Related

How do I add a path that has a colon in a Makefile?

I have a simple Makefile that was included in the nRF52 sdk for one of the Bluetooth examples.
I want to make a copy of the file and move it, hence I need to update some parameters.
The part of the makefile I changed looks as such
SDK_ROOT := C:/Nordic_SDKS/nRF5SDK1702d674dde
It previously was the relative path using ../../../
When I run make I get the following output
make: *** No rule to make target `C\:/Nordic_SDKS/nRF5SDK1702d674dde/modules/nrfx/mdk/gcc_startup_nrf52.S', needed by `_build/nrf52832_xxaa/gcc_startup_nrf52.S.o'. Stop.
My Knowledge of Makefiles is very limited, but I presume the inserted "\" after the C directory is the reason the recipe is failing, since without that backslash that file exists.
Is there a way to stop this from happening, or am I wrong with what the problem is?
A couple of things:
Escaping in Windows/Batch File can be done with a carrot like C^:/Nordic instead of \ but I don't think it's your issue.
Change
SDK_ROOT := C:/Nordic_SDKS/nRF5SDK1702d674dde
to
SDK_ROOT := C:\Nordic_SDKS\nRF5SDK1702d674dde
Then of course verify the path/name combo truly exist with copy and paste to look for typos. In a command prompt
dir C:\Nordic_SDKS\nRF5SDK1702d674dde\modules\nrfx\mdk\gcc_startup_nrf52.S

How can i create a makefile for multiple targets, each having the same identifier in the output, as inputs?

i have a list of input*.in files, and for each of them i want to generate an output*.out file using make.
target1.out : input1.in
{external program} < input1.in > target1.out
I have 0 experience with gnu make, so would much appreciate help
How should i do it best using makefile?
Are you looking for this?
target%.out: input%.in
{external program} < $< >$#
Now make knows how to generate targetXX.out from inputXX.in. You still have to add an actual target, either on the command line (like make targetShirley.out assuming you have inputShirley.in) or in a separate recipe. A common arrangement is to have
sources := $(wildcard input*.in)
targets := $(patsubst input%.in,target%.out,$(sources))
.PHONY: all
all: $(targets)
(typically at the top of the Makefile) and then make all will produce all the files it can.
A common antipattern is to write a single recipe with a loop, like
everything:
for file in input*.in; do \
t=$${file%.in}; \
t=target$${t#input}.out; \
{external program} >"$$t"; \
done
(notice also how the shell's dollar signs have to be doubled to prevent make from attempting to interpret them). Besides being clumsy, this disables the single crucial reason to use make in the first place, namely to avoid creating files which are already up to date.

in makefile, what does a sole dash as the target of a rule mean?

I see a file .missing-syscalls.d which contains
-: /home/ckim/MVP/snake_linux_3.3.mvpe/include/linux/kconfig.h \
include/generated/autoconf.h \
/home/ckim/MVP/snake_linux_3.3.mvpe/arch/sparc/include/asm/types.h \
include/asm-generic/int-ll64.h \
/home/ckim/MVP/snake_linux_3.3.mvpe/arch/sparc/include/asm/bitsperlong.h \
include/asm-generic/bitsperlong.h \
/home/ckim/MVP/snake_linux_3.3.mvpe/arch/sparc/include/asm/unistd.h
I know .d file is only for showing dependancy. But what is '-' as the target?
Hyphen prior to commands in makefiles is used to suppress errors and continue instead of failing like this:
clean:
-rm -f *.o
The same way goes for include syntax in makefiles to suppress the error messages that would otherwise appear if the file isn't available like this:
-include $(SRC:%.c=%.d)
I would assume the .missing-syscalls.d file is used the same way, ignoring non-existing header files it attempts to include.
Either that's an error (from some automated process gone wrong) and that's a literal target of - which defines some extra prereqs (for a target that I can't imagine is ever likely to actually run).
Or that's an attempt to ensure that those files aren't considered as intermediate files by make in case some chain of rules would cause it to consider them as such.
See http://www.gnu.org/software/make/manual/make.html#Chained-Rules for reference.
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 use recursive make with an option telling it not to travel down the tree if needed?

I setup make to build my tree using recursive make. So the setup is
A/Makefile a.c
A/B/Makefile a.c
A/B/C/Makefile a.c
where if I issue the command make all from level A/ then make will travel down the tree building everything and then come back up. Each Makefile contains a list of folders below it to build. There is a common.inc file in the root which is read in each Makefile.
This is just a standard layout for recursive make, and nothing new. The details is gives in many places. here and here are examples.
My question is this: many times I'd like to do make all but only build things in the current folder, and not actually travel down the tree, may be because I want to test some changes in the current folder at this time. So I end up editing the current folder's Makefile by commenting out the SUBDIRS=A B C which lists all folders below, or by adding new special targets for this folder only. Both are annoying things to have to keep doing.
Does any one have an idea or a small example of a recursive makefile that uses a switch to tell it if it should travel down the tree or not when called? may be there is a way to call make and pass it some flag at the command line, and this flag is used to remove SUBDIRS=A B C ..... list so it only stops at the current folder level?
Just to be clear. I am using standard SUBDIRS in the Rules.mk, which each Makefile in the tree includes. Here is the part. I copied this from the net long time ago
$(SUBDIRS)::
#if test -d $#; then \
set $(EXIT_ON_ERROR); \
echo "cd $#; make $#"; \
cd $#; make $#; \
set +e; \
else \
echo "Skipping non-directory $#..."; \
fi \
$(CLICK_STOPWATCH);
endif
and in each folder Makefile I write
SUBDIRS = A B C
include Rules.mk
all:: .......
Then I just write make all to build. If there is a way to do make all LOOP=0 where LOOP is some value I pass it or an option or a string or something and then change the above SUBDIRS logic to check for the value of this LOOP and based on the value then do the recursive make or not, then the problem is solved. The default can be to LOOP=1 if it is missing from the command line.
But I do not know enough Make to program this type of logic.
You should use power of rules' depencies. Add your sources files to the dependencies of the rule called from the "root Makefile". If these files are up to date, the recursivity in an folder will stop because the rule is 'up-to-date', and nothing will be done.
Don't add .PHONY for all your rules in the sub-directory Makefile, otherwise recursives rules will be called.
Play with the dependencies of the rules can be the key to not make recursive call, but if you modify sources in each folder and want to build only from the root Makfile, you have to create another rules. With make all, the make binary may not know if you want build all your projet or not (if all your sources has been modified).
EDIT: choice by the command line
You're near the answer, you can set env var while calling your make all and test the value to decide calling recursivly or not.
CC=g++
SUBDIR=a b
all: ${SUBDIR} main.cc
${CC} main.cc
${SUBDIR}:
ifneq ($(MK_LOOP), 0)
#echo "trust the recursivity !"
${MAKE} -C $#
endif
.PHONY: ${SUBDIR}
If you don't set the MK_LOOP var or you set to something else than 0, it will not be equal to 0 so recursive Makefile will be call; if you set to 0, $(SUBDIR) rule do nothing
42SH $ MK_LOOP=0 make # no recur
42SH $ make all
trust the recursivity !
42SH $ make all MK_LOOP=1 # recur by default; same as : make all
trust the recursivity !
42SH $

Error when running: make clean

I am trying to build some simulation software using makefile provided by them after I have made some changes to the libraries. But when I run make clean, it stops midway and I get the following error
rm: invalid option -- 'l'
Try `rm --help' for more information.
make: *** [neat] Error 1
I checked the man page for rm and there is no -l option, but I don't know why this command is being executed with -l option. Is there anyway to ignore this, or find out which specific file is causing the problem?
EDIT:
I have figured out the source of the error, but dont know how to edit it to make it work properly. Below is a snippet from an included Makefile with the faulty line:
UDP_INTERFACE_SRCS = \
$(UDP_INTERFACE_DIR)/interfaceudp_app.cpp \
$(UDP_INTERFACE_DIR)/interfaceudp.cpp \
$(UDP_INTERFACE_DIR)/external_interface_udp.cpp \
$(UDP_INTERFACE_DIR)/packet_send.cpp \
$(UDP_INTERFACE_DIR)/addr.cpp \
$(UDP_INTERFACE_DIR)/packet_capture.cpp -lpcap \
$(UDP_INTERFACE_DIR)/queue.cpp
In particular, the line: $(UDP_INTERFACE_DIR)/packet_capture.cpp -lpcap \
is causing the error. What does the "-lpcap" added after "packet_capture.cpp" do? Now if I try to remove it, "make" gives an error saying:
./interfaces/extinterface/src/packet_capture.o: In function pcap_sniff_packets(void*)': /home/qualnet/4.5/main/../interfaces/extinterface/src/packet_capture.cpp:63: undefined reference to pcap_setdirection' make: *** [../bin/qualnet] Error 1
I checked the line number 63 in packet_capture.cpp in an effort to understand what -lpcap means. But I have no idea what that code does.
(This is clearly an iterative process, and the comments are getting long, so I'd better start an answer.)
You say: "When I put echo SIM_JOBS: $(SIM_OBJS) in the rule, i get the following when i run make clean: rm -f ../bin/qualnet ../bin/radio_range"
This doesn't make sense. You should get something like
SIM_JOBS: ../bin/qualnet ../bin/radio_range
rm -f ../bin/qualnet ../bin/radio_range
or
SIM_JOBS: something/else
rm -f ../bin/qualnet ../bin/radio_range
or at least
SIM_JOBS:
rm -f ../bin/qualnet ../bin/radio_range
This suggests that you are looking at the wrong rule: the rule which produces rm -f ../bin/qualnet ../bin/radio_range is not the rule in which you put the echo ... command. If it is the rule and you were just being imprecise in the report, put this right above the clean rule:
SIM_JOBS=../bin/qualnet ../bin/radio_range
and tell us what happens.
EDIT:
Sorry, I wrote `SIM_JOBS` when I meant `SIM_OBJS`.
The `echo` command was outside the rule, where it cannot work.
It looks as if the problem. Could you edit your question to show the line you mentioned to #thiton, and a few previous lines? It looks as if the flag "-lpcap" is getting into a variable, where it doesn't belong.
EDIT:
The "-lpcap" is a kludge. My guess is that it's an option intended for the linker. Suppose you want to link a bunch of object files into an executable, and you want to search a certain library called "pcap":
gcc foo.o -lpcap bar.o baz.o
The order is very important; when the linker is searching for something, you want it to search foo.o first, then pcap, then bar, then baz. It's a question of precedence. But you want to store those filenames in a nice tidy variable, and how will you insert the lpcap at the right place? You could do it a good way, or use a lazy hack like this:
OBJECTS = foo.o -lpcap bar.o baz.o
gcc $(OBJECTS)
And if you're deducing the OBJECTS from the SOURCES, you have to put the hack in earlier:
SOURCES = foo.cc -lpcap bar.cc baz.cc
OBJECTS = $(SOURCES:.cc=.o)
Whoever wrote these makefiles saved half an hour with this kludge, and it's taking you days to fix it. If you can confirm that this is what's happening, the easiest way is probably to split the list in two:
SOURCES_LEFT = foo.cc
SOURCES_RIGHT = bar.cc baz.cc
OBJECTS_LEFT = $(SOURCES_LEFT:.cc=.o)
OBJECTS_RIGHT = $(SOURCES_RIGHT:.cc=.o)
gcc $(OBJECTS_LEFT) -lcap $(OBJECTS_RIGHT)
Like #AndrejPanjkov noted in the comments, the standard tool to find out what exactly is going on in Makefiles is the -n (--dry-run) switch of make. It prints all commands as they would be run by the shell, even those normally silenced (e.g. via #).
Have a long, hard look in this output for any pattern like ' -l' (piping the output to less and using / helps). If that doesn't help, try running all commands output by -n by hand in make's shell (normally /bin/sh) or try removing all the silencers (# characters at a rule's start) from the Makefile and running make clean, checking the last line of output.

Resources