workflows/release-binaries: Enable Windows x86 builds #67
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release Binaries | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| release-version: | ||
| description: 'Release Version' | ||
| required: false | ||
| type: string | ||
| upload: | ||
| description: 'Upload binaries to the release page' | ||
| required: true | ||
| default: false | ||
| type: boolean | ||
| runs-on: | ||
| description: "Runner to use for the build" | ||
| required: true | ||
| type: choice | ||
| # We use ubuntu-22.04 rather than the latest version to make the built | ||
| # binaries more portable (eg functional aginast older glibc). | ||
| options: | ||
| - ubuntu-22.04 | ||
| - ubuntu-22.04-arm | ||
| - macos-14 | ||
| - windows-2022 | ||
| workflow_call: | ||
| inputs: | ||
| release-version: | ||
| description: 'Release Version' | ||
| required: false | ||
| type: string | ||
| upload: | ||
| description: 'Upload binaries to the release page' | ||
| required: true | ||
| default: false | ||
| type: boolean | ||
| runs-on: | ||
| description: "Runner to use for the build" | ||
| required: true | ||
| type: string | ||
| secrets: | ||
| RELEASE_TASKS_USER_TOKEN: | ||
| description: "Secret used to check user permissions." | ||
| required: false | ||
| permissions: | ||
| contents: read # Default everything to read-only | ||
| jobs: | ||
| prepare: | ||
| name: Prepare to build binaries | ||
| runs-on: ${{ inputs.runs-on }} | ||
| if: github.repository_owner == 'llvm' | ||
| outputs: | ||
| release-version: ${{ steps.vars.outputs.release-version }} | ||
| ref: ${{ steps.vars.outputs.ref }} | ||
| upload: ${{ steps.vars.outputs.upload }} | ||
| target-cmake-flags: ${{ steps.vars.outputs.target-cmake-flags }} | ||
| build-flang: ${{ steps.vars.outputs.build-flang }} | ||
| release-binary-basename: ${{ steps.vars.outputs.release-binary-basename }} | ||
| release-binary-filename: ${{ steps.vars.outputs.release-binary-filename }} | ||
| build-runs-on: ${{ steps.vars.outputs.build-runs-on }} | ||
| test-runs-on: ${{ steps.vars.outputs.build-runs-on }} | ||
| steps: | ||
| # It's good practice to use setup-python, but this is also required on macos-14 | ||
| # due to https://github.com/actions/runner-images/issues/10385 | ||
| - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 | ||
| with: | ||
| python-version: '3.13' | ||
| - name: Install libxml2 | ||
| if: false | ||
| shell: bash | ||
| env: | ||
| VCPKG_BUILD_TYPE: release | ||
| VCPKG_CMAKE_CONFIGURE_OPTIONS: -DBUILD_SHARED_LIBS=OFF | ||
| VCPKG_ENV_PASSTHROUGH: 1 | ||
| run: | | ||
| vcpkg update | ||
| mkdir custom-triplets | ||
| cp /c/vcpkg/triplets/x64-windows-static.cmake custom-triplets/x64-windows-static-release.cmake | ||
| cat custom-triplets/x64-windows-static-release.cmake | ||
| echo "set(VCPKG_CMAKE_CONFIGURE_OPTIONS -DBUILD_SHARED_LIBS=OFF)" >> custom-triplets/x64-windows-static-release.cmake | ||
| echo "set(VCPKG_BUILD_TYPE release)" >> custom-triplets/x64-windows-static-release.cmake | ||
| echo "set(BUILD_SHARED_LIBS OFF)" >> custom-triplets/x64-windows-static-release.cmake | ||
| vcpkg --debug install libxml2:x64-windows-static-release --overlay-triplets=custom-triplets | ||
| find /c/vcpkg -iname 'libxml*.lib' | ||
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | ||
| if: false | ||
| with: | ||
| name: libxml2 | ||
| path: | | ||
| C:\vcpkg\installed\x64-windows-static-release\lib\libxml2.lib | ||
| - name: Checkout LLVM | ||
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | ||
| - name: Install Dependencies | ||
| shell: bash | ||
| run: | | ||
| pip install --require-hashes -r ./llvm/utils/git/requirements.txt | ||
| - name: Check Permissions | ||
| if: github.event_name != 'pull_request' | ||
| env: | ||
| GITHUB_TOKEN: ${{ github.token }} | ||
| USER_TOKEN: ${{ secrets.RELEASE_TASKS_USER_TOKEN }} | ||
| shell: bash | ||
| run: | | ||
| ./llvm/utils/release/./github-upload-release.py --token "$GITHUB_TOKEN" --user "$GITHUB_ACTOR" --user-token "$USER_TOKEN" check-permissions | ||
| - name: Collect Variables | ||
| id: vars | ||
| shell: bash | ||
| # In order for the test-release.sh script to run correctly, the LLVM | ||
| # source needs to be at the following location relative to the build dir: | ||
| # | X.Y.Z-rcN | ./rcN/llvm-project | ||
| # | X.Y.Z | ./final/llvm-project | ||
| # | ||
| # We also need to set divergent flags based on the release version: | ||
| # | X.Y.Z-rcN | -rc N -test-asserts | ||
| # | X.Y.Z | -final | ||
| run: | | ||
| trimmed=$(echo ${{ inputs.release-version }} | xargs) | ||
| if [ -n "$trimmed" ]; then | ||
| release_version="$trimmed" | ||
| ref="llvmorg-$release_version" | ||
| else | ||
| release_version="${{ (github.event_name == 'pull_request' && format('PR{0}', github.event.pull_request.number)) || 'CI'}}-$GITHUB_SHA" | ||
| ref="$GITHUB_SHA" | ||
| fi | ||
| if [ -n "${{ inputs.upload }}" ]; then | ||
| upload="${{ inputs.upload }}" | ||
| else | ||
| upload="false" | ||
| fi | ||
| echo "release-version=$release_version">> $GITHUB_OUTPUT | ||
| echo "ref=$ref" >> $GITHUB_OUTPUT | ||
| echo "upload=$upload" >> $GITHUB_OUTPUT | ||
| if [ "$RUNNER_OS" = "Windows" ]; then | ||
| # Wix uses .msi | ||
| release_binary_suffix="msi" | ||
| else | ||
| release_binary_suffix="tar.xz" | ||
| fi | ||
| release_binary_basename="LLVM-$release_version-$RUNNER_OS-$RUNNER_ARCH" | ||
| echo "release-binary-basename=$release_binary_basename" >> $GITHUB_OUTPUT | ||
| echo "release-binary-filename=$release_binary_basename.$release_binary_suffix" >> $GITHUB_OUTPUT | ||
| target="$RUNNER_OS-$RUNNER_ARCH" | ||
| # The macOS builds try to cross compile some libraries so we need to | ||
| # add extra CMake args to disable them. | ||
| # See https://github.com/llvm/llvm-project/issues/99767 | ||
| if [ "$RUNNER_OS" = "macOS" ]; then | ||
| target_cmake_flags="$target_cmake_flags -DBOOTSTRAP_BOOTSTRAP_COMPILER_RT_ENABLE_IOS=OFF" | ||
| if [ "$RUNNER_ARCH" = "ARM64" ]; then | ||
| arches=arm64 | ||
| fi | ||
| target_cmake_flags="$target_cmake_flags -DBOOTSTRAP_BOOTSTRAP_DARWIN_osx_ARCHS=$arches -DBOOTSTRAP_BOOTSTRAP_DARWIN_osx_BUILTIN_ARCHS=$arches" | ||
| fi | ||
| if [ "$RUNNER_OS" = "Windows" ]; then | ||
| # LTO causes the WiX generator to crash so we need to disable it: | ||
| # light.exe : error LGHT0001 : Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)) | ||
| # Stack Trace: | ||
| # at Microsoft.Tools.WindowsInstallerXml.Cab.Interop.NativeMethods.CreateCabFinish(IntPtr contextHandle, IntPtr newCabNamesCallBackAddress) | ||
| # at Microsoft.Tools.WindowsInstallerXml.Cab.WixCreateCab.Complete(IntPtr newCabNamesCallBackAddress) | ||
| # at Microsoft.Tools.WindowsInstallerXml.CabinetBuilder.CreateCabinet(CabinetWorkItem cabinetWorkItem) | ||
| #libxml2_prefix="/c/vcpkg/packages/libxml2_x64-windows-static/" | ||
| target_cmake_flags="$target_cmake_flags -DLLVM_RELEASE_ENABLE_LTO=OFF" | ||
| # libxml2 config | ||
| target_cmake_flags="$target_cmake_flags -DBOOTSTRAP_CMAKE_FIND_PACKAGE_PREFER_CONFIG=ON -DBOOTSTRAP_BOOTSTRAP_CMAKE_FIND_PACKAGE_PREFER_CONFIG=ON" | ||
| # We are using the Wix generator which doesn't support strings in | ||
| # the version, so strip out the git suffix and replace the -rc3 suffix | ||
| # with .3. | ||
| set +o pipefail | ||
| rc_version=`grep -o 'LLVM_VERSION_SUFFIX -rc[0-9]' cmake/Modules/LLVMVersion.cmake | cut -d ' ' -f 2 | sed 's/-rc//g'` | ||
| set -o pipefail | ||
| if [ -z "$rc_version" ]; then | ||
| version_suffix="" | ||
| else | ||
| version_suffix=".$rc_version" | ||
| fi | ||
| target_cmake_flags="$target_cmake_flags -DLLVM_VERSION_SUFFIX=$version_suffix" | ||
| fi | ||
| echo "target-cmake-flags=$target_cmake_flags" >> $GITHUB_OUTPUT | ||
| case "${{ inputs.runs-on }}" in | ||
| ubuntu-22.04*|windows-2022) | ||
| build_runs_on="depot-${{ inputs.runs-on }}-16" | ||
| test_runs_on=$build_runs_on | ||
| ;; | ||
| macos-14) | ||
| if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then | ||
| build_runs_on="${{ inputs.runs-on }}" | ||
| else | ||
| build_runs_on="depot-macos-14" | ||
| fi | ||
| test_runs_on="${{ inputs.runs-on }}" | ||
| ;; | ||
| *) | ||
| test_runs_on="${{ inputs.runs-on }}" | ||
| build_runs_on=$test_runs_on | ||
| ;; | ||
| esac | ||
| echo "build-runs-on=$build_runs_on" >> $GITHUB_OUTPUT | ||
| echo "test-runs-on=$test_runs_on" >> $GITHUB_OUTPUT | ||
| build-release-package: | ||
| name: "Build Release Package" | ||
| needs: prepare | ||
| if: github.repository_owner == 'llvm' | ||
| runs-on: ${{ needs.prepare.outputs.build-runs-on }} | ||
| steps: | ||
| # See https://llvm.org/docs/GettingStarted.html#id4 | ||
| - name: Disable autocrlf for git on Windows | ||
| if: runner.os == 'Windows' | ||
| run: | | ||
| git config --global core.autocrlf false | ||
| # Setup python. | ||
| - name: Setup Python | ||
| use: actions/setup-python@797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 | ||
| with: | ||
| python-version: '3.13' | ||
| - name: Checkout LLVM | ||
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | ||
| with: | ||
| ref: ${{ needs.prepare.outputs.ref }} | ||
| - name: Install Ninja | ||
| uses: llvm/actions/install-ninja@a1ea791b03c8e61f53a0e66f2f73db283aa0f01e # main | ||
| - name: Setup Windows | ||
| if: startsWith(runner.os, 'Windows') | ||
| uses: llvm/actions/setup-windows@main | ||
| with: | ||
| arch: amd64 | ||
| # In order to avoid some errors with long paths names, we need to shorten | ||
| # the path names for the build. | ||
| - name: Shorten paths on Windows | ||
| if: startsWith(runner.os, 'Windows') | ||
| run: | | ||
| subst S: ${{ github.workspace }} | ||
| - name: Set Build Prefix | ||
| id: setup-stage | ||
| shell: bash | ||
| run: | | ||
| build_prefix=`pwd` | ||
| if [ "${{ runner.os }}" = "Linux" ]; then | ||
| sudo chown $USER:$USER /mnt/ | ||
| build_prefix=/mnt/ | ||
| elif [ "${{ runner.os }}" = "Windows" ]; then | ||
| build_prefix=/s/ | ||
| fi | ||
| echo "build-prefix=$build_prefix" >> $GITHUB_OUTPUT | ||
| # We will use Wix to generate the installer on Windows, because this | ||
| # reportedly works better with larger installers, though, I haven't actually | ||
| # seen an installer > 2GB, which is the limit for default installer | ||
| # generator. | ||
| - name: Install Wix | ||
| if: runner.os == 'Windows' | ||
| run: | | ||
| dotnet tool install --global wix | ||
| - name: Install libxml2 for Windows | ||
| if: runner.os == 'Windows' && false | ||
| run: | | ||
| # Build libxml2 for windows | ||
| curl -O https://gitlab.gnome.org/GNOME/libxml2/-/archive/v2.9.12/libxml2-v2.9.12.tar.gz | ||
| tar zxf libxml2-v2.9.12.tar.gz | ||
| cmake -S libxml2-v2.9.12 -G Ninja -B libxml-build ` | ||
| -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=libxml-install ` | ||
| -DBUILD_SHARED_LIBS=OFF -DLIBXML2_WITH_C14N=OFF -DLIBXML2_WITH_CATALOG=OFF ` | ||
| -DLIBXML2_WITH_DEBUG=OFF -DLIBXML2_WITH_DOCB=OFF -DLIBXML2_WITH_FTP=OFF ` | ||
| -DLIBXML2_WITH_HTML=OFF -DLIBXML2_WITH_HTTP=OFF -DLIBXML2_WITH_ICONV=OFF ` | ||
| -DLIBXML2_WITH_ICU=OFF -DLIBXML2_WITH_ISO8859X=OFF -DLIBXML2_WITH_LEGACY=OFF ` | ||
| -DLIBXML2_WITH_LZMA=OFF -DLIBXML2_WITH_MEM_DEBUG=OFF -DLIBXML2_WITH_MODULES=OFF ` | ||
| -DLIBXML2_WITH_OUTPUT=ON -DLIBXML2_WITH_PATTERN=OFF -DLIBXML2_WITH_PROGRAMS=OFF ` | ||
| -DLIBXML2_WITH_PUSH=OFF -DLIBXML2_WITH_PYTHON=OFF -DLIBXML2_WITH_READER=OFF ` | ||
| -DLIBXML2_WITH_REGEXPS=OFF -DLIBXML2_WITH_RUN_DEBUG=OFF -DLIBXML2_WITH_SAX1=OFF ` | ||
| -DLIBXML2_WITH_SCHEMAS=OFF -DLIBXML2_WITH_SCHEMATRON=OFF -DLIBXML2_WITH_TESTS=OFF ` | ||
| -DLIBXML2_WITH_THREADS=ON -DLIBXML2_WITH_THREAD_ALLOC=OFF -DLIBXML2_WITH_TREE=ON ` | ||
| -DLIBXML2_WITH_VALID=OFF -DLIBXML2_WITH_WRITER=OFF -DLIBXML2_WITH_XINCLUDE=OFF ` | ||
| -DLIBXML2_WITH_XPATH=OFF -DLIBXML2_WITH_XPTR=OFF -DLIBXML2_WITH_ZLIB=OFF ` | ||
| -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded | ||
| ninja -v -C libxml-build install | ||
| - name: Install libxml2 | ||
| shell: bash | ||
| env: | ||
| VCPKG_BUILD_TYPE: release | ||
| VCPKG_CMAKE_CONFIGURE_OPTIONS: -DLIBXML2_WITH_ZLIB=OFF -DLIBXML2_WITH_ICONV=OFF | ||
| VCPKG_ENV_PASSTHROUGH: VCPKG_CMAKE_CONFIGURE_OPTIONS | ||
| run: | | ||
| # Specify [core] to disable extra features so we don't add extra dll dependencies. | ||
| # Even with [core] there is still one dll dependency which is bcrypt.dll. | ||
| vcpkg install libxml2[core]:x64-windows-static | ||
| #find / -iname 'libxml*.lib' | ||
| ls -l /c/vcpkg/packages/libxml2_x64-windows-static/lib/ | ||
| find /c/vcpkg/ -iname '*.cmake' | ||
| find /c/vcpkg/ -iname '*cmake*' | ||
| cat /c/vcpkg/packages/libxml2_x64-windows-static/share/libxml2/libxml2-config.cmake | ||
| cat "/c/Program Files/CMake/share/cmake-3.31/Modules/FindLibXml2.cmake" | ||
| - name: Install python dependencies | ||
| shell: bash | ||
| run: | | ||
| pip install packaging psutil | ||
| - name: Configure | ||
| id: build | ||
| shell: bash | ||
| env: | ||
| LIBXML2_ROOT: /c/vcpkg/packages/libxml2_x64-windows-static/ | ||
| run: | | ||
| #ls -l /c/vcpkg/packages/libxml2_x64-windows-static/ | ||
| #ls -l /c/vcpkg/packages/libxml2_x64-windows-static/lib/ | ||
| #ls -l /c/vcpkg/packages/libxml2_x64-windows-static/include/ | ||
| #ls -l /c/vcpkg/packages/libxml2_x64-windows-static/include/libxml2 | ||
| #ls -l /c/vcpkg/packages/libxml2_x64-windows-static/include/libxml2/libxml | ||
| # There were some issues on the ARM64 MacOS runners with trying to build x86 object, | ||
| # so we need to set some extra cmake flags to disable this. | ||
| # -DLIBXML2_LIBRARIES=/c/vcpkg/packages/libxml2_x64-windows-static/lib/libxml2.lib \ | ||
| # -DLIBXML2_INCLUDE_DIR=/c/vcpkg/packages/libxml2_x64-windows-static/include/libxml2 \ | ||
| # -DLIBXML2_DEFINITIONS=-DLIBXML_STATIC \ | ||
| #-DLibXml2_DIR=/c/vcpkg/packages/libxml2_x64-windows-static/share/libxml2/ \ | ||
| cmake -G Ninja -S llvm -B ${{ steps.setup-stage.outputs.build-prefix }}/build \ | ||
| ${{ needs.prepare.outputs.target-cmake-flags }} \ | ||
| -DLLVM_ENABLE_LIBXML2=FORCE_ON \ | ||
| -DCMAKE_FIND_PACKAGE_PREFER_CONFIG=ON \ | ||
| -C clang/cmake/caches/Release.cmake \ | ||
| -DBOOTSTRAP_BOOTSTRAP_CPACK_PACKAGE_FILE_NAME="${{ needs.prepare.outputs.release-binary-basename }}" | ||
| - name: Save build | ||
| if: failure() && runner.os == 'Windows' | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | ||
| with: | ||
| name: build | ||
| # Due to path differences on Windows when running in bash vs running on node, | ||
| # we need to search for files in the current workspace. | ||
| path: | | ||
| build | ||
| - name: Build | ||
| shell: bash | ||
| env: | ||
| # Set this variable so that stage2-instrumented and stage2 configuration | ||
| # steps can find libxml2. This only is used on Windows and setting | ||
| # this variable should have no affect on other OSes. | ||
| LIBXML2_ROOT: /c/vcpkg/packages/libxml2_x64-windows-static/ | ||
| run: | | ||
| ninja -v -C ${{ steps.setup-stage.outputs.build-prefix }}/build stage2-package | ||
| release_dir=`find ${{ steps.setup-stage.outputs.build-prefix }}/build -iname 'stage2-bins'` | ||
| mv $release_dir/${{ needs.prepare.outputs.release-binary-filename }} . | ||
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | ||
| with: | ||
| name: ${{ runner.os }}-${{ runner.arch }}-release-binary | ||
| # Due to path differences on Windows when running in bash vs running on node, | ||
| # we need to search for files in the current workspace. | ||
| path: | | ||
| ${{ needs.prepare.outputs.release-binary-filename }} | ||
| - name: Run Tests | ||
| # These almost always fail so don't let them fail the build and prevent the uploads. | ||
| continue-on-error: true | ||
| shell: bash | ||
| env: | ||
| # Some tests seem to timeout on windows, so limit the runtime. | ||
| LIT_OPTS: "--timeout=300" | ||
| run: | | ||
| ninja -C ${{ steps.setup-stage.outputs.build-prefix }}/build stage2-check-all | ||
| - name: Save logs | ||
| if: failure() && runner.os == 'Windows' | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | ||
| with: | ||
| name: ${{ runner.os }}-${{ runner.arch }}-nsis-log | ||
| # Due to path differences on Windows when running in bash vs running on node, | ||
| # we need to search for files in the current workspace. | ||
| path: | | ||
| S:/build/tools/clang/stage2-instrumented-bins/tools/clang/stage2-bins/_CPack_Packages/win64/NSIS/NSISOutput.log | ||
| S:/build/tools/clang/stage2-instrumented-bins/tools/clang/stage2-bins/_CPack_Packages/win64/WIX/wix.log | ||
| S:/build/tools/clang/stage2-instrumented-bins/tools/clang/stage2-bins/CPackConfig.cmake | ||
| upload-release-binaries: | ||
| name: "Upload Release Binaries" | ||
| needs: | ||
| - prepare | ||
| - build-release-package | ||
| if: >- | ||
| github.event_name != 'pull_request' && | ||
| needs.prepare.outputs.upload == 'true' | ||
| runs-on: ubuntu-24.04 | ||
| permissions: | ||
| contents: write # For release uploads | ||
| id-token: write # For artifact attestations | ||
| attestations: write # For artifact attestations | ||
| steps: | ||
| - name: Checkout Release Scripts | ||
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | ||
| with: | ||
| sparse-checkout: | | ||
| llvm/utils/release/github-upload-release.py | ||
| llvm/utils/git/requirements.txt | ||
| sparse-checkout-cone-mode: false | ||
| - name: 'Download artifact' | ||
| uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 | ||
| with: | ||
| pattern: '*-release-binary' | ||
| merge-multiple: true | ||
| - name: Attest Build Provenance | ||
| id: provenance | ||
| uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4 | ||
| with: | ||
| subject-path: ${{ needs.prepare.outputs.release-binary-filename }} | ||
| - name: Rename attestation file | ||
| run: | ||
| mv ${{ steps.provenance.outputs.bundle-path }} ${{ needs.prepare.outputs.release-binary-filename }}.jsonl | ||
| - name: Upload Build Provenance | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | ||
| with: | ||
| name: ${{ needs.prepare.outputs.release-binary-filename }}-attestation | ||
| path: ${{ needs.prepare.outputs.release-binary-filename }}.jsonl | ||
| - name: Install Python Requirements | ||
| run: | | ||
| pip install --require-hashes -r ./llvm/utils/git/requirements.txt | ||
| - name: Upload Release | ||
| shell: bash | ||
| run: | | ||
| ./llvm/utils/release/github-upload-release.py \ | ||
| --token ${{ github.token }} \ | ||
| --release ${{ needs.prepare.outputs.release-version }} \ | ||
| upload \ | ||
| --files ${{ needs.prepare.outputs.release-binary-filename }}* | ||