Make examples: Difference between revisions

From wikinotes
(Created page with "= Step-ByStep C makefile = <blockquote> The following examples all make reference to a sourcetree that looks like the following. <syntaxhighlight lang="bash"> src/ libhel...")
 
No edit summary
 
Line 54: Line 54:
== ex 2: Compile .o for each file, then combine ==
== ex 2: Compile .o for each file, then combine ==
<blockquote>
<blockquote>
<div class="toccolours mw-collapsible mw-collapsed">
This is much more efficent. Every file gets compiled to .o (only as-needed),
This is much more efficent. Every file gets compiled to .o (only as-needed),
then those .o files are built into your final executable.
then those .o files are built into your final executable.
Line 110: Line 109:
== ex 3: low-maintenance makefile ==
== ex 3: low-maintenance makefile ==
<blockquote>
<blockquote>
<div class="toccolours mw-collapsible mw-collapsed">
This produces exactly the same result as the 2nd-example, but it performs
This produces exactly the same result as the 2nd-example, but it performs
additional automation within the makefile.
additional automation within the makefile.
Line 168: Line 165:


}}
}}
</blockquote><!-- low maintenance makefile -->
</blockquote><!-- low maintenance makefile -->
</blockquote><!-- Step-ByStep C makefile -->
</blockquote><!-- Step-ByStep C makefile -->

Latest revision as of 12:37, 6 September 2021

Step-ByStep C makefile

The following examples all make reference to a sourcetree that looks like the following.

src/
    libhello.h
    libhello.c
    main.c       # includes libhello.h

Each example below is a little cleaner than the last, but a little more abstract.

ex 1: compile everything, every time

Makefile


This will get the job done, but will recompile every file every time. Not very efficient.

# =============
# configuration
# =============

# compiler
CC = gcc                    # compiler
DEBUG = -g                  # compiler's debug flag (so can use gdb)
STD = c99                   # the C-standard to compile with
CFLAGS = -Wall $(DEBUG)     # compile-executable flags
LFLAGS = -Wall -c $(DEBUG)  # compile-object (.o) flags


# =============
# build targets
# =============

# default/implied 'make' argument
#
# target: depends1 depends2 ...
bin/main:
	test -d bin   || mkdir bin
	$(CC) -std=$(STD) $(CFLAGS) build/main.c build/libhello.c -o bin/main

clean:
	test -d bin   && rm -rf bin


ex 2: Compile .o for each file, then combine

This is much more efficent. Every file gets compiled to .o (only as-needed), then those .o files are built into your final executable.

My chief complaint here is that this makefile is going to require an exceptional amount of maintenance, defining every single .o file.

Makefile


# =============
# configuration
# =============

# compiler
CC = gcc                    # compiler
DEBUG = -g                  # compiler's debug flag (so can use gdb)
STD = c99                   # the C-standard to compile with
CFLAGS = -Wall $(DEBUG)     # compile-executable flags
LFLAGS = -Wall -c $(DEBUG)  # compile-object (.o) flags


# =============
# build targets
# =============

# default/implied 'make' argument
#
# target: depends1 depends2 ...
bin/main:  build/main.o build/libhello.o
	test -d bin   || mkdir bin
	$(CC) -std=$(STD) $(CFLAGS) build/main.o build/libhello.o -o bin/main

# other possible 'make' arguments
# ex: make clean
# ex: make build/main.o
build/main.o:
	test -d build || mkdir build
	$(CC) -std=$(STD) $(LFLAGS) src/main.c -o $@

build/libhello.o:
	test -d build || mkdir build
	$(CC) -std=$(STD) $(LFLAGS) src/libhello.c -o $@

clean:
	test -d build && rm -rf build
	test -d bin   && rm -rf bin


ex 3: low-maintenance makefile

This produces exactly the same result as the 2nd-example, but it performs additional automation within the makefile.

  • sourcfiles are found automatically
  • .o file definitions and dependencies are produced automatically

Makefile


# =============
# configuration
# =============

# compiler
CC = gcc                    # compiler
DEBUG = -g                  # compiler's debug flag (so can use gdb)
STD = c99                   # the C-standard to compile with
CFLAGS = -Wall $(DEBUG)     # compile-executable flags
LFLAGS = -Wall -c $(DEBUG)  # compile-object (.o) flags

# targets
SRCS = $(shell find src/ -type f -name '*.c')
OBJS = $(patsubst src/%,build/%,$(SRCS:.c=.o))


# =============
# build targets
# =============

# default/implied 'make' argument
#
# target: depends1 depends2 ...
bin/main:  $(OBJS)
	test -d bin   || mkdir bin
	@echo $(OBJS)
	$(CC) -std=$(STD) $(CFLAGS) $(OBJS) -o bin/main    ## IMPORTANT: if this is cpp, before $(OBJS) you must include the target's .cpp file

# .o-target for each .c-file
build/%.o: src/%.c
	test -d build || mkdir build
	$(CC) -std=$(STD) $(LFLAGS) -o $@ $<

# other 'make' arguments
clean:
	test -d build && rm -rf build
	test -d bin   && rm -rf bin
  • $@ is the file being generated
  • $< name of first prerequisite

See https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables