Yes.
Start with just the top-level main program.
Compile/Link it and get the list of unsatisfied references.
For each of the unsatisfied references, add the file containing it.
Repeat these two steps until there are no more unsatisfied references.
This removes all files not needed for a clean build.
Yes, it is a lot of work. Things are not always easy.
If you want to know what's not needed for a run with particular input,
for that you need a coverage tool such as gcov.
Routines that are not used will show a coverage count of 0.
Then if you really want to get rid of them,
extract them into separate source files so you can exclude them, and make sure they are not called.