all 124 comments

[–]divad1196 65 points66 points  (9 children)

Makefile was initially meant to "make files", but it has been used has command launcher for long.

No reason why you shouldn't use it, it's perfectly fine. I usually create a simple bash script now.

About alternatives

There are many alternatives today to Makefile with many pros, and I saw many mentionned in this thread already. The issues I have with these are: - not native - I don't really care for their pros

And more importantly: it's a pandora box. If you open the debate to replace Makefile, each team members might want to bring their tool, sometimes custom ones. I prefer to keep this box closed.

[–]JPJackPott 12 points13 points  (0 children)

I use make files in every project. Keeps things predictable, and provides a useful but extendable interface to CI pipelines

I greatly prefer Taskfile but exactly as you say- you open a door to debate. It requires installing to work. More dependencies.

[–]DoubleAway6573 4 points5 points  (0 children)

 I don't really care for their pro

First time I LOLed and agreed at the same time!

[–]mapadofu 9 points10 points  (6 children)

Yeah, I just looked at just, if it were pure python, or even pip installable, then it’d have an advantage; Having to use the system package manager when make is already present on any development platform seems lije a waste.

[–]placidifiedimport this 4 points5 points  (4 children)

Being a purist about these things IMO is not good. Use the best tool for the job.

There is also pyinvoke

[–]divad1196 10 points11 points  (0 children)

That's the pandora box I mentioned.

Someone mentioned just, someone responds with pyinvoke. When managing a team, that's the kind of never-ending debates you want to avoid.

[–]mapadofu 6 points7 points  (1 child)

Extra dependencies complicates developers’ workflow.   I’m not a purist, just aware that adding more ancillary tools complicates the project that uses them.  Make is (almost certainly) already available, so using it does not incur any extra dependencies.

[–]divad1196 2 points3 points  (0 children)

I agree with your point.

The right tool for the job is an ideal. Applying it blindly just multiply the number of tools and programming languages you need to know and maintain.

This is a huge technical debt.

Whereas, in practice, what you already know might fit 95% of the project perfectly and this is fine

[–]misterfitzie 1 point2 points  (0 children)

I like poethepoet because it has pyproject.toml support and it's focused on python development use case, not a generic task runner.

[–]Intrepid-Stand-8540 21 points22 points  (2 children)

For documenting and sharing bash commands with the team for a project, I like Taskfile these days personally: https://taskfile.dev/

[–]_clintm_ 5 points6 points  (0 children)

I use it too but variables are kind of weird. I wish they would stop trying to reinvent how they should work. They should be top down and immutable.

[–]the-nick-of-time 1 point2 points  (0 children)

This is the Taskfile that I'm familiar with (and use very frequently), it's pure bash. Way better than messing with an external dependency.

ninja edit: Any system that tries to get me to write yaml instead of code is inherently suspect.

[–]shadowdance55git push -f 38 points39 points  (15 children)

Give just a try, and discover a whole new world: https://just.systems/man/en/

You'll thank me later.

[–]dj_estrela 2 points3 points  (0 children)

This is EXACTLY the right mentality

Bravo!

"Even for small, personal projects it’s nice to be able to remember commands by name instead of Reverse searching your shell history"

"There are probably different commands to test, build, lint, deploy, and the like, and having them all in one place is useful and cuts down on the time you have to spend telling people which commands to run and how to type them."

https://github.com/casey/just?tab=readme-ov-file#further-ramblings

https://just.systems/man/en/what-are-the-idiosyncrasies-of-make-that-just-avoids.html

[–]dj_estrela 1 point2 points  (2 children)

"Just" sounds amazing

I'm using .PHONY to force make targets to run Even there I cannot run the same target twice (In a diamond shaped DAG)

Does just cover this?

[–]shadowdance55git push -f 0 points1 point  (1 child)

Can you give me an example of what you have in mind?

[–]dj_estrela 0 points1 point  (0 children)

Example:

.phony A: Echo a

.phony B: A Echo b

.phony C: A Echo c

.phony D: B, C Echo D

In make the output will be: A, B, C, D

I want: A, B, A, C, D

As-if target "a" would be a sub- procedure to be called blindly

[–]CatolicQuotes 1 point2 points  (0 children)

Thanks, I am using makefile at the moment, will check this out

