OpenCobol Makefile - makefile

I am trying to compile an OpenCobol program using make. I am always getting "make: Nothing to be done for test1.cob". Here is my makefile. I had put a TAB before cobc. But still I am getting that message. Please help.
Thanks.
COBCWARN = -W
%: %.cob
cobc $(COBCWARN) -free -x $^ -o $#
And here is my cobol program.
IDENTIFICATION DIVISION.
PROGRAM-ID. TEST1.
PROCEDURE DIVISION.
DISPLAY 'Hello world!'.
STOP RUN.

Your makefile contains no actual targets. You have defined only a pattern rule which tells make how to build targets that match the pattern. But make doesn't go looking for targets out on the filesystem that could match the pattern, it only checks the pattern against targets that have been specifically requested.
You don't have any specific targets (files) listed in your makefile, so the only way make can know about a target is if you give the target to be built on the command line.
You are running this command from within vim, using the % special token, which expands to the name of the file currently being edited. That means you are running the command:
make test1.cob
because you are editing the file test1.cob. So, you are telling make "please try to create the target (file) test1.cob". But, that file already exists (it's the file you're writing). So make says "nothing to do".
If you run make and ask it to create the target you really want created, it will work:
make test1
Now the file test1 doesn't exist, and make can find a pattern rule that knows how to build it, so make will run that rule.
Alternatively, you can edit your makefile to add the specific target, like this:
COBCWARN = -W
test1: test1.cob
%: %.cob
cobc $(COBCWARN) -free -x $^ -o $#
Then you can run make with no arguments at all. Without any command line arguments, make will look in the makefile for explicit targets and find test1 as the first one. It sees that there is a rule (the pattern rule) that matches that target, so it will build that target.
UPDATE
If you want to allow a simple command make to build multiple programs, write your makefile like this:
COBCWARN = -W
all: test1 test2 test3
.PHONY: all
%: %.cob
cobc $(COBCWARN) -free -x $^ -o $#
Now from vim you can just say :!make and that's it.
If you run make with no arguments then it will find the first explicit target in the makefile and build that. In this example the first target is all, and its prerequisites are the possible programs to build. To build each one make sees that it can apply the pattern rule, and so it will do so (if the .cob file has been modified since the last time the program was built).

Related

Global prerequisite in GNU make - is it possible

I have a Makefile with tons of targets and would like for a certain script to get executed first, irrespective of what target is being called. I like to call it a global prerequisite.
I do not want to create a target for the script and set it as a prerequisite for all existing targets (which, as I said aren't few). Besides, someone else could add a target in future and not add my script as a prerequisite for their target, so the global prerequisite would take care of that.
Does GNU-make provide for a means to achieve this?
Another approach:
-include dummy
.PHONY: dummy
dummy:
run-the-script
Make will always attempt to rebuild any file which the makefile attempts to include (if it is out of date or does not exist). In this case there is no such file, and the rule to build it runs the script and does nothing else.
There is a solution without modifying your existing Makefile (main difference with the answers pointed to by tripleee). Just create a makefile containing:
.PHONY: all
all:
pre-script
#$(MAKE) -f Makefile --no-print-directory $(MAKECMDGOALS) MAKE='$(MAKE) -f Makefile'
post-script
$(MAKECMDGOALS): all ;
The only drawback is that the pre- and post- scripts will always be run, even if there is nothing else to do. But they will not be run if you invoke make with one of the --dry-run options (other difference with the answers pointed to by tripleee).

makefile: from 3 input generate one output

I have this version of makefile
[sbsuser#compute-00-01 415]$ make --version GNU Make 3.81
I have directory SOMATIC where I have 3 file . I want to produce a only one output. This is what I wrote.
`
OUTSOMATIC=SOMATIC
FINAL=FINAL
INPUT=$(wildcard $(OUTSOMATIC)/*.vcf)
OUTSORT2= $(patsubst $(OUTSOMATIC)/%.vcf,$(FINAL)/%somatic.ensemble.gz,$(INPUT))
$(info lista $(OUTSORT2))
$(info lista $(INPUT))
.PHONY: all
all: $(INPUT) $(OUTSOMATIC) $(OUTSORT2) $(FINAL)
$(FINAL)/%somatic.ensemble.gz: $(OUTSOMATIC)/%.vcf $(INPUT)
~/jdk1.8.0_121/bin/java -XX:+UseSerialGC -Xms1g -Xmx10g -jar /illumina/software/PROG2/bcbio-variation-recall-0.1.7 ensemble -n 1 $(FINAL)/somatic_ensemble.gz /illumina/software/database/database_2016/hg19_primary.fa $^
`
With this script make 3 time the same files. I don't understand how to create only one output from list of input to use in the same time.
What is the best way to do this?
If I change $(FINAL)/%somatic.ensemble.gz: in $(FINAL)/somatic.ensemble.gz I have this error:
make: *** No rule to make target FINAL/415_merge_mutect2.somaticsomatic.ensemble.gz', needed byall'. Stop`
You probably should review the GNU make manual introductory sections where they describe how make works.
Let's look at your makefile; first you define some variables. Let's assume that you have the files SOMATIC/foo.vcf, SOMATIC/bar.vcf, and SOMATIC/baz.vcf. Then the variables you created will have these values, after they are expanded:
OUTSOMATIC = SOMATIC
FINAL = FINAL
INPUT = SOMATIC/foo.vcf SOMATIC/bar.vcf SOMATIC/baz.vcf
Now your patsubst finds all words in INPUT that match the pattern SOMATIC/%.vcf and replace that with FINAL/%somatic.ensemble.gz, where the part that matches the % in the input is substituted into the output:
OUTSORT2 = FINAL/foosomatic.ensemble.gz FINAL/barsomatic.ensemble.gz FINAL/bazsomatic.ensemble.gz
Now, make sees that you've defined an all target. Since it's the first target in the makefile this is the target that will be run by default. After expansion, it will look like this:
all: SOMATIC/foo.vcf SOMATIC/bar.vcf SOMATIC/baz.vcf SOMATIC FINAL/foosomatic.ensemble.gz FINAL/barsomatic.ensemble.gz FINAL/bazsomatic.ensemble.gz FINAL
So, make will try to build every prerequisite of the all target to be sure it's up to date. First it tries to build the SOMATIC/*.vcf files. Those files already exist and make doesn't have any rules about how to rebuild them, so it assumes they're up to date.
Next it tries to build the SOMATIC file. This is a directory and it also has no rule to be built, so make assumes that's up to date as well.
Next make tries to build the target FINAL/foosomatic.ensemble.gz. Make does have a rule that can build it, you've created one:
$(FINAL)/%somatic.ensemble.gz: $(OUTSOMATIC)/%.vcf $(INPUT)
~/jdk1.8.0_121/bin/java ...
This matches the target you want to build, with a % value of foo, so then make substitutes the % in the prerequisite for foo and finds that SOMATIC/foo.vcf exists and doesn't need to be rebuilt, so it runs your recipe. However your recipe doesn't actually create the target FINAL/foosomatic.ensemble.gz; it creates the target FINAL/somatic_ensemble.gz. So this rule is broken because it tells make it will do one thing, but it does something else.
You should always ensure all your recipes build the file represented by the automatic variable $#; that will ensure that you and make agree on the meaning of your rule. If you want your recipe to build some other file, then your rule is written incorrectly.
Next make does the same thing with the next prerequisite of all: FINAL/barsomatic.ensemble.gz. Since that file doesn't exist, make tries to build it using the pattern rule, but again that creates the same output file.
And again for the third .gz file FINAL/bazsomatic.ensemble.gz. That's why things are run three times.
If you change the pattern rule to an explicit rule building FINAL/somatic.ensemble.gz, which is what you want, then make can't find any way to build the prerequisites of the all target so it gives this error.
Your problem is the creation of OUTSORT2. You want to create only one output file, but you've set OUTSORT2 to contain three different files, so make tries to create all three files. You want this:
OUTSOMATIC = SOMATIC
FINAL = FINAL
INPUT = $(wildcard $(OUTSOMATIC)/*.vcf)
OUTSORT2 = $(FINAL)/somatic.ensemble.gz
.PHONY: all
all: $(OUTSORT2)
$(OUTSORT2): $(INPUT)
~/jdk1.8.0_121/bin/java -XX:+UseSerialGC -Xms1g -Xmx10g -jar /illumina/software/PROG2/bcbio-variation-recall-0.1.7 ensemble -n 1 $# /illumina/software/database/database_2016/hg19_primary.fa $^

Makefile call itself with identical command line input except prepended string

I have a complex, legacy Makefile which I need to run inside of a Docker container. Essentially, I need the Makefile to call itself again, except I need to prepend "docker run ...".
The end user may make multiple targets, and multiple command line variables and options may also be specified, so I need to duplicate the entire command-line call to make - not just recall each target.
I'm expecting something of the form:
<BLACK_MAGIC>:
docker run my_image make <COMPLETE_ORIGINAL_MAKE_COMMAND_LINE>
Suggestions?
Thanks!
Rename the makefile to something else and use the following as a stub
FLAGS := $(if $(MAKEFLAGS),-$(MAKEFLAGS))
.SUFFIXES:
.PHONY: all
%:: all ;
all:
docker run my_image $(MAKE) -f Makefile.old $(FLAGS) $(MAKEOVERRIDES) $(MAKECMDGOALS)
Make removes certain flags from MAKEFLAGS in recipes so they need to be copied in the main body
.SUFFIXES: clears the suffix list in case make tries to apply one of its implicit rules
Make all a .PHONY target just in case the folder contains a file named all
Make other targets depend on all with %:: to avoid invoking make multiple times
Since command line variables won't be placed in MAKEFLAGS until the recipes are invoked they need to be added in separately with MAKEOVERRIDES, we can't use MAKEFLAGS directly due to the first point.

error using makefile, targets and %

I'm trying to debug the following code:
TESTS=$(shell cat yoursourcefile)
all: $(TESTS)
%: compile_design
compile $#_tb.vhd >> log_file.log
simulate $#
I got this error:
makefile_tb.vhd >> log_file.log
as if makefile is a target
this error disappears when I add a character or more before %:
T%: compile_design
compile $#_tb.vhd >> log_file.log
simulate $#
This works but implies that all my targets starts with "T" which is not always the case.
My questions are:
what's exactly the function of % here ?
How to get rid of this error?
As suggested, I added
makefile: ; $#:
at the end, so I have now:
TESTS=$(shell cat yoursourcefile)
all: $(TESTS)
%: compile_design
compile $#_tb.vhd >> log_file.log
simulate $#
makefile: ; $#:
then when I do:
make all
I get [all] error2 all_tb.vhd >> log_file.log
but all_tb.vhd does not exist !
The %: compile_design rule is a "match-anything" pattern rule. It says "hey make, if you ever want to build any file, with any name, then you can do it by running these commands. Oh and by the way, if you have a file you want to build and it's older than the compile_design file, then you need to rebuild it". Generally you want to avoid match-anything rules, but if your target names truly have no specific pattern, you can't.
When you add the T before it then it tells make that instead of any file, that rule can only build files that begin with T.
The reason make is trying to rebuild the makefile is that GNU make has a special feature that allows it to remake its own makefiles. So after it reads its makefile it will try to re-make it. Normally this has no effect because there's no rule to build a makefile, but here you've added a rule that you've told make can build anything. Adding the T keeps the pattern from matching Makefile because Makefile doesn't begin with T.
The simplest thing for you to do is define an explicit rule for the makefile: make always chooses an explicit rule, if it exists, over an implicit rule like a pattern rule:
Makefile: ; #:
This creates an explicit rule that does nothing (: is the shell built-in command that does nothing).

What is the purpose of .PHONY in a Makefile?

What does .PHONY mean in a Makefile? I have gone through this, but it is too complicated.
Can somebody explain it to me in simple terms?
By default, Makefile targets are "file targets" - they are used to build files from other files. Make assumes its target is a file, and this makes writing Makefiles relatively easy:
foo: bar
create_one_from_the_other foo bar
However, sometimes you want your Makefile to run commands that do not represent physical files in the file system. Good examples for this are the common targets "clean" and "all". Chances are this isn't the case, but you may potentially have a file named clean in your main directory. In such a case Make will be confused because by default the clean target would be associated with this file and Make will only run it when the file doesn't appear to be up-to-date with regards to its dependencies.
These special targets are called phony and you can explicitly tell Make they're not associated with files, e.g.:
.PHONY: clean
clean:
rm -rf *.o
Now make clean will run as expected even if you do have a file named clean.
In terms of Make, a phony target is simply a target that is always out-of-date, so whenever you ask make <phony_target>, it will run, independent from the state of the file system. Some common make targets that are often phony are: all, install, clean, distclean, TAGS, info, check.
Let's assume you have install target, which is a very common in makefiles. If you do not use .PHONY, and a file named install exists in the same directory as the Makefile, then make install will do nothing. This is because Make interprets the rule to mean "execute such-and-such recipe to create the file named install". Since the file is already there, and its dependencies didn't change, nothing will be done.
However if you make the install target PHONY, it will tell the make tool that the target is fictional, and that make should not expect it to create the actual file. Hence it will not check whether the install file exists, meaning: a) its behavior will not be altered if the file does exist and b) extra stat() will not be called.
Generally all targets in your Makefile which do not produce an output file with the same name as the target name should be PHONY. This typically includes all, install, clean, distclean, and so on.
NOTE: The make tool reads the makefile and checks the modification time-stamps of the files at both the side of ':' symbol in a rule.
Example
In a directory 'test' following files are present:
prerit#vvdn105:~/test$ ls
hello hello.c makefile
In makefile a rule is defined as follows:
hello:hello.c
cc hello.c -o hello
Now assume that file 'hello' is a text file containing some data, which was created after 'hello.c' file. So the modification (or creation) time-stamp of 'hello' will be newer than that of the 'hello.c'. So when we will invoke 'make hello' from command line, it will print as:
make: `hello' is up to date.
Now access the 'hello.c' file and put some white spaces in it, which doesn't affect the code syntax or logic then save and quit. Now the modification time-stamp of hello.c is newer than that of the 'hello'. Now if you invoke 'make hello', it will execute the commands as:
cc hello.c -o hello
And the file 'hello' (text file) will be overwritten with a new binary file 'hello' (result of above compilation command).
If we use .PHONY in makefile as follow:
.PHONY:hello
hello:hello.c
cc hello.c -o hello
and then invoke 'make hello', it will ignore any file present in the pwd 'test' and execute the command every time.
Now suppose, that 'hello' target has no dependencies declared:
hello:
cc hello.c -o hello
and 'hello' file is already present in the pwd 'test', then 'make hello' will always show as:
make: `hello' is up to date.
.PHONY: install
means the word "install" doesn't represent a file name in this
Makefile;
means the Makefile has nothing to do with a file called "install"
in the same directory.
It is a build target that is not a filename.
The special target .PHONY: allows to declare phony targets, so that make will not check them as actual file names: it will work all the time even if such files still exist.
You can put several .PHONY: in your Makefile :
.PHONY: all
all : prog1 prog2
...
.PHONY: clean distclean
clean :
...
distclean :
...
There is another way to declare phony targets : simply put :: without prerequisites :
all :: prog1 prog2
...
clean ::
...
distclean ::
...
The :: has other special meanings, see here, but without prerequisites it always execute the recipes, even if the target already exists, thus acting as a phony target.
The best explanation is the GNU make manual itself: 4.6 Phony Targets section.
.PHONY is one of make's Special Built-in Target Names. There are other targets that you may be interested in, so it's worth skimming through these references.
When it is time to consider a .PHONY target, make will run its recipe
unconditionally, regardless of whether a file with that name exists or
what its last-modification time is.
You may also be interested in make's Standard Targets such as all and clean.
There's also one important tricky treat of ".PHONY" - when a physical target depends on phony target that depends on another physical target:
TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2
You'd simply expect that if you updated TARGET2, then TARGET1 should be considered stale against TARGET1, so TARGET1 should be rebuild. And it really works this way.
The tricky part is when TARGET2 isn't stale against TARGET1 - in which case you should expect that TARGET1 shouldn't be rebuild.
This surprisingly doesn't work because: the phony target was run anyway (as phony targets normally do), which means that the phony target was considered updated. And because of that TARGET1 is considered stale against the phony target.
Consider:
all: fileall
fileall: file2 filefwd
echo file2 file1 >fileall
file2: file2.src
echo file2.src >file2
file1: file1.src
echo file1.src >file1
echo file1.src >>file1
.PHONY: filefwd
.PHONY: filefwd2
filefwd: filefwd2
filefwd2: file1
#echo "Produced target file1"
prepare:
echo "Some text 1" >> file1.src
echo "Some text 2" >> file2.src
You can play around with this:
first do 'make prepare' to prepare the "source files"
play around with that by touching particular files to see them updated
You can see that fileall depends on file1 indirectly through a phony target - but it always gets rebuilt due to this dependency. If you change the dependency in fileall from filefwd to file, now fileall does not get rebuilt every time, but only when any of dependent targets is stale against it as a file.
I often use them to tell the default target not to fire.
superclean: clean andsomethingelse
blah: superclean
clean:
#echo clean
%:
#echo catcher $#
.PHONY: superclean
Without PHONY, make superclean would fire clean, andsomethingelse, and catcher superclean; but with PHONY, make superclean won't fire the catcher superclean.
We don't have to worry about telling make the clean target is PHONY, because it isn't completely phony. Though it never produces the clean file, it has commands to fire so make will think it's a final target.
However, the superclean target really is phony, so make will try to stack it up with anything else that provides deps for the superclean target — this includes other superclean targets and the % target.
Note that we don't say anything at all about andsomethingelse or blah, so they clearly go to the catcher.
The output looks something like this:
$ make clean
clean
$ make superclean
clean
catcher andsomethingelse
$ make blah
clean
catcher andsomethingelse
catcher blah

Resources