Using GNU Make's 'define' and '$(eval)' to automate rule creation
About once a week I get an email from someone random asking a question about GNU Make. I do my best to answer and figured it might be helpful for others if I shared these questions and my answers. So, here goes. This one starts with a Princess Leia style appeal:
I stumbled across your name when googling for help on a GNUmake related problem, hope you have the time to look at it as you are my last hope. I have the following problem in my Makefile:And my reply:$(LIBDIR)/libfoo.a: $(filter $(OBJDIR)/foo/%,$(OBJECTS)) $(LIBDIR)/libbar.a: $(filter $(OBJDIR)/bar/%,$(OBJECTS)) $(LIBDIR)/libbaz.a: $(filter $(OBJDIR)/baz/%,$(OBJECTS)) $(LIBDIR)/%.a: ar -r $@ $^ ranlib $@so far, so good - it works as expected. The only problem is, that in the real world it's not just foo, bar and baz for me and I hate having to maintain the list manually. What I would like to do is something like this:$(LIBDIR)/lib%.a: $(filter $(OBJDIR)/%/%,$(OBJECTS)) ar -r $@ $^ ranlib $@but now the pattern for filter has two percentage-characters and this seem to confuse GNUmake. I tried to escape it, use $(call …), etc. but nothing really works. Do you have any trick/hint/idea how to solve this??
Thanks for your time, Best Regards,
Thanks for your mail. I can see what you are trying to do. I think the easiest way out of your predicament is as follows:# Example of manually maintained list # # $(LIBDIR)/libfoo.a: $(filter $(OBJDIR)/foo/%,$(OBJECTS)) # $(LIBDIR)/libbar.a: $(filter $(OBJDIR)/bar/%,$(OBJECTS)) # $(LIBDIR)/libbaz.a: $(filter $(OBJDIR)/baz/%,$(OBJECTS)) # # $(LIBDIR)/%.a: # ar -r $@ $^ # ranlib $@ # What you'd like to be able to do # # $(LIBDIR)/lib%.a: $(filter $(OBJDIR)/%/%,$(OBJECTS)) # ar -r $@ $^ # ranlib $@ # The following will work # # Suppose, for example: LIBDIR := lib OBJDIR := obj OBJECTS := $(OBJDIR)/foo/hello.o $(OBJDIR)/foo/bar.o $(OBJDIR)/bar/hello.o \ $(OBJDIR)/baz/bar.o # Extract the names of the first level directories underneath # $(OBJDIR) and make a unique list (sort removes duplicates) and store # that in LIBNAMES. This assumes that there are no spaces in any of # the filenames in $(OBJECTS) and that each element of $(OBJECTS) # starts with $(OBJDIR) LIBNAMES := $(sort $(foreach a,$(patsubst $(OBJDIR)/%,%,$(OBJECTS)),\ $(firstword $(subst /, ,$a)))) # The following function finds all the objects in $(OBJECTS) in a # particular directory whose name can be found in LIBNAMES. So, in # the example here doing $(call find-objects,foo) would return # obj/foo/hello.o obj/foo/bar.o find-objects = $(filter $(OBJDIR)/$1/%,$(OBJECTS)) # Now need to define the rule that handles each of the libraries # mentioned in $(LIBNAMES). This function can be used with $(eval) to # define the rule for a single directory define make-library $(LIBDIR)/lib$1.a: $(call find-objects,$1) ar -r $$@ $$^ ranlib $$@ endef # Now define the rules for all the directories found in $(LIBNAMES) $(foreach d,$(LIBNAMES),$(eval $(call make-library,$d)))You will need a version of GNU Make that supports $(eval).
'리눅스 > 스크립트/유틸' 카테고리의 다른 글
byobu detached 세션 죽이기 (0) | 2013.03.13 |
---|---|
grep sed 를 이용해 여러 파일에 있는 문자 치환하기 (0) | 2013.02.07 |
PATH 변수에서 원하는 path 빼기 (0) | 2012.10.30 |
[Makefile] 대소문자 환경 구분하기 (0) | 2012.10.20 |
[Makefile] if 문 사용하여 파일 존재 여부 확인 (0) | 2012.10.19 |