Search code examples
makefilegtk

How to define the following make rule properly?


I would like to use a make file to generate a gresource file containing templates for my GTK project. I plan to use Blueprints to generate the necessary XML files and then automatically generate the gresource file based on that. To do that I wrote the following make file:

BP_SOURCE_DIR = mpyd-ui/bp
GRESOURCE_DIR = org/navi/mpyd
GRESOURCE_FILE = mpyd.gresource.xml
GRESOURCE_PREFIX = /org/navi/mpyd


COMPILED_BP_DIR = $(GRESOURCE_DIR)/templates
GRESOURCE   = $(subst .xml,,$(GRESOURCE_FILE))
BP_SOURCES  = $(notdir $(shell find $(BP_SOURCE_DIR) -name '*.bp'))     # window.bp player_controls.bp
COMPILED_BP = $(notdir $(BP_SOURCES:.bp=.ui))                           # window.ui player_controls.ui


gresource: $(COMPILED_BP)
    python3 generate_g_resources.py                 \
        $(GRESOURCE_FILE)                           \
        $(GRESOURCE_DIR)                            \
        $(GRESOURCE_PREFIX)                         \
        $(subst $(GRESOURCE_DIR)/,,$(COMPILED_BP))


%.ui: %.bp
    blueprint-compiler compile --output $(COMPILED_BP_DIR)/$@ $(BP_SOURCE_DIR)/$<


.PHONY: all
all: dirs gresource


.PHONY: clean
clean:
    rm -r $(GRESOURCE_DIR)  ||:
    rm $(GRESOURCE_FILE)    ||:
    rm $(GRESOURCE)         ||:


.PHONY: dirs
dirs:
    @echo $(COMPILED_BP)    # window.ui player_controls.ui
    @echo $(BP_SOURCES)     # window.bp player_controls.bp
    mkdir -p $(GRESOURCE_DIR)
    mkdir -p $(COMPILED_BP_DIR)

Unfortunately, this does not work and throws the following error:

make: *** No rule to make target „window.ui“, 
  needed by „gresource“. Stop.

This is confusing to me because I thought that the rule

%.ui: %.bp
    blueprint-compiler compile --output $(COMPILED_BP_DIR)/$@ $(BP_SOURCE_DIR)/$<

would define how to make any file ending in .ui from a .bp with the same stem. What am doing wrong?

This is my folder structure, in case it has something to do with the error:

.
├── generate_g_resources.py
├── Makefile
├── mpyd-ui
│   ├── bp
│   │   ├── player_controls.bp
│   │   └── window.bp


Solution

  • You have this:

    BP_SOURCES  = $(notdir $(shell find $(BP_SOURCE_DIR) -name '*.bp'))
    COMPILED_BP = $(notdir $(BP_SOURCES:.bp=.ui))
    

    So if you find, for example a file mpyd-ui/bp/foobar.bp then BP_SOURCES will be set to foobar.bp because you take the notdir of the files. Then COMPILED_BP will bet set to foobar.ui (I don't know why you have another notdir since you already ran it on BP_SOURCES).

    So make will try to build a file foobar.ui and it will see that your pattern rule matches the target pattern: %.ui with a stem of foobar.

    So then it replaces the stem in the prerequisite pattern %.bp and gets foobar.bp. Then make looks for the file foobar.bp but it doesn't exist (the file is named mpyd-ui/bp/foobar.bp, which is not the same as foobar.bp). Also, make will try to build that target and it will not find any rules that can build it. So, that pattern rule doesn't match and make ignores it and looks for another one.

    Since no other pattern rule matches, make gives up and tells you there's no rule to make the target.

    Basically, the problem is that by adding the notdir to your variables you are removing the ability of make to find your source files.

    One way to solve this is to use VPATH to tell make where to look for source files, like this:

    BP_SOURCES  := $(shell find $(BP_SOURCE_DIR) -name '*.bp')
    COMPILED_BP := $(notdir $(BP_SOURCES:.bp=.ui))
    
    VPATH := $(sort $(dir $(BP_SOURCES))