├── LICENSE ├── Makefile ├── README.md └── example ├── .gitignore ├── Makefile ├── config.mk └── src ├── hello.c ├── hello.h └── main.c /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Martin Dørum 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Variables from config.mk: 2 | # TARGET: compilation target 3 | # 4 | # TOOLCHAIN: prefix for toolchain: TOOLCHAIN=aarch64-linux-gnu- 5 | # COMPILER: what compiler to use 6 | # default: $(CC) for EXT=.c, $(CXX) for EXT=.cc 7 | # 8 | # FILES: list of input files 9 | # default: all files with extension $(EXT) in $(SRC) 10 | # EXT: file extension 11 | # default: .c 12 | # SRC: directory with source files (only applies if you don't specify FILES) 13 | # default: src 14 | # 15 | # FLAGS: general flags 16 | # FLAGS_DBG: flags included only when running $(TARGET)-debug 17 | # default: -g -o0 -DDEBUG 18 | # FLAGS_NDBG: flags included only when not running $(TARGET)-debug 19 | # 20 | # WARN: warning flags 21 | # default: all pedantic 22 | # LINK: libraries to dynamically link with 23 | # INCLUDE: include directories 24 | # LIBS: libraries to statically link with: libfoo.a 25 | # 26 | # DEPS: additional targets to run before the $(TARGET) step 27 | # JUNK: additional files to be cleaned by the clean target 28 | 29 | include config.mk 30 | 31 | # 32 | # Defaults 33 | # 34 | ifeq ($(WARN),) 35 | WARN=all pedantic 36 | endif 37 | ifeq ($(FLAGS_DBG),) 38 | FLAGS_DBG=-g -o0 -DDEBUG 39 | endif 40 | ifeq ($(EXT),) 41 | EXT=.c 42 | endif 43 | ifeq ($(SRC),) 44 | SRC=src 45 | endif 46 | ifeq ($(FILES),) 47 | FILES=$(shell find $(SRC) -name '*$(EXT)' | sed 's/^.\///') 48 | endif 49 | ifeq ($(COMPILER),) 50 | ifeq ($(EXT),.cc) 51 | COMPILER=$(CXX) 52 | else 53 | COMPILER=$(CC) 54 | endif 55 | endif 56 | COMPILER:=$(TOOLCHAIN)$(COMPILER) 57 | 58 | # 59 | # Find .o and .d files 60 | # 61 | OFILES=$(patsubst %$(EXT),obj/$(TARGET)/%.o,$(FILES)) 62 | DFILES=$(patsubst %$(EXT),dep/$(TARGET)/%.d,$(FILES)) 63 | 64 | # 65 | # Create FLAGS based on a bunch of variables 66 | # 67 | FLAGS:=$(FLAGS) \ 68 | $(patsubst %,-W%,$(WARN)) \ 69 | $(patsubst %,-I%,$(INCLUDE)) 70 | ifeq ($(EXT),.cc) 71 | FLAGS:=$(FLAGS) $(CXXFLAGS) 72 | else 73 | FLAGS:=$(FLAGS) $(CFLAGS) 74 | endif 75 | ifeq ($(DEBUG),1) 76 | FLAGS:=$(FLAGS) $(FLAGS_DBG) 77 | else 78 | FLAGS:=$(FLAGS) $(FLAGS_NDBG) 79 | endif 80 | FLAGS:=$(strip $(FLAGS)) 81 | 82 | LINK:=$(patsubst %,-l%,$(LINK)) 83 | 84 | # 85 | # Compile the binary 86 | # 87 | $(TARGET): $(LIBS) $(OFILES) 88 | $(COMPILER) -o $(TARGET) $(OFILES) $(LIBS) $(FLAGS) $(LINK) 89 | 90 | # 91 | # Cleanup 92 | # 93 | clean: 94 | echo cleaning 95 | rm -rf obj dep 96 | rm -f $(TARGET) $(JUNK) 97 | 98 | # 99 | # Create .d files 100 | # 101 | dep/$(TARGET)/%.d: %$(EXT) 102 | @mkdir -p $(@D) 103 | @printf $(dir obj/$(TARGET)/$*) > $@ 104 | 105 | @# Generate deps and write to file. If creating deps fails 106 | @# ((e.g an #include which refers to a file which doesn't exist), 107 | @# remove the dep file. The `&& break` is to make the build still 108 | @# fail; `rm $@` returns exit code 0. 109 | @$(COMPILER) $(FLAGS) -MM $< -o - >> $@ || rm -f "$@" && break 110 | 111 | # 112 | # Include .d files if we're not in make clean 113 | # We're not using a single make.dep file, because we only know the 114 | # source files, not the headers. 115 | # 116 | ifneq ($(MAKECMDGOALS),clean) 117 | -include $(DFILES) 118 | endif 119 | 120 | # 121 | # Create .o files 122 | # 123 | obj/$(TARGET)/%.o: %$(EXT) dep/$(TARGET)/%.d 124 | @mkdir -p $(@D) 125 | $(COMPILER) $(FLAGS) -o $@ -c $< 126 | 127 | .PHONY: clean 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Easy Makefile 2 | 3 | This is a makefile designed to be dropped in to a project and for the most part 4 | "just work" after a little bit of configuration in a `config.mk` file. 5 | 6 | Make is a great tool, but I remember how hard it was to learn. It's very 7 | different from most other build systems. It's my hope that this file can be 8 | useful for someone who's new to C or C++. 9 | 10 | If there's anything you'd like to see changed, for example limitations or bad 11 | practices, feel free to create an issue. 12 | 13 | ## Simple example 14 | 15 | Download the Makefile: 16 | 17 | ``` 18 | wget https://raw.githubusercontent.com/mortie/easy-makefile/master/Makefile 19 | ``` 20 | 21 | and create a config file for it: 22 | 23 | `config.mk`: 24 | ``` 25 | TARGET=example-program 26 | ``` 27 | 28 | Now just run `make`, and all C source files in `src/` will be compiled into a 29 | binary called `example-program`. If you change any header or source file, only 30 | the the necessary files will be recompiled the next time you run `make`. 31 | 32 | To compile C++ instead of C: 33 | 34 | `config.mk`: 35 | ``` 36 | EXT=.cc 37 | TARGET=example-program 38 | ``` 39 | 40 | Here, we set the file extension to .cc (the UNIX convention for C++ files). 41 | Instesad of `$(CC)`, the Makefile will now use `$(CXX)`, which is a C++ 42 | compiler (generally g++ on GNU/Linux systems). 43 | 44 | ## Slightly bigger example 45 | 46 | The [example directory](https://github.com/mortie/easy-makefile/tree/master/example) 47 | contains a small example project. 48 | 49 | ## Variables 50 | 51 | ### TARGET 52 | 53 | `TARGET` is the name of the binary. 54 | 55 | ### FILES 56 | 57 | `FILES` is the list of files to compile. 58 | 59 | Default value: `$(shell find $(SRC) -name '*$(EXT)' | sed 's/^.\///)` - Find 60 | all files with the extension you specify with `EXT` in the directory you 61 | specify with `SRC`. The `sed` command is to remove the annoying `./` prefix you 62 | get when setting `SRC` to the current directory (`.`). 63 | 64 | ### EXT 65 | 66 | `EXT` is the filename extension for your source files, generally `.c` for C and `.cc` for 67 | C++. 68 | 69 | Default value: `.c` 70 | 71 | ### SRC 72 | 73 | `SRC` is the directory which contains the source files. 74 | 75 | Default value: `src` 76 | 77 | ### COMPILER 78 | 79 | `COMPILER` is the compiler. This defaults to `$(CXX)` if `EXT` is `.cc`, and 80 | `$(CC)` otherwise. You generally don't need to change this yourself, as long as 81 | you use the extension `.cc` for C++ and `.c` for C. 82 | 83 | ### WARN 84 | 85 | `WARN` is a list of warning options. 86 | 87 | Default value: `all pedantic` (expands to `-Wall -Wpedantic`) 88 | 89 | ### LINK 90 | 91 | `LINK` is a list of shared libraries to link with. To link with the math 92 | library for example (`libm.so`): `LINK=m` (expands to `-lm`) 93 | 94 | ### INCLUDE 95 | 96 | `INCLUDE` is a list of directories to append to your include search path. To 97 | include a directory called `headers`: `INCLUDE=headers` (expands to 98 | `-Iheaders`) 99 | 100 | ### LIBS 101 | 102 | `LIBS` is a list of statically linked libraries (generally `libfoo.a`), which 103 | the final binary will be linked with. 104 | 105 | ### FLAGS 106 | 107 | `FLAGS` is general compiler flags. 108 | 109 | ### FLAGS\_DBG 110 | 111 | `FLAGS_DBG` is flags which are only applied when compiling in debug mode (aka 112 | `make DEBUG=1`). 113 | 114 | Default: `-g -o0 -DDEBUG` 115 | 116 | ### FLAGS\_NDBG 117 | 118 | `FLAGS_NDBG` is flags which are only applied when compiling without debug mode. 119 | 120 | ### DEPS 121 | 122 | `DEPS` is additional targets you want to add as a dependency for `$(TARGET)`. 123 | 124 | ### JUNK 125 | 126 | `JUNK` is additional files to be deleted with a `make clean`. 127 | 128 | ### TOOLCHAIN 129 | 130 | `TOOLCHAIN` is mainly for cross compiling. If you set 131 | `TOOLCHAIN=aarch64-linux-gnu-` and `CC=gcc`, source files will be compiled with 132 | `aarch64-linux-gnu-gcc`, and thus be compiled for 64-bit ARM. 133 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | obj/ 2 | dep/ 3 | example 4 | example-arm64 5 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | # Variables from config.mk: 2 | # TARGET: compilation target 3 | # 4 | # TOOLCHAIN: prefix for toolchain: TOOLCHAIN=aarch64-linux-gnu- 5 | # COMPILER: what compiler to use 6 | # default: $(CC) for EXT=.c, $(CXX) for EXT=.cc 7 | # 8 | # FILES: list of input files 9 | # default: all files with extension $(EXT) in $(SRC) 10 | # EXT: file extension 11 | # default: .c 12 | # SRC: directory with source files (only applies if you don't specify FILES) 13 | # default: src 14 | # 15 | # FLAGS: general flags 16 | # FLAGS_DBG: flags included only when running $(TARGET)-debug 17 | # default: -g -o0 -DDEBUG 18 | # FLAGS_NDBG: flags included only when not running $(TARGET)-debug 19 | # 20 | # WARN: warning flags 21 | # default: all pedantic 22 | # LINK: libraries to dynamically link with 23 | # INCLUDE: include directories 24 | # LIBS: libraries to statically link with: libfoo.a 25 | # 26 | # DEPS: additional targets to run before the $(TARGET) step 27 | # JUNK: additional files to be cleaned by the clean target 28 | 29 | include config.mk 30 | 31 | # 32 | # Defaults 33 | # 34 | ifeq ($(WARN),) 35 | WARN=all pedantic 36 | endif 37 | ifeq ($(FLAGS_DBG),) 38 | FLAGS_DBG=-g -o0 -DDEBUG 39 | endif 40 | ifeq ($(EXT),) 41 | EXT=.c 42 | endif 43 | ifeq ($(SRC),) 44 | SRC=src 45 | endif 46 | ifeq ($(FILES),) 47 | FILES=$(shell find $(SRC) -name '*$(EXT)' | sed 's/^.\///') 48 | endif 49 | ifeq ($(COMPILER),) 50 | ifeq ($(EXT),.cc) 51 | COMPILER=$(CXX) 52 | else 53 | COMPILER=$(CC) 54 | endif 55 | endif 56 | COMPILER:=$(TOOLCHAIN)$(COMPILER) 57 | 58 | # 59 | # Find .o and .d files 60 | # 61 | OFILES=$(patsubst %$(EXT),obj/$(TARGET)/%.o,$(FILES)) 62 | DFILES=$(patsubst %$(EXT),dep/$(TARGET)/%.d,$(FILES)) 63 | 64 | # 65 | # Create FLAGS based on a bunch of variables 66 | # 67 | FLAGS:=$(FLAGS) \ 68 | $(patsubst %,-W%,$(WARN)) \ 69 | $(patsubst %,-I%,$(INCLUDE)) 70 | ifeq ($(EXT),.cc) 71 | FLAGS:=$(FLAGS) $(CXXFLAGS) 72 | else 73 | FLAGS:=$(FLAGS) $(CFLAGS) 74 | endif 75 | ifeq ($(DEBUG),1) 76 | FLAGS:=$(FLAGS) $(FLAGS_DBG) 77 | else 78 | FLAGS:=$(FLAGS) $(FLAGS_NDBG) 79 | endif 80 | FLAGS:=$(strip $(FLAGS)) 81 | 82 | LINK:=$(patsubst %,-l%,$(LINK)) 83 | 84 | # 85 | # Compile the binary 86 | # 87 | $(TARGET): $(LIBS) $(OFILES) 88 | $(COMPILER) -o $(TARGET) $(OFILES) $(LIBS) $(FLAGS) $(LINK) 89 | 90 | # 91 | # Cleanup 92 | # 93 | clean: 94 | echo cleaning 95 | rm -rf obj dep 96 | rm -f $(TARGET) $(JUNK) 97 | 98 | # 99 | # Create .d files 100 | # 101 | dep/$(TARGET)/%.d: %$(EXT) 102 | @mkdir -p $(@D) 103 | @printf $(dir obj/$(TARGET)/$*) > $@ 104 | 105 | @# Generate deps and write to file. If creating deps fails 106 | @# ((e.g an #include which refers to a file which doesn't exist), 107 | @# remove the dep file. The `&& break` is to make the build still 108 | @# fail; `rm $@` returns exit code 0. 109 | @$(COMPILER) $(FLAGS) -MM $< -o - >> $@ || rm -f "$@" && break 110 | 111 | # 112 | # Include .d files if we're not in make clean 113 | # We're not using a single make.dep file, because we only know the 114 | # source files, not the headers. 115 | # 116 | ifneq ($(MAKECMDGOALS),clean) 117 | -include $(DFILES) 118 | endif 119 | 120 | # 121 | # Create .o files 122 | # 123 | obj/$(TARGET)/%.o: %$(EXT) dep/$(TARGET)/%.d 124 | @mkdir -p $(@D) 125 | $(COMPILER) $(FLAGS) -o $@ -c $< 126 | 127 | .PHONY: clean 128 | -------------------------------------------------------------------------------- /example/config.mk: -------------------------------------------------------------------------------- 1 | TARGET=example 2 | 3 | # Find .c files in src/ 4 | # These are the default values, but are included for completeness 5 | SRC=src 6 | EXT=.c 7 | 8 | # Link with the math library for sqrt 9 | LINK=m 10 | 11 | # Heavily optimize when not in debug mode 12 | FLAGS_NDBG=-O3 13 | 14 | # Enable lots of warnings, and treat warnings as errors 15 | WARN=all pedantic extra error 16 | 17 | # If we compile with `make ARCH=arm64`, cross compile for arm64. 18 | # This is usually not necessary unless you specifically want to support 19 | # cross compiling for ARM out of the box. 20 | ifeq ($(ARCH),arm64) 21 | TOOLCHAIN=aarch64-linux-gnu- 22 | CC=gcc 23 | TARGET:=$(TARGET)-arm64 24 | endif 25 | -------------------------------------------------------------------------------- /example/src/hello.c: -------------------------------------------------------------------------------- 1 | #include "hello.h" 2 | 3 | #include 4 | 5 | void printhello(int num) 6 | { 7 | for (int i = 0; i < num; ++i) 8 | printf("Hello World\n"); 9 | } 10 | -------------------------------------------------------------------------------- /example/src/hello.h: -------------------------------------------------------------------------------- 1 | #ifndef HELLO_H 2 | #define HELLO_H 3 | 4 | // Print Hello World num times 5 | void printhello(int num); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /example/src/main.c: -------------------------------------------------------------------------------- 1 | #include "hello.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | // Say Hello World sqrt(9) times 9 | printhello((int)sqrt(9)); 10 | return 0; 11 | } 12 | --------------------------------------------------------------------------------