diff --git a/programs/bpf/c/sdk/bpf.mk b/programs/bpf/c/sdk/bpf.mk index 1ff171ee21..8387147881 100644 --- a/programs/bpf/c/sdk/bpf.mk +++ b/programs/bpf/c/sdk/bpf.mk @@ -17,10 +17,12 @@ endif ifdef LLVM_DIR CC := $(LLVM_DIR)/bin/clang +CXX := $(LLVM_DIR)/bin/clang++ LLC := $(LLVM_DIR)/bin/llc OBJ_DUMP := $(LLVM_DIR)/bin/llvm-objdump else CC := clang-7 +CXX := clang++-7 LLC := llc-7 OBJ_DUMP := llvm-objdump-7 endif @@ -33,6 +35,11 @@ CC_FLAGS := \ -O2 \ -emit-llvm \ -fno-builtin \ + -std=c17 \ + +CXX_FLAGS := \ + $(CC_FLAGS) \ + -std=c++17 \ LLC_FLAGS := \ -march=bpf \ @@ -46,12 +53,12 @@ OBJ_DUMP_FLAGS := \ help: @echo 'BPF Program makefile' @echo '' - @echo 'This makefile will build BPF Programs from C source files into ELFs' + @echo 'This makefile will build BPF Programs from C or C++ source files into ELFs' @echo '' @echo 'Assumptions:' - @echo ' - Programs are a single .c source file (may include headers)' + @echo ' - Programs are a single .c or .cc source file (may include headers)' @echo ' - Programs are located in the source directory: $(SRC_DIR)' - @echo ' - Programs are named by their basename (eg. file name:foo.c -> program name:foo)' + @echo ' - Programs are named by their basename (eg. file name:foo.c/foo.cc -> program name:foo)' @echo ' - Output files will be placed in the directory: $(OUT_DIR)' @echo '' @echo 'User settings' @@ -90,6 +97,11 @@ $(OUT_DIR)/%.bc: $(SRC_DIR)/%.c $(_@)mkdir -p $(OUT_DIR) $(_@)$(CC) $(CC_FLAGS) $(SYSTEM_INC_DIRS) $(INC_DIRS) -o $@ -c $< -MD -MF $(@:.bc=.d) +$(OUT_DIR)/%.bc: $(SRC_DIR)/%.cc + @echo "[cc] $@ ($<)" + $(_@)mkdir -p $(OUT_DIR) + $(_@)$(CXX) $(CXX_FLAGS) $(SYSTEM_INC_DIRS) $(INC_DIRS) -o $@ -c $< -MD -MF $(@:.bc=.d) + .PRECIOUS: $(OUT_DIR)/%.o $(OUT_DIR)/%.o: $(OUT_DIR)/%.bc @echo "[llc] $@ ($<)" @@ -97,7 +109,7 @@ $(OUT_DIR)/%.o: $(OUT_DIR)/%.bc -include $(wildcard $(OUT_DIR)/*.d) -PROGRAM_NAMES := $(notdir $(basename $(wildcard $(SRC_DIR)/*.c))) +PROGRAM_NAMES := $(notdir $(basename $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/*.cc))) define \n diff --git a/programs/bpf/c/sdk/inc/solana_sdk.h b/programs/bpf/c/sdk/inc/solana_sdk.h index ac12a68c43..9ecf4c8b26 100644 --- a/programs/bpf/c/sdk/inc/solana_sdk.h +++ b/programs/bpf/c/sdk/inc/solana_sdk.h @@ -7,6 +7,16 @@ extern "C" { #endif +/** + * Pick up static_assert if C11 or greater + * + * Inlined here until is available + */ +#if (defined _ISOC11_SOURCE || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L)) && !defined (__cplusplus) +#undef static_assert +#define static_assert _Static_assert +#endif + /** * Numeric types */ @@ -23,15 +33,28 @@ typedef unsigned int uint32_t; typedef signed long int int64_t; typedef unsigned long int uint64_t; +#if defined (__cplusplus) || defined(static_assert) +static_assert(sizeof(int8_t) == 1); +static_assert(sizeof(uint8_t) == 1); +static_assert(sizeof(int16_t) == 2); +static_assert(sizeof(uint16_t) == 2); +static_assert(sizeof(int32_t) == 4); +static_assert(sizeof(uint32_t) == 4); +static_assert(sizeof(int64_t) == 8); +static_assert(sizeof(uint64_t) == 8); +#endif + /** * NULL */ #define NULL 0 +#ifndef __cplusplus /** * Boolean type */ typedef enum { false = 0, true } bool; +#endif /** * Helper function that prints a string to stdout @@ -194,7 +217,7 @@ SOL_FN_PREFIX bool sol_deserialize( // account userdata ka[i].userdata_len = *(uint64_t *) input; input += sizeof(uint64_t); - ka[i].userdata = input; + ka[i].userdata = (uint8_t *) input; input += ka[i].userdata_len; // program_id @@ -240,19 +263,19 @@ SOL_FN_PREFIX void sol_log_array(const uint8_t *array, int len) { /** * Prints the hexadecimal representation of the program's input parameters * - * @param num_ka Numer of SolKeyedAccounts to print * @param ka A pointer to an array of SolKeyedAccounts to print + * @param ka_len Number of SolKeyedAccounts to print * @param data A pointer to the instruction data to print * @param data_len The length in bytes of the instruction data */ SOL_FN_PREFIX void sol_log_params( - uint64_t num_ka, const SolKeyedAccounts *ka, + uint64_t ka_len, const uint8_t *data, uint64_t data_len ) { - sol_log_64(0, 0, 0, 0, num_ka); - for (int i = 0; i < num_ka; i++) { + sol_log_64(0, 0, 0, 0, ka_len); + for (int i = 0; i < ka_len; i++) { sol_log_key(ka[i].key); sol_log_64(0, 0, 0, 0, *ka[i].tokens); sol_log_array(ka[i].userdata, ka[i].userdata_len); diff --git a/programs/bpf/c/src/noop++.cc b/programs/bpf/c/src/noop++.cc new file mode 100644 index 0000000000..efd123bb74 --- /dev/null +++ b/programs/bpf/c/src/noop++.cc @@ -0,0 +1,24 @@ +/** + * @brief Example C++-based BPF program that prints out the parameters + * passed to it + */ +#include + +extern bool entrypoint(const uint8_t *input) { + SolKeyedAccounts ka[1]; + uint64_t ka_len; + const uint8_t *data; + uint64_t data_len; + + sol_log("noop++"); + + if (!sol_deserialize(input, ka, SOL_ARRAY_SIZE(ka), &ka_len, &data, &data_len)) { + return false; + } + + // Log the provided account keys and instruction input data. In the case of + // the no-op program, no account keys or input data are expected but real + // programs will have specific requirements so they can do their work. + sol_log_params(ka, ka_len, data, data_len); + return true; +} diff --git a/programs/bpf/c/src/noop.c b/programs/bpf/c/src/noop.c index c126424ca8..13c5abb5d7 100644 --- a/programs/bpf/c/src/noop.c +++ b/programs/bpf/c/src/noop.c @@ -2,34 +2,23 @@ * @brief Example C-based BPF program that prints out the parameters * passed to it */ - #include -/** - * Number of SolKeyedAccounts expected. The program should bail if an - * unexpected number of accounts are passed to the program's entrypoint - */ -#define NUM_KA 1 - extern bool entrypoint(const uint8_t *input) { - SolKeyedAccounts ka[NUM_KA]; + SolKeyedAccounts ka[1]; + uint64_t ka_len; const uint8_t *data; uint64_t data_len; - - sol_log("noop"); - if (!sol_deserialize(input, ka, NUM_KA, NULL, &data, &data_len)) { + sol_log(__FILE__); + + if (!sol_deserialize(input, ka, SOL_ARRAY_SIZE(ka), &ka_len, &data, &data_len)) { return false; } - sol_log_params(NUM_KA, ka, data, data_len); - sol_assert(sizeof(int8_t) == 1); - sol_assert(sizeof(uint8_t) == 1); - sol_assert(sizeof(int16_t) == 2); - sol_assert(sizeof(uint16_t) == 2); - sol_assert(sizeof(int32_t) == 4); - sol_assert(sizeof(uint32_t) == 4); - sol_assert(sizeof(int64_t) == 8); - sol_assert(sizeof(uint64_t) == 8); + // Log the provided account keys and instruction input data. In the case of + // the no-op program, no account keys or input data are expected but real + // programs will have specific requirements so they can do their work. + sol_log_params(ka, ka_len, data, data_len); return true; }