简体   繁体   中英

Is modification of dependency, of a dependency mentioned in makefile, not recognized by make?

In my code, I have used three classes. All the classes are in separate files. And I am using Makefile to compile and link them. See the implementation below:

class Medicine 
{ 
   int a;
}

class Pain:public Medicine 
{
   int b;
}

class Comb:public Pain   
{
    string salt,com;
}

All classes have just parameterized constructors, virtual destructors and a function with same name call() , in all the three classes. And call() is like

call()
{
     cout<<"You are in class the_name_of_the_class"<<endl;
}

The code of main.cpp goes like:

int main()
{       
    Medicine *p[2];
    p[0]= new Comb("Salt","Com",2,110);
    p[1]= new Comb("SALT","COM",1,100);

    p[0]->call();

    delete p[0];
    delete p[1];
    return 0;
}

When I run this program, I got the expected output. But when I changed the Medicine::call() to be a virtual function, and again used make command, it says all files are up to date. As I have modified medicine.h , so make should created new version of medicine.o . Why is it considering older medicine.o as updated when I have modified medicine.h ?

The Makefile goes like this:

using .PHONY:clean
OBJ:=medicine.o pain.o comb.o main.o
SOU:=medicine.cpp pain.cpp comb.cpp main.cpp

main:$(OBJ)
        g++ -o $@ $^

%.o:%.cpp
        g++ -c -o $@ $<

clean:
        rm *.o main

If you want to see implementation of medicine.h,

class Medicine
{
    int cost;

 public:

    int getCost();
    void setCost(int);

    Medicine();
    Medicine(int);
    Medicine(Medicine &a);
    virtual string getCompany(){};
    virtual string getSalt(){};
    virtual  ~Medicine ();
    virtual void call();
};

This medicine.h I have included in medicine.cpp , where all these functions are defined.

The problem is that medicine.o only depends on medicine.cpp , not on medicine.h . So you have to modify your rules to provide that missing dependency. It has absolutely nothing to do with "virtualness".

You might also want to add the Makefile itself as a dependency, so if you change it and run make, things get re-built.

To clarify, this generic rule:

%.o:%.cpp
    g++ -c -o $@ $<

means that any something.o depends on something.cpp only, and should be built with the following command:

g++ -c -o something.o something.cpp

ie $@ is the target name and $< is the first dependency.

the format is

target : <dependencies>
    command

make is not language-aware, so yes, make does not know whether a function is virtual or not; actually it does not even know what C++ is and that there are functions there.

make operates in terms of targets and dependencies, and those have to be specified explicitly. Here, the rule to make an object does not include any .h file in the dependencies and thus it deduces that .8 files are unused for the target.

It is actually quite difficult to get the proper set of transitive includes needed to build one .cpp file. There are scripts to assist such as make_depend.pl .

The problem is that your makefile doesn't have the dependencies for your header files to the source files, so it doesn't know that you need to recompile "x.cpp" when "yh" has changed (because "yh" is included by "x.cpp").

You can fix that by having rules like:

medicine.o : medicine.cpp medicine.h 

However, as the number of source files get larger, and the relationship of headers to source gets more complex, you are going to forget/leave out some header files that you actually need - this will ALWAYS happen.

What I usually do is something like this:

SOU = medicine.cpp pain.cpp comb.cpp main.cpp
... 

main:$(OBJ) .depends

...

.depends: $(SOU)
     g++ -MM $(SOU) > $@

include .depends

What this does is to let the compiler generate the rules into a file .depends - that way, you don't "forget" to fix it up when you update a file somewhere.

Edit: For large projects, using a single dependency file is a poor idea, because every time a .cpp file is changed, the compiler will have to sort out all the dependencies for every file in the project. But for a small hobby project it's fine. For large projects, one would take the extra penalty of having lots of .depends files (one per source file, probably in a depends directory).

The working of make is like this: It checks the latest modification time of the dependency ( medicine.cpp for eg) and then check the latest modification time of medicine.cpp when medicine.o was created. If both are same, then its not recompiled, otherwise recompiled. In my case, medicine.h was modified, but the latest modification time of medicine.cpp remain unchanged. And that's why make was unable to detect this and not recompiled medicine.cpp .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM