diff --git a/Doxyfile b/Doxyfile index faeaa63..2dd1583 100644 --- a/Doxyfile +++ b/Doxyfile @@ -99,7 +99,7 @@ WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- -INPUT = include/evmc/evmc.h +INPUT = include/evmc/ INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = NO @@ -264,7 +264,7 @@ EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = -PREDEFINED = +PREDEFINED = EVMC_DOCUMENTATION=1 EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- diff --git a/examples/examplevm/CMakeLists.txt b/examples/examplevm/CMakeLists.txt index d418218..031d6eb 100644 --- a/examples/examplevm/CMakeLists.txt +++ b/examples/examplevm/CMakeLists.txt @@ -1,4 +1,4 @@ -# EVMC -- Ethereum Client-VM Connector API +# EVMC: Ethereum Client-VM Connector API # Copyright 2018 Pawel Bylica. # Licensed under the MIT License. See the LICENSE file. @@ -6,9 +6,16 @@ include(GNUInstallDirs) add_library(evmc-examplevm examplevm.c) target_link_libraries(evmc-examplevm PRIVATE evmc) -set_target_properties(evmc-examplevm PROPERTIES DEBUG_POSTFIX "") +set_target_properties( + evmc-examplevm PROPERTIES + DEBUG_POSTFIX "" + RUNTIME_OUTPUT_DIRECTORY .. + LIBRARY_OUTPUT_DIRECTORY .. +) -install(TARGETS evmc-examplevm +install( + TARGETS evmc-examplevm ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/examples/examplevm/examplevm.c b/examples/examplevm/examplevm.c index e1305e7..1ed8dd9 100644 --- a/examples/examplevm/examplevm.c +++ b/examples/examplevm/examplevm.c @@ -11,7 +11,7 @@ struct examplevm int verbose; }; -static void evmc_destroy(struct evmc_instance* evm) +static void destroy(struct evmc_instance* evm) { free(evm); } @@ -19,7 +19,7 @@ static void evmc_destroy(struct evmc_instance* evm) /// Example options. /// /// VMs are allowed to omit this function implementation. -int evmc_set_option(struct evmc_instance* instance, char const* name, char const* value) +static int set_option(struct evmc_instance* instance, char const* name, char const* value) { struct examplevm* vm = (struct examplevm*)instance; if (strcmp(name, "verbose") == 0) @@ -34,7 +34,7 @@ int evmc_set_option(struct evmc_instance* instance, char const* name, char const return 0; } -static void evmc_release_result(struct evmc_result const* result) +static void release_result(struct evmc_result const* result) { (void)result; } @@ -103,7 +103,7 @@ static struct evmc_result execute(struct evmc_instance* instance, return ret; } - ret.release = evmc_release_result; + ret.release = release_result; ret.status_code = EVMC_FAILURE; ret.gas_left = 0; @@ -119,9 +119,9 @@ struct evmc_instance* evmc_create_examplevm() .abi_version = EVMC_ABI_VERSION, .name = "examplevm", .version = "0.0.0", - .destroy = evmc_destroy, + .destroy = destroy, .execute = execute, - .set_option = evmc_set_option, + .set_option = set_option, }; struct examplevm* vm = calloc(1, sizeof(struct examplevm)); struct evmc_instance* interface = &vm->instance; diff --git a/include/evmc/evmc.h b/include/evmc/evmc.h index d8f8cab..e0c88fe 100644 --- a/include/evmc/evmc.h +++ b/include/evmc/evmc.h @@ -732,16 +732,24 @@ struct evmc_instance /* END Python CFFI declarations */ +#if EVMC_DOCUMENTATION /** * Example of a function creating an instance of an example EVM implementation. * - * Each EVM implementation MUST provide a function returning an EVM instance. - * The function SHOULD be named `evmc_create_(void)`. + * Each EVM implementation MUST provide a function returning an EVM instance. + * The function SHOULD be named `evmc_create_(void)`. If the VM name contains hyphens + * replaces them with underscores in the function names. * - * @return EVM instance or NULL indicating instance creation failure. + * @par Binaries naming convention + * For VMs distributed as shared libraries, the name of the library SHOULD match the VM name. + * The convetional library filename prefixes and extensions SHOULD be ignored by the Client. + * For example, the shared library with the "beta-interpreter" implementation may be named + * `libbeta-interpreter.so`. * - * struct evmc_instance* evmc_create_examplevm(void); + * @return EVM instance or NULL indicating instance creation failure. */ +struct evmc_instance* evmc_create_examplevm(void); +#endif #if __cplusplus } diff --git a/include/evmc/utils.h b/include/evmc/utils.h index c527c61..fd0cf90 100644 --- a/include/evmc/utils.h +++ b/include/evmc/utils.h @@ -8,5 +8,5 @@ #ifdef _MSC_VER #define EVMC_EXPORT __declspec(dllexport) #else -#define EVMC_EXPORT __attribute__ ((visibility ("default"))) +#define EVMC_EXPORT __attribute__((visibility("default"))) #endif diff --git a/test/vmtester/CMakeLists.txt b/test/vmtester/CMakeLists.txt index a579dad..fbff90d 100644 --- a/test/vmtester/CMakeLists.txt +++ b/test/vmtester/CMakeLists.txt @@ -8,6 +8,7 @@ hunter_add_package(Boost COMPONENTS program_options filesystem system) find_package(Boost CONFIG REQUIRED program_options filesystem system) add_executable(evmc-vmtester vmtester.hpp vmtester.cpp tests.cpp) +set_target_properties(evmc-vmtester PROPERTIES RUNTIME_OUTPUT_DIRECTORY ..) target_link_libraries( evmc-vmtester diff --git a/test/vmtester/vmtester.cpp b/test/vmtester/vmtester.cpp index 792676f..3c5821c 100644 --- a/test/vmtester/vmtester.cpp +++ b/test/vmtester/vmtester.cpp @@ -35,6 +35,38 @@ evmc_instance* get_vm_instance() return vm.get(); } +std::vector get_vm_names(const fs::path path) +{ + std::vector names; + + // Get the filename without extension. + auto name = path.stem().string(); + + // Skip the optional library name prefix. + const std::string lib_name_prefix{"lib"}; + if (name.find(lib_name_prefix) == 0) + name = name.substr(lib_name_prefix.size()); + + size_t hyphen_pos = 0; + const std::string hyphen{"-"}; + if ((hyphen_pos = name.find(hyphen)) != std::string::npos) + { + // Replace the hyphen with underscore. + name.replace(hyphen_pos, hyphen.size(), "_"); + names.emplace_back(name); + + // Also add the name without the hyphen-separated prefix. + names.emplace_back(name.substr(hyphen_pos + hyphen.size())); + } + else + { + // Add the filename as the name. + names.emplace_back(std::move(name)); + } + + return names; +} + int main(int argc, char* argv[]) { try @@ -65,23 +97,37 @@ int main(int argc, char* argv[]) opts::notify(variables_map); - auto symbols = dll::library_info{vm_path}.symbols(); - auto it = std::find_if(symbols.begin(), symbols.end(), [](const std::string& symbol) { - return symbol.find("evmc_create_") == 0; - }); - if (it == symbols.end()) + std::cout << "Testing " << vm_path.filename().string() << "\n" + << "Path: " << vm_path.string() << "\n"; + + for (auto&& name : get_vm_names(vm_path)) + { + try + { + const std::string create_fn_name = "evmc_create_" + name; + std::cout << "Seeking `" << create_fn_name << "`... "; + create_fn = dll::import(vm_path, create_fn_name); + std::cout << "found.\n"; + break; + } + catch (boost::system::system_error& err) + { + using namespace boost::system; + const error_code windows_error{127, system_category()}; + constexpr auto posix_error = errc::invalid_seek; + if (err.code() != posix_error && err.code() != windows_error) + throw; // Error other than "symbol not found". + std::cout << "not found.\n"; + } + } + + if (!create_fn) { std::cerr << "EVMC create function not found in " << vm_path.string() << "\n"; return 2; } - const std::string& create_fn_name = *it; - - std::cout << "Testing " << vm_path.filename().string() << "\n " - << "Path: " << vm_path.string() << "\n " - << "Create function: " << create_fn_name << "()\n\n"; - - create_fn = dll::import(vm_path, create_fn_name); + std::cout << std::endl; return RUN_ALL_TESTS(); } catch (const std::exception& ex)