name: Mac builds

on:
  workflow_dispatch:
  push:
    branches: [ master ]
    paths-ignore:
    - '.circleci/**'
    - '.github/ISSUE_TEMPLATE/**'
    - '.github/workflows/ci.yml'
    - '.github/workflows/ci_cmake.yml'
    - '.github/workflows/ci_msw.yml'
    - '.github/workflows/ci_msw_cross.yml'
    - '.github/workflows/docs_update.yml'
    - 'build/cmake/**'
    - 'build/tools/appveyor*.bat'
    - 'distrib/**'
    - 'docs/**'
    - 'interface/**'
    - 'include/msvc/**'
    - 'include/wx/dfb/**'
    - 'include/wx/gtk/**'
    - 'include/wx/msw/**'
    - 'include/wx/x11/**'
    - 'locale/**'
    - 'src/dfb/**'
    - 'src/gtk/**'
    - 'src/msw/**'
    - 'src/x11/**'
    - '*.md'
    - '*.yml'
    - 'CMakeLists.txt'
    - 'wxwidgets.props'
  pull_request:
    branches: [ master ]
    paths-ignore:
    - '.circleci/**'
    - '.github/ISSUE_TEMPLATE/**'
    - '.github/workflows/ci.yml'
    - '.github/workflows/ci_cmake.yml'
    - '.github/workflows/ci_msw.yml'
    - '.github/workflows/ci_msw_cross.yml'
    - '.github/workflows/docs_update.yml'
    - 'build/cmake/**'
    - 'build/tools/appveyor*.bat'
    - 'distrib/**'
    - 'docs/**'
    - 'interface/**'
    - 'include/msvc/**'
    - 'include/wx/dfb/**'
    - 'include/wx/gtk/**'
    - 'include/wx/msw/**'
    - 'include/wx/x11/**'
    - 'locale/**'
    - 'src/dfb/**'
    - 'src/gtk/**'
    - 'src/msw/**'
    - 'src/x11/**'
    - '*.md'
    - '*.yml'
    - 'CMakeLists.txt'
    - 'wxwidgets.props'

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  build-and-test:
    defaults:
      run:
        shell: /usr/bin/arch -arch ${{ matrix.arch }} /bin/bash --noprofile --norc -eo pipefail {0}

    runs-on: ${{ matrix.runner }}

    name: ${{ matrix.name }}

    strategy:
      fail-fast: false
      matrix:
        include:
        - name: wxMac ARM with ASAN
          runner: self-hosted
          arch: arm64
          use_asan: true
        - name: wxMac Intel C++17
          runner: self-hosted
          arch: x86_64
          configure_flags: --with-cxx=17 --with-macosx-version-min=10.12 --enable-debug
        - name: wxMac Universal C++14
          runner: self-hosted
          arch: arm64
          configure_flags: --with-cxx=14 --enable-universal_binary=arm64,x86_64 --disable-shared --disable-debug --enable-optimise
        - name: wxMac macOS 11
          runner: macos-11
          arch: x86_64
          configure_flags: --disable-sys-libs
        - name: wxiOS
          runner: macos-11
          arch: x86_64
          configure_flags: --with-osx_iphone --enable-monolithic  --disable-sys-libs --host=i686-apple-darwin_sim --build=x86_64-apple-darwin17.7.0
          configure_env: PKG_CONFIG_LIBDIR=/dev/null
          xcode_sdk: iphonesimulator
          skip_samples: true
          skip_testing: true
          allow_warnings: true

    env:
      wxUSE_ASAN: ${{ matrix.use_asan && 1 || 0 }}
      DEVELOPER_DIR: /Applications/Xcode.app/Contents/Developer
      NSUnbufferedIO: YES

    steps:
    - name: Checkout
      uses: actions/checkout@v4
      with:
        submodules: recursive

    - name: Set environment variables
      run: |
        echo TZ=UTC >> $GITHUB_ENV
        wxPROC_COUNT=`sysctl -n hw.logicalcpu`
        ((wxPROC_COUNT++))
        echo wxPROC_COUNT=$wxPROC_COUNT >> $GITHUB_ENV
        echo wxBUILD_ARGS=-j$wxPROC_COUNT >> $GITHUB_ENV
        # Setting this variable suppresses "Error retrieving accessibility bus address"
        # messages from WebKit tests that we're not interested in.
        echo NO_AT_BRIDGE=1 >> $GITHUB_ENV
        case "${{ matrix.compiler }}" in
          clang)
            echo CC=clang >> $GITHUB_ENV
            echo CXX='clang++ -stdlib=libc++' >> $GITHUB_ENV
            echo LD=clang++ >> $GITHUB_ENV
            allow_warn_opt="-Wno-error=#warnings"
            ;;
          '')
            # Assume gcc.
            allow_warn_opt="-Wno-error=cpp"
            ;;
          *)
            echo "*** Unknown compiler: ${{ matrix.compiler }} ***"
            ;;
        esac
        if [ -z ${{ matrix.allow_warnings }} ]; then
          error_opts="-Werror $allow_warn_opt"
          echo "wxMAKEFILE_ERROR_CXXFLAGS=$error_opts" >> $GITHUB_ENV
          echo "wxMAKEFILE_CXXFLAGS=$wxMAKEFILE_CXXFLAGS $error_opts" >> $GITHUB_ENV
        fi
        echo "wxMAKEFILE_CXXFLAGS=$wxMAKEFILE_CXXFLAGS $error_opts" >> $GITHUB_ENV

    - name: Before install
      run: |
        ./build/tools/before_install.sh
        mkdir -p $PWD/localbin_${{ matrix.arch }}

    - name: Show build environment
      run: |
        echo "Environment:"
        env | sort
        echo

        echo "Compiler version:"
        ${CXX-g++} --version
        echo

    - name: Configuring
      run: |
        wxCONFIGURE_OPTIONS="--disable-optimise --disable-sys-libs --without-liblzma ${{ matrix.configure_flags }} --prefix=${{ github.workspace }}/localbin_${{ matrix.arch }}"

        if [ -n "${{ matrix.xcode_sdk }}" ]; then
          sdk_path=`xcrun --sdk ${{ matrix.xcode_sdk }} --show-sdk-path`
          wxCONFIGURE_OPTIONS="--with-macosx-sdk=$sdk_path $wxCONFIGURE_OPTIONS"
        fi

        if [ ${{ matrix.use_asan }} ]; then
          wxASAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
          wxASAN_CXXFLAGS=$wxASAN_CFLAGS
          wxASAN_LDFLAGS="-fsanitize=address"

          ${{ matrix.configure_env }} ./configure $wxCONFIGURE_OPTIONS --enable-debug "CFLAGS=$wxASAN_CFLAGS" "CXXFLAGS=$wxASAN_CXXFLAGS" "LDFLAGS=$wxASAN_LDFLAGS" || rc=$?
        else
          ${{ matrix.configure_env }} ./configure $wxCONFIGURE_OPTIONS --disable-debug_info || rc=$?
        fi
        if [ -n "$rc" ]; then
          echo '*** Configuring failed, contents of config.log follows: ***'
          echo '-----------------------------------------------------------'
          cat config.log
          echo '-----------------------------------------------------------'
          exit $rc
        fi

    - name: Building
      run: |
        make -k $wxBUILD_ARGS "CXXFLAGS=$wxMAKEFILE_ERROR_CXXFLAGS"

    - name: Building tests
      run: |
        make -C tests $wxBUILD_ARGS failtest
        make -k -C tests $wxBUILD_ARGS "CXXFLAGS=$wxMAKEFILE_CXXFLAGS" "LDFLAGS=$wxMAKEFILE_LDFLAGS"

    - name: Setup Python
      # actions/setup-python broken on self-hosted https://github.com/actions/setup-python/issues/108
      if: matrix.runner != 'self-hosted'
      uses: actions/setup-python@v5
      with:
        python-version: '3.10'

    - name: Testing
      if: matrix.skip_testing != true
      working-directory: tests
      run: |
        . ../build/tools/httpbin.sh
        httpbin_launch
        export ASAN_OPTIONS=fast_unwind_on_malloc=0
        # Explicitly use bash because /bin/sh doesn't have pipefail option
        /bin/bash -o pipefail -c './test 2>&1 | tee test.out' || rc=$?
        if [ -n "$rc" ]; then
          httpbin_show_log
          exit $rc
        fi

    - name: Testing GUI
      if: matrix.skip_testing != true
      working-directory: tests
      run: |
        # We currently need to disable container overflow detection as we get
        # what seems to be a false positive in BitmapComboBoxTestCase triggered
        # by creating a new string from std::allocator<wxString>::construct()
        # used by std::vector<>::insert().
        export ASAN_OPTIONS='fast_unwind_on_malloc=0 detect_container_overflow=0'
        # Exclude tests that are currently known to fail
        wx_tests_selection='~[.] ~[valnum] ~wxPersistTLW ~wxPersistDVC ~wxTopLevel::Show ~wxFont::Weight ~wxFont::NativeFontInfo ~WebView ~RadioButton::Single ~RadioButton::Focus ~wxHtmlPrintout::Pagination ~wxTextCtrl::GetBestSize ~TextCtrlTestCase ~wxExecute::RedirectUTF8 ~Ellipsization::NormalCase ~SpinCtrl::* ~SpinCtrlDouble::* ~NotebookTestCase ~SettingsTestCase ~Window::Show ~ModalDialogsTestCase ~Button::Click ~Button::Disabled ~wxDVC::GetItemRect ~wxDVC::AppendTextColumn ~Grid::KeyboardSelection ~Grid::CellClick ~Grid::ReorderedColumnsCellClick ~Grid::CellSelect ~wxStyledTextCtrl::AutoComp ~EvtLoopTestCase ~EventPropagationTestCase'
        ./test_gui $wx_tests_selection

    - name: Building samples
      if: matrix.skip_testing != true && matrix.skip_samples != true
      run: |
        make -k $wxBUILD_ARGS "CXXFLAGS=$wxMAKEFILE_CXXFLAGS" "LDFLAGS=$wxMAKEFILE_LDFLAGS" samples

    - name: Installing
      if: matrix.skip_testing != true
      run: |
        make install

    - name: Testing installation
      if: matrix.skip_testing != true
      run: |
        make -C samples/minimal -f makefile.unx clean
        make -C samples/minimal -f makefile.unx WX_CONFIG=${{ github.workspace }}/localbin_${{ matrix.arch }}/bin/wx-config $wxBUILD_ARGS "CXXFLAGS=$wxMAKEFILE_CXXFLAGS" "LDFLAGS=$wxMAKEFILE_LDFLAGS"
