#!/bin/bash # build-win32.sh - Windows-specific build logic using clang # Handles Windows APIs, resource compilation, etc. # Usage: ./build-win32.sh [debug|release] [x64|x86] set -e # Exit on error # ============================================================================= # Configuration # ============================================================================= SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CONFIG_DIR="$SCRIPT_DIR/../config" # Source configuration files source "$CONFIG_DIR/build-config.sh" source "$HELPERS_DIR/print-routines.sh" source "$HELPERS_DIR/copy-resources.sh" # ============================================================================= # Platform-specific settings # ============================================================================= setup_win32_vars() { local config=$1 local arch=$2 # Base directories (relative to project root) BUILD_DIR="${BUILD_ROOT:-../build}" CODE_DIR="${CODE_DIR:-../code}" CUSTOM_DIR="${CUSTOM_DIR:-../code/custom}" FOREIGN_DIR="${FOREIGN_DIR:-../non-source/foreign}" # Compiler (using clang with Windows target) CXX="clang++" CC="clang" # Base flags for Windows COMMON_FLAGS=( "${CLANG_OPTS_WINDOWS[@]}" "-I$CODE_DIR" "-I$FOREIGN_DIR/freetype2" ) # Architecture-specific flags case "$arch" in "x64") ARCH_FLAGS=("${ARCH_FLAGS_X64[@]}") FREETYPE_LIB="$FREETYPE_LIB_WINDOWS_X64" ;; "x86") ARCH_FLAGS=("${ARCH_FLAGS_X86[@]}") FREETYPE_LIB="$FREETYPE_LIB_WINDOWS_X86" ;; *) echo "Error: Unsupported architecture: $arch" >&2 return 1 ;; esac # Configuration-specific flags case "$config" in "debug") CONFIG_FLAGS=("${DEBUG_FLAGS[@]}") ;; "release") CONFIG_FLAGS=("${RELEASE_FLAGS[@]}") ;; *) echo "Error: Unsupported config: $config" >&2 return 1 ;; esac # Combine all flags COMPILE_FLAGS=( "${COMMON_FLAGS[@]}" "${ARCH_FLAGS[@]}" "${CONFIG_FLAGS[@]}" ) # Libraries LINK_LIBS=( "${LIBS_WINDOWS[@]}" "$FREETYPE_LIB" ) # Platform includes PLATFORM_INCLUDES=() # Windows doesn't have additional platform includes in the original build print_info "Windows build configuration:" print_info " Architecture: $arch" print_info " Configuration: $config" print_info " Compiler: $CXX" print_info " FreeType: $FREETYPE_LIB" } # ============================================================================= # Resource compilation (Windows-specific) # ============================================================================= compile_resources() { print_step "Compiling Windows resources" local icon_rc="$CODE_DIR/../non-source/res/icon.rc" local icon_res="$BUILD_DIR/icon.res" if [[ -f "$icon_rc" ]]; then print_info "Compiling icon resource..." # Use windres if available, otherwise skip resources if command -v windres &> /dev/null; then windres "$icon_rc" -o "$icon_res" print_success "Icon resource compiled" echo "$icon_res" # Return the resource file path else print_warning "windres not found, skipping resource compilation" echo "" # Return empty string fi else print_warning "Icon resource file not found: $icon_rc" echo "" # Return empty string fi } # ============================================================================= # Build functions # ============================================================================= build_core_engine() { print_step "Building API Parser..." $CUSTOM_DIR/bin/build_one_time.sh $CODE_DIR/4ed_api_parser_main.cpp $BUILD_DIR && cp $BUILD_DIR/one_time $BUILD_DIR/api_parser print_step "Building System API..." $CUSTOM_DIR/bin/build_one_time.sh $CODE_DIR/4ed_system_api.cpp $BUILD_DIR && $BUILD_DIR/one_time print_step "Building API Check..." $CUSTOM_DIR/bin/build_one_time.sh $CODE_DIR/4ed_api_check.cpp $BUILD_DIR && cp $BUILD_DIR/one_time $BUILD_DIR/api_checker print_step "Running API Parser..." $BUILD_DIR/api_parser $CODE_DIR/4ed_api_implementation.cpp print_step "Building Font API..." $CUSTOM_DIR/bin/build_one_time.sh $CODE_DIR/4ed_font_api.cpp $BUILD_DIR && $BUILD_DIR/one_time print_step "Building Graphics API..." $CUSTOM_DIR/bin/build_one_time.sh $CODE_DIR/4ed_graphics_api.cpp $BUILD_DIR && $BUILD_DIR/one_time print_step "Building core engine (4ed_app.dll)" local app_target="$CODE_DIR/4ed_app_target.cpp" local output_lib="$BUILD_DIR/4ed_app.dll" # Build flags for shared library local build_flags=( "${COMPILE_FLAGS[@]}" "-shared" "-DFRED_SUPER" "-DFRED_INTERNAL" ) # Include directories for custom layer local include_flags=( "-I$CUSTOM_DIR" "-I$CUSTOM_DIR/generated" ) print_info "Compiling core application library..." print_info "Input: $app_target" print_info "Output: $output_lib" # Compile core application shared library if [[ "${BUILD_VERBOSE:-}" == "1" ]]; then echo "Executing: $CXX ${build_flags[*]} ${include_flags[*]} -o $output_lib $app_target ${LINK_LIBS[*]}" fi $CXX \ "${build_flags[@]}" \ "${include_flags[@]}" \ -o "$output_lib" \ "$app_target" \ "${LINK_LIBS[@]}" print_success "Core engine built successfully" } build_platform_layer() { print_step "Building platform layer (4ed.exe)" local platform_source="$CODE_DIR/platform_win32/win32_4ed.cpp" local output_exe="$BUILD_DIR/4ed.exe" # Compile resources local resource_file resource_file=$(compile_resources) # Build flags for executable local build_flags=( "${COMPILE_FLAGS[@]}" "${PLATFORM_INCLUDES[@]}" "-DFRED_SUPER" "-DFRED_INTERNAL" ) # Add resource file if it exists local resource_args=() if [[ -n "$resource_file" && -f "$resource_file" ]]; then resource_args=("$resource_file") print_info "Including resource file: $resource_file" fi print_info "Compiling platform layer executable..." print_info "Input: $platform_source" print_info "Output: $output_exe" # Compile platform layer executable if [[ "${BUILD_VERBOSE:-}" == "1" ]]; then echo "Executing: $CXX ${build_flags[*]} -o $output_exe $platform_source ${resource_args[*]} ${LINK_LIBS[*]}" fi $CXX \ "${build_flags[@]}" \ -o "$output_exe" \ "$platform_source" \ "${resource_args[@]}" \ "${LINK_LIBS[@]}" print_success "Platform layer built successfully" } build_custom_layer() { print_step "Building custom layer (custom_4coder.dll)" local custom_target="$CUSTOM_DIR/4coder_default_bindings.cpp" local output_lib="$BUILD_DIR/custom_4coder.dll" local temp_dir="$BUILD_DIR/temp" # Create temp directory mkdir -p "$temp_dir" # Multi-stage custom layer build process # Stage 0: Build and Run Generators mkdir -p "$CODE_DIR/generated" print_step "Building CPP Lexer Gen..." $CUSTOM_DIR/bin/build_one_time.sh $CUSTOM_DIR/languages/4coder_cpp_lexer_gen.cpp $BUILD_DIR && $BUILD_DIR/one_time print_step "Building Generate Keycodes..." $CUSTOM_DIR/bin/build_one_time.sh $CODE_DIR/4ed_generate_keycodes.cpp $BUILD_DIR && $BUILD_DIR/one_time print_step "Building Docs..." $CUSTOM_DIR/bin/build_one_time.sh $CODE_DIR/docs/4ed_doc_custom_api_main.cpp $BUILD_DIR && $BUILD_DIR/one_time # Ensure generated directory exists mkdir -p "$CUSTOM_DIR/generated" # Ensure generated directory exists mkdir -p "$CUSTOM_DIR/generated" # Stage 2: Generate metadata $SCRIPTS_DIR/build-metadata.sh print_success "Metadata generated" # Stage 4: Compile custom layer shared library print_info "Stage 4: Compiling custom layer shared library..." local build_flags=( "${COMPILE_FLAGS[@]}" "-shared" "-I$CUSTOM_DIR" "-I$CUSTOM_DIR/generated" "-DFRED_SUPER" "-DFRED_INTERNAL" ) # Add export flags for Windows DLL local export_flags=( "-Wl,--export-all-symbols" "-Wl,--out-implib,$BUILD_DIR/custom_4coder.lib" ) if [[ "${BUILD_VERBOSE:-}" == "1" ]]; then echo "Executing: $CXX ${build_flags[*]} ${export_flags[*]} -o $output_lib $custom_target" fi $CXX \ "${build_flags[@]}" \ "${export_flags[@]}" \ -o "$output_lib" \ "$custom_target" print_success "Custom layer built successfully" # Clean up temporary files print_info "Cleaning up temporary files..." rm -f "$preprocessed_file" "$metadata_generator" } validate_build() { print_step "Validating build outputs" local all_good=true local expected_files=("4ed.exe" "4ed_app.dll" "custom_4coder.dll") for file in "${expected_files[@]}"; do if [[ -f "$BUILD_DIR/$file" ]]; then local file_size file_size=$(stat -c%s "$BUILD_DIR/$file" 2>/dev/null || echo "unknown") print_success "$file (${file_size} bytes)" else echo -e "${RED}✗${NC} Missing: $file" all_good=false fi done if [[ "$all_good" == "true" ]]; then print_success "All build outputs validated" return 0 else echo -e "${RED}✗${NC} Build validation failed" return 1 fi } # ============================================================================= # Main execution # ============================================================================= main() { local config="${1:-debug}" local arch="${2:-x64}" print_step "Windows Build Process" print_info "Configuration: $config" print_info "Architecture: $arch" # Setup platform-specific variables setup_win32_vars "$config" "$arch" # Create build directory mkdir -p "$BUILD_DIR" # Execute build steps build_custom_layer build_core_engine build_platform_layer copy_resources validate_build print_success "Windows build completed successfully!" } # Only run main if script is executed directly (not sourced) if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi