Retrieve used header and source file names by parsing Makefile - c++

I would like to extract all the *.cc and *.h filenames from a Makefile that also contains unused targets. Example Makefile here : https://gist.github.com/berceanu/7554a9c4371b807e425259c7e99b5de9
I've tried running make -Bnd and looking at the pruned files but I don't know if this misses anything.
make -Bnd | grep "Pruning file" | sort | uniq
Expected result: list of all *.h and *.cc files used by make run on the above Makefile.

Your approach trying to extract this information from the Makefile is probably the wrong way. make doesn't know which header files are actually used. make only knows which header files you've explicitely told make about in the dependencies, and that's not very reliable. The information in the Makefile could be wrong in two ways. It could contain unused targets (as you have noticed) or unused header files. It could miss header files that are actually included but not mentioned in the Makefile. Even worse, what if the actual inclusion of header files depends on macros, like #ifdef XYZ_FEATURE #include "additionalHeaderFile.h" #endif.
There are at least three ways how you could generate the desired list, that is, list of .cc and .h files actually used during compilation:
(blindly trusts the Makefile) make -n --print-data-base
(follows the real files of the build, but also a bit difficult to parse) strace -f make
(relies on a feature present in GCC, clang, armcc and possibly other compilers for Makefile generation, very reliable) Add CPPFLAGS:=-MMD to the Makefile, run make clean, then make, then use cat *.d to get the list of all .cc and .h files used to build run. You could even do that without changing the Makefile: make clean; make CPPFLAGS:=-MMD && cat *.d | sed -e 's/\\//g' -e 's/:/ /g' -e 's/ \+/\n/g' | sort -u.
Also, the Makefile that you've shared in the gist has a large number of issues.
The default target should, by convention, be named all 1 2 3. That doesn't need to be the name of the binary, it would just be a .PHONY target.
The variable with the list of object files should be named OBJS or OBJECTS, not OBJ. The name OBJ is misleading, because it's singular.
Instead of rm use $(RM) which implies -f and thus will not trouble in case a file doesn't exist. (As a side-effect, the Makefile would become more portable, as not all platforms use rm for deleting files.)
clean is not a file and thus should be a .PHONY target.
clean should use :: instead of : for its recipe so that in future, when the Makefile is bigger and split into multiple files, each file can have their own clean target without problems.
Variables that are not rule-specific should be expanded at the moment of definition, not when they are referenced, and thus defined using := instead of =.
Instead of C++ use CXX which is already defined.
Instead of putting the options into C++/CXX, use LDFLAGS, because you're linking.
You should have a source file that has the same basename as the binary. Then you can use the built-in rule for linking.
Explicit dependencies in the Makefile are a pain for maintenance. Every time an #include statement for a project header file is added, removed, or changed, the Makefile would have to be updated, and that's easy to forget, and it's a pain, especially when the #include statement is in a header file. Even with due diligence, this is also an invisible merge conflict. Instead of having explicit dependencies in the Makefile, you should use CPPFLAGS+=-MMD at the start of your Makefile and append -include $(wildcard *.d) at the end of your Makefile, and add *.d to the list of files to delete in clean. You could then remove all dependency rules from the Makefile (except for the one for the linkage).
Naming the binary run is not a good idea. Users that see that your Makefile has a run target would expect this to run the actual program, not to link it.
It is better to have each object mentioned on a line of its own. That significantly reduces merge conflicts in projects when multiple developers change the object list at the same time.
Your actual Makefile should look like this, with the binary renamed from run to program:
LDFLAGS:=-Wno-deprecated -lm
CPPFLAGS+=-MMD
BINARY:=program
OBJECTS:= \
$(BINARY).o \
binomh.o \
# More objects here
.PHONY: all
all: $(BINARY)
$(BINARY): $(OBJECTS)
.PHONY: clean
clean::
$(RM) \
$(BINARY) \
*.[adios] \
-include $(wildcard *.d)
That Makefile will do the "same" thing as your Makefile, but it is almost maintenance-free. No need to update dependencies, as they are automatically taken from the dependency files generated by the C Preprocessor. The *.[adios] will also remove files created in case you added -save-temps to any of the CFLAGS, CXXFLAGS, or CPPFLAGS.
This type of Makefile is known to work for GCC, clang, AOCC (AMD Optimizing C Compiler), and armcc. It probably works for a number of other compilers and preprocessors as well, especially when they are based on, or try to be compatible with, GCC or clang/LLVM.
BTW in case you're interested in knowing that this works for you, with high confidence, besides experience: I've taken your Makefile and added the following lines to it in order to reproduce your source code structure. The header files would just be empty files. The C++ source files would be lists of #include statements taken from the dependencies in your Makefile.
%.cc:
grep '^$*\.o.*:' $(MAKEFILE_LIST) | sed -e 's/.*://' -e 's/.*$*\.cc//' -e 's/ \([^ ]\+\)/#include "\1"\n/g' >$#
%.h:
touch $#

Instead of -Bnd, I would suggest using --dry-run --print-data-base to dump the full database of targets, their dependencies, rules, variables, etc..

Related

How to use makedepend in a non-standard makefile name

I am trying to use makedepend in a makefile named Makefile_abc.
Normally when I have to build a target trg, I say
make -f Makefile_abc trg
and this works beautifully.
I have added following lines in this makefile.
dep:
makedepend main.c
Now, when I do,
make -f Makefile_abc dep
I get the error,
makedepend: error: [mM]akefile is not present
make: *** [depend] Error 1
If I rename my makefile as Makefile, then following command works fine,
make depend
So, I am looking for a way to use makedepend on non-standard makefile names.
This is a basic 'read the manual' question.
Looking at makedepend(1), you need -fMakefile_abc in the recipe for the target dep (optionally with a space between -f and Makefile_abc):
dep:
makedepend -fMakefile_abc main.c
To update the dependencies, you'd run:
$ make -f Makefile_abc dep
This would cause make to run:
makedepend -fMakefile_abc main.c
(Note that the 'standard' — most common — name for the target is depend rather than dep, so you'd normally run make -fMakefile_abc depend or, with a plain makefile file, make depend.)
If you're using GNU Make, you might also add another line to Makefile_abc:
.PHONY: dep # Or depend, depending…
This tells make that there won't be a file dep created by the rule.
You can often get information about how to run a command by using makedepend --help or makedepend -: — the first may (or may not) give a useful help message outlining options, and the second is very unlikely to be a valid option which should generate a 'usage' message that summarizes the options.

Structuring Makefiles with multiple directories

I am trying to compile my project which has the following structure
Project:
MakeFile
Executable
Source1
.cxx
.h
Source2
.cxx
.h
Build
*.o
And I'm having difficulty writting a Makefile to compile. I currently have commands like:
Src1 = $(wildcard $(SRCDIR1)/*.cxx)
Obj1 = $(patsubst $(SRCDIR1)/%.cxx, $(OBJDIR)/%.o, $(Src1))
But then I have difficulty making the compile rules for the object files a) Because I can no longer do:
$(Obj1): %.cxx
$(CXX) $(CFLAGS) -c $(#:.o=.cxx) -o $#
Because the '$#' command now includes the path of the build directory and b) because the prerequisites now include the build path and I should have a source path. I have read large bits of the make manual to try and find a solution but no luck.
Any help towards a solution appreciated!
Jack
From personal experience, after playing around a bit with "raw" Makefiles, I'd really recommend using some tool building the Makefiles for you, like automake or cmake.
You'll still have to specify all the source files manually - but at least I prefer that to manually fiddling around with the Makefiles.
One option I prefer is building an isomorphic directory structure in the build directory. That is, a source file ${src_dir}/project_x/main.cxx builds into ${build_dir}/project_x/main.o. This way you are protected from name clashes when there are source files with the same name in different source directories. The compiler rule would look something like:
${obj_dir}/%.o : ${src_dir}/%.cxx # % includes directory name, e.g. project_x/main
#-mkdir -p ${#D}
${CXX} -c -o $# ${CPPFLAGS} ${CXXFLAGS} $<
Notice how in the above it creates the target directory on the fly. This is a bit simplistic, in a real-world build system object files depend (using order-only dependency) on its directory, so that make automatically creates the destination directory if it does not exist instead of speculatively trying to create them for each target object file even if it already exists.

Feedback about using make on a project with many subdirectories

To my Object Oriented Programming course, I must do a final proyect (academic purposes). I want to make a proyect "the right way" (ie: makefile, modular, DRY, easily scalable, etc) in order to better understand classes, makefile and C++.
The idea I've got is to have a "tree-source-file-structure-directory" so in each subfolder i'd got the source files with it's headers, test files and single makefile.
So if I want to work on the interface, I go to the subfolder interface, I edit the files, I run the tests, if everything is OK, simply I link the objects together on my root directory. Same thing if I want to work on my data structure, and so goes on. The nice feature is that in every subfolder resides along the source code and the object files, so the linker in my root directory would search for object files already compiled on subfolders and link them together
I've been searching on the internet, and I could see many different solutions:
-Doing make recursively, eg:
SUBDIRS=eda
.PHONY: subdirs $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
The problem I found is that my prerequisites on "eda" folder would be "quirky"
-Using Automatic Variable $(#D), but I didn't quite understand how it works
-Maybe using wildcard function, but I am a little confused about this option.
Anyways, the most tempting solution for me was the first one (using make recursively), but I found lot of comments saying that it is not recommended to use make recursively Interesting article
So I want to ask you guys some advices: How can I accomplish my objectives and have every important module in a separate folder? is recursive make the best solution? Maybe I should dive in "automake"? Or perhaps it would be better to take all the object files to a new "object" subfolder on root directory and then link them together?
By the way, I took the inspiration to make my proyect with this tree structure by sniffing Amarok source code: it has a subfolder called "src", and when you enter there, you can see a lot of subfolders: equalizer, playlist, dynamic, statusbar, core, playlistgenerator, playlistmanager, etc. And many subfolders have their own subdirectories... and the result is an incredible music player. If this method works fine to the Amarok team... I could be able to do something similar!
Any comments, feedback, suggestions and others are welcome, thanks in advance!
EDIT #1
Beta, I have some implicit rules (suffix) and a target for the linker that needs a object on my eda folder. Every other prerequisite of this target is built on the current folder.
The problem I have, is that when I run make to build that target, it takes the name of my prerequisite on "eda" folder as a target to build with the implicit rule. That's the tricky/unclean part of the makefile recursive on my proyect: I guess I must create a special implicit rule for every object file that make must search in a subfolder.
That's why I want some feedback: ¿Are there better alternatives? Or the advantages of using make recursive in my proyects overwhelm the other alternatives?
Anyways, if gives you better understanding, here is my draft Makefile (it is in spnish-english :P )
#Makefile hecho para las pruebas de los archivos dentro de esta carpeta
FLAGS=-g -DDEBUG
OUT_TI=TIndividuo
OUT_TP=TProfesor
OUT_TA=TAula
.SUFFIXES: .cpp .c .h .o
.c.o: ; cc $(FLAGS) -c $*.c
.cc.o: ; gcc $(FLAGS) -c $*.cc
.cpp.o: ; g++ $(FLAGS) -c $*.cpp
SUBDIRS=eda
.PHONY: subdirs $(SUBDIRS)
$(OUT_TI): eda/TAula.o CandidatoHorario.o TIndividuo.o TIndividuoTest.o TGen.o
g++ CandidatoHorario.o TIndividuo.o TIndividuoTest.o TGen.o eda/TAula.o -o $#
CandidatoHorario.o: CandidatoHorario.cpp CandidatoHorario.h
TIndividuoTest.o: TIndividuoTest.cpp TIndividuo.h
TIndividuo.o: TIndividuo.cpp TIndividuo.h
TGen.o: TGen.cpp
#eda/TAula.o: eda/TAula.cpp eda/TAula.h
# g++ -c eda/TAula.cpp -o $#
$(SUBDIRS):
$(MAKE) -C $#
clean:
rm -f *.o $(OUT_TI) $(OUT_TA) eda/TAula.o
The "Recursive Make Considered Harmful" is certainly a paper to read and to understand. Afterwards, your selection of tools should really be tailored to your specific projects.
For small projects that you initiate (or where you have the influence to guide high-level decisions), I would recommend spending a bit of time identifying your preferences (project layout, directory structure, unit test framework, etc.) and writing a generic set of makefiles that you will use for all your projects. You could easily end up with a generic master makefile, possibly a few more generic included makefiles for modularity (e.g. to build libraries, or unit tests or automatic dependency detection). You could also provide some extra flexibility with optional included configuration makefiles (e.g. specifying the order of your libraries). Most of the DAG construction would rely heavily on the content of your project directories. An example could look like:
include config.mk
sources := $(wildcard *.cpp)
programs := $(sources:%.cpp=%)
lib_sources := $(wildcard lib/*/*.cpp)
lib_dirs := $(sort $(patsubst %/, %, $(dir $(lib_sources:lib/%=%))))
lib_objects := $(lib_sources:lib/%.cpp=$(BUILD)/%.o)
all: $(programs:%=$(BUILD)/%)
.PRECIOUS: %/.sentinel %.d
# for dependencies on directories in build tree
%/.sentinel:
#mkdir -p $* && touch $#
clean:
$(RM) -r $(BUILD)
programs_aux:=$(programs)
include $(foreach program, $(programs), program.mk)
lib_dirs_aux:=$(lib_dirs)
include $(foreach lib_dir, $(lib_dirs), lib.mk)
# this should probably be in lib.mk
-include $(lib_objects:%.o=%.d)
The included program.mk (and lib.mk) would contain some boilerplate code to iterate over the lists of programs (and lists of libraries) and would factor out the specific parts of the makefile to build programs (and libraries).
To help with the implementation of such makefiles, you could use some standard library like http://gmsl.sourceforge.net.
This approach has several issues:
* it leads to makefiles that require strong skills
* it doesn't always scale very well to very large projects
* it relies heavily on "convention instead of configuration" and requires a clear upfront definition of the conventions that you will use (IMO this is good others might think that it lacks flexibility)
* life is too short to mess around with makefiles
Otherwise, I would suggest using higher-level configuration tools such as SCons or CMake as they tend to be conceptually simpler and they also allow other flavours of generators.

Portably Compile Entire Directory

Is there a clean/portable way to descend recursively from a given directory, compiling all found .cpp files into a single output file? I'm not sure if makefiles are capable of this sort of thing, or if it's a job for some kind of build script, but I'd like to avoid maintaining various IDEs' project files along with my code.
There are different things that you can do here. I would suggest that you use a multiplatform build system, and follow the documentation for it. I have used CMake in the past, but I wouldn't know how to tell it to compile all files in a directory.
The advantage is that the user can use CMake to generate project files for most common IDEs, so it would allow VisualStudio users to generate VS solutions, MacOSX users to generate Xcode projects, Eclipse CDK projects in pretty much any environment, Makefiles...
There's the wildcard function which can be used to match a pattern like so:
CXX_FILES = $(wildcard src/*.cpp) # All .cpp files in the directory
This is not recursive, but will at least save you from having to manually specify the files in a certain directory. The rule for building them would look something like this:
CXX_FILES = $(wildcard src/*.cpp) # All .cpp files in the directory
OBJ_FILES = $(CXX_FILES:src/%.cpp=$(OBJ_DIR)/%.o) # Corresponding .o files
# Rules
all: $(OBJ_FILES)
g++ $(OBJ_FILES) -o output_filename
$(OBJ_DIR)/%.o: src/%.cpp
g++ -c $< -o $#
Oh, and to answer your question, this method is completely portable.

Makefile for compiling a number of .cpp and .h into a lib

I am running Windows 7 with gcc/g++ under Cygwin. What would be the Makefile format (and extension, I think it's .mk?) for compiling a set of .cpp (C++ source) and .h (header) files into a static library (.dll). Say I have a variable set of files:
file1.cpp
file1.h
file2.cpp
file2.h
file3.cpp
file3.h
....
What would be the makefile format (and extension) for compiling these into a static library? (I'm very new to makefiles) What would be the fastest way to do this?
The extension would be none at all, and the file is called Makefile (or makefile) if you want GNU Make to find it automatically.
GNU Make, at least, lets you rely on certain automatic variables that alone give you control over much of the building process with C/C++ files as input. These variables include CC, CPP, CFLAGS, CPPFLAGS, CXX, CXXFLAGS, and LDFLAGS. These control the switches to the C/C++ preprocessor, compiler, and the linker (the program that in the end assembles your program) that make will use.
GNU Make also includes a lot of implicit rules designed to enable it automatically build programs from C/C++ source code, so you don't [always] have to write your own rules.
For instance, even without a makefile, if you try to run make foobar, GNU Make will attempt to first build foobar.o from foobar.c or foobar.cpp if it finds either, by invoking appropriate compiler, and then will attempt to build foobar by assembling (incl. linking) its parts from system libraries and foobar.o. In short, GNU Make knows how to build the foobar program even without a makefile being present -- thanks to implicit rules. You can see these rules by invoking make with the -p switch.
Some people like to rely on GNU Make's implicit rule database to have lean and short makefiles where only that specific to their project is specified, while some people may go as far as to disable the entire implicit rule database (using the -r switch) and have full control of the building process by specifying everything in their makefile(s). I won't comment on superiority of either strategy, rest assured both do work to some degree.
There are a lot of options you can set when building a dll, but here's a basic command that you could use if you were doing it from the command line:
gcc -shared -o mydll.dll file1.o file2.o file3.o
And here's a makefile (typically called Makefile) that will handle the whole build process:
# You will have to modify this line to list the actual files you use.
# You could set it to use all the "fileN" files that you have,
# but that's dangerous for a beginner.
FILES = file1 file2 file3
OBJECTS = $(addsuffix .o,$(FILES)) # This is "file1.o file2.o..."
# This is the rule it uses to assemble file1.o, file2.o... into mydll.dll
mydll.dll: $(OBJECTS)
gcc -shared $^ -o $# # The whitespace at the beginning of this line is a TAB.
# This is the rule it uses to compile fileN.cpp and fileN.h into fileN.o
$(OBJECTS): %.o : %.cpp %.h
g++ -c $< -o $# # Again, a TAB at the beginning.
Now to build mydll.dll, just type "make".
A couple of notes. If you just type "make" without specifying the makefile or the target (the thing to be built), Make will try to use the default makefile ("GNUMakefile", "makefile" or "Makefile") and the default target (the first one in the makefile, in this case mydll.dll).