aboutsummaryrefslogtreecommitdiff
path: root/tools/makefile.go
blob: 7dae41f986da29a00e13962bd557a96ae3c10725 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main

import (
	"bytes"
	"fmt"
	"io/fs"
	"os"
	"path"
	"strings"
)

var (
	outputExe       = "game"
	compilerExe     = "g++"
	compilerOptions = []string{
		"-m64",
		"-fno-strict-aliasing",
		"-pedantic",
		"-Wall",
		"-Wextra",
		"-Wno-deprecated-declarations",
		"-Wno-unused-parameter",
		"-Wno-format-truncation",
		"-std=c++11",
		"-pthread",
		"-DOS_LINUX=1",
		"-DARCH_X64=1",
	}
	linkerOptions = []string{
		"-Wl,-t",
		"-lcrypto",
	}
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("USAGE: makefile.exe SRCDIR")
		os.Exit(1)
	}

	sourceDir := os.Args[1]
	buildDir := path.Join(path.Dir(sourceDir), "build")

	type Object struct{ obj, src string }
	objectFiles := []Object{}
	headerFiles := []string{}

	fs.WalkDir(os.DirFS(sourceDir), ".",
		func(rel string, d fs.DirEntry, err error) error {
			if err == nil && !d.IsDir() {
				ext := path.Ext(rel)
				switch ext {
				case ".cpp", ".cxx", ".cc", ".c":
					src := rel
					obj := rel[:len(src)-len(ext)] + ".obj"
					objectFiles = append(objectFiles, Object{obj, src})
				case ".hpp", ".hxx", ".hh", ".h":
					hdr := rel
					headerFiles = append(headerFiles, hdr)
				}
			}
			return nil
		})

	output := bytes.Buffer{}

	// VARIABLES
	fmt.Fprintf(&output, "SRCDIR = %v\n", sourceDir)
	fmt.Fprintf(&output, "BUILDDIR = %v\n", buildDir)
	fmt.Fprintf(&output, "OUTPUTEXE = %v\n", outputExe)
	fmt.Fprint(&output, "\n")

	fmt.Fprintf(&output, "CC = %v\n", compilerExe)
	fmt.Fprintf(&output, "CFLAGS = %v\n", strings.Join(compilerOptions, " "))
	fmt.Fprintf(&output, "LFLAGS = %v\n", strings.Join(linkerOptions, " "))
	fmt.Fprint(&output, "\n")

	// DEBUG SWITCH
	fmt.Fprint(&output, "DEBUG ?= 0\n")
	fmt.Fprint(&output, "ifneq ($(DEBUG), 0)\n")
	fmt.Fprint(&output, "\tCFLAGS += -g -O0\n")
	fmt.Fprint(&output, "else\n")
	fmt.Fprint(&output, "\tCFLAGS += -O2\n")
	fmt.Fprint(&output, "endif\n\n")

	// HEADERS
	fmt.Fprint(&output, "HEADERS =")
	for _, header := range headerFiles {
		fmt.Fprintf(&output, " $(SRCDIR)/%v", header)
	}
	fmt.Fprint(&output, "\n\n")

	// EXECUTABLE
	fmt.Fprint(&output, "$(BUILDDIR)/$(OUTPUTEXE):")
	for _, object := range objectFiles {
		fmt.Fprintf(&output, " $(BUILDDIR)/%v", object.obj)
	}
	fmt.Fprint(&output, "\n")
	fmt.Fprint(&output, "\t$(CC) $(CFLAGS) -o $@ $^ $(LFLAGS)\n\n")

	// OBJECTS
	for _, object := range objectFiles {
		fmt.Fprintf(&output, "$(BUILDDIR)/%v: $(SRCDIR)/%v $(HEADERS)\n", object.obj, object.src)
		fmt.Fprint(&output, "\t@mkdir -p $(@D)\n")
		fmt.Fprint(&output, "\t$(CC) -c $(CFLAGS) -o $@ $<\n\n")
	}

	// PHONY
	fmt.Fprint(&output, ".PHONY: clean\n\n")
	fmt.Fprint(&output, "clean:\n\t@rm -r $(BUILDDIR)\n\n")

	if err := os.WriteFile("Makefile", output.Bytes(), 0644); err != nil {
		fmt.Printf("failed to write Makefile: %v\n", err)
		os.Exit(1)
	}

	return
}