Makefile: different flags for similar files - makefile

I have several files to compile: one.f two.f ... ten.f
Some need to be compiled with different flags. For example, from one.f to five.f need to be compiled with ifort -O and six.f to ten.f need to be compiled with ifort -O2.
How can I make two implicit rules that know which files compile with which flags? Or any way in which to group then together so I don't have to specify file by file.
Similarly:
Some depend on the module mod.f and others don't. Can I specify this dependency without doing it in a file by file basis?

You can absolutely specify dependencies on a per-target basis but you do need a way of specifying the right targets (likely explicitly) though not necessarily manually if you can construct the list some other way (or have it in a variable already).
The line one.o two.o three.o four.o five.o: mod.f will add that as a prerequisite to those targets (for whatever rule actually builds those targets.
Similarly you can assign 6.11 Target-specific variables and use those.
one.o two.o three.o four.o five.o: FFLAGS+=-O
six.o seven.o eight.o nine.o ten.o: FFLAGS+=-O2
will add the right optimization flag to the built-in %.o: %.f (or anything else that uses $(FFLAGS).

Related

Why does a target archive behave like a .PHONY target in a Makefile?

I have a simple Makefile that builds an archive, libfoo.a, from a single object file, foo.o, like this:
CC=gcc
CFLAGS=-g -Wall
AR=ar
libfoo.a: libfoo.a(foo.o)
foo.o: foo.c
The first time I run make, it compiles the C file, then creates an archive with the object file:
$ make
gcc -g -Wall -c -o foo.o foo.c
ar rv libfoo.a foo.o
ar: creating libfoo.a
a - foo.o
However, if I run make again immediately (without touching foo.o), it still tries to update the archive with ar r (insert foo.o with replacement):
$ make
ar rv libfoo.a foo.o
r - foo.o
Why does Make do this when it shouldn't have to? (If another target depends on libfoo.a, that target will be rebuilt as well, etc.)
According to the output of make -d, it seems to be checking for the non-existent file named libfoo.a(foo.o), and apparently decides to rerun ar r because of that. But is this supposed to happen? Or am I missing something in my Makefile?
You are seeing this because the people who put together your Linux distribution (in particular the people that built the ar program you're using) made a silly decision.
An archive file like libfoo.a contains within it a manifest of the object files contained in the archive, along with the time that the object was added to the archive. That's how make can know if the object is out of date with respect to the archive (make works by comparing timestamps, it has no other way to know if a file is out of date).
In recent times it's become all the rage to have "deterministic builds", where after a build is complete you can do a byte-for-byte comparison between it and some previous build, to tell if anything has changed. When you want to perform deterministic builds it's obviously a non-starter to have your build outputs (like archive files) contain timestamps since these will never be the same.
So, the GNU binutils folks added a new option to ar, the -D option, to enable a "deterministic mode" where a timestamp of 0 is always put into the archive so that file comparisons will succeed. Obviously, doing this will break make's handling of archives since it will always assume the object is out of date.
That's all fine: if you want deterministic builds you add that extra -D option to ar, and you can't use the archive feature in make, and that's just the way it is.
But unfortunately, it went further than that. The GNU binutils developers unwisely (IMO) provided a configuration parameter that allowed the "deterministic mode" to be specified as the default mode, instead of requiring it to be specified via an extra flag.
Then the maintainers of some Linux distros made an even bigger mistake, by adding that configuration option when they built binutils for their distributions.
You are apparently the victim of one of these incorrect Linux distributions and that's why make's archive management doesn't work for your distribution.
You can fix it by adding the -U option, to force timestamps to be used in your archives, when you invoke ar:
ARFLAGS += -U
Or, you could get your Linux distribution to undo this bad mistake and remove that special configuration parameter from their binutils build. Or you could use a different distribution that doesn't have this mistake.
I have no problem with deterministic builds, I think they're a great thing. But it loses features and so it should be an opt-in capability, not an on-by-default capability.

Make file Doesn't detect changes in source files

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 $#

GCC creating dependencies for generated header files in proper directory

I use GCC to create dependency files, from header files stored in a
certain directory. Here is my recipe:
gcc -MM -MG -MT obj/$*.o -MP -MF dep/$*.Td -I include $<
One of these header files is generated (with Bison 3.0.5), so it may not
exist. I therefore use the -MG option as shown above, but it generates
a dependency without the directory. How can I tweak make or GCC to
prepend the include directory to the generated header?
Thanks in advance
dordow
Typically, the search path has many entries, and if the header file does not exist, it is unclear which prefix to pick.
The cook build tool comes with a program, c_incl, which scans C source files for #include directives and can be made to behave in the way you intend, with a command like c_incl -No_Cache -Absent_System_Mention -Iinclude -C. But this tool is fairly obscure.
It is probably better to use a slightly less obscure GNU make feature instead: order-only prerequisites, as described in Types of Prerequisites. You would list the generated header files (or other Bison output files) as order-only prerequisites for all rules that compile C files, so that they are generated early on first build, but do not needlessly trigger rebuilds afterwards. With this approach, you do not need to generate dependencies on files which do not exist yet.

make is not using -std=c++11 option for g++

I am trying to compile c++ files using make. But, it is not using -std=c++11 flag by default. Whenever I need to compile a program which uses c++11 specific features, I have to explicitly compile it using g++.
So, I want to ask how can I have make automatically use the option -std=c++11 for all my c++ files on my system.
If I need to change some global makefile for g++ , what is the location of the makefile on Linux Mint 18 and what needs to be changed or added?
Or do I need to create a Makefile for myself?
EDIT 1: I am invoking make like make myfile
And there are only .cpp files and their binaries in the directory. I don't have any Makefile in the directory.
EDIT 2: Here, myfile is the name of the c++ file which I want to compile.
When I run make with the -d option, I get the following output (I can not paste all of the output as it is quite long and is exceeding the body size limit so, I am including the screenshots of the output).
Image 1
And this image(2) has some lines from the end.
Image 2
I intentionally made a change in the file "MagicalWord.cpp" so that make finds something to make!
There is no "global makefile" and there is no way to change the default flags for all invocations of make (unless you edit the source code to GNU make and compile it yourself, which is a bad idea in this situation).
In your makefile(s), add the line:
CXXFLAGS += -std=c++11
Assuming you're using the built-in rules for compiling things, or that you're using the standard variables with your own rules, that will do what you need.
If that doesn't work we'll need to see your makefile or at least the rules you use to build your C++ source files (things like the -d output aren't useful here--that would be interesting if files weren't being built, that you thought should be or similar).
Setting a system-wide language for all your C++ projects isn't necessarily a good idea. Instead, define a Makefile that specifies any compiler options you'd like:
CXXFLAGS := -std=c++11 $(CXXFLAGS)
The CXXFLAGS are then passed to your compiler when compiling a C++ program (assuming you're using the default GNU Make rules).
If the Makefile lives in your current working directory, you can now run make target in order to compile a target.cpp file into a target executable.
If the Makefile is in another directory, you must specify the path to it:
make -f path/to/your/Makefile target
If you want to add extra parameters just for one run, you can set an environment variable or a make variable on the command line:
# environment:
CXXFLAGS='-std=c++11' make target
# make variable:
make target CXXFLAGS='-std=c++11'
Any of these will cause the execution of g++ -std=c++11 target.cpp -o target or equivalent.
In theory you can edit your shell profile to export CXXFLAGS='-std=c++11' which will make that environment variable available to all programs you run. In practice, setting compiler options through environment variables tends to cause more problems than it solves.
Of all these solutions, just writing a normal Makefile is by far the easiest approach. That way, all of the build configuration is in one place and completely automated.

How do you compile without linking in Automake?

I am new to Automake and I am attempting to compile without linking. My goal is to generate a simple Makefile as shown below using Automake.
CFLAG = -Wall
build: Thread.o
Thread.o: Thread.cc Thread.h
g++ $(CFLAG) -c Thread.cc
clean:
rm -f *.o
My attempt so far has brought me to the following Makefile.ac.
noinst_PROGRAMS = thread
thread_SOURCES = Thread.cc
EXTRA_DIST= Thread.h
How can I simulate my original Makefile?
One way is to do this is to fool Automake by providing link command that does not link:
thread_LINK = true
Other than that, I wouldn't be suprised if Automake did not have such feature.
For your example, you can just ask Automake to build your .o file directly, e.g.:
$ make Thread.o
I believe this is an implicit rule, so you won't see it in the output Makefile.
In general, Automake generates variables containing all the objects required for each executable or library target. It's pretty straightforward to use them in your Makefile, since it just generates their names by appending _OBJECTS to the target name. You could make your own target in Makefile.am like this:
build-thread: $(thread_OBJECTS)
Then you could build just Thread.o (and any other objects needed for thread) like this:
$ make build-thread
Or if you had multiple targets foo, bar, and baz, you could make your compile-only target in Makefile.am like this:
build: $(foo_OBJECTS) $(bar_OBJECTS) $(baz_OBJECTS)
The only pain here is that you'll need to maintain this list yourself based on the targets in your Makefile.am. You can invoke it at the command line like this:
$ make build
Automake is not designed to produce object. It will build either programs or libraries.
It's hard to answer your question without knowing why you'd want to compile a single object file and not something else. Maybe there is a cleaner answer to your "real" problem.
A Makefile.am you could write is
noinst_LIBRARIES = libThread.a
libThread_a_SOURCES = Thread.cc Thread.h # No need to put headers in EXTRA_DIST
The resulting Makefile would build a library libThread.a containing only libThread.o, ans because *.a libraries are just a collection of object files there is no linking involved.
The above Makefile.am also causes the emitted Makefile to contain rules to compile libThread.o, so you can add a build: rule if you like.
If you really want Automake to emit this compile rule, but not build the library, you could go with
EXTRA_LIBRARIES = libThread.a # EXTRA here means "output build rules but don't
# build unless something depends on it".
libThread_a_SOURCES = Thread.cc Thread.h
build: Thread.$(OBJEXT)
Now you are explicitely requiring the file Thread.$(OBJEXT) to be built only when you type make build, as in your original Makefile.
(Automake uses .$(OBJEXT) rather than .o to support extensions like .obj in DOS variants.)
First off, automake is a tool to auto make making Makefiles; make in and of itself is a whole different beast (and I'm pretty sure that what you were looking for was a make solution).
Here's the easiest GNU based Makefile to accomplish what you want:
all: Thread.o
This fills in something (by default) like the following (please change 4-space whitespace to hard tabs):
all: Thread.o
Thread.o: Thread.cc
$(COMPILE.cpp) $(OUTPUT_OPTION) $<
The COMPILE.cpp and OUTPUT_OPTION macros of course expand by default to GNU make specified values and aren't portable; $< is AT&T Make standard syntax though according to pmake(1)'s manpage though.
GNU make has a concept of implicit vs explicit rules, patterns, suffixes, etc that you could use, but that's not portable to all versions of make, and hence that's why all of the Makefile is plainly spelled out in terms of targets and variables as POSIX doesn't describe many of the desired scenarios for how one should write a Makefile.
Run gmake -p for more details and take a look at the texinfo manual for gmake in the topic of implicit, explicit rules, patterns, suffixes, etc.

Resources