Если временные файлы создаются в текущем рабочем каталоге, вы можете использовать подкаталоги (не очень, но редко):
sources = a.xxx b.xxx c.xxx
target = program
all : $(target)
$(target) : $(patsubst %.xxx,%.o,$(sources))
$(CXX) -o $@ $<
%.o : %.cpp
$(CXX) -c -o $@ $<
%.cpp : %.xxx
mkdir $@.d
s=`realpath $<` && cd $@.d && my-pre-processor -o ../$@ "$${s}" || { $(RM) -r $@.d && false; }
$(RM) -r $@.d
Кроме того, поскольку вы используете синтаксис, но не функции, которые доступны исключительно для GNU make, обратите внимание, что следующий эквивалентный Makefile должен быть более переносимым
sources = a.xxx b.xxx c.xxx
target = program
all : $(target)
$(target) : $(sources:.xxx=.o)
$(CXX) -o $@ $<
.cpp.o:
$(CXX) -c -o $@ $<
.xxx.cpp:
mkdir $@.d
s=`realpath $<` && cd $@.d && my-pre-processor -o ../$@ "$${s}" || { $(RM) -r $@.d && false; }
$(RM) -r $@.d
.PHONY: all
.SUFFIXES: .xxx .cpp .o
Также обратите внимание, что встроенное правило GNU make .cpp.o:
позволяет пользователям указывать флаги в командной строке (аналогично)
.cpp.o:
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
, что может понравиться вашим пользователям, когда им нужно предоставить, скажем, пользовательские каталоги включения через -L...