paavaanan
paavaanan

Reputation: 49

make - stripping unused files

In my current project, more than 200MB C files are present. While making targets I can able to see only < 100MB is used to create a binary. How, to identify what are the files are not touched while creating targets. So, that we can strip it off and make the codebase more sleek.

How, to identify the list of files created for target while compiling?

Upvotes: 2

Views: 610

Answers (4)

reinierpost
reinierpost

Reputation: 8611

I think the best approach is to use one of the methods Linux offers for monitoring file system access:

  1. inotifywait
  2. kfsmd
  3. loggerfs
  4. auditd / auditctl / ausearch

You could also run the make command with strace (strace -f make) and parse the output for open() calls. That is what I used to do in the past.

Take your pick.

Upvotes: 1

Mike Kinghan
Mike Kinghan

Reputation: 61630

If your make is GNU make, as seems likely, you could consider variations on the following approach. (For simplicity I'll assume that the only source files of interest are .c files.)

Say we have Makefile in directory dir that makes some default target and possibly others, including intermediate targets.

You can use another makefile, say, unused_srcs.mk that you include in Makefile, such that in dir you can run:

make unused_srcs

which will display a list of all the source files in dir that don't contribute to the default target. Or run:

make unused_srcs target=TARG

for some target TARG, and get a list of all the source files in dir that don't contribute to TARG.

This assumes that Makefile has a clean target, or maybe several variants of clean[-???], that can suitably clean the default target or any target you might be interested in, and that you don't mind a suitable clean[-???] being invoked for the unused_srcs target.

For example, in dir we have:

main.c

extern void boo(void);

int main(void)
{
    boo();
    return 0;
}

boo.c

#include <stdio.h>

void boo(void)
{
    puts("Boo!");
}

noop.c

void noop(void){}

Makefile

.phony: all clean

all: boo

objs = main.o boo.o

boo: $(objs)
    gcc -o $@ $^

clean-obj:
    rm -f *.o

clean: clean-obj
    rm -f boo

# include /some/standard/place/unused_srcs.mk
include unused_srcs.mk

And in some standard place which, for simplicity, we'll assume is again dir, we have:

unused_srcs.mk

.phony: unused_srcs

ifndef $(target)
target = all
endif

ifndef $(cleaner)
cleaner = clean
endif

all_srcs = $(wildcard *.c)
used_srcs = $(filter %.c,$(shell ($(MAKE) $(cleaner) && $(MAKE) -n -d $(target)) \
    | grep -e 'Considering target file' | sed -e "s/[\`\']//g" -e "s/\.$$//g" -))
unused_srcs = $(filter-out $(used_srcs),$(all_srcs))

unused_srcs:
    @echo $(unused_srcs)

In this project:-

  • noop.c is unused by boo (it is completely superfluous)
  • noop.c and main.c are unused by boo.o
  • noop.c and boo.c are unused by main.o

And we can discover such facts with make unused_srcs commands:

$ make unused_srcs
noop.c
$ make unused_srcs target=boo
noop.c
$ make unused_srcs target=boo.o
main.c noop.c
$ make unused_srcs cleaner=clean-obj target=boo.o
main.c noop.c
$ make unused_srcs target=main.o
boo.c noop.c
$ make unused_srcs target=clean
boo.c main.c noop.c

Clearly all the heavy-lifting is done in the evaluation of $(used_srcs) and $(unused_srcs) in unused_srcs.mk, and mostly the former.

The evaluation of $(used_srcs) exploits GNU make's -d option, which generates fulsome debugging info, together with the fact that any source file that does contribute to the chosen TARG must itself be considered a potential target when TARG is made.

Together, these things mean that if we clean TARG and then run make -n -d TARG the output will be the debugging info of a dry-run (-n) of make TARG, and in this output a line like:

Considering target file `FILE.c'.

will appear for each .c file FILE.c that contributes to TARG, and for no other .c files that may be present.

The evaluation of $(used_srcs) generates that debugging info and filters it to extract the names of the .c files.

The evaluating of $(unused_srcs) then just weeds out the $(used_srcs) from the list of all the .c files there are.

Upvotes: 0

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136525

Another method is to open the (autogenerated) dependency files for you executables and shared libraries. They are going to contain .o as prerequisites, which normally correspond to .c.

This works best for non-recursive make build systems with complete dependency trees.

Upvotes: 0

unwind
unwind

Reputation: 400159

I would probably:

  1. make clean
  2. make 2>out to capture the full log of the build to a file
  3. grepthe out file for gcc invocations
  4. Filter out the filenames from the gcc invocations
  5. Build a sorted list of those filenames
  6. Build a sorted list of filenames in the project.
  7. Compare the two.

Or something like that. Shouldn't be too hard.

Upvotes: 1

Related Questions