I've made a simple Makefile for an application and after install I need to restart udev rules.
INSTALLDIR=/pkt/bin
OS:=$(shell uname -v)
LBITS:=$(shell getconf LONG_BIT)
LIBDIR=/usr/lib
ifeq ($(LBITS),64)
LIBDIR64=/usr/lib64
else
LIBDIR64=/usr/lib
endif
all: usbupdater
configuracion.o: configuracion.cpp
g++ -c configuracion.cpp
main.o: main.cpp
g++ -c main.cpp
usbupdater: main.o configuracion.o
#echo "$(PATH)"
#echo "$(LIBDIR)"
g++ main.o configuracion.o $(LIBDIR)/libReadINI.a $(LIBDIR64)/chilkat/li
bchilkat-9.4.1.a -lpthread -lresolv -o usbupdater
clean:
rm -rf *.o *.cgh $(INSTALLDIR)/usbupdater
install:
mv usbupdater $(INSTALLDIR)/usbupdater
cp -rf 99-persistent-usb.rules /etc/udev/rules.d/99-persistent-usb.rules
postinstall:
#echo "$(OS)"
ifeq ($(findstring Debian,$(OS)),Debian) \
#echo "Estoy dentro del if"
$(shell '/etc/init.d/udev' restart) \
else \
#echo "Estoy dentro del else"
$(shell ls -l) \
endif
The problem is that when I type make postinstall is shows me this error:
#1 SMP Debian 3.2.46-1+deb7u1
ifeq (Debian,Debian) \
#echo "Estoy dentro del if"
/bin/sh: 1: Syntax error: word unexpected (expecting ")")
make: *** [postinstall] Error 2
I don't know where the problem is. I compare the result of uname -v with Debian to perform udev restart or udevcontrol reload_rules if it is an Opensuse OS.
Thanks in advance and sorry for my English.
ifeq is a make command. All lines in the makefile (in a recipe context) are passed to the shell. So make is passing ifeq to the shell and the shell is telling you that it has no idea what you're talking about.
You should write this using shell syntax, not make syntax.
Also it's rarely useful to use $(shell ...) functions inside a make recipe. The make recipe will be run by the shell, so when you use $(shell ...) you're just doubling the amount of shells that are running. Plus a command like $(shell ls -l) is not going to work, because $(shell ...) is like backtick and replaces the function with the stdout of the command. That'll be an error in this situation.
I would write it as:
postinstall:
#echo "$(OS)"
#case '$(OS)' in \
(*Debian*) \
echo "Estoy dentro del if"; \
/etc/init.d/udev restart ;; \
(*) \
echo "Estoy dentro del else"; \
ls -l ;; \
esac
You can't use make internal commands (like ifeq) within rule definition block. Use either shell's if or use ifeq outside of rule to generate some variables values, like
ifeq($(blah-blah), blah)
BUILD_CMD:=foo
endif
Also worth noting that else statement isn't exactly standard and may be missing in some versions of make.
Why do you want this, btw? I'd consider really bad practice if make install does something other then just installing (copying) files.
Related
I don't have a configure stage in my baseline (for various reasons), but I need to check whether my C compiler can support the -mavx2 flag or not.
If I have an empty file, call it test.cc then I can do something like:
$(CC) -mavx2 -c test.cc -o test.o
And check the return status code. Obviously I don't want to leave those test.* files lying around though, but can't think of a good way to generate/test/delete them outside of a recipe. Does anyone know of a good pattern to do this?
Or, you could just take input from stdin, and output to /dev/null:
SUPPORTS_MAVX2:=$(shell echo 'void main(){}' | \
gcc -x c -maxv3 -o /dev/null - 2>/dev/null; \
echo $$?)
Then there are no artifact files to be deleted. The -x c is necessary to tell gcc what language it is (as it can't determine that from the filename in this case), and you need the trailing - as well.
Turns out you can use "eval" to remove the temporary file and return the status code, so this works:
AVX2 = $(shell touch test.cc; $(CC) -mavx2 -c test.cc -o /dev/null >& /dev/null; eval "rm -f test.cc; echo $$?")
Edit and without the temporary file (assuming a sane system):
AVX2 = $(shell $(CC) -mavx2 -c /usr/include/stdlib.h -o /dev/null >& /dev/null; echo $?)
This question already has answers here:
What do #, - and + do as prefixes to recipe lines in Make?
(2 answers)
what is the use of parentheses in linux command [duplicate]
(2 answers)
Closed 3 years ago.
I see that in some recipes in Makefiles, the commands are prefixed with a “-“. For example:
Recipe A (the "-" in "-if")
-if test "X$(topdir)" != "X$(BUILD_DIR)" ; then \
$(RM) parser-built y.tab.c y.tab.h ; \
fi
Recipe B
( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $# )
( cd builtins && $(MAKE) $(MFLAGS) $# )
-( cd $(SDIR) && $(MAKE) $(MFLAGS) $# )
-for libdir in ${LIB_SUBDIRS}; do \
(cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $#) ;\
done
-( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $# )
$(RM) $(CREATED_SUPPORT)
Recipe C
-size $(Program)
Been trying to understand what they are, but can’t find anything in both bash shell and GNU make manuals. Does anyone know what they mean? Is it a feature of Bash or Make?
P.S.: Also, what do the brackets mean? eg. -( … )
The parentheses are a shell feature and execute the command in a subshell. This allows you to e.g. modify environment variables temporarily or run multiple commands in background.
Here, it is used to change the working directory temporarily (via cd) without affecting subsequent commands. In this case, this could also be achieved by passing -C to the make command. Calling make from make is called "recursive make" and is somewhat problematic (Google "recursive make considered harmful").
I've replaced my many .sh files from my previous question with a makefile, of sorts. I don't know much about makefiles, admittedly, but this seems to work:
MainPackage=jnitest
Main=SimpleJNITest
cFileName=rtm_simple
targetDir=classes
libDir=lib
srcDir=src
jdkDir="/home/user/local/java/jdk1.7.0_65"
java="$(jdkDir)/bin/java"
javah="$(jdkDir)/bin/javah"
javac="$(jdkDir)/bin/javac"
JAVAC_FLAGS=-d "$(targetDir)" -sourcepath "$(srcDir)" -cp "$(targetDir):$(libDir)/*"
JAVAH_FLAGS=-d "$(ccodeDir)" -cp "$(targetDir)" -jni
JAVA_FLAGS=-Djava.library.path="$(LD_LIBRARY_PATH):$(libDir)" -cp "$(targetDir):$(libDir)/*"
ccodeDir=$(srcDir)/ccode
CC=gcc
CC_FLAGS=-g -shared -fpic -I "$(jdkDir)/include" -I "$(jdkDir)/include/linux"
cFile="$(ccodeDir)/$(cFileName).c"
soFile="$(libDir)/lib$(cFileName).so"
dirs:
mkdir -p "$(targetDir)"
mkdir -p "$(libDir)"
java: dirs
$(javac) $(JAVAC_FLAGS) "$(srcDir)/$(MainPackage)/$(Main).java"
header:
$(javah) $(JAVAH_FLAGS) "$(MainPackage).$(Main)"
c:
$(CC) $(CC_FLAGS) $(cFile) -o $(soFile)
all:
$(MAKE) java
$(MAKE) header
$(MAKE) c
run:
$(java) $(JAVA_FLAGS) "$(MainPackage).$(Main)"
clean:
rm -rf classes
rm -rf lib
rm -f $(ccodeDir)/$(MainPackage)_$(Main).h
My problem, now, lies with MainPackage=jnitest.
So long as MainPackage is a single word, everything is fine.
However, when it is not, I'll be needing it once in slash notation for
$(javac) $(JAVAC_FLAGS) "$(srcDir)/$(MainPackage)/$(Main).java"
and once in dot notation for
$(java) $(JAVA_FLAGS) "$(MainPackage).$(Main)"
In bash, you could do something like
MainPackage_slashed=$(echo "$MainPackage" | tr '.' '/')
How do I insert one such transformation into a makefile?
You're looking for the subst function, see the GNU make manual.
Example:
foo=x.y.z
bar=$(subst .,/,$(foo))
$(info $(bar))
prints x/y/z.
You will need to use shell function in your Makefile like this:
MainPackage_slashed := $(shell echo "$(MainPackage)" | tr '.' '/')
I'm working on a Makefile with changeable sources and compiler.
Basically, what I want it to do is display a message in green if the compilation worked out well and in red otherwise. Additionally I want to avoid displaying the usual error messages (and compilation messages) a Makefile produces. (As I tried to do with all the '#')
Here's what I have for now :
COMP = gcc
NAME = test
RM = rm -f
SRC = main.c
OBJS = $(SRC:.c=.o)
CFLAGS = -Werror
all: $(NAME)
$(NAME):
#$(COMP) -c $(SRC)
#$(COMP) -o $(NAME) $(OBJS)
ifeq ($?, 0)
#echo -e '\033[1;32;40mCompilation : OK\033[0m'
else
#echo -e '\033[1;31;40mCompilation : ERROR\033[0m'
endif
clean:
#$(RM) $(OBJS)
fclean: clean
#$(RM) $(NAME)
re: fclean all
.PHONY: all clean fclean re
All it does is display "Compilation : ERROR" when it compiles well, but I thought that if $? equals 0 that meant it worked out, so I can't find any explanation.
Would you know how to make it do what I'm looking for?
Thanks a lot.
EDIT : Wonderful help from many of you, I'm still looking into the recipe but I've found a way to simply display when it succeeded and when it failed.
$(NAME): $(OBJS)
#$(COMP) $(OBJS) -o $(NAME) && echo -e "\033[32mCompilation: OK\033[0m" || echo -e "\033[31mCompilation: ERROR\033[0m"
I'll keep on digging, thanks.
$? is a shell variable not a make variable, you are testing a make variable with that if statement and the recipe for your target only ever has the one echo line in it.
(See the output from make -qp to see what I mean.)
To do what you want you would need a shell test on $? however realize that make will exit on the first failing command so you will never see the failure echo output this way (unless you capture/hide the failure from make with an if or similar construct on the compilation command).
Something like this will work for capturing/hiding the exit status from the compilation from make but allow you to use it.
#if $(COMP) -c $(SRC); then \
echo -e '\033[1;32;40mCompilation : OK\033[0m'; \
else \
_ret=$$?; \
echo -e '\033[1;31;40mCompilation : ERROR\033[0m'; \
exit $$_ret;\
fi
The bit with _ret is to have make exit with the exit code of the compilation and not a static exit 1 or whatever.
What you want is something like this:
$(NAME):
#$(COMP) -c $(SRC)
#$(COMP) -o $(NAME) $(OBJS); \
if [ $$? == 0 ]; then \
echo -e '\033[1;32;40mCompilation : OK\033[0m'; \
else \
echo -e '\033[1;31;40mCompilation : ERROR\033[0m'; \
fi; \
true
Notice that I used the '\' to concatinate the bash command with the if statement, so they all appear as a single recipe. I also added a true statement to the end such that no matter what the if statement returns, the concatenated recipe will return true, and make will not fail. You could also do:
$(NAME):
#$(COMP) -o $(NAME) $(OBJS) || echo ....
where the echo would only print if the previous command failed.
I have a Makefile building many C files with long long command lines and we've cleaned up the output by having rules such as:
.c${MT}.doj:
#echo "Compiling $<";\
$(COMPILER) $(COPTS) -c -o $# $<
Now this is great as the # suppresses the compilation line being emitted.
But when we get an error, all we get is the error message, no command line.
Can anyone think of a "neat" way to emit the command line?
All I can think of doing is echoing it to a file and have a higher level make catch the error and cat the file. Hacky I know.
Tested and it worked (GNU make in Linux):
.c${MT}.doj:
#echo "Compiling $<";\
$(COMPILER) $(COPTS) -c -o $# $< \
|| echo "Error in command: $(COMPILER) $(COPTS) -c -o $# $<" \
&& false
This question is pretty old, but for those of you Googling, I think what I’ll do in this situation is alias make to make -s (silent mode) in my shell, and only put the # prefix before lines where echo or other diagnostic commands are being invoked. When I want the full output from make, I will override my alias by calling it as \make.
Also note that in this situation that you’ll need to do the typical thing and put the #echo on its own line, with the actual rule commands on separate lines and without #’s.
A simple solution would be to use a simple script abc like the following:
#!/bin/bash
$#
code=$?
if (( code )); then
echo error running $#
fi
exit $code
Then you can write abc $(COMPILER) $(COPTS) -c -o $# $< in your Makefile. Do note that this does not work when you have pipes or redirects (as they will be applied to abc instead of the command you want to run).
You can also just put similar code directly in the Makefile if that's preferable.
I recently used a utility called logtext for the likes of tracking what output had occurred during the course of a bat file executing. Check it out, you may find this pretty useful if you want to know what error occurred where.