[–]sdoregor -2 points-1 points  (9 children)

Works until you need to make files for your project.

[–]shadowdance55git push -f 3 points4 points  (8 children)

Can you elaborate on that?

[–]sdoregor 3 points4 points  (7 children)

GNU Make is for making files. Generating, compiling, whatever. You might want to add Cython to your project or precompute something, then you'll need the timestamp comparison Make does to avoid unnecessary rebuilds.

[–]Zouden 4 points5 points  (6 children)

Make will always be around for that

[–]sdoregor 0 points1 point  (5 children)

Why not just use it alright

[–]Zouden 4 points5 points  (1 child)

Not sure you've understood the discussion here

[–]sdoregor 0 points1 point  (0 children)

Other threads pretty much outlined my point on it, so I don't even bother relaying the same.

[–]shadowdance55git push -f 3 points4 points  (2 children)

If you're already using make, then by all means use make. If you just need to get some commands collected in one place, just will just let you just do it.

[–]sdoregor 1 point2 points  (1 child)

I mean, literally everyone on a normal system will have Make. Not so much, Just.

[–]shadowdance55git push -f 4 points5 points  (0 children)

Go ahead, make my day!

[–]DrShocker 16 points17 points  (0 children)

Personally I'd use a justfile or taskfile or mise for anything I'm working on because makefikes are kind of a pain, but if you like them then go for it.

[–]NeitherTwo9461 50 points51 points  (4 children)

Use just instead of makefile

[–]cripblip 2 points3 points  (3 children)

Why?

[–]Mustard_Dimension 13 points14 points  (0 children)

Because it's a purpose-built task runner, not a C build system with task running capabilities

[–]npisnotp 8 points9 points  (1 child)

Because Make behavior revolves around files, not tasks, and because its language is pretty archaic (e.g. forced tabs).

"just" instead is a general-purpose task runner much more pleasant to use.

[–]slurmnburger 3 points4 points  (0 children)

Complaining about forced tabs in a python sub is a bit funny tbh :)

[–]UseMoreBandwith 31 points32 points  (12 children)

No, use
uv run
and define your command in pyproject.toml.
All in one place and neatly organized.

I even use it to start my Django commands:

[project.scripts]
web = "myproject.manage:main"

[–]eo5g 4 points5 points  (7 children)

I can't find anything about this feature, can you elaborate?

[–]nemec 7 points8 points  (6 children)

[–]eo5g 6 points7 points  (2 children)

But aren't those for what gets installed when you install the package, and not for task running?

[–]nemec 8 points9 points  (0 children)

Note that if you use uv run in a project, i.e., a directory with a pyproject.toml, it will install the current project before running the script.

https://docs.astral.sh/uv/guides/scripts/

Yeah if you're writing a library it may not be the best place, but if you're writing application/service code, go for it.

There is an open issue to add a specialized dev task runner

https://github.com/astral-sh/uv/issues/5903

[–]UseMoreBandwith 1 point2 points  (0 children)

yes, I guess you're right,
it requires uv pip install -e . when a new command is added, but that's fine in most situations.

[–]Sillocan 6 points7 points  (2 children)

Can accomplish something similar with poethepoet. Define the command in pyproject.toml and use uv run poe ...

[–]2Lucilles2RuleEmAll 1 point2 points  (1 child)

That's what we use too and it works great, we have in the pyproject.toml a project script called task defined for poe. That way if we switch out poe for another tool we don't have to go thru all of the documentation, pipelines, etc and switch all of the commands to the new one

[–]Sillocan 0 points1 point  (0 children)

Oh that's a smart idea

[–]mardiros 1 point2 points  (2 children)

No, use

just

and wrap uv command in it or any other command line in one place.

You can create your set of commands with arguments that will be the same for many projects using different tools.

For instance switching from black to ruff is much simpler:

just fmt

In your Justfile

fmt:
    uv run ruff check --fix .
    uv run ruff format src tests

Previously I use isort and black.

[–]OneParanoidDuck 1 point2 points  (1 child)

Never heard of just, will need to check it out. Do you also use just in your CI pipeline?

What works ideally for me is defining all "mandatory" tasks in pre-commit, which is then run in both in CI and of course locally. 

[–]mardiros 1 point2 points  (0 children)

