Pyke
This weekend project is a small clone (most of the code is in a single file of just about 200LoC) of GNU Make with the twist that it rebuilds a target only if the hash of any of its sources changes. This is named Pyke as in Python + Make (I have no hope of being the first coming up with this name for a project).
Usage
Installation
Clone the project and then install it locally with pip.
$ git clone https://github.com/aziis98/pyke
$ cd pyke
$ pip install -e .
Files
Create a pykefile.py
in your project folder and add recipes to build your targets (for now just read below and look at the examples for the syntax).
pykefile.py
The provided globals in this file are
pikefile
is of typePikefile
and holds all the rules and handles the building of the project.rule
is a function and an alias forpikefile.rule
and is used as a decorator to define new rules.run
is just an alias foros.system
used to directly call shell commands.
.pykecache.json
This file stores the checksums of all built targets.
Examples
There are some examples in ./examples.
Simple
This example shows how the checksums approach is better in this case with respect to Make.
@rule('b.txt', ['a.txt'])
def _(target, source, sources):
run(f'head -n 3 {source} > {target}')
run(f'printf "\n" >> {target}')
@rule('c.txt', ['b.txt'])
def _(target, source, sources):
run(f'cat {source} {source} {source} > {target}')
The file b.txt
depends only on a part of a.txt
so changes to its end don't trigger the recompilation of targets that depend only on b.txt
. In this case, Make couldn't have figured that changes to the end of a.txt
don't affect b.txt
.
C
A simple example that shows a generic rule with "%
" for creating object files from the sources main.c
and util.c
and then linking them.
@rule('%.o', ['%.c'])
def _(target, source, sources):
run(f'gcc -c {source} -o {target}')
@rule('main', ['main.o', 'util.o'])
def _(target, source, sources):
run(f'gcc -o {target} {" ".join(sources)}')
Cycle
This example shows the cycle detection feature
@rule('a', ['c'])
def _(target, source, sources):
print("A")
@rule('b', ['a'])
def _(target, source, sources):
print("B")
@rule('c', ['b'])
def _(target, source, sources):
print("C")
Trying to execute pyke
for this project gives
$ pyke
[ERROR] Found dependency cycle caused by "c", aborting! Trace: ['c', 'b', 'a']
TODOs
- Move the code of
pyke.build_with_args()
directly insidebin/pike
and decouple the logging code in its own module to let the logging level be changed from the start script.