Makefile command substitution problem - linux

rebar doesn't automatically rebuild files when given a different configuration file. So, I've tried to do it on the Makefile level:
REBAR=./rebar
REBAR_DEBUG=$(REBAR) -C rebar.debug.config
REBAR_COMPILE=$(REBAR) get-deps compile
LAST_CONFIG:=$(cat config.tmp)
PLT=dialyzer/sqlite3.plt
all: config_normal compile
compile:
$(REBAR_COMPILE)
test:
$(REBAR_COMPILE) eunit
clean:
-rm -rf deps ebin priv doc/* .eunit c_src/*.o
docs:
$(REBAR_COMPILE) doc
static: config_debug
$(REBAR_DEBUG) get-deps compile
ifeq ($(wildcard $(PLT)),)
dialyzer --build_plt --apps kernel stdlib erts --output_plt $(PLT)
else
dialyzer --plt $(PLT) -r ebin
endif
cross_compile: config_cross
$(REBAR_COMPILE) -C rebar.cross_compile.config
valgrind: clean
$(REBAR_DEBUG) get-deps compile
valgrind --tool=memcheck --leak-check=yes --num-callers=20 ./test.sh
ifeq ($(LAST_CONFIG),normal)
config_normal:
echo "$(LAST_CONFIG) == normal"
else
config_normal: clean
echo "$(LAST_CONFIG) != normal"
rm -f config.tmp
echo "normal" > config.tmp
endif
ifeq ($(LAST_CONFIG),debug)
config_debug: ;
else
config_debug: clean
rm -f config.tmp
echo "debug" > config.tmp
endif
ifeq ($(LAST_CONFIG),cross)
config_cross: ;
else
config_cross: clean
rm -f config.tmp
echo "cross" > config.tmp
endif
.PHONY: all compile test clean docs static valgrind config_normal config_debug config_cross
The intention is hopefully obvious: when I use a target which needs a certain config file, check if the same file was used last time; run clean and record the configuration we are using now.
But it doesn't work, and the files get recompiled constantly:
aromanov#alexey-desktop:~/workspace/gmcontroller/lib/sqlite3$ make
rm -rf deps ebin priv doc/* .eunit c_src/*.o
echo " != normal"
!= normal
rm -f config.tmp
echo "normal" > config.tmp
./rebar get-deps compile
==> sqlite3 (get-deps)
==> sqlite3 (compile)
Compiled src/sqlite3_lib.erl
Compiled src/sqlite3.erl
Compiling c_src/sqlite3_drv.c
Despite config.tmp containing "normal":
aromanov#alexey-desktop:~/workspace/gmcontroller/lib/sqlite3$ LAST_CONFIG=$(cat config.tmp); echo $LAST_CONFIG
normal
What am I missing?

You're missing the part where you need to use shell in order to actually call external programs when defining a variable.
LAST_CONFIG:=$(shell cat config.tmp)

You can also use the shell assignment operator
LAST_CONFIG != cat config.tmp
§ How make Reads a Makefile
Example

Related

Linux make command is deleting a source file

I have inherited a project file that has a Makefile in it that is doing something I have never seen before--It is injecting a rm command. I cannot find any reason for the rm command, so I am missing something very obvious or very esoteric.
Thanks
The results of running make are:
bison --defines --xml --graph=calc.gv -o calc.c calc.y
Bison flags =
cc -c -o calc.o calc.c
Making BASE = calc
cc -o calc calc.o
Done making BASE
rm calc.c <======== WHERE IS THIS COMING FROM?
The Makefile is:
BASE = calc
BISON = bison
XSLTPROC = xsltproc
all: $(BASE)
%.c %.h %.xml %.gv: %.y
$(BISON) $(BISONFLAGS) --defines --xml --graph=$*.gv -o $*.c $<
#echo "Bison flags = " $(BISONFLAGS)
$(BASE): $(BASE).o
#echo "Making BASE = " $(BASE)
$(CC) $(CFLAGS) -o $# $^
#echo "Done making BASE"
run: $(BASE)
#echo "Type arithmetic expressions. Quit with ctrl-d."
./$<
html: $(BASE).html
%.html: %.xml
$(XSLTPROC) $(XSLTPROCFLAGS) -o $# $$($(BISON) --print-datadir)/xslt/xml2xhtml.xsl $<
CLEANFILES = $(BASE) *.o $(BASE).[ch] $(BASE).output $(BASE).xml $(BASE).html $(BASE).gv
clean:
#echo "Running clean" $(CLEANFILES)
rm -f $(CLEANFILES)
See https://www.gnu.org/software/make/manual/make.html#Chained-Rules:
The second difference is that if make does create b in order to update something else, it deletes b later on after it is no longer needed. Therefore, an intermediate file which did not exist before make also does not exist after make. make reports the deletion to you by printing a rm -f command showing which file it is deleting.

Running echo with flags in a Makefile under WSL

I am trying to run a Makefile from under WSL that contains the following lines:
debug: create_soft_links
#mkdir -p Debug64
#echo -e 'all: bld' > Debug64/Makefile
#echo >> Debug64/Makefile
#echo -e '%.o: ../../%.c' >> Debug64/Makefile
#echo -e '\tgcc -g $$(CFLAGS) $$(INCLUDE) $$< -o $$#' >> Debug64/Makefile
Problem is that the resulting Debug64/Makefile file looks like this:
-e all: bld
-e %.o: ../../%.c
-e gcc -O3 $(CFLAGS) $(INCLUDE) $< -o $#
A colleague just showed me on an actual Linux machine that the make command works correctly there, and the preceding -e flag is not printed in the generated Debug64/Makefile. What am I doing wrong?
Use instead of echo the printf(1) command. So your last line would be
#printf "\tgcc -g %s %s $$< -o $$#\n" $$(CFLAGS) $$(INCLUDE)
BTW, if you generate your build automation script, consider switching to ninja. You might use Guile or Python or GNU awk as such a generator.

Header in subfolder not found

my compiler does not found a header in a subfolder included in a cpp file
#include "comm\ComPublic.h"
My master makefile :
SUB_POUET=Pouet \
PouetTech \
PouetPrivate
all: $(SUB_POUET)
PouetTech:
#(cd PouetTech && $(MAKE))
Pouet:
#(cd Pouet && $(MAKE))
PouetPrivate:
#(cd PouetPrivate && $(MAKE))
.PHONY: clean mrproper $(SUB_POUET)
clean:
#(cd $(SUB_POUET) && $(MAKE) $#)
mrproper: clean
#(cd $(SUB_POUET) && $(MAKE) $#)
Sub-makefile1 :
include ../Definitions.mif
SRC=$(wildcard *.cpp)
OBJ_FILES=$(addprefix $(OBJECTS_DIR)/,$(notdir $(SRC:.cpp=.o)))
INCLUDES=-I../PouetTech -I../../libs/MPSSE -I../../libs/FTDI/$(OS) -I../shared -I../../libs/libmodbus-3.0.6/src
CXXFLAGS+=$(INCLUDES)
all: $(OBJ_FILES)
$(OBJECTS_DIR)/%o: %cpp | objects_dir
$(CXX) -o $# -c $< $(CXXFLAGS)
objects_dir:
mkdir -p $(OBJECTS_DIR)
.PHONY: clean mrproper
clean:
rm -rf *.o
Sub-makefile 2
include ../Definitions.mif
SRC=$(wildcard *.cpp)
OBJ_FILES=$(addprefix $(OBJECTS_DIR)/,$(notdir $(SRC:.cpp=.o)))
INCLUDES=-I../PouetTech -I../Pouet -I../shared
CXXFLAGS+=$(INCLUDES)
all: $(OBJ_FILES)
$(OBJECTS_DIR)/%o: %cpp | objects_dir
$(CXX) -o $# -c $< $(CXXFLAGS)
objects_dir:
mkdir -p $(OBJECTS_DIR)
.PHONY: clean mrproper
clean:
rm -rf *.o
Sub-makefile 3 is identical to 2.
And my folder are like this:
src
|_makefile
|_Pouet
| |_makefile
|_PouetTech
| |_makefile
|_PouetPrivate
| |_makefile
|_shared
|_comm
|_ComPublic.h
The problem appears during the 3rd makefile (PouetPrivate), but the folder "shared" is included in the makefile.
If I add -I../shared/comm to the makefile and change the include to #include "ComPublic.h" it works. But I dont want to include manually all folder in the makefile.
It's probable just a simple mistake, but I dont have much experience in makefile
Furthermore, its working fine when using mingw / msys under windows or Visual Studio
Edit : and I have the same issue with another subfolder of "comm"
If the include directive in your source is #include "comm\ComPublic.h" as you've written, the problem is simply that you're using the Windows path delimeter \. Linux (and g++) want / and won't recognise the path.
Fortunately, Visual C++ will accept both delimiters so / can be used throughtout.

Build on shell condition with Make

I would like to add to a build list the packages I want to build if it is not installed yet.
The goal is to install some Python packages without pip and from local sources. I don't have access to pip...
So I wrote I Makefile that looks like:
all: natsort foo bar foobar ...
natsort: natsort-4.0.4.tar.gz
tar xvzf $<
cd $(patsubst %.tar.gz,%, $<) && python setup.py install
rm -rf $(patsubst %.tar.gz,%, $<)
python -c 'import natsort'
echo -e "Installation of $< [done]\n" >> install.log
The problem with this implementation is that all the packages will be rebuild and reinstalled each time I run the Make command. I would like to check if the module is already installed. My idea is to do something like this:
ifdef $(shell python -c 'import natsort')
all: natsort
endif
How can I rewrite this to make it works?
You can absolutely do something like that. But it "costs" a shell invocation and an invocation of python every time you run make and that's a relatively high cost.
There are, basically, two ways to do what you want in a cheaper manner.
A stamp file and short-circuiting logic in the recipe.
The stamp file method is basically what you have except you add touch $# to the end of the recipe.
natsort: natsort-4.0.4.tar.gz
tar xvzf $<
cd $(patsubst %.tar.gz,%, $<) && python setup.py install
rm -rf $(patsubst %.tar.gz,%, $<)
python -c 'import natsort'
echo -e "Installation of $< [done]\n" >> install.log
touch $#
That way running the recipe the first time creates the stamp file and until natsort-4.0.4.tar.gz becomes newer than the stamp file or the stamp file gets deleted the recipe will never run again.
Note that second point though. Delete the stamp file and you install again.
That's the thing that the short-circuit logic solution solves.
Instead of your original rule of multiple commands you wrap it all in one command (this is optional but saves repeated checking costs) and check for the module to be installed before doing any work.
natsort: natsort-4.0.4.tar.gz
if ! python -c 'import natsort'; then \
tar xvzf $< || exit 1; \
cd $(patsubst %.tar.gz,%, $<) && python setup.py install || exit 1; \
rm -rf $(patsubst %.tar.gz,%, $<); \
python -c 'import natsort' || exit 1; \
echo -e "Installation of $< [done]\n" >> install.log; \
fi
Note the need to add || exit 1 since we no longer have make handling that for us. Also note that this now always runs the rule (and we should mark natsort and .PHONY) but in the most common case it will stop after the if test.
That all said you can combine these methods to get the best of both worlds.
natsort: natsort-4.0.4.tar.gz
if ! python -c 'import natsort'; then \
tar xvzf $< || exit 1; \
cd $(patsubst %.tar.gz,%, $<) && python setup.py install || exit 1; \
rm -rf $(patsubst %.tar.gz,%, $<); \
python -c 'import natsort' || exit 1; \
echo -e "Installation of $< [done]\n" >> install.log; \
fi
touch $#
and you get the benefits of both methods. The first time you run make the natsort file doesn't exist and the recipe is run. natsort isn't installed so the if test fails and the installation occurs. After that the natsort file it touched. The next time make is installed natsort is newer than natsort-4.0.4.tar.gz so make doesn't think it has anything to do. If, for some reason, you delete the natsort file then the next time make runs it checks for the module to exist, skips the installation and touches the natsort file again to get back into sync.

How can i call make file from other directory

I have directory structure like this
containers/con1
containers/con2
containers/con3
Now every folder like con1, con2 has Makefile in it with targets like build, run
I run it like make run and make build
But i have to go inside that folder.
Is it possible that i have another Makefile in containers/Makefile
and i can run like
Make con1.run Make con2.run
Yes, you can do that. Something like the following should do what you want.
$ cat containers/Makefile
%.run: %
$(MAKE) -C $#
That being said as you can see the command to do what you want is trivial enough to make such a makefile not really necessary (and a simple shell script is as useful here as a makefile).
$ cat run.sh
[ -d "$1" ] || { echo 'No such directory.' >&2; exit 1; }
#make -C "$1"
# OR
#cd "$1" && make
If you wanted to be able to build all the sub-directory projects at once then a makefile could help you with that but even that is a simple enough shell one-liner.
$ for mkfile in */Makefile; do make -C "$(dirname "$mkfile"); done
$ for mkfile in */Makefile; do (cd "$(dirname "$mkfile") && make); done
As far as I understand you want this:
-C dir, --directory=dir
Change to directory dir before reading the makefiles or doing anything else. If multiple -C options are specified, each is interpreted relative to the previous one: -C / -C etc is equivalent to -C /etc. This is typi‐
cally used with recursive invocations of make.
Add -C option like this: make -C con1/
Recursive makes are evil, but if you want that:
# con1.run is a phony target...
.PHONY: con1.run
con1.run:
$(MAKE) -C con1

Resources