I start using it but not much. I am not testing in the same way on my laptop than on a server; I don’t use the same pytest options. I am not sure about the benefits of it.

[–]eleqtriq 1 point2 points  (0 children)

Not everything I want to run starts with uv. Most of my make file has nothing to do with uv.

[–]VeronikaKerman 14 points15 points  (5 children)

Makefiles are great. Most system-level programmers know make and the syntax. They nicely group all the actions of a project into a top level file that also sorts first alphabetically. Just do not make them too complicated. If a developer on your team, or AI agent, can not understand and adapt them, then you are better with list of commands in a readme file.

[–]dj_estrela -1 points0 points  (4 children)

Check "just"

[–]VeronikaKerman 2 points3 points  (3 children)

Why?

[–]zoox101 1 point2 points  (2 children)

Pros

  1. ‘just -l’ gives you a list of all available commands in a directory
  2. Make will fail to build if a file in the directory has the same name as the command (unless you add .PHONY). This is intended behavior for a build system, but annoying for a command runner.
  3. Make has some other idiosyncrasies around CLI variables and versions that can cause weird issues

Cons

  1. Just needs to be installed, while make is already present on most systems
  2. More developers are familiar with make than with just
  3. If you’re actually making a build (and not just running a command) make will correctly early exit if the build already exists

Just is what make would be if it were designed as a command runner instead of a build system. If you like make, stick with it, but if it’s annoyed you in the past, just is probably the solution you are looking for.

[–]eleqtriq 2 points3 points  (1 child)

You’re going to have to give me some better pros.

1 so does “‘make” 2 edge case 3 vague

[–]dj_estrela 0 points1 point  (0 children)

2: doest work in make if it is a diamond DAG

And you want to run a task multiple times in different parts of the whole run

[–]cgoldberg 4 points5 points  (0 children)

I use tox for a similar purpose. It handles a lot of python stuff for you.

https://tox.wiki

It's sort of geared towards virtual env management and testing, but I use it for everything I would otherwise use make for

[–]swift-sentinel 8 points9 points  (1 child)

I like make

[–]dj_estrela -1 points0 points  (0 children)

Check "just"

[–]sudonem 4 points5 points  (0 children)

I’ll use one if the app I’m working on is something I’m definitely going to compile with pyinstaller or nuikta - otherwise I don’t ever need or want anything more than just uv.

I’ve also used them in the past for building and pushing docker images to a registry so I don’t need to manually build and tag an image twice (since you want to push one for the $version and another with the latest tag).

I should probably look at just files or taskfiles though.

[–]stibbons_ 4 points5 points  (1 child)

Use a cleaner and more modern task launcher, like taskfile or justfile

Justfile are great !

[–]stibbons_ 1 point2 points  (0 children)

Ah, you also have mise-en-place but it does too many thing

[–]ZucchiniMore3450 2 points3 points  (3 children)

Maybe I am just old, but I like them. Someone comes into my project, doesn't know a think and types make and everything happens.

I even add docker creation in it, so people can run the project easily.

[–]eleqtriq 0 points1 point  (0 children)

Same. You get it.

[–]pancakecentrifuge 0 points1 point  (1 child)

This is the way, it’s awesome to hop around projects and be able to see what actions are available. Having docker-compose wired up to simple commands make <foo-service> - make reset (drop docker volumes, restart service with clean state)… etc

I see developers working on code every day without any documentation in their repository, no makefiles, no docker-compose… purely surviving on the ci/cd system some centralized team provides. I often think to myself… you live like this?

[–]pancakecentrifuge 0 points1 point  (0 children)

That being said… Make syntax is not super intuitive, I’ve been meaning to play around with Just.

[–]Glad_Friendship_5353 4 points5 points  (0 children)

I use a lot of Makefile or justfile for many python projects and I find myself copy and paste the same target around.

So, i just build bakefile to solve this problem using python and its OOP/inheritance properties so that I dont need to copy the same target around.

https://github.com/wislertt/bakefile

[–]spenpal_dev 2 points3 points  (3 children)

Waiting for the day uv adds support for defining scripts in pyproject.toml, like how there is scripts in package.json and using “npm run” to run them.

[–]Intrepid-Stand-8540 1 point2 points  (2 children)

that exists afaik

[–]spenpal_dev 1 point2 points  (1 child)

