Hacker News new | ask | show | jobs
by nrclark 765 days ago
> What does a makefile look like for "install this list of dependencies with pip/homebrew/apt, and don't run it twice?"

It looks like this:

    default: your_task
    
    VENV_DIR := venv
    
    $(VENV_DIR)/bin/python: requirements.txt
        python -m venv $(VENV_DIR)
        . $(VENV_DIR)/bin/activate && pip install -r requirements.txt
    
    your_task: $(VENV_DIR)/bin/python
        do_your_thing
    
    clean:
        rm -rf $(VENV_DIR)

> C and C++ compilers at this stage are the only places that I work with file based dependencies. Unless you explicitly declare all the headers as dependencies in a makefile, make won't rebuild a cpp file if you change a header. IME ninja (plus cmake to generate it) has entirely superseded make in this space. Tools and languages comes with it's own build tool (see above - go/cargo/dotnet/etc) or state tracking (docker) that break make's assumption of file based dependencies.

In our Python example above, you have a file-based dependency between requirements.txt and your virtual environment. And then you have a file-based dependency on your virtual-environment's Python for whatever task you're trying to run.

> Because every make file I've ever used in recent memory has been 30% workarounds to avoid file based dependencies, and work around subtle footguns that make has, rather than actually doing what I want it to do - execute a build command.

Why would you want to avoid expressing your dependencies? File dependencies exist, and are the simplest / most correct model for 75% of all build automation. When somebody has to sit down and read your Makefile, isn't it nice to have a way to express "these are the files that actually matter for task X"?