Makefile Dependencies, What Should Be a Dependency?

冷暖自知 提交于 2021-02-19 06:57:08

问题


I have a conceptual question regarding makefile dependencies and this is because I see inconsistency online about this.

Let's say I have the following files:

main.cpp         uses->     my_math.cpp and my_strings.cpp
my_math.cpp      uses->     my_math.h
my_strings.cpp   uses->     my_strings.h

If I have a makefile, with the general outlay of:

program: $(all_objs)
     g++ $(all_objs) -o program
main.o: ...
     .......
my_math.o: ...
     .......
my_strings.o: ...
     .......

I don't know what should go into each dependency. Like, math.o #includes my_math.h and my_strings.h, does that mean that main.cpp needs to recompile if I change my_math.h? But why? It uses it like a library, right? It doesn't need to recompile main.cpp or does it?

As in, should the result for main.o be:

1) main.o: main.cpp
         gcc -c main.cpp

2) main.o: main.cpp my_strings.cpp my_strings.h my_math.cpp my_math.h
         gcc -c main.cpp

3) main.o: main.cpp my_strings.cpp my_strings.h my_math.cpp my_math.h
         gcc -c main.cpp my_strings.cpp my_math.cpp

I'm a bit lost on dependencies and how linking works.

Any help would be appreciated! Thank you!


回答1:


The dependencies are everything whose change requires recompiling the source code. That includes not only your #include-d headers, but also the indirectly included system headers, and even (in principle) the compiler and build chain itself (when you upgrade your C++ compiler, you should recompile all your software). If some of your C++ code is generated from some source (e.g. by tools like GNU bison or Qt moc, or by your own script), both the sources and the generating tools are dependencies. Read also about package managers.

Practically speaking, the GCC compiler is able to output most make dependencies, notably with -M and related processor options. Read also about auto dependencies generation. See also this.

(in practice, you generally don't code in your Makefile some explicit dependency on the compiler itself; but you should not forget to make clean when the compiler has been upgraded)

Unless your main.cpp is including my_strings.cpp (which is not conventional and is very bad taste), your make rule won't have a dependency from my_strings.cpp to main.o. But probably your main.cpp is #include-ing (directly or indirectly) my_strings.h so main.o should depend not only on main.cpp but also on my_strings.h

As a rule of thumb, your object file my_strings.o depends on the source file my_strings.cpp and all the header files which are directly or indirectly #include-d in it. Your main program executable depends on all its object files and the libraries you are linking into it. Order of program arguments to g++ matters a lot.

It uses it like a library, right?

From what you are showing, you don't have any own libraries (but you probably use the standard C++ library, and perhaps some other system libraries). On Linux these are lib*.a files (static libraries) or lib*.so files (shared libraries). A library is an organized agglomeration of object code -and sometimes other resources.

I'm a bit lost on dependencies and how linking works.

Understand the difference between source code files, object files (they contain relocation information) and executables (on Linux, object files and executable files and shared libraries are using the ELF format). Read also about the role of compilers, linkers (the g++ program can run both) & build automation (for which you are using make).

Read Program Library HowTo and much more about translation units and linkers (& name mangling), notably Levine's book on Linkers & loaders.

See also this & that & this (examples about Makefile for C++ programs).

BTW, you should use g++ (not gcc) when compiling C++ code. There are significant differences (even if gcc is sometimes able to compile C++ or Fortran code, you'll mostly use gcc to compile C code). And (assuming you use specifically GNU make) your Makefile should mention $(CXX) (not g++). You need to understand the builtin rules of make (run once make -p to get them) and you'll better take advantage of them (e.g. use $(COMPILE.cc) or $(COMPILE.cpp) etc...). You certainly should pass -Wall -Wextra (to get all warnings, and even more), and -g (to get debugging information) to g++. Practically speaking, you should set your CXXFLAGS variable in your Makefile.

Take time to carefully read GNU make documentation and Invoking GCC.

Look into the Makefile-s of existing free software projects. For various reasons, some projects are generating their Makefile-s with tools like autoconf or cmake. But most simple projects don't need that generality, and you should be able to write your own Makefile for your C++ projects. Of course, take inspiration from existing code.




回答2:


If you have

main.cpp         uses->     my_math.cpp and my_strings.cpp
my_math.cpp      uses->     my_math.h
my_strings.cpp   uses->     my_strings.h

The purpose of Make is to maintain dependency between modules in two different ways, by building .o files and by linking .o files.

you can picture it as a dependency tree where main.o is the root

                         main.o 
                       /       \
                   my_math.o   my_strings.o

for each .o there is also a dependency tree with regard to source files e.g.

    main.o               my_math.o               my_strings.o
   /      \              /        \              /           \ 
main.cpp   main.h     my_math.cpp  my_math.h  my_strings.cpp my_strings.h

So when make builds, it sets up a dependency tree with main.o at its root and then tries to build all .o files needed for main. When all .o files have been built they are linked.

By following the dependency tree Make ensures that main will be linked/built when one of the dependent modules is changed.

However if you have used something like say a constant from one of the included headers #define MAXSTRING 32 you are no longer merely dependent on the .o file, you are then dependent on the header content so you need to make sure that main.o is built if the header is changed since linking is then not enough so you add the .h in the dependency

                               main.o 
                            /     |     \
                   my_math.o my_strings.o my_strings.h

Of course there are ways to make the header more robust to avoid that dependency but is another question.




回答3:


Your cpp files do not depend on other cpp files in terms of compilation. Simple cpp file should only depend on h files.

In your question you say main.cpp depends on my_math.cpp and my_strings.cpp, but I think it is not true. I can guess you have #includes there and these are your dependecies.

Generally speaking dependencies for cpp files are all #included h files.

Usually there are no dependencies between cpp files. You just generate o files by compiling them. Then your final binary depends on all o files.



来源:https://stackoverflow.com/questions/41530474/makefile-dependencies-what-should-be-a-dependency

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!