I would like to create a Makefile with multiple ways to produce a file:
.PHONY: app bin tgt
app file: app-dependency ; touch file
bin file: bin-dependency ; touch file
tgt: file ; touch tgt
Such that I could run make tgt and depending on whether the file app-dependency or bin-dependency was present would decide which to targets to run.
When I write something like the above, I get the following warnings:
warning: overriding recipe for target 'file'
warning: ignoring old recipe for target 'file'
Your specification is not 100% complete so let's invent what's missing: if app-dependency exists, use app-rule else if bin-dependency exists, use bin-rule, else raise an error. If it is not what you want, please edit your question and try to add the missing bits of specification.
Make conditionals are a way to do what you want:
.PHONY: app bin tgt
ifeq ($(wildcard app-dependency),app-dependency)
app file: app-dependency
app-rule
else ifeq ($(wildcard bin-dependency),bin-dependency)
bin file: bin-dependency
bin-rule
else
app bin file:
$(error app-dependency and bin-dependency not found)
endif
tgt: file
tgt-rule
Since app, bin, and tgt are phony then the dependencies won't be used anyway, except to prevent a rule from building if it is missing.
There is no way for tgt to know which version of file to build. If file is created identically by both app and bin, then factor it out:
file: ; touch file
app: file ; ...
bin: file ; ...
tgt: file ; ...
If app and bin build different versions of file, then there is no need to make it a target. Tgt won't know which one to build anyway:
app: ; touch file
bin: ; touch file
tgt: file ; ...
If the intent is that tgt should build both app and bin if file is missing (it acts as an "or" dependency), you can factor it out:
app: ; touch file
bin: ; touch file
file: app bin
tgt: file ; ...
Related
I am trying to run build with some new changes in makefile where new folder needs to be created and place some files in that folder.
Here is my target placed in my make file:
tools_mvv32: $(RELEASE_FILES) ## Which has files pointing to TGTTEST32
define file_copy
mkdir -p $(#D)
cp -f $< $#
endef
TGTTEST32 := /home_test/workspace/copy/limited_projects/src/main/scp/build/Linux/project/primary/ktl
$(TGTTEST32)/tools/bin/%: $(TGTTEST32)/bin/%
$(file_copy)
When i try to run build by placing the target i.e. with specific file name with hardcoded as follows, It works fine
/home_test/workspace/copy/limited_projects/src/main/scp/build/Linux/project/primary/ktl/tools/bin/mpf: /home_test/workspace/copy/limited_projects/src/main/scp/build/Linux/project/primary/ktl/bin/mpf
$(file_copy)
May i know if any syntax is incorrect in my generic target ?
I am hitting below issue with my generic target:
gmake: *** No rule to make target /home_test/workspace/copy/limited_projects/src/main/scp/build/Linux/project/primary/ktl/tools/mpf
This seems slightly related to How to write Makefile where target and source files have the same extension?. In that question the extensions are the same, but the input and output files seem to be in the same directory and filenames are being conditionally renamed.
I have a large collection of .txt files in ../src/ that need to be processed, and dumped into ./ (which is a directory called target/) as txt files of the same name. I want to use make, so that only files in ../src/ that have been changed get updated in ./. I would like to get the prototype working before I put the real code in.
My Makefile in ./ is as follows:
DIR = ../src
INPUTS = $(wildcard $(DIR)/*.txt)
OUTPUTS = $(patsubst $(DIR)/%.txt,%.txt,$(INPUTS))
all: $(OUTPUTS)
.PHONY: $(INPUTS)
check:
#echo "DIR = $(DIR)"
#echo "INPUTS = $(INPUTS)"
#echo "OUTPUTS = $(OUTPUTS)"
%.txt: $(DIR)/%.txt
sed -e "s/test/cat/g" "$<" > $#
For now, the contents of ../src/ are test1.txt and test2.txt.
As the Makefile stands now, running make test2.txt generates the file as expected.
target/ $ make test2.txt
sed -e "s/test/cat/g" "../src/test2.txt" > test2.txt
Running make check shows the INPUTS and OUTPUTS correctly.
target/ $ make check
DIR = ../src
INPUTS = ../src/test1.txt ../src/test2.txt
OUTPUTS = test1.txt test2.txt
If I run make all, it generates every file, every time. This is expected with the .PHONY $(INPUTS) line in there.
If I remove the .PHONY $(INPUTS) target, Make gets all bound up in itself trying to find the target to make ../src/test1.txt and keeps prefixing $(DIR) in front of it until it makes too long of a filename and gives up.
make: stat: ../src/../src/../src/ [repeat for a few pages] ../src/../src/test1.txt: File name too long
make: stat: ../src/../src/../src/ [repeat for a few pages] ../src/../src/../src/test1.txt: File name too long
make: *** No rule to make target `../src/../src/../src/[repeat]../src/../src/test1.txt', needed by `../src/[repeat]../src/../src/test1.txt'. Stop.
It never does get to processing test2.txt.
As I was drafting this, I had the idea to remove the ../ from the DIR,
and relocate the Makefile so it was parent to both src/ and target/. That approach seems to work, but isn't ideal. Eventually there would be a chain of these Makefiles, each pulling from one directory to another.
Is there a way to keep the Makefile in 'target/' along with the generated destination files, and base those destination files off of something in a relative path?
Replace
%.txt: $(DIR)/%.txt
with:
${CURDIR}/%.txt: $(DIR)/%.txt
This way %.txt does not match any .txt file in any directory. In other words, you limit this rule's scope to files in ${CURDIR}/ only and this prevents that endless recursion.
See ยง10.5.4 How Patterns Match for more details.
It is also good practice to avoid relative paths:
DIR = $(abspath ../src)
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 $< $#
I'd like a set of makefile rules that create a symlink to one of several code modules before building the project. The name of the make target would determine the file to which the symlink points. For example:
The user invokes 'make R3000'
Make sees that 'data.asm' doesn't exist yet, so a symlink is created from 'data_R3000.asm' to 'data.asm'
The build process continues, using data.asm
How can I set up make rules to do this?
Maybe something like:
MODULES := $(patsubst data_%.asm,%,$(wildcard data_*.asm))
all:
...
data.asm:
[ -n "$(filter $(MAKECMDGOALS),$(MODULES))" ] || { echo unknown module: $(MAKECMDGOALS) ; exit 1; }
ln -s $(filter $(MAKECMDGOALS),$(MODULES)) $#
Then make sure data.asm is listed as a prerequisite in the appropriate rules.
I would do something like this:
.PHONY mklink
mklink:
test -e data_$(MAKECMDGOALS).asm || exit 1
ln -s data_$(MAKECMDGOALS).asm data.asm
and then make all (and other targets) dependent on mklink. The reason you shouldn't make data.asm your target in the rule is that if you run make R3000, then data.asm will be created, and then if you run make L2000, the data.asm file will be pointing to the wrong directory, and will not be overwritten (I'll assuming this is not what you want). The test line checks if the link target exists, and if not, it exits with 1, causing the target to fail. You should also add a check that MAKECMDGOALS is exactly one element as well.
I'm writing a Ruby C Extension. I will be compiling it under Windows and OSX.
What I have been unable to work out is control where the makefile and all the rest of the generated files are placed.
My extconf.rb file got conditional statements for preparing the makefile depending on the OS - so I use one for both of them.
I would like that when I compile under OSX it is all placed in an osx folder and similary under a win folder under Windows in order to keep it all separated.
As it is now all the files are generated in the same folder as my source code.
(I am very green to C and compiling applications. sorry if I have missed something obvious.)
I could write a batch to move the files afterwards, but I find it cleaner if it could be done during generation.
You could put a conditional in the makefile, before the rules. Something like:
OS := $(shell uname)
ifeq ($(OS),Darwin)
FOLDER := /some_path/osx_folder
else
FOLDER := /some_other_path/win_folder
endif
EDIT:
FOLDER is just a variable; it is to be used later in the makefile, like so:
$(FOLDER)/main: $(FOLDER)/main.o $(FOLDER)/foo.o
blah blah link $^ together to build $#
$(FOLDER)/%.o: $(SOURCE_DIRECTORY)/%.c
blah blah compile $< to build $#
(This is a crude example-- more elegant solutions are possible if you have a lot of files to deal with.)
I looked at the source of mkfm.rb and found that if you changed the current directory the Makefile was the current one.
Dir.chdir( OUTPUT_PATH )
create_makefile( EXTENSION_NAME, SOURCE_PATH )
That created the makefile in OUTPUT_PATH. As you see, I then had to provide SOURCE_PATH to create_makefile to account for the face the Makefile wasn't in the same location as the source files.