gtSasha
gtSasha

Reputation: 125

Make target depend on optional files in GNU make

I have a simple Makefile that generates protobuf stubs from .proto files.

PROTOC := protoc.exe
PYTHON := python

NANOPB_GEN := ../lib/generator/
NANOPB_PROTO := $(NANOPB_GEN)proto 
NANOPB_SCRIPT := $(NANOPB_GEN)nanopb_generator.py
CPP_PATH := ../../Firmware/protobuf/
CS_PATH := ../../Console/Networking/DataExchange/

SRCS := $(wildcard *.proto)
CPP_TARGETS := $(patsubst %.proto, $(CPP_PATH)%.pb.cpp, $(SRCS))
CS_TARGETS := $(patsubst %.proto, $(CS_PATH)%.cs, $(SRCS))

$(CPP_PATH)%.pb.cpp: %.proto
    $(PYTHON) $(NANOPB_GEN) -H .h -S .cpp -D $(CPP_PATH) --strip-path $< 

$(CS_PATH)%.cs: %.proto
    $(PROTOC) -I./ -I=$(NANOPB_GEN) -I=$(NANOPB_PROTO) --csharp_out=$(CS_PATH) $<

all: cpp cs
    @echo "making all"

cpp: $(CPP_TARGETS)
    @echo "generating C++ stubs"

cs: $(CS_TARGETS)
    @echo "generating C# stubs"

It works fine, but I also want the makefile to rebuild the stubs if a corresponding .options file changes in addition to the .proto file. For instance, Tag.proto may have an optional Tag.options file that nanopb generator expects. I want to modify the Makefile to rebuild the stubs if .options file changes, but also works if there is no .options file.

I tried this rule:

$(CPP_PATH)%.pb.cpp: %.proto $$(patsubst %.proto, %.options, $$<)

However, this does not handle .proto files that don't have the corresponding *.options file.

Err:

make: *** No rule to make target ../../Firmware/protobuf/Tag.pb.cpp', needed by cpp'. Stop.

How can I define a rule that can use .options ?

Thank you!

Upvotes: 0

Views: 152

Answers (1)

raspy
raspy

Reputation: 4271

I think the easiest way would be to use wildcard function, that will only take a file into account if it exists. The only tricky thing is that you cannot use % within secondary expanded part, but you can use $$* instead, which will expand to the tested stem, i.e.:

$ cat Makefile
.SECONDEXPANSION:
%.pb.cpp: %.proto $$(wildcard $$*.options)
        echo $^ > $@

This will handle both options when the .options file exists or not, e.g.:

$ touch foo.proto bar.proto bar.options
$ make foo.pb.cpp
echo foo.proto > foo.pb.cpp
$ make bar.pb.cpp
echo bar.proto bar.options > bar.pb.cpp

This will also rebuild if .options file gets changed:

$ make bar.pb.cpp
make: 'bar.pb.cpp' is up to date.
$ touch bar.options
$ make bar.pb.cpp
echo bar.proto bar.options > bar.pb.cpp

Upvotes: 1

Related Questions