makefile source file updates not propagating to target - makefile

i have this makefile:
jade = ./node_modules/.bin/jade
nlz = ./node_modules/.bin/nlz
build: build/index.js build/index.css build/index.html build/docs.html
build/index.js: $(find client/*.js)
$(nlz) build client/index.js
build/index.css: $(find client/*.css)
$(nlz) build client/index.css
build/index.html: pages/home.jade pages/layout.jade
$(jade) --path pages/home.jade < pages/home.jade > build/index.html
build/docs.html: pages/docs.jade pages/layout.jade
$(jade) --path pages/docs.jade < pages/docs.jade > build/docs.html
node_modules:
npm install
clean:
rm -rf build
.PHONY: clean
however, when i update one of the .js or .css files, typing make build gives me make: Nothing to be done forbuild'.`. what am i doing wrong?

There is no such make function as $(find ...).
Since it's not a known function, make considers it to be a strangely-named variable which has never been set and so has no value: thus, the build/index.css and build/index.js have no prerequisites. So as long as they exist, they're considered up to date.
Probably you wanted:
build/index.js: $(wildcard client/*.js)
$(nlz) build client/index.js
build/index.css: $(wildcard client/*.css)
$(nlz) build client/index.css

Related

Makefile not updating when dependency changed

all: ./data/for_analysis.csv ./data/tables/*.docx
./data/for_analysis.csv : ./src/convert-xls-to-gold-standard.py ./data/ED-TRAUMA-DELTA-STUDY_3_2019_total.xlsx
python3 $< --rawDataPath $(word 2,$^) --fieldCodesPath ./data/excel_field_codes.json --processedDataPath ./data/for_analysis.csv --logDir ./logs
./data/tables/%.docx : ./src/make-%.py ./data/for_analysis.csv
python3 $< --fieldCodesPath ./data/excel_field_codes.json --processedDataPath ./data/for_analysis.csv --logDir ./logs --tablesDir ./data/tables
When I update ./src/make-table-2.py, the second target isn't updated. This behavior doesn't depend on whether ./data/table/table-2.docx exists or not.
When I run make or make all even after updating the py file, I get the message make: Nothing to be done for 'all'.
It's not exactly clear from your question what the state of your targets is before you run make. But:
all: ./data/for_analysis.csv ./data/tables/*.docx
this can't really work, in general. This tells make, "go find all the files that exist with the filename matching the wildcard ./data/tables/*.docx". E.g., that's the same thing you'd get if you run ls ./data/tables/*.docx before you started make.
But of course, if you haven't built anything yet then there are no files matching that pattern, because that's what you're asking make to build. So this expands to nothing and make won't do anything with them.
You have to list the targets that you want to build explicitly, or else convert them from the source files you want them to be built from, so you can tell make what it should be building.
For example, maybe:
all: ./data/for_analysis.csv $(patsubst ./src/make-%.py,./data/tables/%.docx,$(wildcard ./src/make-*.py))

makefile ignore removed file names

A directory with css files in it and for each file in the directory I want a separate minified .min.css file in the same directory.
So for example my.css get minified into my.min.css in the same directory.
First I tried
css/*.css:
uglifycss $# > $(subst .css,.min.css,$#)
make -B yeaaa victorie its working :D
But after doing make -B again I get a new separate file each time resulting in my.min.css my.min.min.css my.min.min.min.css
Then I tried
.PHONY: clean
css/*.css: clean
uglifycss $# > $(subst .css,.min.css,$#)
clean:
-rm css/*.min.css
DOH! after clean it is still remembering the files it deleted in the first place resulting again in a my.min.min.min.css file
How can I tell make to stop doing my.min.min.min.css?
(make: GNU Make 3.81 OSX)
First get a list of all files with the suffix .css:
ALL := $(wildcard *.css)
then remove files that have the suffix .me.css:
NEW := $(filter-out %.me.css,$(ALL))
and add the suffix to remaining files:
ME := $(patsubst %.css,%.me.css,$(NEW))
Then you add those files as prerequisites to the default target, and add you own recipe that builds those files, in this case a simple echo:
%.me.css:
echo 123 > $#
default: $(ME)
Compared to your approach, this has the benefit that you don't have to use the flag -B, as only the files that need to be built are built. Therefore invoking make is done by simply caling make without any targets or flags (assuming the makefile is named makefile or Makefile):
make

How can I make a Makefile notice the existence of a new file?

I want to use a Makefile to write a file static/config.js in the following manner:
if js/config_local.js exists, copy it to static/config.js
otherwise, copy js/config.js (which always exists) to static/config.js
So far, I have something that looks like this:
# If there's a config_local.js file, use that, otherwise use config.js
ifneq ($(wildcard js/config_local.js),)
config_file = js/config_local.js
else
config_file = js/config.js
endif
static/config.js: js/config.js js/config_local.js
cp $(config_file) static/config.js
js/config_local.js:
clean:
rm -f static/*
This mostly works, except that if there is no js/config_local.js file and I run make, and then I create a js/config_local.js file and run make again, it thinks it doesn't need to do anything. I'm guessing that this is because of the empty js/config_local.js target in the Makefile, but if I remove that, then it can't build if the js/config_local.js file doesn't exist.
I also tried removing the empty js/config_local.js target and setting the dependencies of the static/config.js target to js/*.js, but that has the same problem of not noticing it needs to do something after I create the js/config_local.js file.
Make checks file times, not contents. A .PHONY will always force the operation. The downside is it always copies. Use the -p switch to preserve the file time.
.PHONY: static/config.js
static/config.js : $(firstword $(wildcard js/config_local.js js/config.js))
cp -p $< $#

Make: why do I get error saying "no such file or directory"

When I tried my makefile, I got error saying that No such file or directory, but my directory is right there, what do I do wrong? Thanks.
my project structure :
dev |--- ev
|--- display
|--- install ( makefile is here, try to call makefiles in ev and display folder)
My makefile :
MODULES :=ev display
SRC_DIR :=$(addprefix ../, $(MODULES))
BUILD_DIR:=$(addsuffix /build, $(SRC_DIR))
x:=../ev ------> add temporarily just for test,
------> the same error if x:=$(HOME)/dev/ev
INSTALL_DIR:=EX Frameworks Add-ons
INSTALL_DIR:=$(addprefix $(HOME)/EX/, $(INSTALL_DIR))
vpath %.cpp %.java $(SRC_DIR)
.PHONY: all clean
checkdirs: $(INSTALL_DIR)
$(INSTALL_DIR):
#echo "INSTALL DIR"
#mkdir -p $#
define make-goal
$1:
#echo "start building each part"
cd $# && make -f Makefile_new.osx clean
cd $# && make -f Makefile_new.osx package
endef
clean:
#echo "clean up"
#echo "BUILD_DIR IS $(BUILD_DIR)"
#rm -rf $(BUILD_DIR)
all:
#echo "start build subdirectory"
#echo "SRC_DIR IS $(SRC_DIR)"
#echo "x is $(x)"
$(call make-goal, $(x))) ----> when it comes to here, I got error message
The error messages:
x is ../ev
../x:
make: ../ev:: No such file or directory.
I guess it is about relative path, because I call this makefile from Install folder, then $(x) can't be found from Install folder, but when I tried to make a folder named ev (Install/ev), I still got the same error.
I think it must be something basic I missed here, but what it is.
Thanks.
Update:
I am trying to build a project which includes several sub-projects. the structure is:
dev |---- ev
|---- edf
|----- dt
|------af
|------Install
Inside of Install, I have a makefile, which is at the top level. The makefile in Install folder will call makefiles in other folders to build different subjects,
Ideally, I want to build every sub projects without touching sources. My sources include c++ and java code.
It's not clear what you're trying to do. Also due to some indentation hiccups I can't be sure, but you appear to be defining a variable make-goal that contains a template for a make rule, then using it with $(call ...) inside the recipe for the all target. That cannot work: you cannot create a make rule inside the recipe for another make rule!
The reason this fails is that the $(call ...) is expanding to content which is added to the recipe of the all target, so instead of creating a new make rule it's treating the result as a shell script. The first line is $1:, and you passed in ../ev, so make is trying to run the command ../ev: just as the error shows you.
If you describe what you want to do at a higher level we can give you some ideas on how to do it.
ETA:
If you just want your all target to also build a subdirectory, there's no need for all this complex GNU make advanced capabilities. That stuff is only needed when you get to guru-level makefile creation. Simple "build a target after another target is finished" is the exact thing make was designed to do: nothing special is needed to do that.
For example:
.PHONY: all $(SRC_DIR)
all: $(SRC_DIR)
$(SRC_DIR):
#echo "start building $#"
cd $# && $(MAKE) -f Makefile_new.osx clean
cd $# && $(MAKE) -f Makefile_new.osx package
This is still a pretty non-standard setup but I think it will work the way you want. Remember you'll have to either move the all target up to be the first one in the makefile, or you'll have to run make all explicitly: make only builds the first target in the makefile unless you give it specific targets on the command line.

(GNU make) installcheck a library

How do I implement the make installcheck target when building a library? That is, I have a check target that creates a test program that links to the created library, called by some script in order to check if the library code functions properly, and I wish to perform the same checks but linking to the library after it has been installed; how can I implement this?
Since I can't find any guides on this, I will present the method that I have come up with, which has been patched together from reading the GNU automake manual and some general trial and error. It might be ugly, but it works...
If the check routines for building a library involve linking the library to a test program and seeing if that program works correctly, then to installcheck the library we need only do the same thing but link the test program to the installed library rather than the locally built library.
Let's call the library alpha (so we'll be creating libalpha.so and/or libalpha.a). Supposing alpha's source code is in the file alpha.cpp in the src directory, we'll create src/Makefile.am as usual:
# src/Makefile.am
lib_LTLIBRARIES = libalpha.la
libalpha_la_SOURCES = alpha.cpp
include_HEADERS = alpha.h
The check routine involves creating a binary beta that links to alpha. The source code for beta is in the file beta.cpp in the directory tests. The automake file tests/Makefile.am looks like this:
# tests/Makefile.am
check_PROGRAMS = beta
beta_SOURCES = beta.cpp
beta_CPPFLAGS = -I$(top_srcdir)/src
beta_LDADD = $(top_builddir)/src/libalpha.la
We will create our check and installcheck routines by creating "local" targets in tests/Makefile.am like so:
# tests/Makefile.am
# ...
check-local:
# recipe to run when 'make check' is called.
installcheck-local:
# recipe to run when 'make installcheck' is called.
The check and installcheck targets conflict because use of either target prevents the other target from executing properly (one target "taints" the build tree for the other target); in order for the other target to execute properly we need to remove beta and its object files and have the target recompile and re-link as it sees fit according to its nature (installcheck to installed files, check to local files).
We can solve this issue of tainted build trees by simply running make clean in the recipe of both targets. This will clearly remove the tainted builds, but is overzealous because we don't need to rebuild whenever we run the same target again. The build tree is only tainted whenever we run the other target.
We can only solve this complication by remembering which of the two targets had been called previously, which we can do via the creation/destruction of an intermediary file (let's call it taint). The check target is tainted whenever the file taint exists, which it resolves by cleaning, rebuilding and removing taint; and the installcheck target is tainted when the file taint does not exist, which it resolves by cleaning, rebuilding and creating taint.
Our targets will take the form:
# tests/Makefile.am
# ...
check-local:
# First, check to see if the build tree is tainted and rebuild if so
test ! -f taint || $(MAKE) $(AM_MAKEFLAGS) check_rebuild
# Then, run our check tests. Substitute with your shell scripts or testsuite files as appropriate
./beta
installcheck-local:
# First, check to see if the build tree is tainted and rebuild if so
test -f taint || $(MAKE) $(AM_MAKEFLAGS) installcheck_rebuild
# Then, run our installcheck tests. Substitute with your shell scripts or testsuite files as appropriate
./beta
The target check_rebuild needs to rebuild according to how check will run, and will look like this:
# tests/Makefile.am
# ...
.PHONY: check_rebuild
check_rebuild:
$(MAKE) $(AM_MAKEFLAGS) clean # remove tainted build tree
$(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT) # rebuild beta
rm -f taint # mark build tree as untainted
The target installcheck_rebuild likewise looks like this:
# tests/Makefile.am
# ...
.PHONY: installcheck_rebuild
installcheck_rebuild:
$(MAKE) $(AM_MAKEFLAGS) clean # remove tainted build tree
$(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT) \
beta_CPPFLAGS="-I$(DESTDIR)$(includedir)" \
beta_LDADD="$(DESTDIR)$(libdir)/libalpha.la" \
beta_DEPENDENCIES="$(DESTDIR)$(libdir)/libalpha.la"
echo 1 > taint # mark build tree as untainted
Note that rebuilding beta in installcheck_rebuild now requires the overriding of the automake variables so that they point to the installed library.
Finally, we need to add the taint file to DISTCLEANFILES so that running distcheck does not fail with "files left in build directory after distclean" errors.
And that should be it. The final tests/Makefile.am should look like this:
# tests/Makefile.am
check_PROGRAMS = beta
beta_SOURCES = beta.cpp
beta_CPPFLAGS = -I$(top_srcdir)/src
beta_LDADD = $(top_builddir)/src/libalpha.la
taint_file = .taint
check-local:
test ! -f $(taint_file) || $(MAKE) $(AM_MAKEFLAGS) check_rebuild
./beta # substitute with your actual test routines
installcheck-local:
test -f $(taint_file) || $(MAKE) $(AM_MAKEFLAGS) installcheck_rebuild
./beta # substitute with your actual test routines
.PHONY: check_rebuild
check_rebuild:
$(MAKE) $(AM_MAKEFLAGS) clean
$(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT)
rm -f $(taint_file)
.PHONY: installcheck_rebuild
installcheck_rebuild:
$(MAKE) $(AM_MAKEFLAGS) clean
$(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT) \
beta_CPPFLAGS="-I$(DESTDIR)$(includedir)" \
beta_LDADD="$(DESTDIR)$(libdir)/libalpha.la" \
beta_DEPENDENCIES="$(DESTDIR)$(libdir)/libalpha.la"
echo 1 > $(taint_file)
DISTCLEANFILES = $(taint_file)
Disclaimer
This has been checked on Linux for a "standard" build, but it may not work on other build environments or if you are trying to do something "exotic". Hopefully it should, but it is not something that I have bothered to check. If there are errors, the problem will likely be a missing or misused variable in one of my targets above.
For example, the check_rebuild target has the line:
check_rebuild:
# ...
$(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT)
# ...
The variables $(AM_MAKEFLAGS) and $(EXEEXT) are a part of how automake itself creates routines to populate in the Makefiles it creates, and had I neglected them in my targets above, then it might have caused the build to fail (or at least not function as expected).
I have tried to make sure the targets that I have suggested above are likewise canonically constructed, but I may have missed something out. Your best bet in case of build errors is to open the Makefiles generated by automake itself during the build, seeing how it is creating objects and mimicking those constructs in the corresponding Makefile.am files, as I have tried to do.
The other likely issue may be in the "hackish" way I've built the beta binary in the installcheck_rebuild target. Again, your best bet in diagnosing problems will be to see how automake is doing things in the Makefiles it generates, and trying to mimic that. Otherwise, a read of the automake manual will be in order, and failing that, you will likely need the help of people more knowledgeable than me. Good luck.

Resources