GNUmakefile 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. # disable built-in rules and variables
  2. MAKEFLAGS := Rr
  3. .SUFFIXES:
  4. # An empty variable to defeat make functions that trim whitespace.
  5. [empty] =
  6. [0-9] = 0 1 2 3 4 5 6 7 8 9
  7. [A-Z] = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
  8. [a-z] = a b c d e f g h i j k l m n o p q r s t u v w x y z
  9. [markup] = ` ~ ! @ \# $$ % ^ & * ( ) - _ = + [ { ] } \ | ; : ' " , < . > / ?
  10. [all] = $([0-9]) $([A-Z]) $([a-z]) $([markup])
  11. [space] := $([empty]) $([empty])
  12. # platform detection
  13. ifeq ($(platform),)
  14. ifeq ($(OS),Windows_NT)
  15. platform := windows
  16. endif
  17. endif
  18. ifeq ($(platform),)
  19. uname := $(shell uname)
  20. ifeq ($(uname),)
  21. platform := windows
  22. else ifneq ($(findstring Windows,$(uname)),)
  23. platform := windows
  24. else ifneq ($(findstring NT,$(uname)),)
  25. platform := windows
  26. else ifneq ($(findstring Darwin,$(uname)),)
  27. platform := macos
  28. else ifneq ($(findstring Linux,$(uname)),)
  29. platform := linux
  30. else ifneq ($(findstring BSD,$(uname)),)
  31. platform := bsd
  32. else
  33. $(error unknown platform, please specify manually.)
  34. endif
  35. endif
  36. # common commands
  37. ifeq ($(shell echo ^^),^)
  38. # cmd
  39. delete = $(info Deleting $1 ...) @del /q $(subst /,\,$1)
  40. rdelete = $(info Deleting $1 ...) @del /s /q $(subst /,\,$1) && if exist $(subst /,\,$1) (rmdir /s /q $(subst /,\,$1))
  41. else
  42. # sh
  43. delete = $(info Deleting $1 ...) @rm -f $1
  44. rdelete = $(info Deleting $1 ...) @rm -rf $1
  45. endif
  46. compiler.c = $(compiler) -x c -std=c11
  47. compiler.cpp = $(compiler) -x c++ -std=c++17
  48. compiler.objc = $(compiler) -x objective-c -std=c11
  49. compiler.objcpp = $(compiler) -x objective-c++ -std=c++17
  50. flags.c = -x c -std=c11
  51. flags.cpp = -x c++ -std=c++17
  52. flags.objc = -x objective-c -std=c11
  53. flags.objcpp = -x objective-c++ -std=c++17
  54. flags.deps = -MMD -MP -MF $(@:.o=.d)
  55. # compiler detection
  56. ifeq ($(compiler),)
  57. ifeq ($(platform),windows)
  58. compiler := g++
  59. compiler.cpp = $(compiler) -x c++ -std=gnu++17
  60. flags.cpp = -x c++ -std=gnu++17
  61. else ifeq ($(platform),macos)
  62. compiler := clang++
  63. else ifeq ($(platform),linux)
  64. compiler := g++
  65. else ifeq ($(platform),bsd)
  66. compiler := clang++
  67. else
  68. compiler := g++
  69. endif
  70. endif
  71. # build optimization levels
  72. ifeq ($(build),debug)
  73. flags += -Og -g -DBUILD_DEBUG
  74. else ifeq ($(build),stable)
  75. flags += -O1 -DBUILD_STABLE
  76. else ifeq ($(build),size)
  77. flags += -Os -DBUILD_SIZE
  78. else ifeq ($(build),release)
  79. flags += -O2 -DBUILD_RELEASE
  80. else ifeq ($(build),performance)
  81. flags += -O3 -DBUILD_PERFORMANCE
  82. endif
  83. # link-time optimization
  84. ifeq ($(lto),true)
  85. flags += -fwhole-program -flto -fno-fat-lto-objects
  86. options += -fwhole-program -flto=jobserver
  87. endif
  88. # openmp support
  89. ifeq ($(openmp),true)
  90. # macOS Xcode does not ship with OpenMP support
  91. ifneq ($(platform),macos)
  92. flags += -fopenmp
  93. options += -fopenmp
  94. endif
  95. endif
  96. # clang settings
  97. ifeq ($(findstring clang++,$(compiler)),clang++)
  98. flags += -fno-operator-names -fno-strict-aliasing -fwrapv -Wno-everything
  99. # gcc settings
  100. else ifeq ($(findstring g++,$(compiler)),g++)
  101. flags += -fno-operator-names -fno-strict-aliasing -fwrapv -Wno-trigraphs
  102. endif
  103. # windows settings
  104. ifeq ($(platform),windows)
  105. options += -mthreads -lpthread -lws2_32 -lole32
  106. options += $(if $(findstring g++,$(compiler)),-static -static-libgcc -static-libstdc++)
  107. options += $(if $(findstring true,$(console)),-mconsole,-mwindows)
  108. windres := windres
  109. endif
  110. # macos settings
  111. ifeq ($(platform),macos)
  112. flags += -stdlib=libc++
  113. options += -lc++ -lobjc
  114. endif
  115. # linux settings
  116. ifeq ($(platform),linux)
  117. options += -ldl
  118. endif
  119. # bsd settings
  120. ifeq ($(platform),bsd)
  121. flags += -I/usr/local/include
  122. options += -Wl,-rpath=/usr/local/lib
  123. options += -Wl,-rpath=/usr/local/lib/gcc8
  124. options += -lstdc++ -lm
  125. endif
  126. # threading support
  127. ifeq ($(threaded),true)
  128. ifneq ($(filter $(platform),linux bsd),)
  129. flags += -pthread
  130. options += -pthread -lrt
  131. endif
  132. endif
  133. # paths
  134. ifeq ($(object.path),)
  135. object.path := obj
  136. endif
  137. ifeq ($(output.path),)
  138. output.path := out
  139. endif
  140. # rules
  141. default: all;
  142. nall.verbose:
  143. $(info Compiler Flags:)
  144. $(foreach n,$(sort $(call unique,$(flags))),$(if $(filter-out -I%,$n),$(info $([space]) $n)))
  145. $(info Linker Options:)
  146. $(foreach n,$(sort $(call unique,$(options))),$(if $(filter-out -l%,$n),$(info $([space]) $n)))
  147. %.o: $<
  148. $(info Compiling $(subst ../,,$<) ...)
  149. @$(call compile)
  150. # function compile([arguments])
  151. compile = \
  152. $(strip \
  153. $(if $(filter %.c,$<), \
  154. $(compiler.c) $(flags.deps) $(flags) $1 -c $< -o $@ \
  155. ,$(if $(filter %.cpp,$<), \
  156. $(compiler.cpp) $(flags.deps) $(flags) $1 -c $< -o $@ \
  157. )) \
  158. )
  159. # function rwildcard(directory, pattern)
  160. rwildcard = \
  161. $(strip \
  162. $(filter $(if $2,$2,%), \
  163. $(foreach f, \
  164. $(wildcard $1*), \
  165. $(eval t = $(call rwildcard,$f/)) \
  166. $(if $t,$t,$f) \
  167. ) \
  168. ) \
  169. )
  170. # function unique(source)
  171. unique = \
  172. $(eval __temp :=) \
  173. $(strip \
  174. $(foreach s,$1,$(if $(filter $s,$(__temp)),,$(eval __temp += $s))) \
  175. $(__temp) \
  176. )
  177. # function strtr(source, from, to)
  178. strtr = \
  179. $(eval __temp := $1) \
  180. $(strip \
  181. $(foreach c, \
  182. $(join $(addsuffix :,$2),$3), \
  183. $(eval __temp := \
  184. $(subst $(word 1,$(subst :, ,$c)),$(word 2,$(subst :, ,$c)),$(__temp)) \
  185. ) \
  186. ) \
  187. $(__temp) \
  188. )
  189. # function strupper(source)
  190. strupper = $(call strtr,$1,$([a-z]),$([A-Z]))
  191. # function strlower(source)
  192. strlower = $(call strtr,$1,$([A-Z]),$([a-z]))
  193. # function strlen(source)
  194. strlen = \
  195. $(eval __temp := $(subst $([space]),_,$1)) \
  196. $(words \
  197. $(strip \
  198. $(foreach c, \
  199. $([all]), \
  200. $(eval __temp := \
  201. $(subst $c,$c ,$(__temp)) \
  202. ) \
  203. ) \
  204. $(__temp) \
  205. ) \
  206. )
  207. # function streq(source)
  208. streq = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),,1)
  209. # function strne(source)
  210. strne = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),1,)
  211. # prefix
  212. ifeq ($(platform),windows)
  213. prefix := $(subst $([space]),\$([space]),$(strip $(call strtr,$(LOCALAPPDATA),\,/)))
  214. else
  215. prefix := $(HOME)/.local
  216. endif