I'm trying to clone a repository from git and compile it locally. The relevant part of the Makefile is pasted below.
BUILDDIR = $(PWD)/build
# rest of the Makefile
...
all: release
release: $(BUILDDIR)/buildr/Makedir $(BUILDDIR)/depqbf
$(BUILDDIR)/buildr/Makedir:
mkdir -p $(BUILDDIR)/buildr
$(BUILDDIR)/depqbf:
cd $(BUILDDIR); rm -rf depqbf; git clone git#github.com:lonsing/depqbf.git
cd $(BUILDDIR)/depqbf;./compile.sh
The problem is if I use rm -rf depqbf, the compilation process happens everytime I run make.
If I remove it, and perform make again
fatal: destination path 'depqbf' already exists and is not an empty directory.
Is it possible to only clone and compile if the directory is not present.
the compilation process happens everytime I run make
The target of your recipe:
$(BUILDDIR)/depqbf/depqbf:
cd $(BUILDDIR); rm -rf depqbf; git clone git#github.com:lonsing/depqbf.git
cd $(BUILDDIR)/depqbf;./compile.sh
is the file $(BUILDDIR)/depqbf/depqbf. You are telling Make that, if the target $(BUILDDIR)/depqbf/depqbf
does not exist, then Make is to make the target by running the commands:
cd $(BUILDDIR); rm -rf depqbf; git clone git#github.com:lonsing/depqbf.git
cd $(BUILDDIR)/depqbf;./compile.sh
But those commands never create a file called $(BUILDDIR)/depqbf/depqbf. They
never make the target.
So every time Make considers the target it will decide that it has to made, by
running those commands.
If you remove rm -rf depqbf, then when Make attempts the target:
fatal: destination path 'depqbf' already exists and is not an empty directory.
Naturally, because you cannot clone into an existing non empty-directory. This is
not connected with the fact that the recipe is always being run. It is always being run
because it never makes its target.
Your other recipe:
$(BUILDDIR)/buildr/Makedir:
mkdir -p $(BUILDDIR)/buildr
likewise is one that that never makes it target. The command:
mkdir -p $(BUILDDIR)/buildr
will never create the file $(BUILDDIR)/buildr/Makedir. I do not see the purpose
of this recipe, so I'll assume it is just supposed to create the file
$(BUILDDIR)/buildr/Makedir if it does not exist, for some reason.
Then this makefile will attempt to make the targets if and only if they don't exist:
Makefile
BUILDDIR := $(PWD)/build
.PHONY: all release
all: release
release: $(BUILDDIR)/buildr/Makedir $(BUILDDIR)/depqbf
$(BUILDDIR)/buildr/Makedir: | $(BUILDDIR)/buildr
touch $#
$(BUILDDIR)/depqbf: | $(BUILDDIR)
cd $(dir $#); git clone git#github.com:lonsing/depqbf.git
cd $#; ./compile.sh
$(BUILDDIR) $(BUILDDIR)/buildr:
mkdir -p $#
Useful references in The GNU Make manual:-
An Introduction to Makefiles
Phony Targets
Types of Prerequisites
Automatic Variables
Related
I'm trying to run a makefile as though it is in another directory:
For example something like this but actually works:
cd ../../ && include ./somdir1/somdir2/make_example.mk
My makefile contains a target for node_modules directory, which depends on package.json file:
node_modules: package.json
npm install && touch "$#"
My current project happens to have a "sub-package" with its own set of dependencies. I modify the target above to the following:
%/node_modules: %/package.json
cd $(shell dirname "$<") && npm install && touch node_modules
Now, I can do make path/to/subpackage/node_modules and make runs the expected npm install command. However, I no longer seem to be able to do make node_modules - make exits with status code 0 and message Nothing to be done for 'node_modules'.
This indicates make will now only run the appropriate command for node_modules folders which exist within a subdirectory.
How can I change the target so that it supports both nested and root node_modules directories within the same target?
In other words, I would like to remove the duplicated target definition because the command to make the root's node_modules directory is the same as the command to make the nested path/to/node_modules directory.
As research, I tried to look at the GNU Make tutorial but could not find any relevant information - possibly because I simply do not know what to look for.
It isn't very elegant, but you could use a "canned recipe":
define MAKE_NODE_MODULES
npm install && touch node_modules
endef
node_modules: package.json
$(MAKE_NODE_MODULES)
%/node_modules: %/package.json
cd $* && $(MAKE_NODE_MODULES)
I've written a scons build chain form a little C project, but I'm afraid users won't like to be told "You should install SCons first. Besides, it's really cool!" (expecially my professor, as he's kind of from the old guard).
Is there a way I can set up a Makefile that will wrap scons, not requiring it to be installed on the target system?
After looking for such a solution some time ago, I ended up writing a Makefile for this purpose.
Because SCons also comes as a drop-in userspace package scons-local (see the download page), one can fetch in and run it. Here is a dissectioned and commented version of my Makefile, which I also uploaded as a gist.
all: get_scons
#$(SCONS_EXE)
↑ The default action depends on scons being available, and simply runs the scons command (set later in the script) (the # symbol prevents make from printing the command)
SCONS_VERSION=2.3.4
scons-local-%.tar.gz:
curl -L http://sourceforge.net/projects/scons/files/scons-local/$(SCONS_VERSION)/scons-local-$(SCONS_VERSION).tar.gz > scons-local-$(SCONS_VERSION).tar.gz
touch scons-local-$(SCONS_VERSION).tar.gz
scons-local: scons-local-$(SCONS_VERSION).tar.gz
mkdir -p scons-local
tar xzf scons-local-$(SCONS_VERSION).tar.gz --directory scons-local
touch scons-local
↑ Set up the rules for fetching the tarball and unpack it into the scons-local directory
NATIVE_SCONS=$(strip $(shell which scons 2>/dev/null))
ifeq ($(NATIVE_SCONS),)
SCONS_EXE=python2 ./scons-local/scons.py
get_scons: scons-local
#echo "Couldn't find an installation of SCons, using a local copy"
else
SCONS_EXE=$(NATIVE_SCONS)
get_scons:
#echo "Found SCons installation at $(SCONS_EXE)"
endif
↑ Look for the scons executable in the search path (using the which command): if it is available, set up the get-scons target to simply print it is available. If, instead, it is not available, create the get-scons target instructing it to depend on the scons-local target defined earlier.
clean:
$(SCONS_EXE) -c
rm -rf scons-local
rm -f scons-local-*.tar.gz
.PHONY: all clean get_scons
↑ Finally, set-up the clean target that delegates to scons and deletes the local installation afterwards. The .PHONY rule tells make that the following rules do not correspond to files being created.
At this point, one could add more proxy rules of the kind:
mytarget: get_scons
#$(SCONS_EXE) mytarget
Which will invoke scons with the corresponding target.
Hope this is useful, feel free to correct me in case there's something wrong (I'm actually not a Makefile expert, and I'm trying not to become one by using SCons instead :P )
Okay, I think I'm missing something in my makefile and it's causing me headaches. In my local build I call it with "dev:" and it does the dev target; Great, but I also want it to always do the "all:" target. When I call make dev it runs the dev but not the all, is there a terminology fail here?
here is my makefile
BUILD="build/"
STATIC="static/"
APP_NAME="Open World"
all:
# Remove the current build folder
rm -rf ${BUILD}
# Create the build directory
mkdir -p ${BUILD}
dev:
all
dev=${STATIC}dev
echo "Doing DEVELOPMENT build"
# Copy the package.json
cp ${dev}package.json ${BUILD}
prod:
echo "production"
The default (first) target is only run if no target is explicitly given. If you want it to run when another target is given then you need to make it a dependency of that target.
dev: all
I'm trying to debug a custom Makefile from an open source C++ project. It's not recognizing any targets I make in the "Make Target" view.
I've triple checked the spelling of my targets and they're fine.
If I turn on "Generate Makefiles automatically" it will successfully call the "all" and "clean" targets, but no other targets.
I assume you are using Eclipse/CDT.
Don't choose automatically generate Makefile.
Instead, right click on the makefile and select Make Targets/create. Use the target names from the makefile. The targets will appear in the "Make Targets" window (Window/Show View/MakeTarget). You can then build any of the targets using the hammer symbol in the make targets window.
Glad that solved your problem. By the way you don't have to have the make file in the same location as your source files. Here is an example where we use a make file in one directory that uses cd to run make files in other directories:
all: subsystems
subsystems:
#cd Efficiency && $(MAKE)
#cd List && $(MAKE)
#cd Map && $(MAKE)
#cd Set && $(MAKE)
#cd UsingSTLEfficiently && $(MAKE)
#cd VectorAndArray && $(MAKE)