Search code examples
makefilegnu-make

How can I define a dependency in Make if all files reside in different folders but with similar structure (language dependent)?


I want to use the tool msgfmt in a makefile to generate .mo files from .po sources. The .po sources are per language and reside in a folder structure like this:

$(projectpath)/locale/de/LC_MESSAGES
$(projectpath)/locale/fr/LC_MESSAGES
$(projectpath)/locale/en/LC_MESSAGES

The generated .mo files shall reside in a similar folder structure:

$(buildpath)/locale/de/LC_MESSAGES
$(buildpath)/locale/fr/LC_MESSAGES
$(buildpath)/locale/en/LC_MESSAGES

In the makefile, I have successfully created 2 variables for the sources and the targets:

PO_FILES := $(wildcard $(projectpath)/locale/*/LC_MESSAGES/*.po)
MO_FILES := $(subst $(projectpath)/locale/,$(buildpath)/locale/,$(subst .po,.mo,$(PO_FILES)))

and I am also able to create the target directories for the MO_FILES.

DIRS := $(sort $(dir $(MO_FILES)))

However, I am failing when defining the dependency to trigger the generation.

The following options didn't work:

%.mo:%.po
$(buildpath)/locale/%/LC_MESSAGES/%.mo: $(projectpath)/locale/%/LC_MESSAGES/%.po

I also tried a few other combination with same result. Make claims that it has no rule to make the target.


Solution

  • You would either have to write the mo:po rule for each locale, or use some GNU make magic with call/eval to create the rules with a loop:

    buildpath   := buildpath
    projectpath := projectpath
    locales     := de en fr
    PO_FILES    := $(wildcard $(projectpath)/locale/*/LC_MESSAGES/*.po)
    MO_FILES    := $(subst $(projectpath)/locale/,$(buildpath)/locale/,$(subst .po,.mo,$(PO_FILES)))
    
    all: $(MO_FILES)
    
    define PROGRAM_template =
    $(buildpath)/locale/$(1)/LC_MESSAGES/%.mo: $(projectpath)/locale/$(1)/LC_MESSAGES/%.po
            @echo cp $$< $$@
    endef
    
    $(foreach l,$(locales),$(eval $(call PROGRAM_template,$(l))))
    

    If I run "make" with this, this is what happens:

    cp projectpath/locale/de/LC_MESSAGES/x.po buildpath/locale/de/LC_MESSAGES/x.mo
    cp projectpath/locale/en/LC_MESSAGES/x.po buildpath/locale/en/LC_MESSAGES/x.mo
    cp projectpath/locale/en/LC_MESSAGES/y.po buildpath/locale/en/LC_MESSAGES/y.mo
    cp projectpath/locale/en/LC_MESSAGES/z.po buildpath/locale/en/LC_MESSAGES/z.mo
    cp projectpath/locale/fr/LC_MESSAGES/x.po buildpath/locale/fr/LC_MESSAGES/x.mo
    

    This is pretty much straight out of the GNU make manual, https://www.gnu.org/software/make/manual/make.html#Eval-Function