Passing Variable to make from the command line? - makefile

All,
I'm trying to pass variables to make from the command line. My command is below
make ARCH=arm CROSS_COMPILE=/my_dir/bin/arm-openwrt-linux-g++
The error I received is
g++: error: arm: No such file or directory
But the file 'arm-openwrt-linux-g++' does exist.
I think the problem is I need to pass varibale to sub-make files. Can some help with an example of how to pass varialbes to sub-makefile from the command-line. I have tried using the -e and export options for make, but can't seen to get anything to work.
Thanks
Content of makefile:
# GNU Make solution makefile autogenerated by Premake
# Type "make help" for usage help
ifndef config
config=debug
endif
export config
PROJECTS := json openjaus
.PHONY: all clean help $(PROJECTS)
all: $(PROJECTS)
json:
#echo "==== Building json ($(config)) ===="
#${MAKE} --no-print-directory -C .build -f json.make
openjaus: json
#echo "==== Building openjaus ($(config)) ===="
#${MAKE} --no-print-directory -C .build -f openjaus.make

So, your problem is not related to sending variables over the command line.
Your problem is that in one of the makefiles in your sub-directories, which you haven't shown us, you're using the variable $(ARCH) in an incorrect way such that the expansion of the command line is not a legal g++ command line.
Based on the error message, most likely you're adding a space somewhere where it shouldn't be, so instead of something like -fmarch=arm you're getting -fmarch= arm. Obviously this is just an example because you didn't provide nearly enough information.
One other note: we can't know how your makefiles work but typically makefiles that support a variable like CROSS_COMPILE expect it to be set to just the prefix of the cross-compilation command; in your case it would be CROSS_COMPILE=/my_dir/bin/arm-openwrt-linux-. But, your makefiles might be different.
When asking questions, it's best to if you don't immediately jump to a guess about what the answer is. First describe the problem, and that includes showing the error line as well as a few lines before it. For example in this case you're getting an error from g++ so the command line that make printed out showing you how it invoked g++ would have helped greatly.
Once you've given the underlying detail, then if you think you have an idea about what the problem is go ahead and suggest it, and/or ask about it.
If you provide the rule that invokes g++ and/or the output from make showing the g++ command line, then we can help more.
Cheers!

Here's what I think needs to happen:
You need to make sure that your sub-makefiles actually respect the $(ARCH) and $(CROSS_COMPILE) variables. Are they also generated by Premake? If so, is that how it handles cross-compilation? Check the docs.
In my test (below), I found that variables set on the command line are propagated to sub-makes, which makes me think that your sub-makefiles aren't respecting $(ARCH):
Makefile:
a:
$(MAKE) -C z
z/Makefile:
a:
#echo "MAKE=$(MAKE)"
#echo "ARCH=$(ARCH)"
Running make with no arguments:
$ make
make -C z
make[1]: Entering directory `/home/foo/test/z'
MAKE=make
ARCH=
make[1]: Leaving directory `/home/foo/test/z'
Running make ARCH=bar:
$ make ARCH=bar
make -C z
make[1]: Entering directory `/home/foo/z/z'
MAKE=make
ARCH=bar
make[1]: Leaving directory `/home/foo/z/z'

Related

Search and Replace CFLAGS in a target

I need to add -Werror to the already existing (Exported?) CFLAGS for a build. Right now I am just trying to extract the data CFLAGS holds. I am super new to Make and Makefiles but have to add some pre-existing build files.
Say I have a target in a makefile like this
.PHONY: add_errors
add_errors:
#flags=$(CFLAGS);\
echo $$flags;\
But the issue is, CFLAGS is a really large string that has many options set.
When the makefile is executed I get the following error
/bin/sh: 1: -marm: not found
make[2]: *** [add_errors] Error 127
Which looks like something is taking the first space as the string and then discarding the rest of it.
Inside CFLAGS, a snippet of the text is
-march=armv5te -marm -mthumb-interwork -mtune=arm926ej-s --sysroot=/opt/dspg/v2.11-rc2/sysroots/cortexa9-neon-dspg-linux-gnueabi -Wno-psabi -ggdb -I/opt/dspg/v2.11-rc2/sysroots/cortexa9-neon-dspg-linux-gnueabi/usr/include/libxml2
What can I do?
You should ask a question which actually has some relation to what you really want to do, including relevant parts of the code. This example you gave is not useful for anything so the answer we give probably won't actually help you, but:
The first advice I have for you is NEVER use the # prefix on your recipes. Or at the very least never use them until AFTER your makefile is already working 100% correctly. Suppressing make's output like that is like trying to debug while blindfolded.
The problem is not related to make at all, really: it's just shell quoting rules.
If you remove the # and look at what make prints you'll see it's running this command:
flags=-march=armv5te -marm -mthumb-interwork -mtune=arm926ej-s ...; echo $flags;
If you cut and paste that to your shell, you'll get exactly the same error.
That's because the shell command foo=bar biz baz means, set the environment variable foo to the value bar then run the command biz with the argument baz.
You need to add quoting so that the shell puts all the arguments into the flags variable:
.PHONY: add_errors
add_errors:
#flags='$(CFLAGS)';\
echo $$flags;\
will cause make to run this:
flags='-march=armv5te -marm -mthumb-interwork -mtune=arm926ej-s ...'; echo $flags;

