mirror of
https://github.com/libretro/cpp-cheat.git
synced 2024-11-26 18:20:34 +00:00
Move make and scons in
This commit is contained in:
parent
48c3e8a81e
commit
4e8fc7c1a9
@ -2,7 +2,7 @@
|
||||
|
||||
[![Build Status](https://travis-ci.org/cirosantilli/cpp-cheat.svg?branch=master)](https://travis-ci.org/cirosantilli/cpp-cheat)
|
||||
|
||||
C and C++ minimal examples. Asserts used wherever possible. Hello worlds for cool third party libraries. Cheatsheets, tutorials and mini-projects.
|
||||
C and C++ minimal examples. Asserts used wherever possible. Hello worlds for cool third party libraries and build systems. Cheatsheets, tutorials and mini-projects.
|
||||
|
||||
[Assembly Cheat](https://github.com/cirosantilli/assembly-cheat) contains lower level issues, like assembly, ELF and Binutils.
|
||||
|
||||
@ -22,7 +22,9 @@ C and C++ minimal examples. Asserts used wherever possible. Hello worlds for coo
|
||||
1. [Fortran from C](fortran-from-c/)
|
||||
1. [SWIG](swig/)
|
||||
1. [Build systems](build-systems.md)
|
||||
1. [make](make/)
|
||||
1. [CMake](cmake/)
|
||||
1. [SCons](scons/)
|
||||
1. Analysis tools
|
||||
1. [GDB](gdb/)
|
||||
1. [cflow](cflow.md)
|
||||
|
@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
#include "common.hpp"
|
||||
#include "no_base_no_member.hpp"
|
||||
|
||||
class Empty {};
|
||||
|
||||
@ -1245,8 +1244,7 @@ int main() {
|
||||
MemberConstructorTest o;
|
||||
}
|
||||
|
||||
std::vector<std::string> expectedCallStack =
|
||||
{
|
||||
std::vector<std::string> expectedCallStack{
|
||||
"NoBaseNoMember0::NoBaseNoMember0()",
|
||||
"NoBaseNoMember1::NoBaseNoMember1()",
|
||||
"MemberConstructorTest::MemberConstructorTest()",
|
||||
@ -1285,12 +1283,9 @@ int main() {
|
||||
*/
|
||||
{
|
||||
callStack.clear();
|
||||
|
||||
NoBaseNoMember c; //1 constructor
|
||||
c = NoBaseNoMember(); //1 constructor of the temporary, 1 assign, 1 destructor of the temporary
|
||||
|
||||
std::vector<std::string> expectedCallStack =
|
||||
{
|
||||
NoBaseNoMember c; // 1 constructor
|
||||
c = NoBaseNoMember(); // 1 constructor of the temporary, 1 assign, 1 destructor of the temporary
|
||||
std::vector<std::string> expectedCallStack{
|
||||
"NoBaseNoMember::NoBaseNoMember()",
|
||||
"NoBaseNoMember::NoBaseNoMember()",
|
||||
"NoBaseNoMember::operator=",
|
||||
@ -1308,8 +1303,7 @@ int main() {
|
||||
{
|
||||
callStack.clear();
|
||||
NoBaseNoMember().method();
|
||||
std::vector<std::string> expectedCallStack =
|
||||
{
|
||||
std::vector<std::string> expectedCallStack{
|
||||
"NoBaseNoMember::NoBaseNoMember()",
|
||||
"NoBaseNoMember::method()",
|
||||
"NoBaseNoMember::~NoBaseNoMember()",
|
||||
@ -1364,7 +1358,7 @@ int main() {
|
||||
- <http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three>
|
||||
*/
|
||||
{
|
||||
//every class has a default copy operator and assign constructor
|
||||
// Every class has a default copy operator and assign constructor.
|
||||
{
|
||||
DefaultCopyAssignCtor c0(0);
|
||||
DefaultCopyAssignCtor c1(1);
|
||||
@ -1391,8 +1385,7 @@ int main() {
|
||||
{
|
||||
callStack.clear();
|
||||
NoBaseNoMember c1(c);
|
||||
std::vector<std::string> expectedCallStack =
|
||||
{
|
||||
std::vector<std::string> expectedCallStack{
|
||||
"NoBaseNoMember::NoBaseNoMember(NoBaseNoMember)",
|
||||
};
|
||||
assert(callStack == expectedCallStack);
|
||||
@ -1410,8 +1403,7 @@ int main() {
|
||||
{
|
||||
callStack.clear();
|
||||
NoBaseNoMember c1 = c;
|
||||
std::vector<std::string> expectedCallStack =
|
||||
{
|
||||
std::vector<std::string> expectedCallStack{
|
||||
"NoBaseNoMember::NoBaseNoMember(NoBaseNoMember)",
|
||||
};
|
||||
assert(callStack == expectedCallStack);
|
||||
@ -1507,7 +1499,7 @@ int main() {
|
||||
- All input and output operations occur in the same order and with the same content
|
||||
as if the program was executed as written.
|
||||
|
||||
The only exception to the ruls is copy elision.
|
||||
The only exception to the rule is copy elision.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -96,3 +96,78 @@ const int NUM_OPS = NUM_THREADS * NUM_ITERS;
|
||||
|
||||
// Misc.
|
||||
bool odd(int i){ return (i % 2) == 1; }
|
||||
|
||||
/**
|
||||
* Simple instrumented class for tests on constructor destructor order.
|
||||
*
|
||||
* This class has no members which are objects and no base classes.
|
||||
*
|
||||
* TODO break this class up.
|
||||
* */
|
||||
class NoBaseNoMember {
|
||||
public:
|
||||
|
||||
int i;
|
||||
|
||||
/// Default constructor
|
||||
NoBaseNoMember() : i(0) {
|
||||
callStack.push_back("NoBaseNoMember::NoBaseNoMember()");
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
NoBaseNoMember(const NoBaseNoMember& other) : i(other.i) {
|
||||
callStack.push_back("NoBaseNoMember::NoBaseNoMember(NoBaseNoMember)");
|
||||
}
|
||||
|
||||
NoBaseNoMember(int i) : i(i) {callStack.push_back("NoBaseNoMember::NoBaseNoMember(int)");}
|
||||
|
||||
/// Assign
|
||||
NoBaseNoMember& operator= (const NoBaseNoMember& rhs) {
|
||||
this->i = rhs.i;
|
||||
callStack.push_back("NoBaseNoMember::operator=");
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~NoBaseNoMember() { callStack.push_back("NoBaseNoMember::~NoBaseNoMember()"); }
|
||||
|
||||
void method() { callStack.push_back("NoBaseNoMember::method()"); }
|
||||
|
||||
static NoBaseNoMember create() {
|
||||
return NoBaseNoMember();
|
||||
}
|
||||
|
||||
static NoBaseNoMember createNrvo() {
|
||||
NoBaseNoMember c;
|
||||
return c;
|
||||
}
|
||||
|
||||
/// It would be hard or impossible to do RVO for this function.
|
||||
static NoBaseNoMember createNrvoHard(bool b = false) {
|
||||
//2 int constructors
|
||||
NoBaseNoMember cf = NoBaseNoMember(0);
|
||||
NoBaseNoMember ct = NoBaseNoMember(1);
|
||||
return b ? ct : cf;
|
||||
//2 int destructors
|
||||
}
|
||||
|
||||
static void temporaryReference(NoBaseNoMember& temp) {
|
||||
temp.i = 0;
|
||||
}
|
||||
|
||||
static void temporaryReferenceConst(const NoBaseNoMember& temp) {}
|
||||
};
|
||||
|
||||
class NoBaseNoMember0 {
|
||||
public:
|
||||
NoBaseNoMember0(){callStack.push_back("NoBaseNoMember0::NoBaseNoMember0()");}
|
||||
~NoBaseNoMember0(){callStack.push_back("NoBaseNoMember0::~NoBaseNoMember0()");}
|
||||
void method(){callStack.push_back("NoBaseNoMember0::method()");}
|
||||
};
|
||||
|
||||
class NoBaseNoMember1 {
|
||||
public:
|
||||
NoBaseNoMember1(){callStack.push_back("NoBaseNoMember1::NoBaseNoMember1()");}
|
||||
~NoBaseNoMember1(){callStack.push_back("NoBaseNoMember1::~NoBaseNoMember1()");}
|
||||
void method(){callStack.push_back("NoBaseNoMember1::method()");}
|
||||
};
|
||||
|
@ -33,7 +33,6 @@
|
||||
*/
|
||||
|
||||
#include "common.hpp"
|
||||
#include "no_base_no_member.hpp"
|
||||
|
||||
int main() {
|
||||
/*
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include "common.hpp"
|
||||
#include "no_base_no_member.hpp"
|
||||
|
||||
int main() {
|
||||
#if __cplusplus >= 201103L
|
||||
|
3
make/.gitignore
vendored
Normal file
3
make/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
tmp.*
|
||||
*.tmp
|
||||
*.tmp2
|
393
make/Makefile
Normal file
393
make/Makefile
Normal file
@ -0,0 +1,393 @@
|
||||
# ?deprecated
|
||||
|
||||
# THIS FILE IS DEPRECATED
|
||||
# it is being split up into smaller
|
||||
# more understantable and testable makefiles
|
||||
# and will be completelly removed afterwards
|
||||
|
||||
## conventional targets
|
||||
|
||||
## phony targets
|
||||
|
||||
# if you don't give phony, make thinks you want to build a file
|
||||
# if a file install exists, make does nothing!
|
||||
# http://stackoverflow.com/questions/2145590/what-is-the-purpose-of-phony-in-a-makefile
|
||||
|
||||
.PHONY: all install clean help
|
||||
|
||||
# first target in file is default! all is often it by convention
|
||||
|
||||
# help. can be first if options required
|
||||
|
||||
help:
|
||||
@echo "must use an option:"
|
||||
@echo " c"
|
||||
@echo " cpp"
|
||||
|
||||
# $make #makes first target found on file
|
||||
|
||||
## conventional names
|
||||
|
||||
## help
|
||||
|
||||
# print help on cur makefile options
|
||||
|
||||
## all
|
||||
|
||||
# builds everything
|
||||
|
||||
# usually is the default target (comes first)
|
||||
|
||||
## check
|
||||
|
||||
# do test to check that application is woking properly
|
||||
|
||||
## install
|
||||
|
||||
# install after a build
|
||||
|
||||
# this basically putting built/config files in the right place with right permissions
|
||||
|
||||
# and calling auxiliary programs such as ``ldconfig``
|
||||
|
||||
## clean
|
||||
|
||||
# remove generated output/auxiliary files
|
||||
|
||||
clean:
|
||||
@rm *.o *.tmp
|
||||
|
||||
install:
|
||||
@mv out $(DIRINPATH)
|
||||
|
||||
## .SECONDARY
|
||||
|
||||
# an **intermediate** file is a file that is neither target nor prerequisite.
|
||||
|
||||
# example:
|
||||
|
||||
# a.m4 -> a.c -> a.o
|
||||
|
||||
# with a single rule:
|
||||
|
||||
a.o: a.m4
|
||||
m4 a.m4 > a.c
|
||||
gcc -o a.o a.c
|
||||
|
||||
# here a.c is intermediate.
|
||||
|
||||
# make deletes intermediate files by default because:
|
||||
|
||||
# - they are not desired outputs (those must be targets)
|
||||
# - if one of the base prerequisites is modified, this will be remade anyways
|
||||
|
||||
# if you want to keep them you can use the secondary target:
|
||||
|
||||
.SECONDARY: a.c b.c
|
||||
|
||||
## variables
|
||||
|
||||
CC=gcc
|
||||
CXX=$(CC)
|
||||
FLAGS=-Wall -Wno-unused-variable -Wno-unused-but-set-variable
|
||||
OUTEXT=.out
|
||||
OUTDIR=_out
|
||||
|
||||
$(OUTDIR)/target$(OUTEXT): dep.c
|
||||
$(CC) $(FLAGS) -o $(OUTDIR)/target$(OUTEXT) dep.c
|
||||
|
||||
# multiple vars
|
||||
articles = coat shoes mobile sweater socks\
|
||||
trousers shirt pants undershirt
|
||||
|
||||
$(articles) :; @echo put on $@; touch $@
|
||||
|
||||
# assignment
|
||||
# VARIABLE = value
|
||||
# Normal setting of a variable - values within it are recursively expanded when the variable is used, not when it's declared
|
||||
|
||||
a = $(b)
|
||||
b = $(c)
|
||||
c = c
|
||||
|
||||
echo $(a)
|
||||
# c
|
||||
|
||||
# VARIABLE := value
|
||||
# Setting of a variable with simple expansion of the values inside - values within it are expanded at declaration time.
|
||||
|
||||
# always use this
|
||||
|
||||
c := c
|
||||
b := $(c)
|
||||
a := $(b)
|
||||
|
||||
echo $(a)
|
||||
# c
|
||||
|
||||
# VARIABLE ?= value
|
||||
# Setting of a variable only if it doesn't have a value
|
||||
# VARIABLE += value
|
||||
# Appending the supplied value to the existing value
|
||||
|
||||
## define var inside rule
|
||||
all:
|
||||
$(eval X := $* )
|
||||
# set a variable inside a rule
|
||||
echo $(X)
|
||||
|
||||
## special vars
|
||||
|
||||
# $@: cur target
|
||||
# $*: part that matches % of cur target
|
||||
# $<: first cur dep
|
||||
$(OUTDIR)/target$(OUTEXT): dep.c
|
||||
$(CC) $(FLAGS) -o $@ $<
|
||||
# $? The names of all the prerequisites that are newer than the target, with spaces between them.
|
||||
# $^ and $+ The names of all the prerequisites, with spaces between them.
|
||||
# The value of $^ omits duplicate prerequisites, while $+ retains them and preserves their order.
|
||||
|
||||
## spaces
|
||||
|
||||
# **PAY ATTENTION TO THIS BECAUSE MAKE IS FUSSY ABOUT SPACES**!
|
||||
|
||||
# - you simply cannot have filenames with spaces in them. use hyphens '-' or '_' instead
|
||||
|
||||
# - in variable definition, traillinw whitespaces that follow are included!!
|
||||
|
||||
# ex:
|
||||
|
||||
a = b
|
||||
|
||||
# a = "b "
|
||||
|
||||
# never use trailling spaces!!!
|
||||
|
||||
# - you cannot have a blank line for a rule:
|
||||
|
||||
all:
|
||||
echo a
|
||||
|
||||
echo b
|
||||
|
||||
# only `echo a` will be executed!!!
|
||||
|
||||
all:
|
||||
echo a
|
||||
echo b
|
||||
|
||||
# `echo a` and `echo b` are executed
|
||||
|
||||
## include
|
||||
|
||||
# sources a file
|
||||
include make.inc
|
||||
|
||||
# continue even if missing
|
||||
-include make.inc
|
||||
|
||||
## implicit rules
|
||||
|
||||
# An explicit rule assigns the commands for several targets
|
||||
coat shoes mobile sweater socks trousers\
|
||||
shirt pants undershirt: ; @echo put on $@; touch $@
|
||||
|
||||
# Implicit rules state the prerequisites
|
||||
coat: shoes mobile sweater
|
||||
shoes: socks trousers
|
||||
mobile: trousers
|
||||
sweater: shirt
|
||||
trousers: pants shirt
|
||||
shirt: undershirt
|
||||
|
||||
## duplicate rules
|
||||
|
||||
# must use double colons
|
||||
|
||||
# socks will build both
|
||||
socks:: ; @echo get into left sock
|
||||
socks:: ; @echo get into right sock
|
||||
|
||||
## call other makefiles
|
||||
|
||||
$(MAKE)
|
||||
|
||||
## command line variables
|
||||
|
||||
###
|
||||
$make run A='"1"'
|
||||
echo $(A)
|
||||
# 1
|
||||
|
||||
###
|
||||
$make run A='"1"'
|
||||
A=2
|
||||
echo $(A)
|
||||
# 1
|
||||
|
||||
###
|
||||
$make run A='"1"'
|
||||
A=2
|
||||
echo $(A)
|
||||
# 2
|
||||
|
||||
###
|
||||
$make run A='"1"'
|
||||
A?=2
|
||||
echo $(A)
|
||||
# 1
|
||||
|
||||
$make run A='"as df"'
|
||||
echo $(A)
|
||||
# as df
|
||||
|
||||
## conditional
|
||||
|
||||
A=defined
|
||||
all: a.out
|
||||
ifdef A
|
||||
echo $(A)
|
||||
else
|
||||
echo undefined
|
||||
endif
|
||||
|
||||
## builtin functions
|
||||
|
||||
## wildcard
|
||||
|
||||
# makes an array with wildcard.
|
||||
|
||||
SRCS = $(wildcard *$(INEXT))
|
||||
|
||||
## patsubst
|
||||
|
||||
# makes an array with wildcard.
|
||||
|
||||
OUTS = $(patsubst %$(INEXT),%$(OUTEXT),$(SRCS))
|
||||
|
||||
# compile all files of a type
|
||||
|
||||
INEXT=.c
|
||||
OUTEXT=
|
||||
SRCS = $(wildcard *$(INEXT))
|
||||
OUTS = $(patsubst %$(INEXT),%$(OUTEXT),$(SRCS))
|
||||
all: $(OUTS)
|
||||
%: %$(INEXT)
|
||||
$(CC) $(CFLAGS) -o $@$(OUTEXT) $<
|
||||
|
||||
## foreach
|
||||
|
||||
# do a loop and concatenate results
|
||||
|
||||
# select all files with one of the given extensions in current directory
|
||||
|
||||
IN_DIR := ./
|
||||
IN_EXTS := .lex .y .c .cpp
|
||||
INS := $(foreach IN_EXT, $(IN_EXTS), $(wildcard $(IN_DIR)*$(IN_EXT)) )
|
||||
|
||||
## eval
|
||||
|
||||
define a variable inside a rule
|
||||
|
||||
$(eval X := $(AUX_DIR)$* )
|
||||
|
||||
$(subst from,to,text) Replace from with to in text.
|
||||
$(patsubst pattern,replacement,text) Replace words matching pattern with replacement in text.
|
||||
$(strip string) Remove excess whitespace characters from string.
|
||||
$(findstring find,text) Locate find in text.
|
||||
$(filter pattern...,text) Select words in text that match one of the pattern words.
|
||||
$(filter-out pattern...,text) Select words in text that do not match any of the pattern words.
|
||||
$(sort list) Sort the words in list lexicographically, removing duplicates.
|
||||
$(dir names...) Extract the directory part of each file name.
|
||||
$(notdir names...) Extract the non-directory part of each file name.
|
||||
$(suffix names...) Extract the suffix (the last dot and following characters) of each file name.
|
||||
$(basename names...) Extract the base name (name without suffix) of each file name.
|
||||
$(addsuffix suffix,names...) Append suffix to each word in names.
|
||||
$(addprefix prefix,names...) Prepend prefix to each word in names.
|
||||
$(join list1,list2) Join two parallel lists of words.
|
||||
$(word n,text) Extract the nth word (one-origin) of text.
|
||||
$(words text) Count the number of words in text.
|
||||
$(wordlist s,e,text) Returns the list of words in text from s to e.
|
||||
$(firstword names...) Extract the first word of names.
|
||||
$(wildcard pattern...) Find file names matching a shell file name pattern (not a '%' pattern).
|
||||
$(error text...) When this function is evaluated, make generates a fatal error with the message text.
|
||||
$(warning text...) When this function is evaluated, make generates a warning with the message text.
|
||||
|
||||
$(shell command) Execute a shell command and return its output.
|
||||
LIBS=$(shell pkg-config opencv --libs)
|
||||
|
||||
$(origin variable) Return a string describing how the make variable variable was defined.
|
||||
$(call var,param,...) Evaluate the variable var replacing any references to $(1),$(2) with the first, second, etc. param values.
|
||||
|
||||
## submake
|
||||
|
||||
# call other makefiles
|
||||
|
||||
mkdir a
|
||||
|
||||
echo -e 'a=b
|
||||
all:
|
||||
\t@echo $(a)
|
||||
\t@$(MAKE) -C a all' > makefile
|
||||
|
||||
echo -e 'all:
|
||||
\t@echo $(a)' > a/makefile
|
||||
|
||||
make
|
||||
|
||||
## implicit builtins
|
||||
|
||||
# make has some built-in rules and variables
|
||||
|
||||
# PAY ATTENTION OR THIS WILL F*** YOU UP LATER,
|
||||
# SINCE THEY MAY OVERRIDE YOUR OWN RULES AND VARIABLES WITHOUT WARNING!!!!!!!!!!!!!
|
||||
|
||||
# in this way, for example, c.c -> c.o happens automatically
|
||||
|
||||
# suffixes for which there are implicit rules (may override your own rules!):
|
||||
|
||||
# .out, .a, .ln, .o, .c, .cc, .C, .cpp, .p, .f, .F, .m, .r, .y, .l, .ym, .lm, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch .web, .sh, .elc, .el
|
||||
|
||||
# predefined vars ( ?= won't work for them! ):
|
||||
|
||||
# AR AS CC CPP FC M2C PC CO GET LEX YACC LINT MAKEINFO TEX TEXI2DVI WEAVE CWEAVE TANGLE CTANGLE RM ARFLAGS ASFLAGS CFLAGS CXXFLAGS COFLAGS CPPFLAGS FFLAGS GFLAGS LDFLAGS LFLAGS YFLAGS PFLAGS RFLAGS LINTFLAGS
|
||||
|
||||
# those vars are mainly used to control the automatic rules.
|
||||
|
||||
# to turn off the implicit rules: add a phony empty rule:
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
# as you may guess, this specifies for which suffixes automatic rules will work or not.
|
||||
|
||||
# **I SUGGEST YOU ALWAYS USE THIS**!
|
||||
|
||||
## recipes
|
||||
|
||||
## make all files of an extension inside given path
|
||||
|
||||
CC=pdflatex
|
||||
IN_EXT=.tex
|
||||
IN_DIR=src/
|
||||
OUT_DIR=_out/
|
||||
OUT_EXT=.pdf
|
||||
|
||||
INS=$(wildcard $(IN_DIR)*$(IN_EXT))
|
||||
INS_NODIR=$(notdir $(INS))
|
||||
OUTS_NODIR=$(patsubst %$(IN_EXT),%$(OUT_EXT),$(INS_NODIR))
|
||||
OUTS=$(addprefix $(OUT_DIR),$(OUTS_NODIR))
|
||||
|
||||
.PHONY: all mkdir clean
|
||||
|
||||
all: mkdir $(OUTS)
|
||||
|
||||
mkdir:
|
||||
mkdir -p "$(OUT_DIR)"
|
||||
|
||||
$(OUT_DIR)%$(OUT_EXT): $(IN_DIR)%$(IN_EXT)
|
||||
$(CC) -o "$@" "$<"u al
|
||||
|
||||
clean:
|
||||
rm -rf $(OUT_DIR) $(AUX_DIR)
|
||||
# rm *.$(OUT_EXT)
|
||||
# compile command
|
1
make/README.md
Normal file
1
make/README.md
Normal file
@ -0,0 +1 @@
|
||||
Moved to:
|
26
make/automatic-variables.mk
Normal file
26
make/automatic-variables.mk
Normal file
@ -0,0 +1,26 @@
|
||||
.POSIX:
|
||||
|
||||
## Automatic variables.
|
||||
|
||||
# https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
|
||||
|
||||
## $@
|
||||
|
||||
# Target.
|
||||
|
||||
## $<
|
||||
|
||||
# First dependency.
|
||||
|
||||
## $^
|
||||
|
||||
# All dependencies.
|
||||
|
||||
a: b c
|
||||
[ '$@' = 'a' ]
|
||||
[ '$<' = 'b' ]
|
||||
[ '$^' = 'b c' ]
|
||||
|
||||
b:
|
||||
|
||||
c:
|
7
make/bibliography.md
Normal file
7
make/bibliography.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Bibliography
|
||||
|
||||
- <http://www.jfranken.de/homepages/johannes/vortraege/make_inhalt.en.html>
|
||||
|
||||
Good first tutorial to make.
|
||||
|
||||
- <http://www-cip.physik.uni-bonn.de/pool/infos/make/advanced.html>
|
56
make/builtin-functions/Makefile
Normal file
56
make/builtin-functions/Makefile
Normal file
@ -0,0 +1,56 @@
|
||||
## shell
|
||||
|
||||
# Evaluate shell command
|
||||
|
||||
# Expands like a variable
|
||||
|
||||
SHELL_IN := a
|
||||
SHELL_OUT := $(shell echo $(SHELL_IN))
|
||||
|
||||
# Newlines and carriage returns are converted to single spaces:
|
||||
|
||||
shell_newline := $(shell printf 'a\nb')
|
||||
|
||||
## error
|
||||
|
||||
# Print error message and stop make execution.
|
||||
|
||||
ifeq (0,1)
|
||||
$(error Error message)
|
||||
endif
|
||||
|
||||
##info
|
||||
|
||||
#Print an information message.
|
||||
|
||||
$(info info message before fule)
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all:
|
||||
@[ ! '$(SHELL_OUT)' = 'a' ]
|
||||
@[ ! '$(shell echo a)' = 'a' ]
|
||||
@# Replace pattern.
|
||||
@echo patsubst:
|
||||
@echo $(patsubst %.a, %.b, a.a b.a b.b)
|
||||
@# Can only have on single `%`:
|
||||
@echo $(patsubst %.%, %, a.a b.a b.b)
|
||||
@## Path operations
|
||||
@### Basename
|
||||
@#remove extensions only! does not do the same as the POSIX basename utility!
|
||||
@echo "basename: $(basename a/b a/b.c)"
|
||||
@echo "dir: $(dir a/b a/b/ a /)" #a a/a/ ./ /
|
||||
@echo "notdir: $(notdir a/b a/b/ b /)" #b b
|
||||
@echo "filter: $(filter %.a %.b, a.a a.ab a.b )"
|
||||
@echo "filter: $(filter-out %.a %.b, a.a a.ab a.b )"
|
||||
@## eval
|
||||
@#Do make operations instead of sh operations inside a recipe.
|
||||
$(eval EVAL_VAR := a)
|
||||
@[ ! '$(EVAL_VAR)' = 'a' ]
|
||||
@## error
|
||||
@[ ! '$(shell_newline)' = 'a b' ]
|
||||
ifeq (0,1)
|
||||
$(error error message)
|
||||
endif
|
||||
@# This will be printed before other outputs.
|
||||
$(info info message rule)
|
1
make/builtin-functions/README.md
Normal file
1
make/builtin-functions/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Built-in functions
|
2
make/default-targets/.gitignore
vendored
Normal file
2
make/default-targets/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
c
|
||||
cpp
|
6
make/default-targets/README.md
Normal file
6
make/default-targets/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
Some rules are automatically defined.
|
||||
|
||||
They can be run even if you don't have a makefile in the current directory.
|
||||
|
||||
This can be a convenient way of compiling simple test files,
|
||||
but beware if make is not going to do things which you did not intend it to do behind your back!
|
8
make/default-targets/c.c
Normal file
8
make/default-targets/c.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
puts( "c" );
|
||||
return EXIT_SUCCESS;
|
||||
}
|
4
make/default-targets/clean.sh
Executable file
4
make/default-targets/clean.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
rm c
|
||||
rm cpp
|
8
make/default-targets/cpp.cpp
Normal file
8
make/default-targets/cpp.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
std::cout << "cpp" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
4
make/default-targets/make.sh
Executable file
4
make/default-targets/make.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
make c
|
||||
make cpp
|
84
make/directives/conditional/Makefile
Normal file
84
make/directives/conditional/Makefile
Normal file
@ -0,0 +1,84 @@
|
||||
## Conditional
|
||||
|
||||
## ifeq
|
||||
|
||||
ifeq (a,a)
|
||||
ifeqaa := 1
|
||||
else
|
||||
ifeqaa := 0
|
||||
endif
|
||||
|
||||
ifeq (a,b)
|
||||
ifeqab := 1
|
||||
else
|
||||
ifeqab := 0
|
||||
endif
|
||||
|
||||
# Can be used both for variable definitions and in rules.
|
||||
|
||||
# Syntax gotchas:
|
||||
|
||||
# - you **must** put a space after `ifeq`!
|
||||
# The following fails gives a separator missing error:
|
||||
|
||||
#ifeq(a,a)
|
||||
#endif
|
||||
|
||||
# - **must** be the first thing on a line. The following fails:
|
||||
|
||||
#ifeq (a,a)
|
||||
#endif
|
||||
|
||||
# Can be nested:
|
||||
|
||||
ifeq (a,a)
|
||||
ifeq (a,a)
|
||||
if_nest_eqaa := 1
|
||||
endif
|
||||
endif
|
||||
|
||||
# Only evals done before the rules are taken into account:
|
||||
|
||||
EVAL_BEFORE:=0
|
||||
|
||||
empty :=
|
||||
nonempty := a
|
||||
|
||||
.PHONY: all
|
||||
.POSIX:
|
||||
|
||||
all:
|
||||
@if [ ! $(ifeqaa) = 1 ]; then exit 1; fi
|
||||
@if [ ! $(if_nest_eqaa) = 1 ]; then exit 1; fi
|
||||
@if [ ! $(ifeqab) = 0 ]; then exit 1; fi
|
||||
ifeq (a,a)
|
||||
else
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
ifeq (a,b)
|
||||
@exit 1
|
||||
else
|
||||
endif
|
||||
|
||||
@#test if variable is empty (or just contains just spaces)
|
||||
ifeq ($(strip $(empty)),)
|
||||
else
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(nonempty)),)
|
||||
@exit 1
|
||||
else
|
||||
endif
|
||||
|
||||
@#this eval is *not* taken into acccount by ifeq! (ifeq is like a macro)
|
||||
$(eval EVAL_RULE:=0)
|
||||
ifeq ($(EVAL_RULE),0)
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
ifeq ($(EVAL_BEFORE),0)
|
||||
else
|
||||
@exit 1
|
||||
endif
|
6
make/environment-variables.mk
Normal file
6
make/environment-variables.mk
Normal file
@ -0,0 +1,6 @@
|
||||
.POSIX:
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all:
|
||||
@echo '$(my_var)'
|
20
make/include/Makefile
Normal file
20
make/include/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
.POSIX:
|
||||
|
||||
## include
|
||||
|
||||
# Copy paste given file here.
|
||||
|
||||
# Both rules and definitions can be included.
|
||||
|
||||
# Sources another makefile here like shell `.` (dot)
|
||||
|
||||
include a.makefile
|
||||
include b.makefile
|
||||
|
||||
# If the file does not exist, generate an error:
|
||||
|
||||
#include idontexist
|
||||
|
||||
# Ignore the error if the file does not exist:
|
||||
|
||||
-include idontexist-but-you-ignore-me
|
1
make/include/a.makefile
Normal file
1
make/include/a.makefile
Normal file
@ -0,0 +1 @@
|
||||
a := b
|
4
make/include/b.makefile
Normal file
4
make/include/b.makefile
Normal file
@ -0,0 +1,4 @@
|
||||
.PHONY: all
|
||||
|
||||
all:
|
||||
echo 'a = $(a)'
|
22
make/indent.mk
Normal file
22
make/indent.mk
Normal file
@ -0,0 +1,22 @@
|
||||
.POSIX:
|
||||
# This is to terminate the .POSIX: target,
|
||||
# or else following tab indented commands would be put inside it.
|
||||
a := b
|
||||
|
||||
# It you put a command that is not a valid make statment, you get `"commands commence before first target"`.
|
||||
# http://stackoverflow.com/questions/4713663/gnu-make-yields-commands-commence-before-first-target-error
|
||||
# So just use spaces always.
|
||||
|
||||
# ERROR:
|
||||
|
||||
# echo a
|
||||
|
||||
# Valid Make commands however are interpreted:
|
||||
|
||||
a := c
|
||||
|
||||
# The Linux kernel currently has a mixture of 2, 4, and 8 spaces for non-rule Makefile indentation,
|
||||
# so don't look at it for style guidance!
|
||||
|
||||
a:
|
||||
[ '$a' = 'c' ]
|
38
make/introduction.md
Normal file
38
make/introduction.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Introduction
|
||||
|
||||
Make is specified by POSIX 7 <http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html> and implemented by GNU with extensions. It is the de facto standard make tool for POSIX systems.
|
||||
|
||||
Make allows you to:
|
||||
|
||||
- make command line interfaces of the type:
|
||||
|
||||
make <something> a=b c=d
|
||||
|
||||
*very* easily.
|
||||
|
||||
- only build outputs when inputs have changed
|
||||
|
||||
This may save lots of time when building large projects.
|
||||
|
||||
## Pros and cons
|
||||
|
||||
The main problems of make are:
|
||||
|
||||
- not available on Windows
|
||||
- its Yet Another Scripting Language to learn, and uses Bash inside of it
|
||||
|
||||
## Alternatives
|
||||
|
||||
Because of the downsides of make, many other make systems have been devised. None has yet dominated on most applications, but important ones include:
|
||||
|
||||
- CMake
|
||||
|
||||
- Rake.
|
||||
|
||||
Similar to `make`, Ruby implemented with Makefiles written in pure Ruby.
|
||||
|
||||
- Apache Ant.
|
||||
|
||||
Written in Java, mainly used for Java project.
|
||||
|
||||
Makefiles are written in XML, so a bit verbose to write by hand.
|
48
make/invocation.md
Normal file
48
make/invocation.md
Normal file
@ -0,0 +1,48 @@
|
||||
# Invocation
|
||||
|
||||
## Makefile filename case
|
||||
|
||||
- http://stackoverflow.com/questions/12669367/should-i-name-makefile-or-makefile
|
||||
|
||||
GNU Make tries the following names, in order: `GNUmakefile`, `makefile` and `Makefile`.
|
||||
|
||||
`Makefile` has the advantages:
|
||||
|
||||
- appears at the top of ls by default because ASCII uppercase comes before ASCII lowercase
|
||||
- more conventional
|
||||
|
||||
`makefile` has the advantages:
|
||||
|
||||
- sticks to the other widespread convention of naming everything lowercase
|
||||
|
||||
You can also chose the file explicitly with `-f`.
|
||||
|
||||
## File extension
|
||||
|
||||
We often need pieces of makefiles that will be included in other make files.
|
||||
|
||||
The most common naming pattern for those is:
|
||||
|
||||
include.mk
|
||||
|
||||
`.mk` is recognized as makefile by most editors.
|
||||
|
||||
## f
|
||||
|
||||
Chose a makefile explicitly:
|
||||
|
||||
make -f anything.mk
|
||||
|
||||
## j
|
||||
|
||||
Let make run in 5 threads:
|
||||
|
||||
make -j5
|
||||
|
||||
*Be warned*: this will make standard output of all threads mix up so the stdout will be meaningless.
|
||||
|
||||
Also, this *may break your makefiles*, since in a rule like:
|
||||
|
||||
all: a b c
|
||||
|
||||
`a`, `b`, and `c` are run in parallel, it it might be the case that `c` *must* run only after `a` and `b`.
|
51
make/multifile/Makefile
Normal file
51
make/multifile/Makefile
Normal file
@ -0,0 +1,51 @@
|
||||
.POSIX:
|
||||
|
||||
A := a
|
||||
B := b
|
||||
|
||||
## Export
|
||||
|
||||
# Export all variables to makefiles called from this one:
|
||||
|
||||
export
|
||||
|
||||
# Export only specific variables:
|
||||
|
||||
# export A B
|
||||
|
||||
# Preventin exporting specific variables:
|
||||
|
||||
unexport B
|
||||
|
||||
# Works even with variables that were explicitly previously exported.
|
||||
|
||||
.PHONY: all a
|
||||
|
||||
all:
|
||||
## MAKE variable
|
||||
|
||||
# https://www.gnu.org/software/make/manual/html_node/MAKE-Variable.html#MAKE-Variable
|
||||
|
||||
# Standard way to call on different directory:
|
||||
|
||||
$(MAKE) -C d
|
||||
|
||||
# -C: call make on a different directory
|
||||
|
||||
# Always use the MAKE variable since this does good magic for you
|
||||
|
||||
# Equivalent way:
|
||||
|
||||
cd d && $(MAKE)
|
||||
|
||||
# `-f`: use a given file as a makefile
|
||||
|
||||
$(MAKE) -f makefile-other
|
||||
|
||||
# `-f` does not change the current directory to the directory of the given file:
|
||||
|
||||
$(MAKE) -f d/makefile
|
||||
|
||||
@# include:
|
||||
|
||||
@if [ ! "$(include_var)" = "include_var_val" ]; then exit 1; fi
|
3
make/multifile/README.md
Normal file
3
make/multifile/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
Concepts involving multiple makefiles.
|
||||
|
||||
How to call one makefile from another is called submake on the manual.
|
7
make/multifile/d/Makefile
Normal file
7
make/multifile/d/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
.PHONY: all
|
||||
|
||||
all:
|
||||
[ '$A' = 'a' ]
|
||||
[ -z '$B' ]
|
||||
@echo d
|
||||
@pwd
|
13
make/multiline-variables.mk
Normal file
13
make/multiline-variables.mk
Normal file
@ -0,0 +1,13 @@
|
||||
.POSIX:
|
||||
|
||||
# This does not work: unquoted variable error.
|
||||
multiline_inner := multiline_2
|
||||
define multiline =
|
||||
@echo multiline_1
|
||||
@echo $(multiline_inner)
|
||||
endef
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all:
|
||||
@# [ "$(multiline_TODO)" = "$$(printf '1\n2)"' ]
|
16
make/plus-sign/Makefile
Normal file
16
make/plus-sign/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
.POSIX:
|
||||
|
||||
## +
|
||||
|
||||
## plus sign prefix
|
||||
|
||||
# Run command even if `-n`, `-q`, `-t` are passed on the command line.
|
||||
|
||||
# TODO: not running with `-q`?
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all:
|
||||
echo $cmd
|
||||
echo 'no plus'
|
||||
+echo 'plus'
|
12
make/plus-sign/test
Executable file
12
make/plus-sign/test
Executable file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
echo '## default'
|
||||
make
|
||||
echo
|
||||
echo '## -n'
|
||||
make -n
|
||||
echo
|
||||
echo '## -q'
|
||||
make -q
|
||||
echo
|
||||
echo '## -t'
|
||||
make -t
|
11
make/precious/Makefile
Normal file
11
make/precious/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
.PRECIOUS: a.tmp2
|
||||
.PHONY: clean
|
||||
|
||||
%.tmp: b.tmp2
|
||||
touch a.tmp
|
||||
|
||||
%.tmp2:
|
||||
touch a.tmp2
|
||||
|
||||
clean:
|
||||
rm -f *.tmp *.tmp2
|
21
make/precious/README.md
Normal file
21
make/precious/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# PRECIOUS
|
||||
|
||||
POSIX 7.
|
||||
|
||||
Special target.
|
||||
|
||||
Keeps given intermediate build files.
|
||||
|
||||
Test:
|
||||
|
||||
make a.tmp
|
||||
|
||||
With precious: both `a.tmp` and `a.tmp2` are created.
|
||||
|
||||
Without: `a.tmp2` is created but gets removed afterwards. You can observe this with `make --dry-run a.tmp` which shows:
|
||||
|
||||
touch a.tmp2
|
||||
touch a.tmp
|
||||
rm b.tmp2
|
||||
|
||||
TODO understand better with more examples.
|
81
make/recipes/Makefile
Normal file
81
make/recipes/Makefile
Normal file
@ -0,0 +1,81 @@
|
||||
.POSIX:
|
||||
|
||||
separate-invocations:
|
||||
|
||||
## Separate invocations
|
||||
|
||||
# Each line is a separate invocation of the interpreter.
|
||||
a=true
|
||||
$$a && echo 'fail'
|
||||
|
||||
## $
|
||||
|
||||
## Escape dollar sign
|
||||
|
||||
# Must escape dollar or else make thinks its a make variable
|
||||
|
||||
dollar-escape:
|
||||
a='pass' && echo $$a
|
||||
|
||||
## Multi-line instructions
|
||||
|
||||
# If a recipe line ends in `\`, the next line is appended to it
|
||||
# and passed to the interpreter:
|
||||
#
|
||||
# - including the `\`
|
||||
# - without the newline
|
||||
|
||||
# The next line can then start at char 0 to avoid extra spaces being
|
||||
# added to the rule.
|
||||
|
||||
multiline-command:
|
||||
a='pass';\
|
||||
echo "$$a"
|
||||
|
||||
## hyphen prefix
|
||||
|
||||
## -
|
||||
|
||||
# If one interpret line returns non-0, the rule stops.
|
||||
# unless you add an hyphen `-` before that line.
|
||||
|
||||
# This can be achieved for all lines with:
|
||||
|
||||
# - the `-i` command line option
|
||||
# - the `.IGNORE` special targets
|
||||
|
||||
no-hyphen:
|
||||
false
|
||||
echo 'pass'
|
||||
|
||||
hyphen:
|
||||
-false
|
||||
echo 'pass'
|
||||
|
||||
## at sign prefix
|
||||
|
||||
## @
|
||||
|
||||
# Rule lines get put into stdout, unless you add an at sign `@` before the line.
|
||||
|
||||
# A major application is to give user messages with echo, without seeing the literal `echo`.
|
||||
|
||||
no-at:
|
||||
echo a
|
||||
|
||||
at:
|
||||
@echo a
|
||||
|
||||
# You can combine `@` and `-`.
|
||||
|
||||
at-hyphen:
|
||||
@-false
|
||||
@echo at-hyphen
|
||||
|
||||
# `@` can be stored in a variable. The Linux Kernel uses that to toggle quiet building.
|
||||
|
||||
at-var:
|
||||
$(eval Q := )
|
||||
$(Q)true
|
||||
$(eval Q := @)
|
||||
$(Q)true
|
1
make/recipes/README.md
Normal file
1
make/recipes/README.md
Normal file
@ -0,0 +1 @@
|
||||
The part that says what each rule will do.
|
8
make/recipes/interpreter/Makefile
Normal file
8
make/recipes/interpreter/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
SHELL := /usr/bin/python
|
||||
|
||||
0:
|
||||
print 0
|
||||
|
||||
1:
|
||||
a = 1;\
|
||||
print a
|
10
make/recipes/interpreter/README.md
Normal file
10
make/recipes/interpreter/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
Which program will be used to run the recipes
|
||||
|
||||
Make uses `$SHELL` var (makefile var) to determine the interpreter to use
|
||||
|
||||
Reminders:
|
||||
|
||||
- each recipe line means one separated shell invocation
|
||||
- recipe lines ending in `\\` get following line appended and are passed together to the interpreter #**with** the `\\`
|
||||
|
||||
Default: `sh`
|
19
make/recipes/test
Executable file
19
make/recipes/test
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
targets="
|
||||
separate-invocations
|
||||
dollar
|
||||
multiline-command
|
||||
dollar
|
||||
no-at
|
||||
at
|
||||
no-hyphen
|
||||
hyphen
|
||||
at-hyphen
|
||||
"
|
||||
|
||||
for target in $targets; do
|
||||
printf "\033[1;31m## $target\033[0m\n"
|
||||
make "$target"
|
||||
echo
|
||||
done
|
77
make/rule/Makefile
Normal file
77
make/rule/Makefile
Normal file
@ -0,0 +1,77 @@
|
||||
## Special rules.
|
||||
|
||||
## POSIX
|
||||
|
||||
# If not present as the first non-comment line the behaviour of Make is unspecified...
|
||||
|
||||
# This hints at how many incompatible implementations there must be out there.
|
||||
|
||||
.POSIX:
|
||||
|
||||
### PHONY
|
||||
|
||||
# If the target is given, use POSIX compliance
|
||||
|
||||
.PHONY: first depends depended depended2
|
||||
|
||||
### SUFFIXES
|
||||
|
||||
# List of file extension for which automatic rules shall be generated:
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
# You can retrive those extensions with the `SUFFIXES` automatic variable
|
||||
|
||||
### SILENT
|
||||
|
||||
# Supress command echoing from the given dependencies,
|
||||
# much like `@` for individual lines.
|
||||
|
||||
# Try:
|
||||
|
||||
# `make silent`
|
||||
# `make not-silent`
|
||||
|
||||
.SILENT: silent
|
||||
|
||||
## Default rule
|
||||
|
||||
# Whatever its name, the first rule is the default if no args.
|
||||
|
||||
# However, `all` is a very standard name whith you should use.
|
||||
|
||||
first:
|
||||
@echo first
|
||||
|
||||
depended:
|
||||
@echo depended
|
||||
|
||||
depended2:
|
||||
@echo depended2
|
||||
|
||||
## %
|
||||
|
||||
## Percent
|
||||
|
||||
# `%` equals the regex: `[^/]+`
|
||||
|
||||
# It generates a rule only when the input files exists.
|
||||
|
||||
# Or can be made by another rule.
|
||||
|
||||
# Try:
|
||||
|
||||
# - `make percent/a.elf`: a
|
||||
# - `make a.elf`: no rule because no input (`%` does not do `/`)
|
||||
# - `make percent/b.elf`: works because `b.c` is generated by another rule
|
||||
|
||||
percent/%.elf: percent/%.c
|
||||
@echo "percent/%.elf"
|
||||
#the `%` part:
|
||||
@echo "$*"
|
||||
|
||||
percent/b.c:
|
||||
touch percent/b.c
|
||||
|
||||
clean:
|
||||
percent/b.c
|
12
make/rule/README.md
Normal file
12
make/rule/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Rule
|
||||
|
||||
Rules say:
|
||||
|
||||
- I depend on another rule
|
||||
- what recipe to do for me
|
||||
|
||||
Keep in mind the rule syntax and the name of each part of a rule:
|
||||
|
||||
targets : prerequisites
|
||||
recipe
|
||||
...
|
25
make/rule/redefine/Makefile
Normal file
25
make/rule/redefine/Makefile
Normal file
@ -0,0 +1,25 @@
|
||||
# Redefining a target GNU make ignores the first, and gives a warning.
|
||||
|
||||
# It seems that POSIX says nothing about this, so the behaviour is undefined.
|
||||
|
||||
a:
|
||||
echo a0
|
||||
|
||||
a:
|
||||
echo a1
|
||||
|
||||
## Double colon suffix
|
||||
|
||||
## ::
|
||||
|
||||
# GNU extension.
|
||||
|
||||
# A target with double colon can be redefined without error.
|
||||
|
||||
# Both targets are executed, first the first one to be defined, and then the other one.
|
||||
|
||||
b::
|
||||
echo b0
|
||||
|
||||
b::
|
||||
echo b1
|
3
make/rule/redefine/README.md
Normal file
3
make/rule/redefine/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
Redefining a target GNU make ignores the first, and gives a warning.
|
||||
|
||||
It seems that POSIX says nothing about this, so the behaviour is undefined.
|
4
make/rule/timestamp/.gitignore
vendored
Normal file
4
make/rule/timestamp/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/in
|
||||
/out
|
||||
/nodep
|
||||
/phony
|
44
make/rule/timestamp/Makefile
Normal file
44
make/rule/timestamp/Makefile
Normal file
@ -0,0 +1,44 @@
|
||||
##phony
|
||||
|
||||
#if the rule is phony, then it is run even if the file exists
|
||||
|
||||
#if a target depends on a phony rule, it is always run,
|
||||
#because phony rules are never considered already done (they have no timestamp)
|
||||
|
||||
#to avoid this TODO
|
||||
|
||||
.PHONY: clean change_in phony
|
||||
|
||||
#this rule is only run if `in` is newer than `out`
|
||||
out: in
|
||||
@echo "$@"
|
||||
cp in out
|
||||
|
||||
in:
|
||||
@echo "$@"
|
||||
echo a > in
|
||||
|
||||
change_in:
|
||||
@echo "$@"
|
||||
echo a >> in
|
||||
|
||||
#if there are no dependencies,
|
||||
#the rule is only run if the file does not exist
|
||||
nodep:
|
||||
@echo "$@"
|
||||
|
||||
change_nodep:
|
||||
@echo "$@"
|
||||
echo a >> nodep
|
||||
|
||||
phony:
|
||||
@echo "$@"
|
||||
|
||||
change_phony:
|
||||
@echo "$@"
|
||||
echo a >> phony
|
||||
|
||||
clean:
|
||||
rm -f in out nodep phony
|
||||
|
||||
depends_on_phony: phony
|
7
make/rule/timestamp/README.md
Normal file
7
make/rule/timestamp/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
Rules are only made if inputs have been changed after the outputs.
|
||||
|
||||
Make determines this by comparing the time of last modification timestamp of inputs and outputs.
|
||||
|
||||
# PHONY
|
||||
|
||||
Dependencies are understood to be files unless they are put under the `.PHONY` special target.
|
32
make/rule/timestamp/test.sh
Executable file
32
make/rule/timestamp/test.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
## in out
|
||||
|
||||
#create `in`:
|
||||
make change_in
|
||||
#create `out`:
|
||||
make out
|
||||
#nothing happens because `in` is not newer than out:
|
||||
make out
|
||||
make change_in
|
||||
#out happens because `in` is newer than `out`:
|
||||
make out
|
||||
make clean
|
||||
|
||||
## nodep
|
||||
|
||||
#runs:
|
||||
make nodep
|
||||
make change_nodep
|
||||
#does not run because `nodep` exists:
|
||||
make nodep
|
||||
make clean
|
||||
|
||||
## phony
|
||||
|
||||
#runs:
|
||||
make phony
|
||||
make change_phony
|
||||
#also runs, because phony is PHONY:
|
||||
make phony
|
||||
make clean
|
20
make/target-specific-variable.mk
Normal file
20
make/target-specific-variable.mk
Normal file
@ -0,0 +1,20 @@
|
||||
.POSIX:
|
||||
|
||||
# Set a variable for a single target.
|
||||
|
||||
# TODO check: It is only possible to set one per line.
|
||||
|
||||
# TODO check: not possible to define on the same line
|
||||
# as the actual rule to avoid repeating the target.
|
||||
# But we could work around that by storing the target in a variable.
|
||||
|
||||
x := 0
|
||||
|
||||
.PHONY: a
|
||||
|
||||
a: x := 1
|
||||
a:
|
||||
@[ '$x' = '1' ]
|
||||
|
||||
b:
|
||||
@[ '$x' = '0' ]
|
5
make/template.mk
Normal file
5
make/template.mk
Normal file
@ -0,0 +1,5 @@
|
||||
.POSIX:
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all:
|
9
make/templates/README.md
Normal file
9
make/templates/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
Templates
|
||||
|
||||
Starting points for new projects.
|
||||
|
||||
Naming conventions:
|
||||
|
||||
- `single`: compile a single file into a single executable
|
||||
- `many`: compile every file in the directory to a separate executable
|
||||
- `one`: compile multiple input files into a single executable
|
1
make/templates/c-many/.gitignore
vendored
Normal file
1
make/templates/c-many/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.out
|
53
make/templates/c-many/Makefile
Normal file
53
make/templates/c-many/Makefile
Normal file
@ -0,0 +1,53 @@
|
||||
.POSIX:
|
||||
|
||||
-include params.makefile
|
||||
|
||||
O ?= 0
|
||||
STD ?= c89
|
||||
CCC ?= gcc -ggdb3 -pedantic-errors -std=$(STD) -O$(O) -Wextra
|
||||
IN_EXT ?= .c
|
||||
LIBS ?= -lm
|
||||
OUT_EXT ?= .out
|
||||
RUN ?= main
|
||||
TEST ?= test
|
||||
|
||||
OUTS := $(addsuffix $(OUT_EXT), $(basename $(wildcard *$(IN_EXT))))
|
||||
|
||||
.PHONY: all clean run
|
||||
|
||||
all: $(OUTS)
|
||||
|
||||
%$(OUT_EXT): %$(IN_EXT)
|
||||
$(CCC) -o '$@' '$<' $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f *'$(OUT_EXT)'
|
||||
|
||||
run: all
|
||||
./'$(RUN)$(OUT_EXT)'
|
||||
|
||||
run-%: %$(OUT_EXT)
|
||||
./'$<'
|
||||
|
||||
# If a `test` script exists, use it.
|
||||
# Otherwise, run a default test script which checks if all programs exit 0.
|
||||
test: all
|
||||
@\
|
||||
if [ -x $(TEST) ]; then\
|
||||
./$(TEST) '$(OUT_EXT)';\
|
||||
else\
|
||||
fail=false;\
|
||||
for t in *"$(OUT_EXT)"; do\
|
||||
if ! ./"$$t"; then\
|
||||
fail=true;\
|
||||
break;\
|
||||
fi;\
|
||||
done;\
|
||||
if $$fail; then\
|
||||
echo "ASSERT FAILED: $$t";\
|
||||
exit 1;\
|
||||
else\
|
||||
echo 'ALL ASSERTS PASSED';\
|
||||
exit 0;\
|
||||
fi;\
|
||||
fi;\
|
6
make/templates/c-many/a.c
Normal file
6
make/templates/c-many/a.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
puts("a");
|
||||
return 0;
|
||||
}
|
6
make/templates/c-many/main.c
Normal file
6
make/templates/c-many/main.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
puts("main");
|
||||
return 0;
|
||||
}
|
11
make/templates/c-many/test
Normal file
11
make/templates/c-many/test
Normal file
@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
out_ext="$1"
|
||||
for t in *"$out_ext"; do
|
||||
if ! ./"$t"; then
|
||||
echo "ASSERT FAILED: $t"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo 'ALL ASSERTS PASSED'
|
1
make/templates/c-one/.gitignore
vendored
Normal file
1
make/templates/c-one/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.out
|
27
make/templates/c-one/Makefile
Normal file
27
make/templates/c-one/Makefile
Normal file
@ -0,0 +1,27 @@
|
||||
.POSIX:
|
||||
|
||||
O ?= 0
|
||||
STD ?= c89
|
||||
CCC ?= gcc -ggdb3 -pedantic-errors -std=$(STD) -O$(O) -Wextra
|
||||
IN_EXT ?= .c
|
||||
OUT_EXT ?= .out
|
||||
RUN ?= main
|
||||
TMP_EXT ?= .o
|
||||
|
||||
INS := $(wildcard *$(IN_EXT))
|
||||
OUTS := $(INS:$(IN_EXT)=$(TMP_EXT))
|
||||
RUN_BASENAME := $(RUN)$(OUT_EXT)
|
||||
|
||||
.PHONY: clean run
|
||||
|
||||
$(RUN_BASENAME): $(OUTS)
|
||||
$(CCC) -o '$@' $+
|
||||
|
||||
%$(TMP_EXT): %$(IN_EXT)
|
||||
$(CCC) -c '$<' -o '$@'
|
||||
|
||||
clean:
|
||||
rm -f *'$(TMP_EXT)' '$(RUN_BASENAME)'
|
||||
|
||||
run: $(RUN_BASENAME)
|
||||
./'$(RUN_BASENAME)'
|
5
make/templates/c-one/a.c
Normal file
5
make/templates/c-one/a.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int a() {
|
||||
return 1;
|
||||
}
|
8
make/templates/c-one/main.c
Normal file
8
make/templates/c-one/main.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int a();
|
||||
|
||||
int main() {
|
||||
printf("%d\n", a());
|
||||
return 0;
|
||||
}
|
1
make/templates/c-single/.gitignore
vendored
Normal file
1
make/templates/c-single/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.out
|
11
make/templates/c-single/Makefile
Normal file
11
make/templates/c-single/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
.POSIX:
|
||||
.PHONY: clean run
|
||||
|
||||
main.out: main.c
|
||||
gcc -pedantic-errors -std=c89 -Wall -o '$@' '$<'
|
||||
|
||||
clean:
|
||||
rm -f main.out
|
||||
|
||||
run: main.out
|
||||
./'$<'
|
6
make/templates/c-single/main.c
Normal file
6
make/templates/c-single/main.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
puts("main");
|
||||
return 0;
|
||||
}
|
13
make/templates/fortran-one.makefile
Normal file
13
make/templates/fortran-one.makefile
Normal file
@ -0,0 +1,13 @@
|
||||
EXT ?= f
|
||||
RUN ?= main
|
||||
|
||||
.PROXY: clean run
|
||||
|
||||
main: main.f
|
||||
gfortran -o '$(RUN)' '$(RUN).$(EXT)'
|
||||
|
||||
clean:
|
||||
rm '$(RUN)'
|
||||
|
||||
run: $(RUN)
|
||||
./'$(RUN)'
|
1
make/templates/java/.gitignore
vendored
Normal file
1
make/templates/java/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.class
|
6
make/templates/java/B.java
Normal file
6
make/templates/java/B.java
Normal file
@ -0,0 +1,6 @@
|
||||
public final class B {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("B");
|
||||
System.out.println(C.c());
|
||||
}
|
||||
}
|
5
make/templates/java/C.java
Normal file
5
make/templates/java/C.java
Normal file
@ -0,0 +1,5 @@
|
||||
public final class C {
|
||||
public static String c() {
|
||||
return "C";
|
||||
}
|
||||
}
|
5
make/templates/java/Main.java
Normal file
5
make/templates/java/Main.java
Normal file
@ -0,0 +1,5 @@
|
||||
public final class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Main");
|
||||
}
|
||||
}
|
14
make/templates/java/Makefile
Normal file
14
make/templates/java/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
.POSIX:
|
||||
|
||||
RUN ?= Main
|
||||
|
||||
.PHONY: all clean run
|
||||
|
||||
all:
|
||||
javac *.java
|
||||
|
||||
clean:
|
||||
rm -f *.class
|
||||
|
||||
run: all
|
||||
java -ea '$(RUN)'
|
8
make/templates/java/README.md
Normal file
8
make/templates/java/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Java
|
||||
|
||||
javac already:
|
||||
|
||||
- compiles only if necessary based on timestamps.
|
||||
- takes care of imports for us
|
||||
|
||||
So this simple Makefile deals with all our use cases.
|
27
make/templates/nasm-many.makefile
Normal file
27
make/templates/nasm-many.makefile
Normal file
@ -0,0 +1,27 @@
|
||||
LD ?= ld
|
||||
LIB_DIR ?= lib/
|
||||
NASM ?= nasm -w+all -f $(shell if [ "`uname -m`" = 'x86_64' ]; then printf 'elf64'; else printf 'elf32'; fi )
|
||||
OUT_EXT ?= .out
|
||||
RUN ?= hello_world
|
||||
|
||||
IN_EXT := .asm
|
||||
INS := $(wildcard *$(IN_EXT))
|
||||
OUTS := $(patsubst %$(IN_EXT),%$(OUT_EXT),$(INS))
|
||||
OUT_BNAME := $(RUN)$(OUT_EXT)
|
||||
|
||||
.PRECIOUS: %.o
|
||||
.PHONY: all clean run
|
||||
|
||||
all: driver $(OUTS)
|
||||
|
||||
%$(OUT_EXT): $(OUT_DIR)%.o
|
||||
$(LD) -o '$@' '$<'
|
||||
|
||||
%.o: %.asm
|
||||
$(NASM) $(DEFINES) -o '$@' '$<'
|
||||
|
||||
clean:
|
||||
rm -f *.o *.out
|
||||
|
||||
run: all
|
||||
./$(OUT_BNAME)
|
18
make/templates/nasm-single-dry.makefile
Normal file
18
make/templates/nasm-single-dry.makefile
Normal file
@ -0,0 +1,18 @@
|
||||
NASM ?= nasm -w+all -f $(shell if [ "`uname -m`" = 'x86_64' ]; then printf 'elf64'; else printf 'elf32'; fi )
|
||||
TMP_EXT ?= .o
|
||||
OUT_EXT ?= .out
|
||||
RUN ?= main
|
||||
|
||||
OUT := $(RUN)$(OUT_EXT)
|
||||
|
||||
.PHONY: clean run
|
||||
|
||||
$(OUT): $(RUN).asm
|
||||
$(NASM) -o '$(RUN)$(TMP_EXT)' '$<'
|
||||
ld -o '$@' -s '$(RUN)$(TMP_EXT)'
|
||||
|
||||
clean:
|
||||
rm -f *$(TMP_EXT) *$(OUT_EXT)
|
||||
|
||||
run: $(OUT)
|
||||
./'$<'
|
11
make/templates/nasm-single.makefile
Normal file
11
make/templates/nasm-single.makefile
Normal file
@ -0,0 +1,11 @@
|
||||
.PHONY: clean run
|
||||
|
||||
main.out: main.asm
|
||||
nasm -w+all -f elf64 -o main.o main.asm
|
||||
ld -o main.out -s main.o
|
||||
|
||||
clean:
|
||||
rm -f *.o *.out
|
||||
|
||||
run: main.out
|
||||
./main.out
|
10
make/templates/toplevel-reuse/Makefile
Normal file
10
make/templates/toplevel-reuse/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
.POSIX:
|
||||
|
||||
DIR ?= a/
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: f g $(DIR)f
|
||||
cat $(DIR)f
|
||||
cat f
|
||||
cat g
|
18
make/templates/toplevel-reuse/README.md
Normal file
18
make/templates/toplevel-reuse/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Toplevel reuse
|
||||
|
||||
Use case: you want to reuse:
|
||||
|
||||
- a makefile
|
||||
- several build files (e.g. includes)
|
||||
|
||||
for multiple directories.
|
||||
|
||||
Concrete example: <https://github.com/cirosantilli/jamesmolloy-kernel-development-tutorials/tree/1d358ed406e6ebe49d2ee8657798aa72652c6bab>
|
||||
|
||||
## Rationale
|
||||
|
||||
The `proxy.makefile` simply forwards to the main Makefile at the toplevel directory.
|
||||
|
||||
We do this instead of directly linking to the toplevel Makefile, as it makes it easier to reuse the shared files on the toplevel like boot.asm without making a new symlink per toplevel file.
|
||||
|
||||
Another alternative to this would be to make a directory with shared files, and symlink that directory in. But still that requires one extra symlink per directory, so this method is better.
|
1
make/templates/toplevel-reuse/a/Makefile
Symbolic link
1
make/templates/toplevel-reuse/a/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../proxy.makefile
|
1
make/templates/toplevel-reuse/a/f
Normal file
1
make/templates/toplevel-reuse/a/f
Normal file
@ -0,0 +1 @@
|
||||
a
|
1
make/templates/toplevel-reuse/b/Makefile
Symbolic link
1
make/templates/toplevel-reuse/b/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../proxy.makefile
|
1
make/templates/toplevel-reuse/b/f
Normal file
1
make/templates/toplevel-reuse/b/f
Normal file
@ -0,0 +1 @@
|
||||
b
|
1
make/templates/toplevel-reuse/f
Normal file
1
make/templates/toplevel-reuse/f
Normal file
@ -0,0 +1 @@
|
||||
F
|
1
make/templates/toplevel-reuse/g
Normal file
1
make/templates/toplevel-reuse/g
Normal file
@ -0,0 +1 @@
|
||||
G
|
5
make/templates/toplevel-reuse/proxy.makefile
Normal file
5
make/templates/toplevel-reuse/proxy.makefile
Normal file
@ -0,0 +1,5 @@
|
||||
.POSIX:
|
||||
.PHONY: all
|
||||
RULE = $(MAKE) -C ../ $@ DIR='$(notdir $(shell pwd))/' $(MAKEFLAGS)
|
||||
all: ; $(RULE)
|
||||
%: ; $(RULE)
|
27
make/test
Executable file
27
make/test
Executable file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
ext='.mk'
|
||||
|
||||
assert_failed() {
|
||||
echo "ASSERT FAILED: $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_make() {
|
||||
make -f "$1" || assert_failed "$1"
|
||||
}
|
||||
|
||||
# Tests that run make without any arguments.
|
||||
# All asserts are in the makefile itself.
|
||||
for t in *"$ext"; do
|
||||
assert_make "$t"
|
||||
done
|
||||
|
||||
# Tests that need to pass arguments to makefile.
|
||||
# Asserts are made here in the shell.
|
||||
t='environment-variables.mk'
|
||||
[ "$(my_var='asdf' make -f "$t")" = 'asdf' ] || assert_failed "$t"
|
||||
|
||||
echo 'ALL ASSERTS PASSED'
|
189
make/variables.mk
Normal file
189
make/variables.mk
Normal file
@ -0,0 +1,189 @@
|
||||
.POSIX:
|
||||
|
||||
## Identifiers
|
||||
|
||||
# Things which can be part of the identifier:
|
||||
|
||||
# A variable name may be any sequence of characters not containing ‘:’, ‘#’, ‘=’, or whitespace.
|
||||
|
||||
# Variable names can even start with things that have normally other meanings in a Makefile, like `+` and `-`.
|
||||
|
||||
+plus := a
|
||||
-minus := a
|
||||
|
||||
## := vs =
|
||||
|
||||
## Lazy evaluation
|
||||
|
||||
colon_rval := a
|
||||
|
||||
# Without colon, variable expands here as in c:
|
||||
|
||||
colon := $(colon_rval)
|
||||
|
||||
# Without the colon, expansion takes the value of $(a) at the time of usage:
|
||||
|
||||
nocolon = $(colon_rval)
|
||||
colon_rval := b
|
||||
|
||||
# Summary: always use colon unless you have a very good reason not to do so,
|
||||
# non colon equals is confusing and harder to decide!
|
||||
|
||||
## eval and =
|
||||
|
||||
# lazy eval also works with eval built-in
|
||||
|
||||
nocolon_eval_rvar := a
|
||||
nocolon_eval = $(nocolon_eval_rvar)
|
||||
|
||||
## +=
|
||||
|
||||
# evaluates immediately like `:=` if lvar was first defined with `:=`
|
||||
# and later if it was first defined with `=` or `?=`
|
||||
|
||||
colon_plus_rval := c
|
||||
|
||||
colon_plus := a
|
||||
colon_plus += b
|
||||
colon_plus += $(colon_plus_rval)
|
||||
|
||||
nocolon_plus = a
|
||||
nocolon_plus += b
|
||||
nocolon_plus += $(colon_plus_rval)
|
||||
|
||||
colon_plus_rval := d
|
||||
|
||||
## ?=
|
||||
|
||||
# Define variable only if it is not defined.
|
||||
|
||||
question_var := a
|
||||
question_var ?= b
|
||||
|
||||
# Empty variables are still defined.
|
||||
|
||||
# Evaluation is defferred like in `=` (unlike `:=`)
|
||||
|
||||
question_rval_defer := a
|
||||
question_var_defer ?= $(question_rval_defer)
|
||||
question_rval_defer := b
|
||||
|
||||
## Where variables can be used
|
||||
|
||||
# You can use variables:
|
||||
|
||||
# - to give other variable names
|
||||
# - to define rules
|
||||
# - to define recipes
|
||||
|
||||
# Name a variable with another variable:
|
||||
|
||||
varname := avarname
|
||||
$(varname) := avarname_val
|
||||
|
||||
varname2 := varname
|
||||
|
||||
# TODO why does this not work:
|
||||
|
||||
# vardef := vardef_name := vardef_val
|
||||
# $(vardef)
|
||||
|
||||
# Write a rule with a variable:
|
||||
|
||||
rule := varrule: all
|
||||
|
||||
## Predefined variables
|
||||
|
||||
# Variables that are automatically set, either at startup of MAKE or inside of rules
|
||||
# depending on the rule such as $@ or $?
|
||||
|
||||
# some automatic variables can be defined in makefiles and have an effect
|
||||
|
||||
## MAKE
|
||||
|
||||
# Should be used to call other makefiles recursively.
|
||||
|
||||
# Major difference from literal `make`: uses the same interpreter,
|
||||
# e.g. `/usr/bin/mycustom/make`.
|
||||
|
||||
### MAKECMDGOALS
|
||||
|
||||
# Contains all targets given at commandline invocation.
|
||||
|
||||
# The default target if any does not count.
|
||||
|
||||
## MAKEFLAGS
|
||||
|
||||
# Flags given at invocation, e.g. `make A=b`.
|
||||
|
||||
## MAKELEVEL
|
||||
|
||||
# recursion level of make (how many makes called other makes)
|
||||
|
||||
# starts at 0
|
||||
|
||||
## MAKEFILES
|
||||
|
||||
# Input environment variable:
|
||||
# https://www.gnu.org/software/make/manual/html_node/MAKEFILES-Variable.html
|
||||
|
||||
## SHELL
|
||||
|
||||
# Interpreter used to read each line.
|
||||
|
||||
## SUFFIXES
|
||||
|
||||
# List of suffixes for which make automatically defines rules
|
||||
|
||||
## VPATH
|
||||
|
||||
# Directories where to look for prerequisite files not found in current dir.
|
||||
#
|
||||
|
||||
## Substitution variables
|
||||
|
||||
## Replace extensions
|
||||
|
||||
subst_var := a.c b.c c.c
|
||||
|
||||
## Substitution variables
|
||||
|
||||
.PHONY: all sh makecmdgoals
|
||||
|
||||
all:
|
||||
@[ '$(+plus)' = 'a' ]
|
||||
@[ '$(-minus)' = 'a' ]
|
||||
@[ '$(colon)' = 'a' ]
|
||||
@[ '$(nocolon)' = 'b' ]
|
||||
$(eval nocolon_eval_rvar := b)
|
||||
@[ '$(nocolon_eval)' = 'b' ]
|
||||
@[ '$(colon_plus)' = 'a b c' ]
|
||||
@[ '$(nocolon_plus)' = 'a b d' ]
|
||||
@[ '$(avarname)' = 'avarname_val' ]
|
||||
@[ '$(question_var)' = 'a' ]
|
||||
@[ '$(question_var_defer)' = 'b' ]
|
||||
@# You can use variables inside variables: varname2 -> avarname -> avarname:
|
||||
@[ '$($(varname2))' = 'avarname' ]
|
||||
@# if [ ! "$(vardef_name)" = "vardef_val" ]; then exit 1; fi
|
||||
$(multiline)
|
||||
@echo 'CURDIR = $(CURDIR)'
|
||||
@echo 'MAKE = $(MAKE)'
|
||||
@echo 'MAKECMDGOALS = $(MAKECMDGOALS)'
|
||||
@echo 'MAKEFLAGS = $(MAKEFLAGS)'
|
||||
@echo 'MAKEFILES = $(MAKEFILES)'
|
||||
@echo 'MAKELEVEL = $(MAKELEVEL)'
|
||||
@echo 'SHELL = $(SHELL)'
|
||||
@echo 'SUFFIXES = $(SUFFIXES)'
|
||||
@echo 'VPATH = $(VPATH)'
|
||||
@[ '$(subst_var:.c=.o)' = 'a.o b.o c.o' ]
|
||||
|
||||
$(rule)
|
||||
@echo varrule
|
||||
|
||||
# You can also use built-ins anywhere just like variables.
|
||||
# Try this with `make sh`:
|
||||
$(shell echo sh):
|
||||
@echo sh
|
||||
|
||||
makecmdgoals:
|
||||
@#
|
9
make/verbose.md
Normal file
9
make/verbose.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Verbose
|
||||
|
||||
How to print the commands that are being run and other things in order to debug large makefiles.
|
||||
|
||||
<http://stackoverflow.com/questions/5820303/how-do-i-force-make-gcc-to-show-me-the-commands>
|
||||
|
||||
make -n -f verbose.mk
|
||||
make -f verbose.mk SHELL='sh -x'
|
||||
make -f verbose.mk -p SHELL='sh -x'
|
8
make/verbose.mk
Normal file
8
make/verbose.mk
Normal file
@ -0,0 +1,8 @@
|
||||
.POSIX:
|
||||
|
||||
.PHONY:
|
||||
|
||||
A := b
|
||||
|
||||
a:
|
||||
@echo $A
|
4
scons/.gitignore
vendored
Normal file
4
scons/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*.log
|
||||
*.o
|
||||
*.out
|
||||
.sconsign.dblite
|
17
scons/README.md
Normal file
17
scons/README.md
Normal file
@ -0,0 +1,17 @@
|
||||
# SCons
|
||||
|
||||
Tested on SCons v2.3.0.
|
||||
|
||||
1. [Hello](hello/)
|
||||
1. [Multi target](multi-target/)
|
||||
1. [Alias](alias/)
|
||||
1. [Alias 2](alias2/)
|
||||
1. [Multi source](multi-source/)
|
||||
1. [Glob](glob/)
|
||||
1. [CPPPATH](cpppath/)
|
||||
1. [Library](library/)
|
||||
1. [ARGUMENTS](arguments/)
|
||||
1. [Install](install/)
|
||||
1. Compiler parameters
|
||||
1. [Define](define/)
|
||||
1. [CFLAGS](cflags/)
|
8
scons/alias/README.md
Normal file
8
scons/alias/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Alias
|
||||
|
||||
Give a new name for a target.
|
||||
|
||||
Both will have the same effect:
|
||||
|
||||
scons main.out
|
||||
scons asdf
|
3
scons/alias/SConstruct
Normal file
3
scons/alias/SConstruct
Normal file
@ -0,0 +1,3 @@
|
||||
env = Environment()
|
||||
program = env.Program(target='main.out', source=['main.c'])
|
||||
env.Alias('asdf', program)
|
5
scons/alias/main.c
Normal file
5
scons/alias/main.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
puts("hello");
|
||||
}
|
7
scons/alias2/README.md
Normal file
7
scons/alias2/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Alias 2
|
||||
|
||||
`Alias` can be called multiple times with the same name to add multiple programs to an alias:
|
||||
|
||||
scons asdf
|
||||
./main.out
|
||||
./main2.out
|
5
scons/alias2/SConstruct
Normal file
5
scons/alias2/SConstruct
Normal file
@ -0,0 +1,5 @@
|
||||
env = Environment()
|
||||
p1 = env.Program(target='main.out', source=['main.c'])
|
||||
p2 = env.Program(target='main2.out', source=['main2.c'])
|
||||
env.Alias('asdf', p1)
|
||||
env.Alias('asdf', p2)
|
5
scons/alias2/main.c
Normal file
5
scons/alias2/main.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
puts("hello");
|
||||
}
|
5
scons/alias2/main2.c
Normal file
5
scons/alias2/main2.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
puts("hello2");
|
||||
}
|
3
scons/arguments/README.md
Normal file
3
scons/arguments/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# ARGUMENTS
|
||||
|
||||
Command line arguments passed to SCons.
|
4
scons/arguments/SConstruct
Normal file
4
scons/arguments/SConstruct
Normal file
@ -0,0 +1,4 @@
|
||||
env = Environment()
|
||||
x = ARGUMENTS.get('x', '0')
|
||||
env.Append(CPPDEFINES=['X=' + x])
|
||||
env.Program(target = 'main.out', source = ['main.c'])
|
5
scons/arguments/main.c
Normal file
5
scons/arguments/main.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
printf("%d\n", X);
|
||||
}
|
7
scons/cflags/README.md
Normal file
7
scons/cflags/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
Pass compiler flags.
|
||||
|
||||
Comments on type:
|
||||
|
||||
//
|
||||
|
||||
are only legal in C99+, so C89 should fail on those.
|
5
scons/cflags/SConstruct
Normal file
5
scons/cflags/SConstruct
Normal file
@ -0,0 +1,5 @@
|
||||
env = Environment()
|
||||
std = ARGUMENTS.get('std', 'c99')
|
||||
env.Append(CCFLAGS = '-std=' + std)
|
||||
env.Append(CCFLAGS = '-Werror')
|
||||
env.Program(target = 'main.out', source = ['main.c'])
|
4
scons/cflags/main.c
Normal file
4
scons/cflags/main.c
Normal file
@ -0,0 +1,4 @@
|
||||
int main(void) {
|
||||
// C99
|
||||
return 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user