GCC creating dependencies for generated header files in proper directory - gcc

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.

Related

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

make dependencies: skip vendor and package headers with gcc?

I'm starting a new project and thinking of using gcc 6.3.1 -MM to generate the dependencies into a file called Make.Dep, that I'll include from Makefile.
The -M option outputs all headers, including system headers. The -MM option doesn't output system headers, but I'm still buried in literally thousands of vendor and package headers such as Sybase and Boost, which I don't think will change (and if they do I'm happy to have to do a full rebuild manually).
Obviously I could wrap gcc -MM in a perl script or what have you that knows what directories I consider packages, but is there some more widely-accepted solution?
Note that one of my vendors' headers look for specific gcc-defined pre-processor symbols to configure their portability. I'd rather not curate a set of such symbols manually to allow dependency generation with some non-gcc method (e.g., makedepend).
Instead of -I, use -isystem to state directories that you don't wish to be output with -MM.
This is not mentioned currently at https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html despite it seeming to be very closely tied to -M and -MM options.
Example: this creates correct dependencies of foo.cpp and bar.cpp, including Sybase headers:
gcc -MM -I/opt/nmr/sap/sybaseASE/sybclient-16.0.3-7/OCS-16_0/include foo.cpp bar.cpp
Example: this does the same, but not including Sybase headers:
gcc -MM -isystem /opt/nmr/sap/sybaseASE/sybclient-16.0.3-7/OCS-16_0/include foo.cpp bar.cpp
Here is a sample Makefile implementation for gmake. The patsubst function is a pattern substitution using % as a part that matches on the "before" that is then captured and used in the "after." isystem appears to need a space after it, but this is easy to generate with patsubst as the percent sign keeps the space from being truncated. The minus option on -include tells gmake not to complain if the file named doesn't exist. This allows you to use gmake to make depend and produce Make.Dep even before there is a Make.Dep. Finally, this assumes $(PkgIncDirs) hold package include directories none of which should be changing, while $(ProjIncDirs) would be include directories inside the project that you'd want dependencies to be generated for.
depend:
gcc -MM $(CFlags) $(Defines) $(patsubst -I%, -isystem %, $(PkgIncDirs)) $(ProjIncDirs) $(Source) >Make.Dep
-include Make.Dep

GNU make in newly created subdirectory

First - I know there are a lot of discussions similar to this, but I've spent hours without them working for me.
My makefile first creates a directory named by the current date and time. I then have the makefile append to a header file a line which creates a string with this directory name. For this reason, I first need to copy all the source files (including the header) into the newly created subdirectory, so that I can preserve the original header and only modify the header (in the subdirectory) which will be used for compilation. I would then like to build in that new directory.
My trouble is getting make to properly build the .o files in the new subdirectory. The solution I've found is to have
$(NOW)%.o: $(NOW)%.cpp
$(CC) -c $(FLAGS) $<
where $(NOW)$ is the subdirectory name. The issue is that my $(FLAGS) seem to be ignored: the output is, roughly
g++ -c -o <.o file> <.cpp file>
(Yes, there is actually extra introduced space between g++ and -c.) Whereas building in the top level directory a la
%.o: %.cpp
$(CC) -c $(FLAGS) $<
correctly outputs
g++ -c <my flags> -o <.o file> <.cpp file>
To summarize, I am unable to compile normally by transferring the source files to a newly-created subdirectory and building the .o files in that directory. TYIA.
Ad John points out, there's no way to definitively diagnose your problem with the tiny bit of makefile you provided, because the error is not in the code you provided, it's in some other part of your makefile. You need to provide a SSCCE ideally, but if not that then at least we need to see how the NOW variable is set and the linker rule so we know what make is trying to build.
I should also point out that by convention you should not use CC to hold the C++ compiler; the CC variable holds the C compiler. Use CXX for the C++ compiler and CXXFLAGS for the C++ compiler flags.
One possibility is that you are assigning the NOW variable using a recursive assignment so that the timestamp is recreated every time the variable is evaluated; it could be that the timestamp changes over the lifetime of the makefile.
The other very common problem is that you created the pattern rule, but make is not using it because the targets make wants to build don't match the pattern.
So for example, if your link line looks like this:
SRCS = foo.cpp
OBJS = $(SRC:.cpp=.o)
myprog: $(OBJS)
$(CXX) ...
$(NOW)%.o : $(NOW)%.cpp
$(CXX) ...
then your pattern will not be matched because make is trying to build the file foo.o and your rule tells it how to build $(NOW)foo.o which are not the same thing.

Makefile: different flags for similar files

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).

Make file possible accidental order-only dependency?

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

Resources