Move make and scons in

This commit is contained in:
Ciro Santilli 2018-02-20 18:05:35 +00:00
parent 48c3e8a81e
commit 4e8fc7c1a9
135 changed files with 2125 additions and 20 deletions

View File

@ -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)

View File

@ -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.
*/
/*

View File

@ -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()");}
};

View File

@ -33,7 +33,6 @@
*/
#include "common.hpp"
#include "no_base_no_member.hpp"
int main() {
/*

View File

@ -7,7 +7,6 @@
*/
#include "common.hpp"
#include "no_base_no_member.hpp"
int main() {
#if __cplusplus >= 201103L

3
make/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
tmp.*
*.tmp
*.tmp2

393
make/Makefile Normal file
View 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
View File

@ -0,0 +1 @@
Moved to:

View 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
View 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>

View 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)

View File

@ -0,0 +1 @@
# Built-in functions

2
make/default-targets/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
c
cpp

View 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
View 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
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
rm c
rm cpp

View 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
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
make c
make cpp

View 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

View File

@ -0,0 +1,6 @@
.POSIX:
.PHONY: all
all:
@echo '$(my_var)'

20
make/include/Makefile Normal file
View 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
View File

@ -0,0 +1 @@
a := b

4
make/include/b.makefile Normal file
View File

@ -0,0 +1,4 @@
.PHONY: all
all:
echo 'a = $(a)'

22
make/indent.mk Normal file
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
Concepts involving multiple makefiles.
How to call one makefile from another is called submake on the manual.

View File

@ -0,0 +1,7 @@
.PHONY: all
all:
[ '$A' = 'a' ]
[ -z '$B' ]
@echo d
@pwd

View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1 @@
The part that says what each rule will do.

View File

@ -0,0 +1,8 @@
SHELL := /usr/bin/python
0:
print 0
1:
a = 1;\
print a

View 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
View 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
View 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
View 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
...

View 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

View 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
View File

@ -0,0 +1,4 @@
/in
/out
/nodep
/phony

View 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

View 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
View 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

View 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
View File

@ -0,0 +1,5 @@
.POSIX:
.PHONY: all
all:

9
make/templates/README.md Normal file
View 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
View File

@ -0,0 +1 @@
*.out

View 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;\

View File

@ -0,0 +1,6 @@
#include <stdio.h>
int main() {
puts("a");
return 0;
}

View File

@ -0,0 +1,6 @@
#include <stdio.h>
int main() {
puts("main");
return 0;
}

View 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
View File

@ -0,0 +1 @@
*.out

View 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
View File

@ -0,0 +1,5 @@
#include <stdio.h>
int a() {
return 1;
}

View 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
View File

@ -0,0 +1 @@
*.out

View 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
./'$<'

View File

@ -0,0 +1,6 @@
#include <stdio.h>
int main() {
puts("main");
return 0;
}

View 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
View File

@ -0,0 +1 @@
*.class

View File

@ -0,0 +1,6 @@
public final class B {
public static void main(String[] args) {
System.out.println("B");
System.out.println(C.c());
}
}

View File

@ -0,0 +1,5 @@
public final class C {
public static String c() {
return "C";
}
}

View File

@ -0,0 +1,5 @@
public final class Main {
public static void main(String[] args) {
System.out.println("Main");
}
}

View File

@ -0,0 +1,14 @@
.POSIX:
RUN ?= Main
.PHONY: all clean run
all:
javac *.java
clean:
rm -f *.class
run: all
java -ea '$(RUN)'

View 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.

View 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)

View 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)
./'$<'

View 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

View File

@ -0,0 +1,10 @@
.POSIX:
DIR ?= a/
.PHONY: all
all: f g $(DIR)f
cat $(DIR)f
cat f
cat g

View 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.

View File

@ -0,0 +1 @@
../proxy.makefile

View File

@ -0,0 +1 @@
a

View File

@ -0,0 +1 @@
../proxy.makefile

View File

@ -0,0 +1 @@
b

View File

@ -0,0 +1 @@
F

View File

@ -0,0 +1 @@
G

View File

@ -0,0 +1,5 @@
.POSIX:
.PHONY: all
RULE = $(MAKE) -C ../ $@ DIR='$(notdir $(shell pwd))/' $(MAKEFLAGS)
all: ; $(RULE)
%: ; $(RULE)

27
make/test Executable file
View 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
View 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
View 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
View File

@ -0,0 +1,8 @@
.POSIX:
.PHONY:
A := b
a:
@echo $A

4
scons/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.log
*.o
*.out
.sconsign.dblite

17
scons/README.md Normal file
View 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
View 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
View 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
View File

@ -0,0 +1,5 @@
#include <stdio.h>
int main(void) {
puts("hello");
}

7
scons/alias2/README.md Normal file
View 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
View 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
View File

@ -0,0 +1,5 @@
#include <stdio.h>
int main(void) {
puts("hello");
}

5
scons/alias2/main2.c Normal file
View File

@ -0,0 +1,5 @@
#include <stdio.h>
int main(void) {
puts("hello2");
}

View File

@ -0,0 +1,3 @@
# ARGUMENTS
Command line arguments passed to SCons.

View 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
View File

@ -0,0 +1,5 @@
#include <stdio.h>
int main(void) {
printf("%d\n", X);
}

7
scons/cflags/README.md Normal file
View 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
View 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
View 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