ProjFolder
\
Subfolder
sources.cpp
makefile
makefile
Subfolder is supposed to be a separate external repo, pulled in when checking out the project. When I call make all to the top-level makefile, the following recipes get executed:
all: $(NAME).elf $(NAME).s19 $(NAME).hex
$(NAME).elf: $(OBJECTS) $(LDSCRIPT) Subfolder/lib.a
make -C CppAudioPeriphs all
# echo "...linking"
$(CC) $(OBJECTS) Subfolder/lib.a $(LDFLAGS) $(LIBS) -o $#
As you can see, if the final product of Subfolder - the file lib.a is changed, the Subfolder makefile gets called in order to remake it, and then all product get linked into the final flash image.
The problem is the order. I want to always first call the sub-makefile. It knows when and how to remake lib.a. And THEN check if lib.a is modified to determine if to remake $(NAME).elf.
Here is one solution.
.PHONY all $(NAME).elf
This just instructs make to remake $(NAME).elf no matter what. I have used this solution in the past for tiny projects, but for the current one it is not acceptable.
As pointed out by MadScientist (and who better) I missed the obvious solution to this problem.
The solution is to FORCE the Subfolder/lib.a target to always be attempted. And as long as the Subfolder makefile only updates lib.a when something has changed the rest will fall out correctly.
So you want the following for your Subfolder/lib.a target. The rest can stay as-is. The trick here, as indicated before, is that you can force make to run the Subfolder/lib.a target itself but if the timestamp on Subfolder/lib.a the file doesn't change then things that list Subfolder/lib.a as a prerequisite will not need to be rebuilt.
FORCE: ;
Subfolder/lib.a: FORCE
$(MAKE) -C $(#D) target-to-build-lib.a*
You might try putting your stuff in a subfolder also (e.g. Mystuff) with its own makefile. Then you can write a top-level makefile along the lines of
all: Mystuff
Mystuff: Subfolder
Subfolder Mystuff:
${MAKE} -C $#
But then, Recursive Make Considered Harmful :)
Related
I have project and few subproject
Some of subprojects are very independent. They works without any knowledge about whole project, they are build differently and have its own Makefile. This Makefile is located in subproject root dir.
Whole subproject is built to single object file.
Is there any way to properly include such object file to main Makefile? By "properly" I mean preserving all dependencies and building this file using method in subproject Makefile.
I tried to create rule for building this object file:
path_to_subproject/some_object.o:
$(MAKE) -C path_to_subproject
But that way I cannot preserve any dependencies.
What I need is to convert all relative path in subproject Makefile and include it to main Makefile.
Another way could be telling main Makefile that some_object.o is built using different Makefile, so make should use it to check dependencies etc.
Suppose the makefile in subproject/ looks like this:
some_object.o: some_source.cc some_header.h
$(CXX) -c $< -o $# -I.
You can modify it like so:
HERE:=/full/path/to/subproject
$(HERE)/some_object.o: $(HERE)/some_source.cc $(HERE)/some_header.h
$(CXX) -c $< -o $# -I$(HERE)
This will act the same as the original when used by itself (except that you can no longer make some_object.o from subproject/, you must make /full/path/to/subproject/some_object.o-- that can be fixed, but you must make a design decision or two).
Now you can add a line to the bottom of the master makefile:
include path_to_subproject/Makefile
and then the master makefile can use that object:
some_executable: local_object.o /full/path/to/subproject/some_object.o
whatever
More sophisticated variations are possible, once you have this working.
I am learning how to set up makefiles, and have ran into a problem. To demonstrate this I have created a simple "project" consisting of source files main.m and test.m.
I am trying to setup make to compile these files (only if somethings changed), and store the object files in somewhere else (here build/)
My Makefile:
OBJ = ./build
SOURCES=main.m test.m
OBJECTS=$(addprefix $(OBJ)/,$(SOURCES:.m=.o))
EXECUTABLE=test
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
gcc $(OBJECTS) -o $(EXECUTABLE)
$(OBJECTS): $(OBJ)/%.o: %.m build/
gcc -c $< -o $#
build/:
mkdir build
When I run it for the first time (with only the Makefile and the sources in the current directory) it does what I expect it to do:
gcc -c main.m -o build/main.o
gcc -c test.m -o build/test.o
gcc ./build/main.o ./build/test.o -o test
However if I run make again:
gcc -c main.m -o build/main.o
gcc ./build/main.o ./build/test.o -o test
What have I done wrong? Also noting any other errors in the Makefile is appreciated, as I am trying to learn to create "good" Makefiles.
EDIT:
What I spotted from make -d:
Finished prerequisites of target file `build/main.o'.
Prerequisite `main.m' is older than target `build/main.o'.
Prerequisite `build/' is older than target `build/main.o'.
No need to remake target `build/main.o'.
and
Finished prerequisites of target file `build/test.o'.
Prerequisite `test.m' is older than target `build/test.o'.
Prerequisite `build/' is newer than target `build/test.o'.
Must remake target `build/test.o'.
Your make -d output shows that make thinks your build directory has been updated, and so that file needs to be rebuilt.
I guess that happens because some operation either on your build system's part or by something else in your filesystem is causing some timestamp on that directory to be updated.
You can fix the problem by making build an order-only prerequisite by adding a | to that rule:
$(OBJECTS): $(OBJ)/%.o: %.m | build
I deleted the / too, since it wasn't doing anything.
Since you asked, some other editorial notes:
Add a clean target. Something like:
clean:
rm -rf $(EXECUTABLE) $(OBJ)
You don't need the ./ when you set OBJ. Just OBJ = build is enough.
You don't need the / on build as mentioned above. But that doesn't really matter, since you shouldn't be referring it to it anyway. Repalce build with $(OBJ) wherever you see it.
mkdir will fail if the directory already exists. You probably should prefix that command with a -:
$(OBJ):
-mkdir $(OBJ)
Note that I've done the replacement with $(OBJ) that I mentioned in #3 above.
Auto-generation of dependencies is very helpful. Your project as shown isn't big enough to really need it, but it's easy enough to add, so why not. You'll need to do a couple of things. First, get the appropriate dependency file names:
DEPFILES = $(addprefix $(OBJ)/,$(SOURCES:.m=.d))
Then get the compiler to generate them by adding the -MMD flag:
gcc -MMD -c $< -o $#
Lastly, include them in your makefile if they're available, by adding a line at the end of your makefile:
-include $(DEPFILES)
So, I'm trying to understand makefiles. At this moment I have a project with some modules, which are more or less non-dependent on each others.
My directory tree is like this:
root/
- Source/ <-- referenced as $(INPUTPATH)
- Build/ <-- referenced as $(BUILDPATH)
- Release/ <-- referenced as $(OUTPUTPATH)
- Makefile
I want to have the source (.cpp/.h) on the Source/, the objects on the Build/, and the executable on the Release/*.
So, my idea was to have several different targets, and use them like this:
all: maps auxiliars methods
#echo "linking...";\
$(CC) $(CFLAGS) $(OBJS) $(CLIBS) -o ${OUTPUTPATH}/MainProgram
dependency1: $(INPUTPATH)/foo.cpp
#echo "compiling ArbPrecision...";\
cd ${BUILDPATH};\
$(CC) $(CFLAGS) $(CINCLUDE) -c ../$?
dependency2: dependency1 $(INPUTPATH)/bar.cpp
#echo "compiling saddleConstructor...";\
cd ${BUILDPATH};\
$(CC) $(CFLAGS) $(CINCLUDE) -c ../$(INPUTPATH)/bar.cpp
maps: dependency2 $(INPUTPATH)/*Map.cpp
#echo "compiling maps...";\
cd ${BUILDPATH};\
$(CC) $(CFLAGS) $(CINCLUDE) -c ../$(INPUTPATH)/*Map.cpp
... (auxiliars and methods)
The $CINCLUDE and CFLAGS are just compiler stuff like headers and external libs.
Everything works almost perfect: on every target, it asks for other target's dependencies, and for the *cpp on the source. If this does not exist, it calls the target and compiles the *cpp. The executable is created without errors.
However, if I call the "make" twice, the time it takes to compile is the same for the first and second time, even if I don't make any changes on the source. So, apparently, I'm not putting the dependencies right.
Can anyone point me the right direction to perform this compilation? I'm doing something wrong and I'm not getting what it is.
Thanks,
Jorge
Make expects to operate off of files. For each rule, it checks to see if the target file named by that rule (1) exists and (2) is up to date (i.e., modified after any of its dependencies). If the file is not up to date, then it executes the rule to bring it up to date.
Therefore, as your makefile is currently written, when you run make, Make does the following:
all is the first rule, so if you don't specify any arguments, make processes the all rule.
No file named all exists, so the all rule needs to be executed.
all depends on the dependency1 rule. No file named dependency1 exists, so the dependency1 rule needs to be executed.
dependency1 depends on the dependency2 rule. No file named dependency2 exists, so the dependency2 rule needs to be executed.
What you instead want is something similar to the following:
OBJS := foo.o bar.o Map.o
all: $(OUTPUTPATH)/MainProgram
$(OUTPUTPATH)/MainProgram: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) $(CLIBS) -o $(OUTPUTPATH)/MainProgram
%.o: %.cpp
$(CC) $(CFLAGS) $(CINCLUDE) $< -c $#
.PHONY: all
Note the following:
Since Make operates on files, rules' targets and dependencies are listed by filename wherever possible.
Rather than listing the .cpp files individually, an pattern rule is used to build each .o file. Within the pattern rule, the $< and $# automatic variables are used to specify the first prerequisite (file) and the target (file), respectively.
Make echoes its commands by default, so there's no need to echo yourself.
For GNU Make, all is listed as a phony target, to keep Make from looking for a file named all.
Actually i have a library 'cryptopp' and what i want is that when i make any change to a file and issue the make command it should take care of the changes made in any file in the source directory. well, the GNUMakefile of cryptoopp takes care of the changes 'if' made in the '.cpp' files but not for the changes made in a '.h' file.
So what changes can i make in the 'GNUMakefile' of cryptopp so that it looks at all the modified header files and recompiles all the files dependent on the 'modified' header file.
If you are building with g++ you can let g++ generate dependancy makefiles.
You can include these in your main makefile.
Use the -M and -M* arguments to use this feature. (see http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Preprocessor-Options.html#Preprocessor-Options)
You have to add all the dependencies to your Makefile:
mycode.o: mycode.cpp mycode.h somelib.h resources.h
$(CXX) -c -o $# $< $(CXXFLAGS) $(INCLUDES)
If you already have a generic pattern matching command line, you don't have to say the command again, you can just list the dependencies:
%o: %.cpp
$(CXX) -c -o $# $< $(CXXFLAGS) $(INCLUDES)
mycode.o: mycode.cpp mycode.h somelib.h resources.h
yourcode.o: yourcode.cpp yourcode.h mycode.h somethingelse.h
# ...
In general, this is a terrible and unscalable mess. You'll almost definitely want a higher-level build system to generate the Makefile for you. Even for very small projects keeping the header dependencies up to date in the Makefile is such a pain that it is simply not worth it.
There are several popular portable build environments. I personally like cmake a lot, which includes discovery if you changed the build settings (say from Debug to Release) and will always build all the necessary files (for example, if you change the cmake master file and type "make" it'll automatically run cmake again for you first).
For a Unix-only solution you could try makedepend, or the infamous autotools, though that's a whole other headache...
You might try 'makedepend' if it's installed on your system. The easiest way is to add a target to your makefile. Something like:
depend:
makedepend *.cc
You might have to replace the '*.cc' with a list of your source files. Then you can regenerate all the dependencies with 'make depend' command. You might want to redirect error messages to /dev/null since it always seems to generate a lot of noise.
I've followed the instructions online to set up gcc (actually g++) to generate .d files for dependencies, and now my makefile looks something like this:
CPPFLAGS := ... -MMD -MP
...
OBJECTS := $(shell find *.cpp *.s | sed -e 's/\.cpp/\.o/' -e 's/\.s/\.o/')
all: setupdir $(OBJECTS) link image
And then at the end of the file:
-include $(pathsubst %.d,obj/%.d,$(OBJECTS:.o=.d))
The .d files are being correctly generated, and all show up in the obj directory. The problem is, now, even with the assembly files that don't have .d files generated for them the entire source tree is being rebuilt every time I run make. The project doesn't take long to compile, but still, how would one go about fixing it so that make runs correctly?
It's important to note that -M is not magic bullet for dependencies, in many cases you'll need to specify certain headers so things are re-built appropriately if they change. In fact, the most common problem with letting gcc handle dependencies is things not being re-built that should be (broadly depending on the version of GCC being used by whoever runs make).
That being said, I don't see anything blatantly wrong with what you're doing.
What I recommend doing is eliminating the shell tricks, since it's quite easy to specify exactly what you want. E.g.
foo_SOURCES = \
src/foo.cpp \
src/bar.cpp
foo_OBJECTS = $(foo_SOURCES:.cpp=.o)
foo_DEPS = $(foo_OBJECTS:.o=.d)
%.o : %.cpp
$(CC) $(CFLAGS) ... $< -o $#
$(CC) -M $< > $(#.o=.d)
# lots more rules and targets here
# and finally, at the bottom:
-include $(foo_DEPS)
This is off the top of my head in meta form, so check it to be sure. I believe your problem is actually the dependencies not being included, but I don't see anything obviously wrong with the way you are using pathsubst.
As people have noted in comments, running make with debug on may be helpful, but a good first step would be to specify your objects and dependencies without talking to the shell.
If you get that working, try just storing the results of your shell calls and echoing them to the screen. That's a lot less noisy than make's debug output.