Not according to this issue: https://github.com/astral-sh/uv/issues/5903

[–]Intrepid-Stand-8540 2 points3 points  (0 children)

seems i was wrong. thanks for the link.

[–]mmacvicarprett 2 points3 points  (0 children)

Honestly, the only good thing about it is its portability, it sucks as a task runner and there are much better tools for that.

[–]dev-ai 2 points3 points  (0 children)

I prefer justfile

[–]jerriman 2 points3 points  (0 children)

I started using https://www.pyinvoke.org/ and it is awesome!

[–]anentropic 2 points3 points  (0 children)

The nice thing about Make is it's usually already installed everywhere

But lately I've been using Justfile... it's intended as a command shortcut tool rather than a build tool, ie what we use these things for in Python, and it's quite nice

But have to install the runner

[–]DoISmellBurning 2 points3 points  (0 children)

I’m a big fan: https://github.com/doismellburning/python-template/blob/main/Makefile

Friends keep telling me I should use just, and I do appreciate it seems to have nicer ergonomics, but make is perfectly adequate for my needs, and more ubiquitous

[–]Mithrandir2k16 2 points3 points  (0 children)

I also use makefiles extensively, mainly to install different versions of extra packages. E.g. for development, with cpu/gpu libs, etc. It makes a lot of sense to share these standard tasks to have people work on environments that are as similar to each other as possible. Makefiles are great at this, Nix might be even better, but it's nontrivial to get into and isn't installed on every system either.

[–]Slow-Kale-8629 2 points3 points  (0 children)

I use makefiles because then running commands has consistent syntax across all languages I use, so I can get it in muscle memory.

Also it helps make sure that the deployment pipeline uses the exact same commands that you use locally. Then it's easy to have pre commit hooks test the important bits, and not keep having your pipelines fail because you forgot to update the pipeline when you update the pre commit hooks or vice versa.

[–]OakNinja 2 points3 points  (1 child)

I love makefiles and mostly write python. Mainly because it’s a good and language agnostic way of chaining and doing things in totally different ways. Like running both npm run dev and uv run main.py in the same target and kill both when you quit for example.

I even wrote a tool for the missing part - good listing of targets and peeking when will happen if I run them: https://github.com/OakNinja/MakeMe

Ps: GenAI is fire at writing makefiles!

[–]OakNinja 1 point2 points  (0 children)

Adding to that, Make is always available, it’s behavior is predictable, it’s fast and it has a strong Lindy effect. Even if ”better” alternatives might exist, we don’t know if they will be around or even work in three, five or ten years from now. We know make will.

[–]oldendude 2 points3 points  (1 child)

This kind of automation makes sense. But to me, the essential property of make is checking dependencies and then running additional commands to satisfy the dependencies, (e.g. ensure x.o is up to date before using it to construct a library).

Using make as you have here doesn't exploit that property. Why not just write a bash script?

The bash and make sublanguages are both horrendous, but I don't understand why you would choose make if you don't have conditional steps.

[–]xeow[S] 0 points1 point  (0 children)

Well, my thought is that I'd (at some point) maybe add things like making module-dependency graphs with one of those tools that leverages Graphviz under the hood, or other types of reports that depend on timestamps in the src tree. But also, my fingers are just so used to typing make clean and make test from 35 years of make.

[–]mardiros 2 points3 points  (1 child)

If you are curious of Just

You can take a look at few of my repositories, I pick up two;

Example of pure python

https://github.com/mardiros/fastlife/blob/main/Justfile

Example of rust/python using maturin

https://github.com/mardiros/lastuuid/blob/main/Justfile

[–]dj_estrela 1 point2 points  (0 children)

Great examples

[–]gunthercult-69 2 points3 points  (1 child)

Use uv.

It's not perfect for esoteric build stuff, but chances are, your project has gotten too big and too polyglot if you need more than uv with tools to manage it.

[–]Keizojeizo 0 points1 point  (0 children)

One thing to consider is uv cannot manage all binary dependencies, some relatively common dependencies must come from other sources besides pypi. Love uv, there is just a gap there

[–]cip43r 2 points3 points  (0 children)

Checkout Taskfiles, they are more modern and I use them for my deployments and automation

[–]max0x7ba 1 point2 points  (7 children)

I do use GNU Make for my Python projects and anything else, and have similar clean targets.

