Question

I'm trying to write an etags target in make based on the dependency information generated by gcc. Is there some way of getting at all the dependencies in one go? Or, failing that, how would I write a rule that is only executed when the "tags" target is made and that passes all the source and header files to etags? I only want to index the files actually compiled (including headers). I'm aware that I can sed around in the .d files myself but I'm trying to find a more elegant and less brittle solution.

I have the following (excerpt)

DEPFILES = $(OBJFILES:.o=.d)

%.o : %.c
    @echo "Compiling $<"
    $(NO_ECHO) $(CC) $(CFLAGS) -MMD -MF $(@:.o=.d) -o $@ -c $<

%.o : %.S
    @echo "Compiling $<"
    $(NO_ECHO) $(CC) $(ASFLAGS) -MMD -MF $(@:.o=.d) -o $@ -c $<

$(TARGET) : $(OBJFILES)
    @echo "Linking $@"
    $(NO_ECHO) $(LD) $(LDFLAGS) -o $@ $(OBJFILES) $(LIBS:%=-l%)

.PHONY: clean

# Order-only dependency to make Dep/obj-directories if they are not
# present
$(OBJFILES) : | $(ALLPATHS)

$(ALLPATHS):
    $(NO_ECHO) mkdir -p $(ALLPATHS)

# Depend on the makefiles
$(OBJFILES) : $(SRC_PATH)/Makefile $(MAKECFG) $(BUILDCFG)

# Include dependency files

sinclude $(DEPFILES)

Edit : The following seems to work but I'd really like to find a more elegant solution (the double sort/uniq is just for performance).

tags : $(TARGET)
    cat $(DEPFILES) | sort | uniq | sed 's/.*:.*$$//' | tr -d '\\' | tr "\n" " " | xargs -n 1 readlink -f | sort | uniq | xargs etags -a 
Was it helpful?

Solution

I came here looking for an answer to the same thing as the original question, but went away as didn't think it was adequately answered and found a solution that doesn't require sed etc.

Below I assume a Makefile similar to the Makefile in the original question which generates dep files using the compiler and includes them.

For the compiling rule where the .d files are generated, I modified the compiler options to ask it to also make the tags target depend on the dependancies of the object file. I added -MQ $@ -MQ tags to the options. These options explicitly tell the compiler the names of the target for the dependancies.

%.o : %.c
    $(CC) $(CFLAGS) -MMD -MF $(@:.o=.d) -o $@ -c $< -MQ $@ -MQ tags

Now we don't need to explicitly give the tags target a list of dependencies, it will be generated when we compile and will be updated accordingly as the source files change. In my case I am using ctags and this is what the options are I used it with:

tags:
    ctags $^ -o $@

The $^ variable is the list of dependancies. This will be a list of source and header files as each .d file will look something like this:

main.o tags: main.c a.h b.h

Hope that helps.

OTHER TIPS

You need to create a mini tag file for each .d file and then use that to update your etags file. Note this appends stuff to the file, rather than removing and replacing, so you might need to remote the tags file occasionally (ctags has a --update option)

TAGFILES = $(OBJFILES:.o=.t)

# prune the .d files a bit to get a list of files for etags to scan
%.t: %.d
    cat $< | sed stuff > $@
    cat $@ | etags -a $@

.PHONY: tags
tags: $(TAGFILES)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top