sbf.mk 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. LOCAL_PATH := $(dir $(lastword $(MAKEFILE_LIST)))
  2. INSTALL_SH := $(abspath $(LOCAL_PATH)/../scripts/install.sh)
  3. all:
  4. .PHONY: help all clean
  5. ifneq ($(V),1)
  6. _@ :=@
  7. endif
  8. INC_DIRS ?=
  9. SRC_DIR ?= ./src
  10. TEST_PREFIX ?= test_
  11. OUT_DIR ?= ./out
  12. OS := $(shell uname)
  13. LLVM_DIR = $(LOCAL_PATH)../dependencies/platform-tools/llvm
  14. LLVM_SYSTEM_INC_DIRS := $(LLVM_DIR)/lib/clang/17/include
  15. COMPILER_RT_DIR = $(LOCAL_PATH)../dependencies/platform-tools/rust/lib/rustlib/sbf-solana-solana/lib
  16. STD_INC_DIRS := $(LLVM_DIR)/include
  17. STD_LIB_DIRS := $(LLVM_DIR)/lib
  18. ifdef LLVM_DIR
  19. CC := $(LLVM_DIR)/bin/clang
  20. CXX := $(LLVM_DIR)/bin/clang++
  21. LLD := $(LLVM_DIR)/bin/ld.lld
  22. OBJ_DUMP := $(LLVM_DIR)/bin/llvm-objdump
  23. READ_ELF := $(LLVM_DIR)/bin/llvm-readelf
  24. endif
  25. SYSTEM_INC_DIRS := \
  26. $(LOCAL_PATH)inc \
  27. $(LLVM_SYSTEM_INC_DIRS) \
  28. C_FLAGS := \
  29. -Werror \
  30. -O2 \
  31. -fno-builtin \
  32. -std=c17 \
  33. $(addprefix -isystem,$(SYSTEM_INC_DIRS)) \
  34. $(addprefix -I,$(STD_INC_DIRS)) \
  35. $(addprefix -I,$(INC_DIRS)) \
  36. ifeq ($(SOL_SBFV2),1)
  37. C_FLAGS := \
  38. $(C_FLAGS) \
  39. -DSOL_SBFV2=1
  40. endif
  41. CXX_FLAGS := \
  42. $(C_FLAGS) \
  43. -std=c++17 \
  44. SBF_C_FLAGS := \
  45. $(C_FLAGS) \
  46. -target sbf \
  47. -fPIC
  48. SBF_CXX_FLAGS := \
  49. $(CXX_FLAGS) \
  50. -target sbf \
  51. -fPIC \
  52. -fomit-frame-pointer \
  53. -fno-exceptions \
  54. -fno-asynchronous-unwind-tables \
  55. -fno-unwind-tables
  56. SBF_LLD_FLAGS := \
  57. -z notext \
  58. -shared \
  59. --Bdynamic \
  60. $(LOCAL_PATH)sbf.ld \
  61. --entry entrypoint \
  62. -L $(STD_LIB_DIRS) \
  63. -lc \
  64. ifeq ($(SOL_SBFV2),1)
  65. SBF_LLD_FLAGS := \
  66. $(SBF_LLD_FLAGS) \
  67. --pack-dyn-relocs=relr
  68. endif
  69. OBJ_DUMP_FLAGS := \
  70. --source \
  71. --disassemble \
  72. READ_ELF_FLAGS := \
  73. --all \
  74. TESTFRAMEWORK_RPATH := $(abspath $(LOCAL_PATH)../dependencies/criterion/lib)
  75. TESTFRAMEWORK_FLAGS := \
  76. -DSOL_TEST \
  77. -isystem $(LOCAL_PATH)../dependencies/criterion/include \
  78. -L $(LOCAL_PATH)../dependencies/criterion/lib \
  79. -rpath $(TESTFRAMEWORK_RPATH) \
  80. -lcriterion \
  81. MACOS_ADJUST_TEST_DYLIB := \
  82. $(if $(filter $(OS),Darwin),\
  83. $(_@)install_name_tool -change libcriterion.3.dylib $(TESTFRAMEWORK_RPATH)/libcriterion.3.dylib, \
  84. : \
  85. )
  86. TEST_C_FLAGS := \
  87. $(C_FLAGS) \
  88. $(TESTFRAMEWORK_FLAGS) \
  89. TEST_CXX_FLAGS := \
  90. $(CXX_FLAGS) \
  91. $(TESTFRAMEWORK_FLAGS) \
  92. help:
  93. @echo ''
  94. @echo 'Solana VM Program makefile'
  95. @echo ''
  96. @echo 'This makefile will build Solana Programs from C or C++ source files into ELFs'
  97. @echo ''
  98. @echo 'Assumptions:'
  99. @echo ' - Programs are located in the source directory: $(SRC_DIR)/<program name>'
  100. @echo ' - Programs are named by their directory name (eg. directory name:src/foo/ -> program name:foo)'
  101. @echo ' - Tests are located in their corresponding program directory and must being with "test_"'
  102. @echo ' - Output files will be placed in the directory: $(OUT_DIR)'
  103. @echo ''
  104. @echo 'User settings'
  105. @echo ' - The following setting are overridable on the command line, default values shown:'
  106. @echo ' - Show commands while building: V=1'
  107. @echo ' V=$(V)'
  108. @echo ' - List of include directories:'
  109. @echo ' INC_DIRS=$(INC_DIRS)'
  110. @echo ' - List of system include directories:'
  111. @echo ' SYSTEM_INC_DIRS=$(SYSTEM_INC_DIRS)'
  112. @echo ' - List of standard library include directories:'
  113. @echo ' STD_INC_DIRS=$(STD_INC_DIRS)'
  114. @echo ' - List of standard library archive directories:'
  115. @echo ' STD_LIB_DIRS=$(STD_LIB_DIRS)'
  116. @echo ' - Location of source directories:'
  117. @echo ' SRC_DIR=$(SRC_DIR)'
  118. @echo ' - Location to place output files:'
  119. @echo ' OUT_DIR=$(OUT_DIR)'
  120. @echo ' - Location of LLVM:'
  121. @echo ' LLVM_DIR=$(LLVM_DIR)'
  122. @echo ''
  123. @echo 'Usage:'
  124. @echo ' - make help - This help message'
  125. @echo ' - make all - Build all the programs and tests, run the tests'
  126. @echo ' - make programs - Build all the programs'
  127. @echo ' - make tests - Build and run all tests'
  128. @echo ' - make dump_<program name> - Dump the contents of the program to stdout'
  129. @echo ' - make readelf_<program name> - Display information about the ELF binary'
  130. @echo ' - make <program name> - Build a single program by name'
  131. @echo ' - make <test name> - Build and run a single test by name'
  132. @echo ''
  133. @echo 'Available programs:'
  134. $(foreach name, $(PROGRAM_NAMES), @echo ' - $(name)'$(\n))
  135. @echo ''
  136. @echo 'Available tests:'
  137. $(foreach name, $(TEST_NAMES), @echo ' - $(name)'$(\n))
  138. @echo ''
  139. @echo 'Example:'
  140. @echo ' - Assuming a program named foo (src/foo/foo.c)'
  141. @echo ' - make foo'
  142. @echo ' - make dump_foo'
  143. @echo ''
  144. define C_RULE
  145. $1: $2
  146. @echo "[cc] $1 ($2)"
  147. $(_@)mkdir -p $(dir $1)
  148. $(_@)$(CC) $(SBF_C_FLAGS) -o $1 -c $2
  149. endef
  150. define CC_RULE
  151. $1: $2
  152. @echo "[cxx] $1 ($2)"
  153. $(_@)mkdir -p $(dir $1)
  154. $(_@)$(CXX) $(SBF_CXX_FLAGS) -o $1 -c $2
  155. endef
  156. define D_RULE
  157. $1: $2 $(LOCAL_PATH)/sbf.mk
  158. @echo "[GEN] $1 ($2)"
  159. $(_@)mkdir -p $(dir $1)
  160. $(_@)$(CC) -M -MT '$(basename $1).o' $(SBF_C_FLAGS) $2 | sed 's,\($(basename $1)\)\.o[ :]*,\1.o $1 : ,g' > $1
  161. endef
  162. define DXX_RULE
  163. $1: $2 $(LOCAL_PATH)/sbf.mk
  164. @echo "[GEN] $1 ($2)"
  165. $(_@)mkdir -p $(dir $1)
  166. $(_@)$(CXX) -M -MT '$(basename $1).o' $(SBF_CXX_FLAGS) $2 | sed 's,\($(basename $1)\)\.o[ :]*,\1.o $1 : ,g' > $1
  167. endef
  168. define O_RULE
  169. $1: $2
  170. @echo "[llc] $1 ($2)"
  171. $(_@)mkdir -p $(dir $1)
  172. $(_@)$(LLC) $(SBF_LLC_FLAGS) -o $1 $2
  173. endef
  174. define SO_RULE
  175. $1: $2
  176. @echo "[lld] $1 ($2)"
  177. $(_@)mkdir -p $(dir $1)
  178. $(_@)$(LLD) $(SBF_LLD_FLAGS) -o $1 $2 $(COMPILER_RT_DIR)/libcompiler_builtins-*.rlib
  179. ifeq (,$(wildcard $(subst .so,-keypair.json,$1)))
  180. $(_@)solana-keygen new --no-passphrase --silent -o $(subst .so,-keypair.json,$1)
  181. endif
  182. @echo To deploy this program:
  183. @echo $$$$ solana program deploy $(abspath $1)
  184. endef
  185. define TEST_C_RULE
  186. $1: $2
  187. @echo "[test cc] $1 ($2)"
  188. $(_@)mkdir -p $(dir $1)
  189. $(_@)$(CC) $(TEST_C_FLAGS) -o $1 $2
  190. $(_@)$(MACOS_ADJUST_TEST_DYLIB) $1
  191. endef
  192. define TEST_CC_RULE
  193. $1: $2
  194. @echo "[test cxx] $1 ($2)"
  195. $(_@)mkdir -p $(dir $1)
  196. $(_@)$(CXX) $(TEST_CXX_FLAGS) -o $1 $2
  197. $(_@)$(MACOS_ADJUST_TEST_DYLIB) $1
  198. endef
  199. define TEST_D_RULE
  200. $1: $2 $(LOCAL_PATH)/sbf.mk
  201. @echo "[GEN] $1 ($2)"
  202. $(_@)mkdir -p $(dir $1)
  203. $(_@)$(CC) -M -MT '$(basename $1)' $(TEST_C_FLAGS) $2 | sed 's,\($(basename $1)\)[ :]*,\1 $1 : ,g' > $1
  204. endef
  205. define TEST_DXX_RULE
  206. $1: $2 $(LOCAL_PATH)/sbf.mk
  207. @echo "[GEN] $1 ($2)"
  208. $(_@)mkdir -p $(dir $1)
  209. $(_@)$(CXX) -M -MT '$(basename $1)' $(TEST_CXX_FLAGS) $2 | sed 's,\($(basename $1)\)[ :]*,\1 $1 : ,g' > $1
  210. endef
  211. define TEST_EXEC_RULE
  212. $1: $2
  213. LD_LIBRARY_PATH=$(TESTFRAMEWORK_RPATH) \
  214. $2$(\n)
  215. endef
  216. .PHONY: $(INSTALL_SH)
  217. $(INSTALL_SH):
  218. $(_@)$(INSTALL_SH)
  219. PROGRAM_NAMES := $(notdir $(basename $(wildcard $(SRC_DIR)/*)))
  220. define \n
  221. endef
  222. all: programs tests
  223. $(foreach PROGRAM, $(PROGRAM_NAMES), \
  224. $(eval -include $(wildcard $(OUT_DIR)/$(PROGRAM)/*.d)) \
  225. \
  226. $(eval $(PROGRAM): %: $(addprefix $(OUT_DIR)/, %.so)) \
  227. $(eval $(PROGRAM)_SRCS := \
  228. $(addprefix $(SRC_DIR)/$(PROGRAM)/, \
  229. $(filter-out $(TEST_PREFIX)%,$(notdir $(wildcard $(SRC_DIR)/$(PROGRAM)/*.c $(SRC_DIR)/$(PROGRAM)/*.cc))))) \
  230. $(eval $(PROGRAM)_OBJS := $(subst $(SRC_DIR), $(OUT_DIR), \
  231. $(patsubst %.c,%.o, \
  232. $(patsubst %.cc,%.o,$($(PROGRAM)_SRCS))))) \
  233. $(eval $($(PROGRAM)_SRCS): $(INSTALL_SH)) \
  234. $(eval $(call SO_RULE,$(OUT_DIR)/$(PROGRAM).so,$($(PROGRAM)_OBJS))) \
  235. $(foreach _,$(filter %.c,$($(PROGRAM)_SRCS)), \
  236. $(eval $(call D_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.c=%.d)),$_)) \
  237. $(eval $(call C_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.c=%.o)),$_))) \
  238. $(foreach _,$(filter %.cc,$($(PROGRAM)_SRCS)), \
  239. $(eval $(call DXX_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.cc=%.d)),$_)) \
  240. $(eval $(call CC_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.cc=%.o)),$_))) \
  241. \
  242. $(eval TESTS := $(notdir $(basename $(wildcard $(SRC_DIR)/$(PROGRAM)/$(TEST_PREFIX)*.c)))) \
  243. $(eval $(TESTS) : %: $(addprefix $(OUT_DIR)/$(PROGRAM)/, %)) \
  244. $(eval TEST_NAMES := $(TEST_NAMES) $(TESTS)) \
  245. $(foreach TEST, $(TESTS), \
  246. $(eval $(TEST)_SRCS := \
  247. $(addprefix $(SRC_DIR)/$(PROGRAM)/, \
  248. $(notdir $(wildcard $(SRC_DIR)/$(PROGRAM)/$(TEST).c $(SRC_DIR)/$(PROGRAM)/$(TEST).cc)))) \
  249. $(eval $($(TEST)_SRCS): $(INSTALL_SH)) \
  250. $(foreach _,$(filter %.c,$($(TEST)_SRCS)), \
  251. $(eval $(call TEST_D_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.c=%.d)),$_)) \
  252. $(eval $(call TEST_C_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.c=%)),$_))) \
  253. $(foreach _,$(filter %.cc, $($(TEST)_SRCS)), \
  254. $(eval $(call TEST_DXX_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.cc=%.d)),$_)) \
  255. $(eval $(call TEST_CC_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.cc=%)),$_))) \
  256. $(eval $(call TEST_EXEC_RULE,$(TEST),$(addprefix $(OUT_DIR)/$(PROGRAM)/, $(TEST)))) \
  257. ) \
  258. )
  259. .PHONY: $(PROGRAM_NAMES)
  260. programs: $(PROGRAM_NAMES)
  261. .PHONY: $(TEST_NAMES)
  262. tests: $(TEST_NAMES)
  263. dump_%: %
  264. $(_@)$(OBJ_DUMP) $(OBJ_DUMP_FLAGS) $(addprefix $(OUT_DIR)/, $(addsuffix .so, $<))
  265. readelf_%: %
  266. $(_@)$(READ_ELF) $(READ_ELF_FLAGS) $(addprefix $(OUT_DIR)/, $(addsuffix .so, $<))
  267. clean:
  268. rm -rf $(OUT_DIR)