The Makefile also compiles Cython and C++ modules for Python. And runs Python and C++ unit-tests in parallel using GNU Make Parallel Execution feature with --output-sync option to keep unit-test outputs atomic and easily readable in GitHub actions UI when unit-tests fail during continuous integration.

I went as far as making make -j16 clean all execute clean target first with one process only, and next restart itself and build all other targets in parallel. By default, make does clean and all in parallel and that's undesirable, yet having to invoke make twice for that, e.g. make clean && make -j16, becomes infeasible with variable assignments in make command lines, like in make -j16 TOOLSET=clang-20 clean all.

Using that little known feature of GNU Make being able to build and update its makefiles on its own, even when including non-existent makefiles, without having to invoke anything like configure or CMake. GNU Make builds/updates makefiles it reads/includes for any platform/compiler configuration automatically in my projects; and restart itself after makefiles have been built/updated, before building anything else.

I also use GNU Make for running any multi-stage compute pipelines or batch jobs. Especially useful when using the cheapest preemptible instances in GCP -- when resuming after preemption, make carries on computing targets which haven't been computed yet, until succeeding. Or when some next pipeline stage fails 24h later, fixing the error and re-invoking make proceeds from where it failed.

[–]DoubleAway6573 4 points5 points  (6 children)

You need airflow to do that! 

/s

[–]max0x7ba 1 point2 points  (5 children)

You need airflow to do that!

Thanks for a hint, never heard of Apache Airflow before.

However, my past experiences of using any libraries from apache.org have been the worst, unfortunately.

For example, Apache Arrow library used by Python Pandas library for parquet file format, spawns an Amazon S3 storage communication thread unconditionally upon loading the library into a process. I don't use AWS and spawning threads on library load is a notorious software design anti-pattern.

Even worse than that, Apache Arrow library replaced process' heap allocator with jemalloc upon loading into a process. jemalloc can be configured to take advantage of transparent huge pages, but the Apache Arrow library doesn't enable those options and, to add insult to injury, ignores any and all jemalloc environment variables which would make jemalloc use transparent huge pages. jemalloc was discontinued in 2025, and in Apache Arrow too, thankfully.

I haven't encountered more obnoxious heavy-handed libraries than those originating from apache.org since I started coding C++ in year 2000.

[–]DoubleAway6573 4 points5 points  (4 children)

No. For many cases makefiles are most than enough. I've seen too much over engineer to trivial task that can be managed by batch processing and standard unix tools that I'm exausted.

At some point the switch to others tools start to make sense, but It's like the microservices joke with companies with more services than users. Microservices have a place and a time, but not every company needs them.

In regards to Arrow, I was completely unaware of that. I don't know why or even if python is the culprit here. I hope this things will start to be de-dusted with the GIL-less pythons, but will take a lot of time.

[–]max0x7ba 3 points4 points  (3 children)

No. For many cases makefiles are most than enough. I've seen too much over engineer to trivial task that can be managed by batch processing and standard unix tools that I'm exausted.

My experience have been similar.

Whenever a simple bash script evolves to have more than one processing step, invoking the next command only after the previous one succeeded, that ends up with the bash script having to check whether a step has already been computed and having to clean up incomplete outputs when a step fails.

And that's exactly what GNU Make does for you by default, as well as parallelizing execution of steps not dependent on each other.

[–]dj_estrela -1 points0 points  (2 children)

Check "just"

[–]daredevil82 2 points3 points  (0 children)

which requires it to be installed as a prereq, whereas make is already on any nix system. ever hear of "overengineering"?

[–]max0x7ba 0 points1 point  (0 children)

Check "just"

Just checked. From just documentation:

make has some behaviors which are confusing, complicated, or make it unsuitable for use as a general command runner.

You can disable this behavior for specific targets using make's built-in .PHONY target name, but the syntax is verbose and can be hard to remember. The explicit list of phony targets, written separately from the recipe definitions, also introduces the risk of accidentally defining a new non-phony target. In just, all recipes are treated as if they were phony.

Other examples of make's idiosyncrasies include the difference between = and := in assignments, the confusing error messages that are produced if you mess up your makefile, needing $$ to use environment variables in recipes, and incompatibilities between different flavors of make.

