Files
SVMClassifier/validate_build.sh
Ricardo Montañana Gómez 5302dd9a8a
Some checks failed
CI/CD Pipeline / Code Linting (push) Failing after 24s
CI/CD Pipeline / Build and Test (Debug, clang, ubuntu-latest) (push) Failing after 5m17s
CI/CD Pipeline / Build and Test (Debug, gcc, ubuntu-latest) (push) Failing after 5m32s
CI/CD Pipeline / Build and Test (Release, clang, ubuntu-20.04) (push) Failing after 5m45s
CI/CD Pipeline / Build and Test (Release, clang, ubuntu-latest) (push) Failing after 5m12s
CI/CD Pipeline / Build and Test (Release, gcc, ubuntu-20.04) (push) Failing after 5m22s
CI/CD Pipeline / Build and Test (Release, gcc, ubuntu-latest) (push) Failing after 5m26s
CI/CD Pipeline / Docker Build Test (push) Failing after 1m7s
CI/CD Pipeline / Performance Benchmarks (push) Has been skipped
CI/CD Pipeline / Build Documentation (push) Failing after 18s
CI/CD Pipeline / Create Release Package (push) Has been skipped
Add docs support
2025-06-23 10:02:36 +02:00

659 lines
18 KiB
Bash
Executable File

