Reputation: 840
I want to create a list of dependencies for particular file. For example:
//a.cpp
#include "b.h"
#include <cstdio>
int main(){printf("%d\n",fn());}
//b.h
int fn();
//b.cpp
#include "b.h"
#include "c.h"
int fn(){return fn2();}
//c.h
inf fn2();
//c.cpp
#include "c.h"
int fn2(){return 5;}
For those files, a depends on b which depends on c. So the result of the wanted program should be:
a: a.o b.o c.o
Yes, it is for makefiles. For some reasons I do not want the list to include ALL .o
files in directory, so %.o
won't work. Also, I'm aware of g++ -MMD
option, and it almost works as I want - but it lists only direct dependencies, in this case:
a.o: a.cpp b.h
(the extensions are not an issue, I can post-process them later)
Is there an easy way for generating such a list?
Upvotes: 1
Views: 3072
Reputation: 153792
It seems you are still going on about this... The first thing to understand is that object files do not depend on other object files. The dependencies list which files are necessary to build something. To create an object file you need some source file and the headers it is using. This is exactly the information the variations of the -MD
flags give you.
If you want to determine which object files are necessary to build an executable, you need something different: you need to create a dependency graph between object files and then create a graph search starting at the node with the entry point (i.e., the main()
function). The tools to do that are nm
which prints symbol information of an object an object file and something like tsort
which, however, just provides a topological order rather than a connected component. However, you could use the same information tsort
uses to do its job.
The nm
program just dumps out all symbols defined or referenced in an object file. You'd use all symbols with a capital character to indicate that an object file, i.e., a node, either provides this symbol (if it is something different than 'U'
) or needs that symbol (i.e., the character is 'U'
). The exact meaning of the symbols (e.g., 'T'
for "text", i.e., program code) doesn't matter other than 'U'
meaning "undefined" and everything else being a definition (well, 'W'
may put up a bit of a fight because these are "weak" symbols and multiple translation units may have them). You'd connect two nodes, if one nodes has a symbol undefined and the other has the symbol defined.
Once the graph is build, you'd use the node defining 'main()'
as the start node and search the reachable graph. All object files (nodes) reached are needed to build the corresponding program. That's the algorithmic description. The actual implementation may be different and actually simpler:
tsort
to bring the object files into a proper dependency order. If there are cycles, remove them.main()
and record it as a dependency.Other than the linker I'm not aware of any tool doing this. The reason is that changing any object file can change the dependencies and you need to reevaluate the dependencies for each program. Incidentally, this is what a linker does.
Maybe you'd get better help if you stated what your actual goal is rather than asking about aspects of the envisioned solution.
Upvotes: 4