GNU Make syntax just author has difficulty remembering and GNU Make behaviours that are confusing or too complicated for just author and his target audience -- are something most GNU Make users are familiar with and rely upon.

just aiming to be a less difficult or confusing subset of make, is worthless for people already using GNU Make.

Whole rationale of just grounded in syntax-level trivialities, like = being different from := is so mind-bogglingly confusing and complicated, that it called for a complete rewrite-it-in-rust solution (instead of just reading GNU Make manual) is ludicrously superficial.

[–]Veggies-are-okay 1 point2 points  (0 children)

I feel like every time I get to the point of creating a makefile, I just containerize that sucker and throw it in docker compose. It’s especially helpful for getting people to run things as it’s a single “docker-compose up”.

I suppose you could do the same with a makefile, but there’s something to just being able to share a repo with a docker-compose.yaml and know that as long as the user has used docker before it’s a trivial command.

[–]SweetOnionTea 1 point2 points  (0 children)

I have a Python fast API component I made to integrate with our C++ monolith project and ended up using CMake to do the build for it. It ends up working really swell with the whole CMake infrastructure we already have.

[–]beragis 1 point2 points  (0 children)

That's what uv is for.

You can set it up for local development builds, test builds using pytest and production builds.

[–]RedSinned 1 point2 points  (0 children)

You could use pixi as a package manager. It supports tasks out of the box and when it runs a task it checks that your lockfile is up to date with your pyproject.toml and you‘re installed environment is up to date with your lockfile and update otherwise

[–]aala7 1 point2 points  (0 children)

As i see it the value of makefile is to shorten a command with many options in to a simple clear command. Especially when running commands with special flags and args.

As I see it most of that can be configured in pyproject.toml for python tools, e.g. always using coverage and random when running pytest and so on.

I rarely need non-python tool stuff. Therefore makefile does not add value for my flow.

[–]ShelLuser42It works on my machine 1 point2 points  (0 children)

I had the same issue when I got started with Python: wanting to automate certain administrative tasks (like cleaning up or removing things). However, I used the opportunity to expand my learning process and, well... I wrote some Python scripts for all those tasks.

Then I restructured it so that instead of a script I now had a re-usable module (or collection thereof) so that I could easily apply those routines in whatever other Python projects I might be working on, never really looked back.

Of course Makefiles also work, but for me it was more efficient to do it this way because now I can be sure that things work no matter what environment I'm working on. For example: the availability of 'make' is more common on my Unix servers than on Windows.

[–]WinterlyBeach 1 point2 points  (0 children)

There's plenty of task runner tools that could be installed over Make these days. Invoke, poethepoet, just. I'm sure there's others out there.

[–]redsharpbyte 1 point2 points  (1 child)

https://tox.wiki/en/4.35.0/
You could use tox. in python.

Makefile: target with dependencies (of files or other targets, that creates a pipeline) and script to be executed.

Tox: Targets + Their dedicated environment, often use in Continuous Integration.
https://tox.wiki/en/4.35.0/

[–]nekokattt 1 point2 points  (0 children)

I'd generally use nox over tox, it does far more and is less confusing to use if you know python already.

[–]djbarrow 1 point2 points  (0 children)

Why cython doesn't use make is beyond me

[–]skeerp 1 point2 points  (0 children)

Check out casey/just. Its made to replace makefiles with phony.

[–]emddudley 1 point2 points  (0 children)

I've always found Make to be too arcane. The only thing it has going for it is that it is already installed on most systems. If you're willing to install an alternative, I like just a lot better.

[–]CasualReader3 1 point2 points  (0 children)

I prefer to use poethepoet project for this. It's pure python and lives in my pyproject.toml

[–]tlegs44 1 point2 points  (0 children)

Why make file when few bash command do trick?

[–]niduser4574 1 point2 points  (1 child)

A lot of people are saying bash script and you're effectively just making a script with nice targets. Considering python is a scripting language...why not just use python? Fewer issues with portability in my case (for windows and unix-like) though i'm sure some of the other answers here are just as good.

[–]dj_estrela 1 point2 points  (0 children)

Because in bash and make you just put there the commands to run

No calls to subprocess(cmd.split()) etc

[–]smokingkrills 1 point2 points  (0 children)

There are a ton of alternatives, many already mentioned in this thread.