#!/bin/bash
# SVMClassifier Build Validation Script
# This script performs comprehensive validation of the build system
set -e # Exit on any error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Configuration
BUILD_DIR="build_validation"
INSTALL_DIR="install_validation"
TEST_TIMEOUT=300 # 5 minutes
VERBOSE=false
CLEAN_BUILD=true
RUN_PERFORMANCE_TESTS=false
RUN_MEMORY_CHECKS=false
TORCH_VERSION="2.7.1"
# Counters for test results
TESTS_PASSED=0
TESTS_FAILED=0
TESTS_SKIPPED=0
# Function to print colored output
print_header() {
echo -e "${PURPLE}================================${NC}"
echo -e "${PURPLE}$1${NC}"
echo -e "${PURPLE}================================${NC}"
}
print_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
print_success() {
echo -e "${GREEN}[PASS]${NC} $1"
((TESTS_PASSED++))
}
print_failure() {
echo -e "${RED}[FAIL]${NC} $1"
((TESTS_FAILED++))
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
print_skip() {
echo -e "${CYAN}[SKIP]${NC} $1"
((TESTS_SKIPPED++))
}
print_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
# Function to show usage
show_usage() {
cat << EOF
SVMClassifier Build Validation Script
Usage: $0 [OPTIONS]
OPTIONS:
-h, --help Show this help message
-v, --verbose Enable verbose output
--no-clean Don't clean build directory
--performance Run performance tests
--memory-check Run memory checks with valgrind
--build-dir DIR Build directory (default: build_validation)
--install-dir DIR Install directory (default: install_validation)
--torch-version VER PyTorch version (default: 2.1.0)
EXAMPLES:
$0 # Standard validation
$0 --verbose # Verbose validation
$0 --performance # Include performance benchmarks
$0 --memory-check # Include memory checks
EOF
}
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_usage
exit 0
;;
-v|--verbose)
VERBOSE=true
shift
;;
--no-clean)
CLEAN_BUILD=false
shift
;;
--performance)
RUN_PERFORMANCE_TESTS=true
shift
;;
--memory-check)
RUN_MEMORY_CHECKS=true
shift
;;
--build-dir)
BUILD_DIR="$2"
shift 2
;;
--install-dir)
INSTALL_DIR="$2"
shift 2
;;
--torch-version)
TORCH_VERSION="$2"
shift 2
;;
*)
echo "Unknown option: $1"
show_usage
exit 1
;;
esac
done
# Set verbose mode
if [ "$VERBOSE" = true ]; then
set -x
fi
# Validation functions
check_prerequisites() {
print_header "CHECKING PREREQUISITES"
# Check if we're in the right directory
if [ ! -f "CMakeLists.txt" ] || [ ! -d "src" ] || [ ! -d "include" ]; then
print_failure "Please run this script from the SVMClassifier root directory"
exit 1
fi
print_success "Running from correct directory"
# Check for required tools
local missing_tools=()
for tool in cmake git gcc g++ pkg-config; do
if ! command -v "$tool" >/dev/null 2>&1; then
missing_tools+=("$tool")
fi
done
if [ ${#missing_tools[@]} -gt 0 ]; then
print_failure "Missing required tools: ${missing_tools[*]}"
exit 1
fi
print_success "All required tools found"
# Check CMake version
CMAKE_VERSION=$(cmake --version | head -1 | cut -d' ' -f3)
print_info "CMake version: $CMAKE_VERSION"
# Check GCC version
GCC_VERSION=$(gcc --version | head -1)
print_info "GCC version: $GCC_VERSION"
# Check for optional tools
for tool in valgrind lcov doxygen; do
if command -v "$tool" >/dev/null 2>&1; then
print_info "$tool available"
else
print_warning "$tool not available (optional)"
fi
done
}
setup_pytorch() {
print_header "SETTING UP PYTORCH"
TORCH_DIR="/opt/libtorch"
if [ ! -d "$TORCH_DIR" ] && [ ! -d "libtorch" ]; then
print_step "Downloading PyTorch C++ version $TORCH_VERSION"
TORCH_URL="https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-${TORCH_VERSION}%2Bcpu.zip"
wget -q "$TORCH_URL" -O libtorch.zip
unzip -q libtorch.zip
rm libtorch.zip
TORCH_DIR="$(pwd)/libtorch"
print_success "PyTorch C++ downloaded and extracted"
else
if [ -d "/opt/libtorch" ]; then
TORCH_DIR="/opt/libtorch"
else
TORCH_DIR="$(pwd)/libtorch"
fi
print_success "PyTorch C++ found at $TORCH_DIR"
fi
export Torch_DIR="$TORCH_DIR"
export LD_LIBRARY_PATH="$TORCH_DIR/lib:$LD_LIBRARY_PATH"
}
configure_build() {
print_header "CONFIGURING BUILD"
if [ "$CLEAN_BUILD" = true ] && [ -d "$BUILD_DIR" ]; then
print_step "Cleaning build directory"
rm -rf "$BUILD_DIR"
print_success "Build directory cleaned"
fi
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
print_step "Running CMake configuration"
CMAKE_ARGS=(
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_PREFIX_PATH="$Torch_DIR"
-DCMAKE_INSTALL_PREFIX="../$INSTALL_DIR"
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
)
if [ "$VERBOSE" = true ]; then
CMAKE_ARGS+=(-DCMAKE_VERBOSE_MAKEFILE=ON)
fi
if cmake .. "${CMAKE_ARGS[@]}"; then
print_success "CMake configuration successful"
else
print_failure "CMake configuration failed"
exit 1
fi
cd ..
}
build_project() {
print_header "BUILDING PROJECT"
cd "$BUILD_DIR"
print_step "Building main library"
if cmake --build . --config Release -j$(nproc); then
print_success "Main library build successful"
else
print_failure "Main library build failed"
exit 1
fi
print_step "Building examples"
if make examples >/dev/null 2>&1 || true; then
print_success "Examples build successful"
else
print_warning "Examples build failed or not available"
fi
print_step "Building tests"
if make svm_classifier_tests >/dev/null 2>&1; then
print_success "Tests build successful"
else
print_failure "Tests build failed"
exit 1
fi
cd ..
}
run_unit_tests() {
print_header "RUNNING UNIT TESTS"
cd "$BUILD_DIR"
export LD_LIBRARY_PATH="$Torch_DIR/lib:$LD_LIBRARY_PATH"
print_step "Running all unit tests"
if timeout $TEST_TIMEOUT ./svm_classifier_tests "[unit]" --reporter console; then
print_success "Unit tests passed"
else
print_failure "Unit tests failed"
fi
print_step "Running integration tests"
if timeout $TEST_TIMEOUT ./svm_classifier_tests "[integration]" --reporter console; then
print_success "Integration tests passed"
else
print_failure "Integration tests failed"
fi
cd ..
}
run_performance_tests() {
if [ "$RUN_PERFORMANCE_TESTS" = false ]; then
print_skip "Performance tests (use --performance to enable)"
return
fi
print_header "RUNNING PERFORMANCE TESTS"
cd "$BUILD_DIR"
export LD_LIBRARY_PATH="$Torch_DIR/lib:$LD_LIBRARY_PATH"
print_step "Running performance benchmarks"
if timeout $((TEST_TIMEOUT * 2)) ./svm_classifier_tests "[performance]" --reporter console; then
print_success "Performance tests completed"
else
print_warning "Performance tests failed or timed out"
fi
cd ..
}
run_memory_checks() {
if [ "$RUN_MEMORY_CHECKS" = false ]; then
print_skip "Memory checks (use --memory-check to enable)"
return
fi
if ! command -v valgrind >/dev/null 2>&1; then
print_skip "Memory checks (valgrind not available)"
return
fi
print_header "RUNNING MEMORY CHECKS"
cd "$BUILD_DIR"
export LD_LIBRARY_PATH="$Torch_DIR/lib:$LD_LIBRARY_PATH"
print_step "Running memory leak detection"
if timeout $((TEST_TIMEOUT * 3)) valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all \
--track-origins=yes --error-exitcode=1 ./svm_classifier_tests "[unit]" >/dev/null 2>valgrind.log; then
print_success "No memory leaks detected"
else
print_failure "Memory leaks or errors detected"
print_info "Check valgrind.log for details"
fi
cd ..
}
test_examples() {
print_header "TESTING EXAMPLES"
cd "$BUILD_DIR"
export LD_LIBRARY_PATH="$Torch_DIR/lib:$LD_LIBRARY_PATH"
if [ -f "examples/basic_usage" ]; then
print_step "Running basic usage example"
if timeout $TEST_TIMEOUT ./examples/basic_usage >/dev/null 2>&1; then
print_success "Basic usage example ran successfully"
else
print_failure "Basic usage example failed"
fi
else
print_skip "Basic usage example (not built)"
fi
if [ -f "examples/advanced_usage" ]; then
print_step "Running advanced usage example"
if timeout $((TEST_TIMEOUT * 2)) ./examples/advanced_usage >/dev/null 2>&1; then
print_success "Advanced usage example ran successfully"
else
print_warning "Advanced usage example failed or timed out"
fi
else
print_skip "Advanced usage example (not built)"
fi
cd ..
}
test_installation() {
print_header "TESTING INSTALLATION"
cd "$BUILD_DIR"
print_step "Installing to test directory"
if cmake --install . --config Release; then
print_success "Installation successful"
else
print_failure "Installation failed"
cd ..
return
fi
cd ..
# Test that installed files exist
local install_files=(
"$INSTALL_DIR/lib/libsvm_classifier.a"
"$INSTALL_DIR/include/svm_classifier/svm_classifier.hpp"
"$INSTALL_DIR/lib/cmake/SVMClassifier/SVMClassifierConfig.cmake"
)
for file in "${install_files[@]}"; do
if [ -f "$file" ]; then
print_success "Installed file found: $(basename "$file")"
else
print_failure "Missing installed file: $file"
fi
done
# Test CMake find_package
print_step "Testing CMake find_package"
cat > test_find_package.cmake << 'EOF'
cmake_minimum_required(VERSION 3.15)
project(TestFindPackage)
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/install_validation")
find_package(SVMClassifier REQUIRED)
if(TARGET SVMClassifier::svm_classifier)
message(STATUS "SVMClassifier found successfully")
else()
message(FATAL_ERROR "SVMClassifier target not found")
endif()
EOF
if cmake -P test_find_package.cmake >/dev/null 2>&1; then
print_success "CMake find_package test passed"
else
print_failure "CMake find_package test failed"
fi
rm -f test_find_package.cmake
}
test_compiler_compatibility() {
print_header "TESTING COMPILER COMPATIBILITY"
# Test with different C++ standards if supported
for std in 17 20; do
print_step "Testing C++$std compatibility"
TEST_BUILD_DIR="build_cpp$std"
mkdir -p "$TEST_BUILD_DIR"
cd "$TEST_BUILD_DIR"
if cmake .. -DCMAKE_CXX_STANDARD=$std -DCMAKE_PREFIX_PATH="$Torch_DIR" >/dev/null 2>&1; then
if cmake --build . --target svm_classifier -j$(nproc) >/dev/null 2>&1; then
print_success "C++$std compatibility verified"
else
print_warning "C++$std build failed"
fi
else
print_warning "C++$std configuration failed"
fi
cd ..
rm -rf "$TEST_BUILD_DIR"
done
}
generate_coverage_report() {
if ! command -v lcov >/dev/null 2>&1; then
print_skip "Coverage report (lcov not available)"
return
fi
print_header "GENERATING COVERAGE REPORT"
# Build with coverage flags
DEBUG_BUILD_DIR="build_coverage"
mkdir -p "$DEBUG_BUILD_DIR"
cd "$DEBUG_BUILD_DIR"
print_step "Building with coverage flags"
if cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH="$Torch_DIR" \
-DCMAKE_CXX_FLAGS="--coverage" -DCMAKE_C_FLAGS="--coverage" >/dev/null 2>&1; then
if cmake --build . -j$(nproc) >/dev/null 2>&1; then
export LD_LIBRARY_PATH="$Torch_DIR/lib:$LD_LIBRARY_PATH"
print_step "Running tests for coverage"
if ./svm_classifier_tests "[unit]" >/dev/null 2>&1; then
print_step "Generating coverage report"
if lcov --capture --directory . --output-file coverage.info >/dev/null 2>&1 && \
lcov --remove coverage.info '/usr/*' '*/external/*' '*/tests/*' \
--output-file coverage_filtered.info >/dev/null 2>&1; then
COVERAGE_PERCENT=$(lcov --summary coverage_filtered.info 2>/dev/null | \
grep "lines" | grep -o '[0-9.]*%' | head -1)
print_success "Coverage report generated: $COVERAGE_PERCENT"
else
print_warning "Coverage report generation failed"
fi
else
print_warning "Tests failed during coverage run"
fi
else
print_warning "Coverage build failed"
fi
else
print_warning "Coverage configuration failed"
fi
cd ..
rm -rf "$DEBUG_BUILD_DIR"
}
validate_documentation() {
if ! command -v doxygen >/dev/null 2>&1; then
print_skip "Documentation validation (doxygen not available)"
return
fi
print_header "VALIDATING DOCUMENTATION"
cd "$BUILD_DIR"
print_step "Generating documentation with CMake target"
if cmake --build . --target doxygen >/dev/null 2>doxygen_warnings.log; then
if [ -f "docs/html/index.html" ]; then
print_success "Documentation generated successfully"
# Check documentation size (should be substantial)
DOC_SIZE=$(du -sh docs/html 2>/dev/null | cut -f1)
print_info "Documentation size: $DOC_SIZE"
else
print_failure "Documentation files not found"
fi
# Check for warnings
if [ -s doxygen_warnings.log ]; then
WARNING_COUNT=$(wc -l < doxygen_warnings.log)
print_warning "Documentation has $WARNING_COUNT warnings"
if [ "$VERBOSE" = true ]; then
print_info "Sample warnings:"
head -5 doxygen_warnings.log | while read -r line; do
print_info " $line"
done
fi
else
print_success "Documentation generated without warnings"
fi
# Check for essential documentation files
DOC_FILES=(
"docs/html/index.html"
"docs/html/annotated.html"
"docs/html/classes.html"
"docs/html/files.html"
)
for doc_file in "${DOC_FILES[@]}"; do
if [ -f "$doc_file" ]; then
print_success "Found: $(basename "$doc_file")"
else
print_warning "Missing: $(basename "$doc_file")"
fi
done
else
print_failure "Documentation generation failed"
if [ -s doxygen_warnings.log ]; then
print_info "Error log:"
head -10 doxygen_warnings.log | while read -r line; do
print_info " $line"
done
fi
fi
cd ..
rm -f doxygen_warnings.log
}
test_packaging() {
print_header "TESTING PACKAGING"
cd "$BUILD_DIR"
print_step "Testing CPack configuration"
if cpack --config CPackConfig.cmake >/dev/null 2>&1; then
print_success "Package generation successful"
# List generated packages
for pkg in *.tar.gz *.deb *.rpm *.zip ; do
if [ -f "$pkg" ]; then
print_info "Generated package: $pkg"
fi
done
else
print_warning "Package generation failed"
fi
cd ..
}
cleanup() {
print_header "CLEANUP"
if [ "$VERBOSE" = false ]; then
print_step "Cleaning up temporary files"
rm -rf "$BUILD_DIR" "$INSTALL_DIR" build_cpp* docs/
print_success "Cleanup completed"
else
print_info "Keeping build files for inspection (verbose mode)"
fi
}
print_summary() {
print_header "VALIDATION SUMMARY"
echo -e "${BLUE}Test Results:${NC}"
echo -e " ${GREEN}Passed: $TESTS_PASSED${NC}"
echo -e " ${RED}Failed: $TESTS_FAILED${NC}"
echo -e " ${CYAN}Skipped: $TESTS_SKIPPED${NC}"
echo -e " ${PURPLE}Total: $((TESTS_PASSED + TESTS_FAILED + TESTS_SKIPPED))${NC}"
if [ $TESTS_FAILED -eq 0 ]; then
echo -e "\n${GREEN}✅ ALL CRITICAL TESTS PASSED!${NC}"
echo -e "${GREEN}The SVMClassifier build system is working correctly.${NC}"
exit 0
else
echo -e "\n${RED}❌ SOME TESTS FAILED!${NC}"
echo -e "${RED}Please review the failed tests above.${NC}"
exit 1
fi
}
# Main execution
main() {
print_header "SVMClassifier Build Validation"
print_info "Starting comprehensive build validation..."
check_prerequisites
setup_pytorch
configure_build
build_project
run_unit_tests
run_performance_tests
run_memory_checks
test_examples
test_installation
test_compiler_compatibility
generate_coverage_report
validate_documentation
test_packaging
cleanup
print_summary
}
# Handle signals for cleanup
trap 'echo -e "\n${RED}Validation interrupted!${NC}"; cleanup; exit 1' INT TERM
# Run main function
main "$@"