regexbashmakefile

How to extract filename without extension in Makefile


Below is my Makefile where I want to generate a PDF from an .adoc:

SHELL := /bin/bash

.DEFAULT_GOAL := all

# version and build for the target
VERSION := 1.0.0
BUILD := `git rev-parse HEAD`

# source directory
SRCDIR := ${CURDIR}/src

# create output directory
OUTDIR := ${CURDIR}/build
MAKE_OUTDIR = $(shell mkdir -p $(OUTDIR))

.PHONY: all build-html build-pdf clean

build: $(MAKE_OUTDIR) build-html build-pdf

build-html:
    @$(foreach file, $(wildcard $(SRCDIR)/*.adoc), asciidoctor \
        -r asciidoctor-diagram \
        -o $(OUTDIR)/html/$(file%.*)_$(VERSION) $(file);)

build-pdf:
    @$(foreach file, $(wildcard $(SRCDIR)/*.adoc), asciidoctor-pdf \
        -r asciidoctor-diagram \
        -o $(OUTDIR)/html/$(file%.*)_$(VERSION) $(file);)

clean:
    @rm -rf $(OUTDIR)

Problem is that the output filename is just _1_0_0 (the version)... and the base filename doesn't get extracted. What am I missing?


Solution

  • Your use of make is quite unusual. make is not a scripting language. All it does is based on product-dependencies relations. And its recipes are already shell scripts, there is no reason to use the shell make function in a recipe. Never. A more traditional way to use GNU make in your case could be something like:

    .DEFAULT_GOAL := all
    
    # version and build for the target
    VERSION := 1.0.0
    BUILD   := $(shell git rev-parse HEAD)
    
    # source directory
    SRCDIR := $(CURDIR)/src
    
    # source files
    ADOCS := $(wildcard $(SRCDIR)/*.adoc)
    
    # output directory
    OUTDIR := $(CURDIR)/build
    
    # output files
    HTMLS := $(patsubst $(SRCDIR)/%.adoc,$(OUTDIR)/html/%_$(VERSION).html,$(ADOCS))
    PDFS  := $(patsubst $(SRCDIR)/%.adoc,$(OUTDIR)/html/%_$(VERSION).pdf,$(ADOCS))
    
    .PHONY: all clean build build-html build-pdf
    
    all: build
    build: build-html build-pdf
    build-html: $(HTMLS)
    build-pdf: $(PDFS)
    
    $(HTMLS): $(OUTDIR)/html/%_$(VERSION).html: $(SRCDIR)/%.adoc | $(OUTDIR)/html
        asciidoctor -r asciidoctor-diagram -o $@ $<
    
    $(PDFS): $(OUTDIR)/html/%_$(VERSION).pdf: $(SRCDIR)/%.adoc  | $(OUTDIR)/html
        asciidoctor-pdf -r asciidoctor-diagram -o $@ $<
    
    $(OUTDIR)/html:
        mkdir -p $@
    
    clean:
        rm -rf $(OUTDIR)
    

    It is not only more traditional, it has 2 main advantages:

    1. If a target (HTML or PDF) is up to date it will not be rebuilt.
    2. If you have, say 12 cores, and you use the -j12 option of make, it will run up to 12 jobs in parallel.