-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathMakefile.msvc
117 lines (95 loc) · 3.75 KB
/
Makefile.msvc
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
# Makefile fragment for MSVC - v. 2019-04-16
# - for use with gnu make built for Windows: http://www.equation.com/servlet/equation.cmd?fa=make
TARGET:=$(TARGET).exe
# should we also define _UNICODE to use for C stdlib fns?
# common C and C++ flags
# /MD to use dynamic C runtime (msvcrt DLL); /MT to statically link C runtime (libcmt)
# if link complains about defaultlib ('LIBCMT' or 'MSVCRT'), try /verbose switch to which .lib is requesting
# LIBCMT vs. MSVCRT
CFLAGS = /MT
# C++
CXX = cl /nologo
CXXFLAGS = /std:c++14 /GR-
# C
CC = cl /nologo
CCFLAGS =
# linkerc
LD = link /nologo
LDFLAGS = /SUBSYSTEM:CONSOLE
# resource compiler
RC = rc
RCFLAGS =
DEBUG ?= 0
ifneq ($(DEBUG), 0)
CFLAGS += /Od /Zi
LDFLAGS += /DEBUG
BUILDDIR = Debug
else
# for now, we produce debug info (.pdb file) for release builds, which precludes /GL /LTCG optimizations (?)
CFLAGS += /DNDEBUG /O2 /Zi /Zo
LDFLAGS += /DEBUG /INCREMENTAL:NO /OPT:REF /OPT:ICF
BUILDDIR = Release
endif
# RTC (run-time checks) errors will cause debugger break in Visual Studio
SANITIZE ?= 0
ifneq ($(SANITIZE), 0)
CFLAGS += /RTC1
endif
ifneq ($(TOPDIR),)
OBJDIR=$(BUILDDIR)/$(TOPDIR)
else
OBJDIR=$(BUILDDIR)
endif
# include paths
INCFLAGS = $(INC:%=/I%)
INCFLAGS += $(INCSYS:%=/I%)
# defines
CFLAGS += $(DEFS:%=/D%)
# filter for cl with /showIncludes. If the 5th character of line printed by cl happens to be ':'
# it will get swallowed - we could add more matches, e.g., /C:"^[^N]" /C:"^N[^o] etc. if this is a problem.
DEPENDFILT = findstr /I /R /C:"^....[^:]" /C:"^Note:[ ]including[ ]file:[ ][ ]*$(DEPENDBASE)"
SRCBASE=$(basename $(SOURCES))
OBJ=$(SRCBASE:%=$(OBJDIR)/%.obj)
QUOTEOBJ=$(SRCBASE:%="$(OBJDIR)/%.obj")
DEPS=$(SRCBASE:%=$(OBJDIR)/%.d)
RESBASE=$(basename $(RESOURCES))
RES=$(RESBASE:%=$(OBJDIR)/%.res)
TGT=$(BUILDDIR)/$(TARGET)
# compiler will not create directories, so depend on existence of all directories in output folder
# sort removes duplicates (which cause make error)
BUILDDIRS=$(sort $(dir $(OBJ)))
# on Windows, existence check doesn't work for directories (?), so use an empty file in each directory instead
BUILDDIRSMADE=$(BUILDDIRS:%=%.made)
FCPPBASE=$(basename $(FORCECPP))
FCPPOBJ=$(FCPPBASE:%=$(OBJDIR)/%.obj)
.PHONY: all clean distclean
all: $(TGT)
# force C/C++
$(FCPPOBJ): CFLAGS += /TP $(CXXFLAGS)
# echo | set /p x="..." is trick to suppress newline; also used for each dependency added to file because I was
# unable to get rid of trailing whitespace otherwise (code that didn't add trailing whitespace when run from
# batch file did add one when pasted here!).
$(OBJDIR)/%.obj: %.cpp
@echo|set /p x="$@: " > $(basename $@).d
@($(CXX) /c $< /Fo:$@ /showIncludes $(CFLAGS) $(CXXFLAGS) $(INCFLAGS) || echo XXXDIE) | @FOR /F "tokens=1,2,3,*" %%A IN ('$(DEPENDFILT)') DO @IF "%%A"=="Note:" (echo|set /p x="%%D ">>$(basename $@).d) ELSE (@IF "%%A"=="XXXDIE" (exit 2) ELSE echo %%A %%B %%C %%D)
$(OBJDIR)/%.obj: %.c
@echo|set /p x="$@: " > $(basename $@).d
@($(CC) /c $< /Fo:$@ /showIncludes $(CFLAGS) $(CCFLAGS) $(INCFLAGS) || echo XXXDIE) | @FOR /F "tokens=1,2,3,*" %%A IN ('$(DEPENDFILT)') DO @IF "%%A"=="Note:" (echo|set /p x="%%D ">>$(basename $@).d) ELSE (@IF "%%A"=="XXXDIE" (exit 2) ELSE echo %%A %%B %%C %%D)
$(OBJDIR)/%.res: %.rc
$(RC) $(RCFLAGS) /fo $@ $<
$(TGT): $(OBJ) $(RES)
$(LD) /out:$@ $^ $(LDFLAGS) $(LIBS)
echo Built $@
# | (pipe) operator causes make to just check for existence instead of timestamp
$(OBJ): | $(BUILDDIRSMADE)
# use quoted arg so that mkdir doesn't think '/' path separators are option switches
# || VER>NUL suppresses errors thrown if folders already exist
$(BUILDDIRSMADE):
mkdir "$(dir $@)" || VER>NUL
type nul > $@
clean:
cd $(BUILDDIR) && del /S "*.obj" "*.d" "$(TARGET)"
distclean:
rd /s /q .\Debug .\Release
# header dependency files
-include $(DEPS)