Emacs Lisp. Following are simple elisp functions I use to compile a C file, nothing extraordinary:
(defun my-c-save-compile ()
"Save, and compile c file."
(interactive)
(save-buffer)
(compile
(format "cc -Wall -Wextra -pedantic -std=c11 -g %s -o ./bin/%s"
(buffer-file-name)
(file-name-base (buffer-file-name)))))
(defun my-c-run ()
"Run c code."
(interactive)
(compile (format "./bin/%s"
(file-name-base (buffer-file-name)))))
Another reason I don't use Makefiles more often could be, the Bourne Again Shell. I find it easier to quickly write shell aliases for repetitive tasks. The following is some aliases I sometimes use whenever I'm doing Django development:
#!/bin/sh
# my weird aliases
alias djo_runserver="python manage.py runserver"
alias djo_shell="python manage.py shell"
alias djo_shellp="python manage.py shell_plus"
alias djo_make="python manage.py makemigrations"
alias djo_mig="python manage.py migrate"
alias djo_csu="python manage.py createsuperuser"
alias djo_smtpd="python -m smtpd -n -c DebuggingServer localhost:1025"
Make do have a reputation for being complex. Indeed, it can be very esoteric. The full manual is a 183 pages. Fortunately, you can ignore most of this, Make can be used in a very simple and incredibly useful way.
The following, is a Makefile I sometimes use in replacement of the shell aliases above:
# Makefile for (the project)
#
# Nsukami
# November 2016
SHELL := /bin/sh
PROJECT := tas
PYTHON_BIN := $(VIRTUAL_ENV)/bin
DEV_SETTINGS = $(PROJECT).settings.dev
PROD_SETTINGS = $(PROJECT).settings.prod
TEST_SETTINGS = $(PROJECT).settings.test
BASE_DIR = $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
PMP = python manage.py
# if not on prod server, use dev settings
ifneq ($(shell uname -n),phobos)
SETTINGS = $(DEV_SETTINGS)
else
SETTINGS = $(PROD_SETTINGS)
endif
# target: all - Default target. Does nothing.
all:
@echo "Nothing to do by default. Try 'make help'"
# target: help - Show list of targets + description
help:
@egrep "^# target:" [Mm]akefile
# target: init - Install that a dev needs to get up and running.
init: bootstrap.sh
cd $(BASE_DIR) && sudo ./bootstrap.sh
# target: clean - remove all useless files
clean: clean-pyc clean-build
# target: clean-pyc - remove all auto generated files
clean-pyc:
find . -name '*.pyc' -exec rm --force {} +
find . -name '*.pyo' -exec rm --force {} +
find . -name '*~' -exec rm --force {} +
# target: clean-build - remove all auto generated folders
clean-build:
-rm --force --recursive build/
-rm --force --recursive dist/
-rm --force --recursive htmlcov
-rm --force --recursive .coverage
-rm --force --recursive *.egg-info
# target: translate - calls the "makemessages" django command
translate:
cd $(BASE_DIR) && $(PMP) makemessages --settings=$(SETTINGS) -a
# target: test - calls the "test" django command
test:
$(PMP) test --settings=$(TEST_SETTINGS)
# target: run - calls the "runserver" django command
run:
$(PMP) runserver --settings=$(SETTINGS)
# target: update - install (and update) pip requirements
update:
pip install -U -r $(BASE_DIR)/requirements/dev.txt
# target: collect - calls the "collectstatic" django command
collect:
$(PMP) collectstatic --settings=$(SETTINGS) --noinput
# target: rebuild - rebuild tables from models
rebuild:
$(PMP) makemigrations --settings=$(SETTINGS)
$(PMP) migrate --settings=$(SETTINGS)
# target: deploy - let make take care of deployment
deploy:
# Should I call fabric here?
.ONESHELL:
.PHONY: all help translate test clean update collect rebuild run clean-pyc clean-build clean init
Finally, the other reason, and probably the main reason I don't use Makefiles more often, it's because of Fabric. Following is a fabfile more or less doing the same thing as the Makefile above:
#!/usr/bin/env python
# -*- coding: utf-8 -*- #
""" fabric commands """
from fabric.api import env, sudo, cd, local, task, run
import fabric.contrib.project as project
import os
# Local path configuration (can be absolute or relative to fabfile)
env.hosts = ['localhost']
env.use_ssh_config = True
env.ssh_config_path = '/home/nsukami/.ssh/config'
env.owner = 'nsukami'
PROJECT = "tas"
DEV_SETTINGS = PROJECT + ".settings.dev"
PROD_SETTINGS = PROJECT + ".settings.prod"
TEST_SETTINGS = PROJECT + ".settings.test"
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
PMP = "python manage.py "
def uname():
""" Prints information about the host. """
local("uname -n")
if uname() is not "phobos":
SETTINGS = DEV_SETTINGS
else:
SETTINGS = PROD_SETTINGS
@task
def init():
"init - Install that a dev needs to get up and running."
with cd(BASE_DIR):
sudo("./bootstrap.sh")
@task
def clean():
"clean - remove all useless files"
clean_pyc()
clean_build()
def clean_pyc():
"# clean-pyc - remove all auto generated files"
local("find . -name '*.pyc' -exec rm --force {} +")
local("find . -name '*.pyo' -exec rm --force {} +")
local("find . -name '*~' -exec rm --force {} +")
def clean_build():
"clean-build - remove all auto generated folders"
local("rm --force --recursive build")
local("rm --force --recursive dist")
local("rm --force --recursive htmlcov")
local("rm --force --recursive .coverage")
local("rm --force --recursive *.egg-info")
@task
def translate():
"translate - calls the 'makemessages' django command"
with cd(BASE_DIR):
cmd = PMP + "makemessages --settings={} -a".format(SETTINGS)
local(cmd)
@task
def test():
"test - calls the 'test' django command"
cmd = PMP + "test --settings={}".format(SETTINGS)
local(cmd)
@task
def runserver():
"run - calls the 'runserver' django command"
cmd = PMP + "runserver --settings={}".format(SETTINGS)
local(cmd)
@task
def update():
"update - install (and update) pip requirements"
cmd = "pip install -U -r {}/requirements/dev.txt".format(BASE_DIR)
local(cmd)
We see that Fabric can be used as a build tool even though it isn't one. It is easy to read and write, especially for a Python developer. The drawback may be, it does require Python to run. Seriously, who cares?
New year resolution: using Makefiles more often.
More on the topic: