Make: Difference between revisions

From wikinotes
No edit summary
 
No edit summary
 
(11 intermediate revisions by the same user not shown)
Line 1: Line 1:
__TOC__
Makefiles are automation built around shellscripts,<br>
 
they are normally used to manage compilation of C/C++ projects, but can be used for anything.
 
Makefiles are automation built around sh-scripts,  
which allow you to only require recompiling of changed
elements when recompiling C++ projects.


= Documentation =
= Documentation =
Line 12: Line 8:
| Gnu Makefile conventions || https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html
| Gnu Makefile conventions || https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html
|-
|-
| Text Function Reference (ex: <code>($shell ..) $(patsubst ..)</code>)|| https://www.gnu.org/software/make/manual/html_node/Text-Functions.html
| Text Function Reference<br>(ex: <code>($shell ..) $(patsubst ..)</code>)|| https://www.gnu.org/software/make/manual/html_node/Text-Functions.html
|-
|-
| Automatic Variables (ex: <code>$@, $<</code>) || https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables
| Automatic Variables (ex: <code>$@, $<</code>) || https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables
Line 18: Line 14:
</blockquote>
</blockquote>


 
= Tutorials =
= Usage =
<blockquote>
<blockquote>
<syntaxhighlight lang="bash">
{| class="wikitable"
make ## compile
|-
make -d v    ## additional debug information
| university of maryland tutorial || http://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/makefile.html
make clean ## delete all .o files and program
|-
 
| mrbook tutorial || http://mrbook.org/blog/tutorials/make/
</syntaxhighlight>
|-
 
|}
</blockquote><!-- Usage -->
</blockquote><!-- Tutorials -->


= Core Concepts =
= Notes =
<blockquote>
<blockquote>
At it's core, a makefile is responsible for doing 3x things:
{|
* configuring compiler to use, and compiler-flags
|-
* defining program to compile, and all the object-files it is dependent on
| [[make usage]]
* defining each object-file, it's cpp/header files, and all other dependent header files
|-
</blockquote><!-- core concepts -->
| [[make basics]]
|-
| [[make syntax]]
|-
| [[make conventions]]
|-
| [[make examples]]
|-
|}
</blockquote><!-- Notes -->


= Examples =
= Other =
<blockquote>
The following examples all make reference to a sourcetree that looks like the following.
 
<source lang="bash">
src/
    libhello.h
    libhello.c
    main.c      # includes libhello.h
</source>
 
Each example below is a little cleaner than the last, but a little more abstract.
 
<br>
<br>
 
== ex 1: compile everything, every time ==
<blockquote>
<div class="toccolours mw-collapsible mw-collapsed">
This will get the job done, but will recompile every file every time. Not very efficient.
<div class="mw-collapsible-content">
<source lang="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:
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
</source>
</div>
</div>
 
</blockquote><!-- compile every time -->
 
== ex 2: Compile .o for each file, then combine ==
<blockquote>
<div class="toccolours mw-collapsible mw-collapsed">
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.
<div class="mw-collapsible-content">
<source lang="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
 
 
</source>
</div>
</div>
 
 
</blockquote><!-- .o file intermediary -->
 
== ex 3: low-maintenance makefile ==
<blockquote>
<blockquote>
{{ TODO |
expand in the ''syntax'' section, and remove from here
}}


<div class="toccolours mw-collapsible mw-collapsed">
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
<div class="mw-collapsible-content">
<source lang="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
</source>
* <code>$@</code> is the file being generated
* <code>$<</code> name of first prerequisite
See https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables
</div>
</div>
</blockquote><!-- low maintenance makefile -->
</blockquote><!-- Examples -->
= makefile =
<blockquote>
== Compiler ==
<blockquote>
The makefile itself seems quite flexible with how you use it,
but there seems to be an agreed-upon standard for what variables
refer to what. Here are some of the more common variables:
<syntaxhighlight lang="bash">
PROG= ## name of output executable
OBJS= ## name of all *.o files to be included (?)
CC= ## compiler name
DEBUG= ## compiler flags for debug-mode (allow use of gdb)
CFLAGS= ## compiler flags for *.o object-file compilation
LFLAGS= ## compiler flags to determine libraries (?)
</syntaxhighlight>
</blockquote><!-- compiler config -->
== files/dependencies ==
<blockquote>
The majority of your makefile defines files to be compiled,
and their dependencies. You can define as many executables or *.o
as you like, but by default only the first program (and all
*.o files it is dependent on) are compiled.
<syntaxhighlight lang="bash">
Movie.o: Movie.cpp Movie.h OtherModule.h
g++ -Wall -c Movie.cpp
</syntaxhighlight>
</blockquote><!-- files/dependencies -->
</blockquote><!-- makefile -->
= Other =
<blockquote>
== make builtins ==
== make builtins ==
<blockquote>
<blockquote>
Line 291: Line 94:
</blockquote><!-- echo variable -->
</blockquote><!-- echo variable -->
</blockquote><!-- Other -->
</blockquote><!-- Other -->
= Sources =
<blockquote>
{|
| http://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/makefile.html
|-
| http://mrbook.org/blog/tutorials/make/
|}
</blockquote><!-- sources -->

Latest revision as of 13:34, 6 September 2021

Makefiles are automation built around shellscripts,
they are normally used to manage compilation of C/C++ projects, but can be used for anything.

Documentation

Gnu Makefile conventions https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html
Text Function Reference
(ex: ($shell ..) $(patsubst ..))
https://www.gnu.org/software/make/manual/html_node/Text-Functions.html
Automatic Variables (ex: $@, $<) https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables

Tutorials

university of maryland tutorial http://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/makefile.html
mrbook tutorial http://mrbook.org/blog/tutorials/make/

Notes

make usage
make basics
make syntax
make conventions
make examples

Other

TODO:

expand in the syntax section, and remove from here

make builtins

gnu-make has a subset of commands that you can use within your makefile.

See excellent documentation: https://www.gnu.org/software/make/manual/html_node/Text-Functions.html .

@command              # run cli-command
$(shell  command)     # assign output of cli-command to var

$(subst from,to,text)
$(patsubst %.c,%.o,file1.c file2.c file3.c)  # '%' is a wildcard match. '%'s value is preserved in replacement
$(var:pattern=replacement)                   # single variable pattern-replacement

create directory

Occasionally, it makes sense to specify the creation of directories in your makefile. (such as creating a /bin directory that can be put in .gitignore). You can do this with the following snippet:

BINDIR = bin
   dummy_build_folder := $(shell mkdir -p $(BINDIR))


echo variable

Sometimes it's handy to try to figure out just what exactly your compiler is running. You can do this. using a prefix of @ runs a shell command.

all:
	@clear
	@echo "_INCL:   $(_INCL)"
	@echo "_SRCDIR: $(_SRCDIR)"