I use a shared library.so in order to avoid to remake executables (which are linked against it) when only the implementation (library.cpp), but not the interface (library.hpp), has changed, i.e.
obj/library.o: library.cpp library.hpp
lib/library.so: obj/library.o
program : program.cpp library.hpp
$(CXX) program.cpp -Llib -lrary
Thus, program does not depend on library.cpp or library.so. However, when making it from scratch (rather than remaking it because of changes to some files), library.so must be made before program. This can be ensured by setting:
default: library.so program
But when using make -j this is broken.
So what is the correct way to 1) ensure library.so is made before program but 2) avoid re-making program if only library.cpp has changed?
The solution for what you want is an order-only prerequisite.
From the Types of Prerequisites section of the GNU make Manual:
Occasionally, however, you have a situation where you want to impose a specific ordering on the rules to be invoked without forcing the target to be updated if one of those rules is executed. In that case, you want to define order-only prerequisites. Order-only prerequisites can be specified by placing a pipe symbol (|) in the prerequisites list: any prerequisites to the left of the pipe symbol are normal; any prerequisites to the right are order-only:
targets : normal-prerequisites | order-only-prerequisites
Related
I am very much new to make files , I am facing very basic problem , My Makefile doesn't detect changes I made to source files . The problem is , when I first time generate consoleapp binary from my source file i get expected output . But When I change source file again and when I run make again it says
make: 'consoleapp' is up to date , So what changes I have to give to make file so that it detects my changes
Below is my Makefile :
consoleapp:
g++ consoleapp.cpp -o consoleapp
clean:
rm -rf *.o consoleapp
This is my Source File :
#include <iostream>
using namespace std;
int main()
{
cout<<"I am ok \n"; // I am changing this line again after giving make
return 0;
}
make relies on the makefile author to tell it what each target's prerequisites are -- that is, which other targets or files affect the construction of the target in question, so that if they are newer or themselves out of date then the target is out of date and should be rebuilt. As your other answer already indicates, you do not designate any prerequisites for your targets, so make considers them out of date if and only if they don't exist at all.
That's actually problematic for both targets, albeit in different ways. For target consoleapp, which represents an actual file that you want to build, the failure to specify any prerequisites yields the problem you ask about: make does not recognize that changes to the source file necessitate a rebuild. The easiest way to fix that would be to just add the source file name to the recipe's header line, after the colon:
consoleapp: consoleapp.cpp
g++ consoleapp.cpp -o consoleapp
Generally speaking, however, it is wise to minimize duplication in your makefile code, and to that end you can use some of make's automatic variables to avoid repeating target and prerequisite names in your rule's recipe. In particular, I recommend always using $# to designate the rule's target inside its recipe:
consoleapp: consoleapp.cpp
g++ consoleapp.cpp -o $#
It's a bit more situational for prerequisites. In this case, all the prerequisites are source files to be compiled, and furthermore there is only one. If you are willing to rely on GNU extensions then in the recipe you might represent the sources via either $< (which represents the first prerequisite), or as $^ (which represents the whole prerequisite list, with any duplicates removed). For example,
consoleapp: consoleapp.cpp
g++ $^ -o $#
If you are not using GNU make, however, or if you want to support other people who don't, then you are stuck with some repetition here. You can still save yourself some effort, especially in the event of a change to the source list, by creating a make variable for the sources and duplicating that instead of duplicating the source list itself:
consoleapp_SRCS = consoleapp.cpp
consoleapp: $(consoleapp_SRCS)
g++ $(consoleapp_SRCS) -o $#
I mentioned earlier that there are problems with both of your rules. But what could be wrong with the clean rule, you may ask? It does not create a file named "clean", so its recipe will be run every time you execute make clean, just as you want, right? Not necessarily. Although that rule does not create a file named "clean", if such a file is created by some other means then suddenly your clean rule will stop working, as that file will be found already up to date with respect to its (empty) list of prerequisites.
POSIX standard make has no solution for that, but GNU make provides for it with the special target .PHONY. With GNU make, any targets designated as prerequisites of .PHONY are always considered out of date, and the filesystem is not even checked for them. This is exactly to support targets such as clean, which are used to designate actions to perform that do not produce persistent artifacts on the file system. Although that's a GNU extension, it is portable in the sense that it uses standard make syntax and the target's form is reserved for extensions, so a make that does not support .PHONY in the GNU sense is likely either to just ignore it or to treat it as an ordinary rule:
.PHONY: clean
clean:
rm -rf *.o consoleapp
because your target has no dependence. Please use this codes that rely to all cpp file in current dir to update binary.
SRCS=consoleapp.cpp
consoleapp: $(SRCS)
g++ $< -o $#
I have this makefile in a directory with a set of .cpp, each one representing a single program with some header-only dependences. All files are in the same directory.
To compile for example the program a, I do make a. The make's implicit rules will compile successfully a from a.cpp, but make must also remake the target when their header-only dependencies change.
However, once a program compiles, the following makefile doesn't rebuild anything if I do, for example, touch utils.hpp and then retry compilation. What's going on?
src := $(shell find . -maxdepth 1 -name "*.cpp")
exe := $(src:.cpp=)
# In case I want to build every program, w/o a cmd-line target.
all: $(exe)
%: utils.hpp test.hpp
My make version is GNU Make 4.1.
Your last resort rule cannot be used to express the kind of dependencies you want. It is considered only if make needs to build something and knows no other rule to do it. Instead you should express this dependencies on your executable list:
$(exe): utils.hpp test.hpp
I'm studying how 'make' works and I encountered a little oddity
Suppose I have a folder with only 'helloworld.c' and 'Makefile'
Makefile contains
helloworld: helloworld.o
gcc -o helloworld helloworld.o
The output of 'make' in a bash console is
cc -c -o helloworld.o helloworld.c
gcc -o helloworld helloworld.o
The rule "helloworld" depends on the file "helloworld.o" which is not present, hence make creates it (the first line in the output).
But why?
I would have expected it to fail, in absence of a "helloworld.o:" rule that tells it how to compile said file. Why does it run the first command out of its own will?
Thanks
The reason is implicit rules.
From the GNU Make manual:
Implicit rules tell make how to use customary techniques so that you
do not have to specify them in detail when you want to use them. For
example, there is an implicit rule for C compilation. File names
determine which implicit rules are run. For example, C compilation
typically takes a .c file and makes a .o file. So make applies the
implicit rule for C compilation when it sees this combination of file
name endings.
In other words, make knows how to build helloworld.o from helloworld.c even if you don't specify an appropriate rule.
To get more information on this subject you can follow GNU Make manual, especially section 10, which is devoted to the usage of implicit rules.
I am using implicit rules only - removing the makefile altogether for a minimal test case. I have an empty (no problem for GNU assembler) program.s file. Executing:
make program
Gives me following output from make:
cc program.s -o program
(and of course the expected errors, which here is of no importance for the question: since my assembler source file is empty, there is no "_start" and all kinds of linking fails.)
I wonder, why does make choose to attempt to build the program in one go? As opposed to first using as program.s ... and then ld program.o ...? Is this because it considers the object file unnecessary in my scenario here?
If I do make program.o, then as program.as ... is invoked, producing my program.o as expected.
Make will always choose one-step implicit rules in preference to multi-step implicit rules, to get the same result. In this case, make contains built-in rules that create an executable both from an object file, but also directly from various source files including assembly:
%: %.s
# recipe to execute (built-in):
$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $#
Since this is shorter than first building the .o then building the executable from the .o, and since your makefile doesn't say you want the .o, make uses the shortest set of steps.
I am pulling out my hair trying to debug an issue with make. It seems like make is randomly treating certain prerequisites as order-only prerequisites, resulting in them being left out of the static library target that depends on them. Most of the time the build works find but occasionaly some .cpp files are built but not included in the .a. When i run Make with --debug I see the following output for the suspect prerequisites.
Prerequisite `blah.o' is newer than target `/path/to/foo.a`
Prerequisite `blah1.o' is newer than target `/path/to/foo.a`
Prerequisite `blah2.o' is newer than target `/path/to/foo.a`
No need to remake target `/path/to/foo.a'
For all of the prereqs that do make it into the .a the last line is "Must remate target /path/to/foo.a" as I would expect.
Because make is invoked in several subdirectories, target /path/to/foo.a is updated several times. We are not running make in parallel so I don't think updates to the file are stomping each other. It seems that make is deliberately not updating the .a file despite the fact that the .o's are newer. The recipe to make foo.a is as follows:
$(OBJLIB): $(OBJS)
$(AR) $(ARFLAGS) $(OBJLIB) $?
Where ARFLAGS=rv and OBJLIB would be /path/to/foo.a.
Am i right in thinking that the .o files are being treated as order-only dependencies? Is there something else I'm missing here? I am using $(info) to output the contents of OBJLIB and OBJS and there are no errant pipe ('|') characters making their way into the variable contents that would induce order-only dependencies.
Unfortunately the answer had nothing to do with make. As far as I can tell the filesystem is the real culprit. Several people were experiencing success with the build but I was not. The difference between our systems which were using a common build environment was that I was building on an ext3 filesystem while they were using an ext4 filesystem.
Since ext3 does not support sub-1s timestamps (ext4 does) in some cases when the rule was invoked with only a few CPP files they were being compiled in the same second that the archive was updated by a previous invocation and everything was ending up with the same timestamps. Copying the directory over to an ext4 filesystem fixed the issue.
The real fix is to write a proper set of make rules but at least we have an answer as to why it was working for everyone but me.
You mentioned several updates to the .a file because make is invoked in different subdirectories. Probably the message
No need to remake target `/path/to/foo.a'
comes from one subdirectory, and is newer- from another. Consider building the lib out of all objects in one step.
Try this instead.
$(OBJLIB): $(OBJS)
$(AR) $(ARFLAGS) $(OBJLIB) $^
Your problem is that the variable $? is a list of dependencies that are newer than the target, while $^ is a list of all dependencies.
Also, you can use $# for to be more idiomatic.
$(OBJLIB): $(OBJS)
$(AR) $(ARFLAGS) $# $^