8

I've seen that make is useful for large projects, especially with confusing dependencies described in a Makefile, and also helping with workflow.  I haven't heard any advantages for using make for small projects.  Are there any?

13
  • 2
    optimism for growth? :) good habits? This might stray into opinion territory.
    – Jeff Schaller
    Mar 2, 2019 at 16:38
  • type make to discover the answer. make a decent template Makefile and just edit its source files variable. no need to type all that jazz.
    – user2497
    Mar 2, 2019 at 18:05
  • they're kind of a nightmare for large projects, so honestly, i'd say they're only good for small projects ;)
    – Eevee
    Mar 2, 2019 at 19:07
  • I could use makefiles, but I don't. I've divided my source code for my biggest (personal) project into 10 files, recompile the first, and the first has #includes for the other nine. With the speed of recompilation, it doesn't matter to me if it all gets recompiled every time.
    – Jennifer
    Mar 2, 2019 at 20:40
  • 1
    Laziness :-) make is so much quicker a command to type than most others, even if you don't create a smart Makefile to handle dependencies cleanly :-) Mar 3, 2019 at 1:06

6 Answers 6

15

A lot of other people are getting into the details of more complex makefiles and a lot of the complexity that comes with them. I typically use makefiles for a completely different reason:

I don't want to remember anything.

Even if your project is really boring and simple, and you don't use makefiles "correctly":

all:
    gcc main.c -o project

I don't need to think about it or treat it any differently than a project that's more complex:

all:
    gcc libA.c libB.c main.c -o project2

Or if I specified flags (e.g. -O2) I don't need to remember what they were.

Also, if you start with a simple makefile, and you need to merge/refactor things later, you don't need to remember to build every project differently.

1
  • I use makefiles even in non-compiled projects. I create 'phony' rules that run complex commands relevant for just the the directory involved. Eg: cleanup, installation to right locations, installing docker images. It just makes it easier.
    – anthony
    Jul 18, 2019 at 1:01
11

As opposed to what?

Suppose you have a program that you have split into two files, which you have imaginatively named file1.c and file2.c.  You can compile the program by running

cc file1.c file2.c -o yourprogram

But this requires recompiling both files every time, even if only one has changed.  You can decompose the compilation steps into

cc -c file1.c
cc -c file2.c
cc    file1.o file2.o -o yourprogram

and then, when you edit one of the files, recompile only that file (and perform the linking step no matter what you changed).  But what if you edit one file, and then the other, and you forget that you edited both files, and accidentally recompile only one?

Also, even for just two files, you’ve got about 60 characters’ worth of commands there.  That quickly gets tedious to type.  OK, sure, you could put them into a script, but then you’re back to recompiling every time.  Or you could write a really fancy, complicated script that checks what file(s) had been modified and does only the necessary compilations.  Do you see where I’m going with this?

3
  • For very small projects, gcc -O3 -march=native -fwhole-program *.c is basically fine for an edit / compile / profile cycle. But you still want a Makefile for other people to use. Being able to use -fwhole-program is a fun advantage of compiling everything together, but -flto normally gives you pretty much the same optimizations. Mar 2, 2019 at 20:19
  • 2
    Once I start adding switches to the compiler command line (even for one source file), I find it gets tricky to remember them the next time. Occasionally I'll just put a comment in the source file, but at that point I should just use a Makefile... Mar 2, 2019 at 21:23
  • @ger Lipscombe: And if you need to compile for different environments, it's as simple as defining a few macros in your makefile. And with a little creativity, you can hook the make command to an editior function key, capture the output in a file, and use another key to put you at the position of any errors...
    – jamesqf
    Mar 3, 2019 at 0:39
5

Even with small project it can be helpful keeping the dependency logic under control and builds automated. I also used it to trigger installs and deinstallations, so it was a main switch resetting the stage.

3

If you link your app from 2 sources (.c files) , you do not need to recompile each file, but only the changed one if you are using make.

Also, I will give you example from BSD world. They have framework of system-based Makefiles. They provide you paths to system directories and have targets to install your software and manual pages.

For example, you just wrote beer.c app and manual for it called beer.6. You create Makefile:

PROG=   beer
MAN=    beer.6

.include <bsd.prog.mk>

..and call make install. It automatically compiles and installs your app to /usr/bin and compiles and installs your man page to the place where man can find it. You just installed your app with one simple command!

Very convenient and absolutely transparent for anyone who is familiar with BSD. Much better than manual script.

1

Example Makefile for my very small project: getPixelColor

It does exactly what its name says, taking two optional arguments, the coordinates.

I especially like the way things get dependent there.

COORDS ?= 0 0

CXX := g++-8
CXXFLAGS := -std=c++17 -Wall -Wextra -Werror -Wpedantic -pedantic-errors
LDLIBS := -lX11
RM := rm -f

BIN := getPixelColor
SRC := $(BIN).cpp

$(BIN): $(SRC)
    $(CXX) $(CXXFLAGS) $(SRC) -o $(BIN) $(LDLIBS)

.PHONY: clean
clean:
    $(RM) $(BIN)

.PHONY: run
run: $(BIN)
    ./$(BIN) $(COORDS)

As you can see, it can do all you need, without typing anything extra:


Usage

You can run it these ways:

  1. Clean-up the old binary:

    make clean
    
  2. Compile a new binary:

    make
    
  3. Run the executable in 2 ways:

    • the default coordinates [0,0]

      make run     # equals COORDS='0 0'
      
    • any given coordinates

      COORDS='5 6' make run
      

Makefiles can be extremely helpful at times. The bigger the project, the bigger the benefit. But even with that my smallest C++ project, as you can see on examples saves you a lot of headaches.

0

make is pretty reliably available. If you distribute your project with a makefile, users will have a simple reference for how to achieve tasks in the same way you do. The makefile can be for more than just compilation.

Take a project that doesn't require compilation, for example. I recall working on a Python project that had a make command to clear out all the .pyc files, a make command to run the tests, one to download a copy of the static data from the development server, etc.

Not the answer you're looking for? Browse other questions tagged .