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' $