There are lots of factors and answers tend to need lots of qualifications. With a small project you get certain situations and with larger projects other factors start to dominate.
To go fast you want to keep your computer's, or computer cluster's, processor cores as busy as possible and your storage as busy as possible with useful work. If you overload any resources, however, that can also introduce inefficiency (like RAM). The natural dependency structure of your build can be helpful for parallelism or it can block it. If the natural dependencies allow lots of jobs to be done in parallel then you can run a fast build but sometimes the recursive structure prevents this even when it is possible. There's no rule - sometimes recursive make doesn't have any big impact. You won't really notice this in a small build or in a build with few processor cores. I was one of the creators of a NON-recursive build system based on make because we read that same paper about recursive make being harmful. In some cases our system was very good at keeping the processors busy and building fast but we made a mistake (I did): The makefiles were quite big and could not be read in parallel by make and they were complicated. For this reason it took quite a long time just to generate the makefiles and for make to load the makefiles. Eventually this time was the last thing that was slow about our build. Your example is so small and the source files so small that I don't think any of these effects really matter. They might when your build gets large. Regards, Tim On Tue, 7 Mar 2023 at 06:29, ljh via Users list for the GNU implementation of make <help-make@gnu.org> wrote: > I split my project into modules, eg. main, foo. > The main module calls foo which is shared object library. > > > If I change the foo.c (not the interface foo.h), > only foo.c is compiled and foo is linked. > > > So, is not what people say a matter of project organization? > > > > > $ pwd > /home/ljh/Documents/hello_makefile_OutOfSRC/src > $ ls > foo main Makefile > $ > > > $ tree --charset C > . > |-- foo > | |-- foo.c > | |-- foo.h > | `-- Makefile > |-- main > | |-- main.c > | `-- Makefile > `-- Makefile > > > $ > > > $ make > make[1]: Entering directory > '/home/ljh/Documents/hello_makefile_OutOfSRC/src/foo' > make[1]: Nothing to be done for 'all'. > make[1]: Leaving directory > '/home/ljh/Documents/hello_makefile_OutOfSRC/src/foo' > make[1]: Entering directory > '/home/ljh/Documents/hello_makefile_OutOfSRC/src/main' > make[1]: Nothing to be done for 'all'. > make[1]: Leaving directory > '/home/ljh/Documents/hello_makefile_OutOfSRC/src/main' > $ > > > $ touch foo/foo.c > > > $ make > make[1]: Entering directory > '/home/ljh/Documents/hello_makefile_OutOfSRC/src/foo' > cc -fPIC -g -MMD -MP -c -o > /home/ljh/Documents/hello_makefile_OutOfSRC/src/build/foo/foo.o foo.c > cc -shared > -Wl,-rpath,/home/ljh/Documents/hello_makefile_OutOfSRC/src/build/bar > -Wl,-rpath,'$ORIGIN/../lib' -Wl,-soname,libfoo.so.1 -fsanitize=address > /home/ljh/Documents/hello_makefile_OutOfSRC/src/build/foo/foo.o -o > /home/ljh/Documents/hello_makefile_OutOfSRC/src/build/foo/foo > make[1]: Leaving directory > '/home/ljh/Documents/hello_makefile_OutOfSRC/src/foo' > make[1]: Entering directory > '/home/ljh/Documents/hello_makefile_OutOfSRC/src/main' > make[1]: Nothing to be done for 'all'. > make[1]: Leaving directory > '/home/ljh/Documents/hello_makefile_OutOfSRC/src/main' > $