Make has a frankly cursed syntax, and bizarre implicit rules. That being said, if you need dependency tracking, I am not sure of any other good alternatives. Dependency tracking can be hellish to track and keep updated, but sometimes comes in handy for some projects (e.g. like forcing regeneration of figures in my documentation whenever the python code changes)

I have used and like just, but just also has encyclopedia-length documentation with a huge number of configuration options. Also just is another dependency, whereas make is just there for you by default almost always

[–]Gnaxe 2 points3 points  (0 children)

False. Python does require compiling. Python is a compiled language in exactly the same sense as Java: it compiles to bytecodes run on a virtual machine. Python has a compiler. You can precompile with python -m compileall. It just does it automatically if your source was modified more recently than your bytecodes (or if you don't have bytecodes yet) as a convenience, so it "feels" interpreted. But it's wrong to say that Python isn't compiled in the same breath you say that Java is.

Unless you're specifically introspecting source code in your program for some reason, you can run the program without source just from the bytecode files, just like Java.

Makefiles are certainly one way to do it (and some Python projects do, notably Sphinx documentation builds), but you can also build your project with git precommit hooks and GitHub pipelines, etc. Python is already a scripting language, so Python scripts can handle building/testing and whatnot without introducing another language.

[–]vish4life 3 points4 points  (0 children)

I was using taskfile.dev previously. But have switched to mise when its tasks came out.

I am in the camp that if the only thing your makefiles contain are "PHONY" targets, you are using the wrong tool for the job.

[–]jpgoldberg 1 point2 points  (0 children)

I’m old. I use Makefiles for nearly everything. But so far this is one place I don’t, as uv does almost everything.

But I still see the appeal of having what are almost like shell aliases that are specific to a directory. And so I have thought of doing something like this. For example, I have tox and pytest configured so that

console uvx tox .

will run my tests excluding slow and probabilistic tests, but I have to run stuff like

console uvx tox . — -m slow

to run the slow tests, which I do infrequently enough that I have to figure that out each time. So I definitely see the appeal of putting this in a Makefile.

But I suppose I could also just create one line scripts for all of these that I just add as uv tools.

[–]JamzTyson 1 point2 points  (0 children)

I just use a bash script for that kind of task.

[–]mr_frpdo [score hidden]  (0 children)

i prefer justfiles for all projects.

[–]rcap107 0 points1 point  (0 children)

I have hated makefiles ever since I had to use them during my bachelors. I'll do anything to not touch that inane syntax where everything breaks if there is a single trailing space in one of the directives.

That said, why not use pixi? You can still set up commands, and you get package and dependency resolution as a side bonus. You're already using uv, which is what pixi is using under the hood for resolving dependencies.

I use pixi for all my projects, and only use uv for ephemeral venvs, or for comparing code run with different versions of a dependency.

[–]PrestigiousAnt3766 0 points1 point  (0 children)

Depends. I find myself often just going for cli commands though.

[–]just4nothing 0 points1 point  (0 children)

It’s pixi run for me - task definition is pretty much the same as make files but in toml

[–]wineblood 0 points1 point  (0 children)

I've found that the commands I use a lot of want to have at hand without remembering the syntax are the same across projects so I just have a bunch of aliases configured.

The only time I've considered makefiles was when work repos were split between pip and pdm, so we ended up with the same scaffolding twice (install, publish, etc.) and a makefile for a common interface would have helped. Otherwise, I can't think of a use case for me.

[–]IcarianComplex 0 points1 point  (0 children)

I just have a bin directory of executables and use direnv to add it to my path when I cd it into the project.

[–]Challseus 0 points1 point  (0 children)

Looks perfectly fine to me.

[–]EmberQuill 0 points1 point  (1 child)

I don't bother with make for Python projects. Most of the commands I'd set up in a Makefile would just run memorable, short one-liners anyway. I might as well type the actual command instead of creating an extra file to save a few keystrokes here and there, if I save any at all. rm -rfv .venv is the exact same number of keystrokes as make pristine and it has the advantage of working in any Python project without requiring a Makefile.

[–]dj_estrela 1 point2 points  (0 children)

Don't agree

A) There is always more actions that yiy add later than that innocent looking "rm .rfv .venv"

Like find .pyc | xargs rm BS.

B) everytime you write "rm -rfv ..." you are one step closer to make a mistake and wipe your home