makefilecross-compilinggnu-makeexpansiongdkpixbuf

Secondary expansion and two makefiles


I have a command with two dollar signs (secondary expansion)

$(PREFIX)/bin/gdk-pixbuf-query-loaders > $(shell $(PREFIX)/bin/gdk-pixbuf-query-loaders | awk -F "=" '/LoaderDir/ {print $$2}' | tr -d ' ')/../loaders.cache

The shell command should extract a path from the following output:

...
# LoaderDir = /home/redux/x-libs/i686-nptl-linux-gnu/lib/gdk-pixbuf-2.0/2.10.0/loaders
...

When I run make then the rule expands to the following command:

/home/redux/x-libs/i686-nptl-linux-gnu/bin/gdk-pixbuf-query-loaders > /home/redux/x-libs/i686-nptl-linux-gnu/lib/gdk-pixbuf-2.0/2.10.0/loaders/../loaders.cache

That's OK, but if I use a second makefile that starts the first one, then the rule expands to

/home/redux/x-libs/i686-nptl-linux-gnu/bin/gdk-pixbuf-query-loaders > /../loaders.cache

and an error occures:

/bin/sh: 11: cannot create /../loaders.cache: Permission denied

The command to start the first makefile from the second makefile is as follows:

$(MAKE) -f $(makefile_path)/build_libs_for_host.mk .print_and_write_triplets $(RULES) JOBS=$(JOBS) HOST=$(patsubst build_host_%,%,$@)

And the command (in bash) to start the second makefile (that starts the first one I created) is:

time make -f ~/_dev/_pro/second.mk all RULES=build_gdk_pixbuf JOBS=-j4 |& tee ~/log_20170221_x-libs.txt

Both makefiles use .SECONDEXPANSION:. I can't see the mistake.

Now I'm stuck. What's wrong with this expansion?

GNU make has some magic rules and maybe I have to add a parameter to the $(MAKE) line?


Solution

  • I found a solution. My full rule is too complex so I post simplified code to explain my solution.

    First we have a rule that creates a folder and uses $(shell ...) in the same command:

    all:
        mkdir -p $(PREFIX) && \
        cd $(PREFIX) && \
        cat $(PREFIX)/../$(INPUT) > $(shell cat $(PREFIX)/../$(INPUT) | awk -F "=" '/LoaderDir/ {print $$2}' | tr -d ' ')/./loaders.cache
        touch $@
        @echo [DONE]
    

    This can fail, if the folder was not created before. In that case $(shell ...) will expand to an empty string. And the cat command will fail. We see here that this is not an expansion problem. It's a timing problem.

    The solution is to break this rule into two parts:

    all_pass1:
        mkdir -p $(PREFIX) && \
        touch $@
        @echo [DONE]
    
    all_pass2: all_pass1
        cd $(PREFIX) && \
        cat $(PREFIX)/../$(INPUT) > $(shell cat $(PREFIX)/../$(INPUT) | awk -F "=" '/LoaderDir/ {print $$2}' | tr -d ' ')/./loaders.cache
        touch $@
        @echo [DONE]
    

    Ok I have a solution. But I wonder why my first makefile worked and the second that started the first fail. And that's the reason why I posted this problem. That still seems to me like some GNU make magic.

    For me it's solved, but feel free to comment or present a better solution, if you think there is a better one.