Is there a way to tell my makefile to output a custom error message if a certain an include file is not found?

I have a configure script that generates a config.inc file containing some variable definitions and a makefile that imports those configurations using
include config.inc
The thing that bothers me is that if the user tries to run the makefile directly without first running configure they get an unhelpful error message:
makefile:2: config.inc: No such file or directory
make: *** No rule to make target 'config.inc'. Stop.
Is there a way for me to produce a better error message, instructing the user to first run the configure script, without resorting to the autoconf strategy of generating the full makefile from inside configure?
Sure, no problem; just do something like this:
atarget:
echo here is a target
ifeq ($(wildcard config.inc),)
$(error Please run configure first!)
endif
another:
echo here is another target
include config.inc
final:
echo here is a final target
Note this is definitely specific to GNU make; there's no portable way to do this.
EDIT: the above example will work fine. If the file config.inc exists, then it will be included. If the file config.inc does not exist, then make will exit as it reads the makefile (as a result of the error function) and never get to the include line so there will be no obscure error about missing include files. That's what the original poster asked for.
EDIT2: Here's an example run:
$ cat Makefile
all:
#echo hello world
ifeq ($(wildcard config.inc),)
$(error Please run configure first!)
endif
include config.inc
$ touch config.inc
$ make
hello world
$ rm config.inc
$ make
Makefile:5: *** Please run configure first!. Stop.
I gave up and decided to use autoconf and automake to handle my makefile-generation needs.

Makefile not rebuilding dependencies

I'm new to using makefiles and trying to produce a basic makefile as part of an exercise for university. I have two source code files, chello.c and writeexit.s, which have to be compiled/assembled and then linked to produce chello.
This is the code I have so far for the makefile:
chello: chello.o writeexit.o
ld -N chello.o writeexit.o -o chello
chello.o: chello.c
gcc -c chello.c -o chello.o
writeexit.o: writeexit.s
as writeexit.s -o writeexit.o
The whitespace before ld, gcc and as are all tabs, so I think the whitespacing is fine. When I call 'make makefile', it returns 'make: Nothing to be done for `makefile'.' However, if I change the dependencies of chello, like chello.c, the same message is returned and chello's behaviour is not modified.
From man make:
make executes commands in the makefile to update one or more target
names, where name is typically a program. If no -f option is present,
make will look for the makefiles GNUmakefile, makefile, and Makefile,
in that order.
make makefile will actually execute your "makefile" (because it is listed among the default names in the man page) file, trying to build the "makefile" target (because of the argument you are passing), which already exists
What you need is to build the "chello" binary, so you have to type:
make chello
Or alternatively:
make -f makefile chello
Alternative account here, it seems to work fine if I just call "make" instead of "make makefile". This question can be ignored.

multiple makefiles in one directory

I have a makefile in a directory of mine which builds scripts with certain environment variables set. What if I want to create another makefile in the same directory with different environment variables set? How should I name the two make files? Does makefile.1 and makefile.2 work? How do I call them?
You can give sensible names to the files like makefile.win and makefile.nix and use them:
make -f makefile.win
make -f makefile.nix
or have a Makefile that contains:
win:
make -f makefile.win
nix:
make -f makefile.nix
and use make win or make nix
You can name makefile whatever you want. I usually name it like somename.mk. To use it later you need to tell make what makefile you want. Use -f option for this:
make -f somename.mk
Actually you can have two set of environment variables in the same make file. for example
COMPILER = gcc
CCFLAGS1 = -g
CCFLAGS2 = -Wall
a: main.c
${COMPILER} ${CCFLAGS1} main.c
b: test.c
${COMPILER} ${CCFLAGS2} test.c
then you can just say make a or make b. Depending on what you want.
Also it is possible with -f flag to call which makefile you want to call.
You can do something like this rather than using multiple makefiles for the same purpose. You can pass the environment or set a flag to the same makefile. For eg:
ifeq ($(ENV),ENV1)
ENV_VAR = THIS
else
ENV_VAR = THAT
endif
default : test
.PHONY : test
test:
#echo $(ENV_VAR)
Then you can simply run the make command with arguments
make ENV=ENV1
I have two makefiles in the same directory. Many of the recipes have identical names and here are two solutions:
1. Prefix in make
proja_hello:
#echo "hello A"
projb_hello:
#echo "hello N"
2. Keep two separate files
Project A has makefile. Type make hello.
Project B has a separate make file called projb.mk. Type bmake hello.
This works since I've added alias bmake ='make -f projb.mk to my .bashrc. Note! This command can be called anywhere but only works where projb.mk exists.
Note! You lose autocompletion of make with the alias and typing make -f projb.mk hello is not better than typing make projb_hello.

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