diff --git a/Makefile b/Makefile index f749649..45b2b16 100644 --- a/Makefile +++ b/Makefile @@ -4,27 +4,28 @@ # redeclaration bug (map.go vs linkname_swiss.go conflict). export GOEXPERIMENT=noswissmap -BUILD_DIR := build -TEST_BIN := $(BUILD_DIR)/test/c/Test -BENCH_LIGHT := $(BUILD_DIR)/src/benchmark/Benchmark_LIGHT -BENCH_FULL := $(BUILD_DIR)/src/benchmark/Benchmark_FULL +BUILD_DIR := build +BENCH_DIR := $(BUILD_DIR)/src/benchmark + +BUILD_INPUTS := $(shell find src test/c cmake -type f \( \ + -name '*.c' -o -name '*.h' -o -name '*.cpp' -o \ + -name '*.cmake' -o -name 'CMakeLists.txt' \)) +BUILD_INPUTS += $(wildcard *.go) go.mod go.sum CMakeLists.txt Makefile build.sh \ + setup.py test/python/requirements.txt # --------------------------------------------------------------------------- # Build targets # --------------------------------------------------------------------------- # Stamp file: touched by build.sh on success to track freshness. -$(BUILD_DIR)/.built: $(shell find src -name '*.c' -o -name '*.h' -o -name '*.cpp') \ - ethash.go ethashc.go compat.go go.mod CMakeLists.txt +$(BUILD_DIR)/.built: $(BUILD_INPUTS) ./build.sh - @touch $(BUILD_DIR)/.built build: $(BUILD_DIR)/.built + @test -n "$$(find $(BUILD_DIR)/test/c -type f \( -name Test -o -name Test.exe \) -print 2>/dev/null | head -n 1)" || { echo "Required C test binary is missing under $(BUILD_DIR)/test/c" >&2; exit 1; } -$(BENCH_LIGHT) $(BENCH_FULL): $(BUILD_DIR)/.built - cd $(BUILD_DIR) && make Benchmark_LIGHT Benchmark_FULL - -build-bench: $(BENCH_LIGHT) $(BENCH_FULL) +build-bench: $(BUILD_DIR)/.built + cmake --build $(BUILD_DIR) --config Release --target Benchmark_LIGHT Benchmark_FULL # --------------------------------------------------------------------------- # Test targets (each depends only on the build it actually needs) @@ -46,11 +47,17 @@ test-all: $(BUILD_DIR)/.built # Benchmark targets # --------------------------------------------------------------------------- -bench-light: $(BENCH_LIGHT) - cd $(BUILD_DIR) && ./src/benchmark/Benchmark_LIGHT - -bench-full: $(BENCH_FULL) - cd $(BUILD_DIR) && ./src/benchmark/Benchmark_FULL +bench-light: build-bench + @BENCH_BIN="$$(find "$(abspath $(BENCH_DIR))" -type f \( -name Benchmark_LIGHT -o -name Benchmark_LIGHT.exe \) -path '*/Release/*' -print -quit)"; \ + [ -n "$$BENCH_BIN" ] || BENCH_BIN="$$(find "$(abspath $(BENCH_DIR))" -type f \( -name Benchmark_LIGHT -o -name Benchmark_LIGHT.exe \) -print -quit)"; \ + [ -n "$$BENCH_BIN" ] || { echo "Benchmark_LIGHT is missing under $(BENCH_DIR)" >&2; exit 1; }; \ + cd $(BUILD_DIR) && "$$BENCH_BIN" + +bench-full: build-bench + @BENCH_BIN="$$(find "$(abspath $(BENCH_DIR))" -type f \( -name Benchmark_FULL -o -name Benchmark_FULL.exe \) -path '*/Release/*' -print -quit)"; \ + [ -n "$$BENCH_BIN" ] || BENCH_BIN="$$(find "$(abspath $(BENCH_DIR))" -type f \( -name Benchmark_FULL -o -name Benchmark_FULL.exe \) -print -quit)"; \ + [ -n "$$BENCH_BIN" ] || { echo "Benchmark_FULL is missing under $(BENCH_DIR)" >&2; exit 1; }; \ + cd $(BUILD_DIR) && "$$BENCH_BIN" bench: bench-light bench-full diff --git a/README.md b/README.md index 2b2c3b5..aec3a10 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,39 @@ For details on this project, please see the Ethereum wiki: https://github.com/ethereum/wiki/wiki/Ethash +## Building + +The C test suite requires CMake, a C/C++ compiler, and the Boost filesystem, +system, and unit test framework components. Missing components cause the build +to fail during CMake configuration rather than silently skipping the tests. + +On Ubuntu/Debian: + +```sh +sudo apt update +sudo apt install -y cmake build-essential libboost-test-dev \ + libboost-filesystem-dev libboost-system-dev python3-venv python3-dev +``` + +On macOS with Homebrew: + +```sh +brew install cmake boost python@3.13 +``` + +If using a versioned, keg-only Boost formula, expose its prefix to CMake: + +```sh +export BOOST_ROOT="$(brew --prefix boost@1.85)" +``` + +Then build and run all tests: + +```sh +make rebuild +make test-all +``` + ### Coding Style for C++ code: Follow the same exact style as in [cpp-ethereum](https://github.com/ethereum/cpp-ethereum/blob/develop/CodingStandards.txt) diff --git a/build.sh b/build.sh index 22ef5eb..d410ed1 100755 --- a/build.sh +++ b/build.sh @@ -29,6 +29,8 @@ fi # C/C++ build (cmake → libethash.a + Test binary + Python extension) # --------------------------------------------------------------------------- mkdir -p "$BUILD_DIR" +# Never leave a stale success marker after a failed rebuild. +rm -f "$BUILD_DIR/.built" cd "$BUILD_DIR" cmake "$REPO_ROOT" -DCMAKE_BUILD_TYPE=Release > /dev/null 2>&1 || { @@ -44,13 +46,22 @@ if grep -q "microsoft\|WSL" /proc/version 2>/dev/null; then touch "$REPO_ROOT/src/python/core.c" fi -make +# Test is a required build artifact. Build it explicitly so a missing CMake +# target fails this script before the success stamp is written. Use CMake's +# build command so this also works with Ninja and non-Makefile generators. +cmake --build "$BUILD_DIR" --config Release --target Test + +TEST_BIN="$(find "$BUILD_DIR/test/c" -type f \( -name Test -o -name Test.exe \) -print 2>/dev/null | head -n 1 || true)" +if [[ -z "$TEST_BIN" ]]; then + echo "[build/c] Required C test binary was not generated under $BUILD_DIR/test/c" >&2 + exit 1 +fi echo "[build/c] Done — binaries in $BUILD_DIR" # Build benchmark binaries if --bench flag is passed if [[ "$DO_BENCH" -eq 1 ]]; then echo "[build/bench] Building benchmark binaries..." - make Benchmark_LIGHT Benchmark_FULL + cmake --build "$BUILD_DIR" --config Release --target Benchmark_LIGHT Benchmark_FULL echo "[build/bench] Done — binaries in $BUILD_DIR/src/benchmark/" fi @@ -74,8 +85,6 @@ else echo "[build/go] vet passed" fi -touch "$BUILD_DIR/.built" - # --------------------------------------------------------------------------- # Python extension build (compiles src/python/core.c via pip editable install) # --------------------------------------------------------------------------- @@ -93,4 +102,5 @@ pip install -e "$REPO_ROOT" -q --no-build-isolation deactivate echo "[build/python] Done" +touch "$BUILD_DIR/.built" echo "[build] All done" diff --git a/test/c/CMakeLists.txt b/test/c/CMakeLists.txt index 8b1c593..9a14a2e 100644 --- a/test/c/CMakeLists.txt +++ b/test/c/CMakeLists.txt @@ -1,54 +1,52 @@ -if (MSVC) - if (NOT BOOST_ROOT) - set (BOOST_ROOT "$ENV{BOOST_ROOT}") - endif() - set (CMAKE_PREFIX_PATH BOOST_ROOT) +if (NOT BOOST_ROOT AND DEFINED ENV{BOOST_ROOT}) + set(BOOST_ROOT "$ENV{BOOST_ROOT}") +endif() +if (BOOST_ROOT) + set(CMAKE_PREFIX_PATH "${BOOST_ROOT};${CMAKE_PREFIX_PATH}") endif() -IF( NOT Boost_FOUND ) - # use multithreaded boost libraries, with -mt suffix - set(Boost_USE_MULTITHREADED ON) - - if (MSVC) - # TODO handle other msvc versions or it will fail find them - set(Boost_COMPILER -vc120) - # use static boost libraries *.lib - set(Boost_USE_STATIC_LIBS ON) - elseif (APPLE) - - # use static boost libraries *.a - set(Boost_USE_STATIC_LIBS ON) - - elseif (UNIX) - # use dynamic boost libraries .dll - set(Boost_USE_STATIC_LIBS OFF) - - endif() - find_package(Boost 1.48.0 COMPONENTS unit_test_framework system filesystem) -ENDIF() - -IF (Boost_FOUND) - message(STATUS "boost header: ${Boost_INCLUDE_DIRS}") - message(STATUS "boost libs : ${Boost_LIBRARIES}") - - include_directories( ${Boost_INCLUDE_DIR} ) - include_directories(../../src) +# The C test suite is required by the build, so fail during configuration when +# any of its Boost components are unavailable instead of omitting Test. +# use multithreaded boost libraries, with -mt suffix +set(Boost_USE_MULTITHREADED ON) - link_directories(${Boost_LIBRARY_DIRS}) - file(GLOB HEADERS "*.h") - if ((NOT MSVC) AND (NOT APPLE)) - ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) - endif() - if (NOT MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ") - endif() +if (MSVC) + # use static boost libraries *.lib + set(Boost_USE_STATIC_LIBS ON) +elseif (APPLE) + # use static boost libraries *.a + set(Boost_USE_STATIC_LIBS ON) +elseif (UNIX) + # use shared boost libraries + set(Boost_USE_STATIC_LIBS OFF) +endif() - add_executable (Test "./test.cpp" ${HEADERS}) - target_link_libraries(Test ${ETHHASH_LIBS}) - target_link_libraries(Test ${Boost_FILESYSTEM_LIBRARIES}) - target_link_libraries(Test ${Boost_SYSTEM_LIBRARIES}) - target_link_libraries(Test ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) +# Prefer the package configuration shipped by modern Boost distributions (for +# example Homebrew on macOS), then fall back to CMake's legacy FindBoost module +# for system packages that do not ship BoostConfig.cmake. +find_package(Boost 1.48.0 CONFIG QUIET COMPONENTS unit_test_framework system filesystem) +if (NOT Boost_FOUND) + find_package(Boost 1.48.0 MODULE REQUIRED COMPONENTS unit_test_framework system filesystem) +endif() - enable_testing () - add_test(NAME ethash COMMAND Test) -ENDIF() +file(GLOB HEADERS "*.h") + +add_executable(Test "./test.cpp" ${HEADERS}) +set_target_properties(Test PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES + CXX_EXTENSIONS NO +) +target_include_directories(Test PRIVATE ../../src) +if ((NOT MSVC) AND (NOT APPLE)) + target_compile_definitions(Test PRIVATE BOOST_TEST_DYN_LINK) +endif() +target_link_libraries(Test PRIVATE + ${ETHHASH_LIBS} + Boost::filesystem + Boost::system + Boost::unit_test_framework +) + +enable_testing() +add_test(NAME ethash COMMAND Test) diff --git a/test/c/test.sh b/test/c/test.sh index b0ef731..47ff48d 100755 --- a/test/c/test.sh +++ b/test/c/test.sh @@ -27,6 +27,15 @@ if [ ! -f "$BUILD_DIR/.built" ]; then "$REPO_ROOT/build.sh" fi +if [ ! -f "$TEST_BIN" ]; then + TEST_BIN="$(find "$BUILD_DIR/test/c" -type f \( -name Test -o -name Test.exe \) -print 2>/dev/null | head -n 1 || true)" + if [ -z "$TEST_BIN" ]; then + echo "[test/c] Required C test binary is missing under $BUILD_DIR/test/c" >&2 + echo "[test/c] Run 'make rebuild' after installing the required Boost components." >&2 + exit 1 + fi +fi + echo "[test/c] Running $TEST_BIN" # mmap(MAP_SHARED) on NTFS via WSL DrvFs (/mnt/d/...) does not properly flush