You'reNotARobot
You'reNotARobot

Reputation: 61

Applying makefile in a nested directory and mirror that structure

I have a folder for notes called md which can have nested folders inside. I have written a python script to convert a markdown file into a html file and fix links etc. It can be invoked by running the command python3 md2html <markdown_file> <output*file>. I also made a python script which basically does a tree traversal on the md directory, and invokes this md2html program on each markdown file in this directory (ignoring other filetypes), and builds a corresponding html directory like so.

.
|-- html
|   |-- mydir
|   |   |-- one.html
|   |-- apps.html
|   |-- c_assignment.html
|   |-- ewd35.html
|-- md
|   |-- Makefile
|   |-- mydir
|   |   |-- lorem.html
|   |   |-- lorem.ms
|   |   |-- lorem.ps
|   |   `-- one.md
|   |-- apps.md
|   |-- c_assignment.md
|   |-- ewd35.md
|   |-- ewd35.pdf

I recently learned about Makefile, and to my understanding I can make it so that the md2html program is only run on md files that have been modified since the last time their corresponding html file was created. I am struggling to understand how I can write a Makefile to replicate the structure of the md directory, as it is fixed. I searched and I saw that recursive Makefiles are not a good idea so I am asking here. Thank you.

Upvotes: 0

Views: 110

Answers (1)

MadScientist
MadScientist

Reputation: 100856

To begin, you don't specify which variant of make you are using. You'll need GNU Make to be able to do this. Standard POSIX make cannot do it.

First, you need to find all the .md files. You can either list them explicitly, which means you'll need to update your makefile when you create (or delete) .md files:

MD_FILES := ./mydir/one.md ./apps.md ./c_assignment.md ./ewd35.md

Or, you can have make find them itself. If you don't want to assume anything about the data structure you can have it invoke find to do it for you:

MD_FILES := $(shell find . -name \*.md)

Next you convert those pathnames to be the ones you want to create:

HTML_ROOT := ../html
HTML_FILES := $(patsubst ./%.md,$(HTML_ROOT)/%.html,$(MD_FILES))

Now you write a target that depends on the HTML files that need to be created:

all: $(HTML_FILES)
.PHONY: all

(you can use any target you want, it doesn't have to be all... just make sure it comes as the first explicit target in the makefile).

Finally, write a pattern rule that tells make how to build one .html file from one .md file:

$(HTML_ROOT)/%.html : %.md
        mkdir -p $(@D)
        python3 md2html $< $@

See the GNU Make manual to understand what these special variables mean.

And you're done! GNU Make will figure out which .html files are outdated and run the recipe here for each one.

Upvotes: 1

Related Questions