Search code examples
c++makefilegnu-make

"No rule to make target" with % in Makefile Error


I am writing my first Makefile. In it, I want all files that have been updated in a folder called FOLDER/assets to be copied to FOLDER/export_bin/application/assets. I've been using https://makefiletutorial.com/ as a reference.

Here's the code I wrote for it:

build_game:
    $(MAKE) $(export_folder)/application/assets/%
    ...

$(export_folder)/application/assets/%: ../assets/%
    cp $@ $<

I get the error:

make[1]: *** No rule to make target 'debug/application/assets/%'.  Stop.

How should I do this instead?


Solution

  • Here you go:

    base := FOLDER
    export_folder := $(base)/export_bin
    import_folder := $(base)/assets
    input_files := $(wildcard $(import_folder)/*)
    # See https://makefiletutorial.com/#string-substitution
    output_files := $(patsubst $(import_folder)/%,$(export_folder)/application/assets/%,$(input_files))
    
    # See https://makefiletutorial.com/#phony
    .PHONY: build_game
    build_game: $(output_files)
    
    $(export_folder)/application/assets/%: $(import_folder)/%
        cp $< $@
    

    The first few lines set up the directories we will be using. The key line is the input_files assignment calling $(wildcard). (This is a GNU extension.) The tutorial you went to doesn't appear to cover this feature.

    Then we construct the output file list by substituting the import paths for the output path. The .PHONY: pseudo-target indicates that build_game is not intended to be a real file; otherwise make can get confused. We make the build_game target dependent on the output files; this triggers the rules for making the output files at the end. Finally we have the output file rule; it's essentially the same as what you used, except you swapped the $< and $@ and used a relative path, which might work but I wouldn't recommend it.