Compare commits

..

1 Commits

Author SHA1 Message Date
Cyrill Leutwiler c04c2560ac wip
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-06 09:55:43 +02:00
348 changed files with 11243 additions and 24655 deletions
-17
View File
@@ -1,17 +0,0 @@
[target.wasm32-unknown-emscripten]
rustflags = [
"-Clink-arg=-sEXPORTED_FUNCTIONS=_main,_free,_malloc",
"-Clink-arg=-sNO_INVOKE_RUN=1",
"-Clink-arg=-sEXIT_RUNTIME=1",
"-Clink-arg=-sALLOW_MEMORY_GROWTH=1",
"-Clink-arg=-sEXPORTED_RUNTIME_METHODS=FS,callMain,stringToNewUTF8",
"-Clink-arg=-sMODULARIZE=1",
"-Clink-arg=-sEXPORT_NAME=createRevive",
"-Clink-arg=-sWASM_ASYNC_COMPILATION=0",
"-Clink-arg=-sDYNAMIC_EXECUTION=0",
"-Clink-arg=-sALLOW_TABLE_GROWTH=1",
"-Clink-arg=--js-library=js/emscripten/embed/soljson_interface.js",
"-Clink-arg=--pre-js=js/emscripten/embed/pre.js",
"-Clink-arg=-sSTACK_SIZE=128kb",
"-Clink-arg=-sNODEJS_CATCH_EXIT=0"
]
-7
View File
@@ -1,7 +0,0 @@
emsdk
llvm*/
target-llvm/
target/
node_modules/
utils/
build/
-19
View File
@@ -1,19 +0,0 @@
name: "Get Emscripten SDK"
inputs:
version:
description: ""
required: false
default: "3.1.64"
runs:
using: "composite"
steps:
- name: install emsdk
shell: bash
run: |
git clone https://github.com/emscripten-core/emsdk.git ./emsdk/
cd emsdk
git checkout tags/${{ inputs.version }}
./emsdk install ${{ inputs.version }}
./emsdk activate ${{ inputs.version }}
-70
View File
@@ -1,70 +0,0 @@
# example:
# - uses: ./.github/actions/get-llvm
# with:
# target: x86_64-unknown-linux-gnu
name: "Download LLVM"
inputs:
target:
required: true
runs:
using: "composite"
steps:
- name: find asset
id: find
uses: actions/github-script@v7
env:
target: ${{ inputs.target }}
with:
result-encoding: string
script: |
let page = 1;
let releases = [];
let releasePrefix = "llvm-"
let target = process.env.target
do {
const res = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 50,
page,
});
releases = res.data
releases.sort((a, b) => {
return (a.published_at < b.published_at) ? 1 : ((a.published_at > b.published_at) ? -1 : 0);
});
let llvmLatestRelease = releases.find(release => {
return release.tag_name.startsWith(releasePrefix);
});
if (llvmLatestRelease){
let asset = llvmLatestRelease.assets.find(asset =>{
return asset.name.includes(target);
});
if (!asset){
core.setFailed(`Artifact for '${target}' not found in release ${llvmLatestRelease.tag_name} (${llvmLatestRelease.html_url})`);
process.exit();
}
return asset.browser_download_url;
}
page++;
} while(releases.length > 0);
core.setFailed(`No LLVM releases with '${releasePrefix}' atifacts found! Please release LLVM before running this workflow.`);
process.exit();
- name: download
shell: bash
run: |
curl -sSLo llvm.tar.gz ${{ steps.find.outputs.result }}
- name: unpack
shell: bash
run: |
tar -xf llvm.tar.gz
rm llvm.tar.gz
-36
View File
@@ -1,36 +0,0 @@
name: "Install Solidity Compiler"
description: "Installs the Ethereum solc Solidity compiler frontend executable"
runs:
using: "composite"
steps:
- name: Figure out Solc Download URL
shell: bash
run: |
if [[ "${{ runner.os }}" == "Linux" ]]; then
echo "SOLC_NAME=solc-static-linux" >> $GITHUB_ENV
elif [[ "${{ runner.os }}" == "Windows" ]]; then
echo "SOLC_NAME=solc-windows.exe" >> $GITHUB_ENV
else
echo "SOLC_NAME=solc-macos" >> $GITHUB_ENV
fi
- name: Download Solc
shell: bash
run: |
mkdir -p solc
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.29/${SOLC_NAME}
- name: Make Solc Executable
if: ${{ runner.os == 'Windows' }}
shell: bash
run: |
echo "$(pwd -W)\\solc" >> $GITHUB_PATH
mv solc/solc solc/solc.exe
- name: Make Solc Executable
if: ${{ runner.os != 'Windows' }}
shell: bash
run: |
echo "$(pwd)/solc" >> $GITHUB_PATH
chmod +x solc/solc
-165
View File
@@ -1,165 +0,0 @@
import os
import sys
import json
import requests
def validate_github_token():
"""Validate that GITHUB_TOKEN environment variable is set."""
if 'GITHUB_TOKEN' not in os.environ:
print("Error: GITHUB_TOKEN environment variable is not set.")
sys.exit(1)
def fetch_release_data(repo, tag):
"""Fetch release data from GitHub API."""
url = f"https://api.github.com/repos/{repo}/releases/tags/{tag}"
headers = {
'Authorization': f"Bearer {os.environ['GITHUB_TOKEN']}",
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28'
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"Error fetching release data: {e}")
sys.exit(1)
def fetch_checksum_file(release_data):
"""
Fetch the checksum.txt file from the release assets
and parse it into a dictionary mapping file names to their SHA256 checksums.
"""
checksums = {}
# Find the checksum.txt asset URL
checksum_asset = None
for asset in release_data['assets']:
if asset['name'] == 'checksums.txt':
checksum_asset = asset
break
if not checksum_asset:
print("Warning: checksum.txt file not found in release assets.")
return checksums
# Download the checksum file
headers = {
'Authorization': f"Bearer {os.environ['GITHUB_TOKEN']}",
'Accept': 'application/octet-stream'
}
try:
response = requests.get(checksum_asset['browser_download_url'], headers=headers)
response.raise_for_status()
# Parse checksum file
for line in response.text.splitlines():
if line.strip():
checksum, filename = line.strip().split(None, 1)
checksums[filename] = checksum
return checksums
except requests.RequestException as e:
print(f"Error fetching checksum file: {e}")
return checksums
except Exception as e:
print(f"Error parsing checksum file: {e}")
return checksums
def extract_build_hash(target_commitish):
"""Extract the first 8 characters of the commit hash."""
return f"commit.{target_commitish[:8]}"
def generate_asset_json(release_data, asset, checksums):
"""Generate JSON for a specific asset."""
version = release_data['tag_name'].lstrip('v')
build = extract_build_hash(release_data['target_commitish'])
long_version = f"{version}+{build}"
# Get SHA256 checksum if available
sha256 = checksums.get(asset['name'], "")
return {
"name": asset['name'],
"version": version,
"build": build,
"longVersion": long_version,
"url": asset['browser_download_url'],
"sha256": sha256,
"firstSolcVersion": os.environ.get("FIRST_SOLC_VERSION", ""),
"lastSolcVersion": os.environ.get("LAST_SOLC_VERSION", "")
}
def save_platform_json(platform_folder, asset_json, tag):
"""Save asset JSON and update list.json for a specific platform."""
# Create platform folder if it doesn't exist
os.makedirs(platform_folder, exist_ok=True)
# Update or create list.json
list_file_path = os.path.join(platform_folder, "list.json")
if os.path.exists(list_file_path):
with open(list_file_path, 'r') as f:
try:
list_data = json.load(f)
except json.JSONDecodeError:
list_data = {"builds": [], "releases": {}, "latestRelease": ""}
else:
list_data = {"builds": [], "releases": {}, "latestRelease": ""}
# Remove any existing entry with the same path
list_data['builds'] = [
build for build in list_data['builds']
if build['version'] != asset_json['version']
]
# Add the new build
list_data['builds'].append(asset_json)
# Update releases
version = asset_json['version']
list_data['releases'][version] = f"{asset_json['name']}+{asset_json['longVersion']}"
# Update latest release
list_data['latestRelease'] = version
with open(list_file_path, 'w') as f:
json.dump(list_data, f, indent=4)
def main():
# Validate arguments
if len(sys.argv) != 3:
print("Usage: python script.py <repo> <tag>")
sys.exit(1)
repo, tag = sys.argv[1], sys.argv[2]
# Validate GitHub token
validate_github_token()
# Fetch release data
release_data = fetch_release_data(repo, tag)
# Fetch checksums
checksums = fetch_checksum_file(release_data)
# Mapping of asset names to platform folders
platform_mapping = {
'resolc-x86_64-unknown-linux-musl': 'linux',
'resolc-universal-apple-darwin': 'macos',
'resolc-x86_64-pc-windows-msvc.exe': 'windows',
'resolc_web.js': 'wasm'
}
# Process each asset
for asset in release_data['assets']:
platform_name = platform_mapping.get(asset['name'])
if platform_name:
platform_folder = os.path.join(platform_name)
asset_json = generate_asset_json(release_data, asset, checksums)
save_platform_json(platform_folder, asset_json, tag)
print(f"Processed {asset['name']} for {platform_name}")
if __name__ == "__main__":
main()
-64
View File
@@ -1,64 +0,0 @@
name: Generate JSON for resolc-bin
on:
release:
types: [published]
jobs:
generateJson:
runs-on: ubuntu-latest
if: contains(github.event.release.tag_name, 'llvm') == false
environment: tags
env:
# the token is needed for json_generator.py
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
path: tmp
- name: Checkout
uses: actions/checkout@v4
with:
repository: paritytech/resolc-bin
path: resolc-bin
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.REVIVE_JSON_APP_ID }}
private-key: ${{ secrets.REVIVE_JSON_APP_KEY }}
owner: paritytech
repositories: resolc-bin
- name: Generate json and push
env:
TOKEN: ${{ steps.app-token.outputs.token }}
APP_NAME: "paritytech-revive-json"
Green: "\e[32m"
NC: "\e[0m"
run: |
sudo apt-get update && sudo apt-get install -y wget
wget https://github.com/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/resolc-x86_64-unknown-linux-musl
chmod +x resolc-x86_64-unknown-linux-musl
export FIRST_SOLC_VERSION=$(./resolc-x86_64-unknown-linux-musl --supported-solc-versions | cut -f 1 -d "," | tr -d ">=")
export LAST_SOLC_VERSION=$(./resolc-x86_64-unknown-linux-musl --supported-solc-versions | cut -f 2 -d "," | tr -d "<=")
cd resolc-bin
python ../tmp/.github/scripts/json_generator.py ${GITHUB_REPOSITORY} ${{ github.event.release.tag_name }}
echo "${Green}Add new remote with gh app token${NC}"
git remote set-url origin $(git config remote.origin.url | sed "s/github.com/${APP_NAME}:${TOKEN}@github.com/g")
echo "${Green}Remove http section that causes issues with gh app auth token${NC}"
sed -i.bak '/\[http/d' ./.git/config
sed -i.bak '/extraheader/d' ./.git/config
git config user.email "ci@parity.io"
git config user.name "${APP_NAME}"
git add .
git commit -m "Update json"
git push origin main
echo "::notice::info.list files were successfully published to https://github.com/paritytech/resolc-bin"
-137
View File
@@ -1,137 +0,0 @@
name: Release LLVM
on:
workflow_dispatch:
inputs:
llvm_version:
type: string
required: true
description: llvm version in "x.x.x" format, e.g. "18.1.8"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
create-release-draft:
runs-on: ubuntu-24.04
permissions:
contents: write
outputs:
version: ${{ steps.resolve-version.outputs.version }}
steps:
- id: resolve-version
run: |
echo "version=llvm-${{ inputs.llvm_version }}-revive.${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
- name: Create Release
uses: softprops/action-gh-release@v2
with:
name: ${{ steps.resolve-version.outputs.version }}
body: "LLVM is a dependency of revive. The LLVM releases are used by our CI to build revive."
draft: true
tag_name: ${{ steps.resolve-version.outputs.version }}
build:
strategy:
matrix:
target: [x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl, wasm32-unknown-emscripten, aarch64-apple-darwin, x86_64-apple-darwin, x86_64-pc-windows-msvc]
include:
- target: x86_64-unknown-linux-gnu
builder-arg: gnu
host: linux
runner: parity-large
- target: x86_64-unknown-linux-musl
builder-arg: musl
host: linux
runner: parity-large
- target: wasm32-unknown-emscripten
builder-arg: emscripten
host: linux
runner: parity-large
- target: aarch64-apple-darwin
builder-arg: gnu
host: macos
runner: macos-14
- target: x86_64-apple-darwin
builder-arg: gnu
host: macos
runner: macos-13
- target: x86_64-pc-windows-msvc
builder-arg: gnu
host: windows
runner: windows-2022
needs: create-release-draft
runs-on: ${{ matrix.runner }}
env:
RUST_LOG: trace
permissions:
contents: write # for uploading assets to release
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
# without this it will override our rust flags
rustflags: ""
cache-key: ${{ matrix.target }}
- name: Install Dependencies
if: ${{ matrix.host == 'linux' }}
run: |
sudo apt-get update && sudo apt-get install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl
- name: Install Dependencies
if: ${{ matrix.host == 'macos' }}
run: |
brew install ninja
- name: Install Dependencies
if: ${{ matrix.host == 'windows' }}
run: |
choco install ninja
- name: Install LLVM Builder
run: |
cargo install --path crates/llvm-builder
- name: Clone LLVM
run: |
revive-llvm --target-env ${{ matrix.builder-arg }} clone
- name: Build LLVM
if: ${{ matrix.target != 'wasm32-unknown-emscripten' }}
run: |
revive-llvm --target-env ${{ matrix.builder-arg }} build --llvm-projects lld --llvm-projects clang
- name: Build LLVM
if: ${{ matrix.target == 'wasm32-unknown-emscripten' }}
run: |
source emsdk/emsdk_env.sh
revive-llvm --target-env ${{ matrix.builder-arg }} build --llvm-projects lld
- name: Remove Unnecessary Binaries
shell: bash
run: |
cd target-llvm/${{ matrix.builder-arg }}/target-final/bin/
rm -f diagtool* llvm-libtool-darwin* llvm-lipo* llvm-pdbutil* llvm-dwarfdump* llvm-nm* llvm-readobj* llvm-cfi-verify* \
sancov* llvm-debuginfo-analyzer* llvm-objdump* llvm-profgen* llvm-extract* llvm-jitlink* llvm-c-test* llvm-gsymutil* llvm-dwp* \
dsymutil* llvm-dwarfutil* llvm-exegesis* lli clang-rename* bugpoint* clang-extdef-mapping* clang-refactor* c-index-test* \
llvm-reduce* llvm-lto* clang-linker-wrapper* llc* llvm-lto2* llvm-otool* llvm-readelf* \
clang-repl* clang-check* clang-scan-deps*
cd -
- name: Package Artifact
shell: bash
run: |
mv target-llvm/${{ matrix.builder-arg }}/target-final/ llvm-${{ matrix.target }}
tar -czf "${{ needs.create-release-draft.outputs.version }}-${{ matrix.target }}.tar.gz" llvm-${{ matrix.target }}
- name: Add Artifact to Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.create-release-draft.outputs.version }}
draft: true
files: |
${{ needs.create-release-draft.outputs.version }}-${{ matrix.target }}.tar.gz
-331
View File
@@ -1,331 +0,0 @@
name: Build & Release
on:
push:
branches: ["main"]
tags:
- "v*"
pull_request:
branches: ["main"]
types: [opened, synchronize, labeled, unlabeled]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
RUST_MUSL_CROSS_IMAGE: messense/rust-musl-cross@sha256:68b86bc7cb2867259e6b233415a665ff4469c28b57763e78c3bfea1c68091561
jobs:
check-version-changed:
runs-on: ubuntu-24.04
permissions:
contents: write
env:
CURRENT_TAG: ${{ github.ref_name }}
outputs:
RELEASE_NOTES: ${{ steps.versions.outputs.RELEASE_NOTES }}
steps:
- uses: actions/checkout@v4
# Check that tag and version in Cargo.toml match
- name: Check versions
id: versions
run: |
if [[ $CURRENT_TAG == 'main' ]];
then
echo "::notice::Tag $CURRENT_TAG is not a release tag, skipping the check in the main branch";
exit 0
fi
if [[ $CURRENT_TAG != "v"* ]];
then
echo "::notice::Tag $CURRENT_TAG is not a release tag, skipping the check in a PR";
exit 0
fi
export PKG_VER=v$(cat Cargo.toml | grep -A 5 package] | grep version | cut -d '=' -f 2 | tr -d '"' | tr -d " ")
echo "Current tag $CURRENT_TAG"
echo "Package version $PKG_VER"
#
if [[ $CURRENT_TAG != $PKG_VER ]];
then
echo "::error::Tag $CURRENT_TAG doesn't match package version $PKG_VER in Cargo.toml, please fix";
exit 1
fi
# Generating release notes early, in order to avoid checkout at the last step
export RELEASE_NOTES="$(sed '/^## '${CURRENT_TAG}'/,/^## v/!d' CHANGELOG.md | sed -e '1d' -e '$d')"
echo "Release notes:"
echo "$RELEASE_NOTES"
echo 'RELEASE_NOTES<<EOF' >> $GITHUB_OUTPUT
echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
echo 'EOF' >> $GITHUB_OUTPUT
build:
strategy:
matrix:
target:
[
x86_64-unknown-linux-musl,
aarch64-apple-darwin,
x86_64-apple-darwin,
x86_64-pc-windows-msvc,
]
include:
- target: x86_64-unknown-linux-musl
type: musl
runner: ubuntu-24.04
- target: aarch64-apple-darwin
type: native
runner: macos-14
- target: x86_64-apple-darwin
type: native
runner: macos-13
- target: x86_64-pc-windows-msvc
type: native
runner: windows-2022
runs-on: ${{ matrix.runner }}
needs: [check-version-changed]
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
# without this it will override our rust flags
rustflags: ""
cache-key: ${{ matrix.target }}
- name: Download LLVM
uses: ./.github/actions/get-llvm
with:
target: ${{ matrix.target }}
- name: Build
if: ${{ matrix.type == 'native' }}
shell: bash
run: |
export LLVM_SYS_181_PREFIX=$PWD/llvm-${{ matrix.target }}
make install-bin
mv target/release/resolc resolc-${{ matrix.target }} || mv target/release/resolc.exe resolc-${{ matrix.target }}.exe
- name: Build
if: ${{ matrix.type == 'musl' }}
run: |
docker run -v $PWD:/opt/revive $RUST_MUSL_CROSS_IMAGE /bin/bash -c "
cd /opt/revive
chown -R root:root .
apt update && apt upgrade -y && apt install -y pkg-config
export LLVM_SYS_181_PREFIX=/opt/revive/llvm-${{ matrix.target }}
make install-bin
mv target/${{ matrix.target }}/release/resolc resolc-${{ matrix.target }}
"
sudo chown -R $(id -u):$(id -g) .
- name: Install Solc
uses: ./.github/actions/get-solc
- name: Basic Sanity Check
shell: bash
run: |
result=$(./resolc-${{ matrix.target }} --bin crates/integration/contracts/flipper.sol)
echo $result
if [[ $result == *'0x50564d'* ]]; then exit 0; else exit 1; fi
- uses: actions/upload-artifact@v4
with:
name: resolc-${{ matrix.target }}
path: resolc-${{ matrix.target }}*
retention-days: 1
build-wasm:
runs-on: ubuntu-24.04
needs: [check-version-changed]
env:
RELEASE_RESOLC_WASM_URI: https://github.com/paritytech/revive-workflow-test/releases/download/${{ github.ref_name }}/resolc.wasm
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
target: wasm32-unknown-emscripten
# without this it will override our rust flags
rustflags: ""
- name: Download Host LLVM
uses: ./.github/actions/get-llvm
with:
target: x86_64-unknown-linux-gnu
- name: Download Wasm LLVM
uses: ./.github/actions/get-llvm
with:
target: wasm32-unknown-emscripten
- name: Download EMSDK
uses: ./.github/actions/get-emsdk
- name: Build
run: |
export LLVM_SYS_181_PREFIX=$PWD/llvm-x86_64-unknown-linux-gnu
export REVIVE_LLVM_TARGET_PREFIX=$PWD/llvm-wasm32-unknown-emscripten
source emsdk/emsdk_env.sh
make install-wasm
chmod -x ./target/wasm32-unknown-emscripten/release/resolc.wasm
- name: Set Up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
- name: Basic Sanity Check
run: |
mkdir -p solc
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.29/soljson.js
node -e "
const soljson = require('solc/soljson');
const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js');
const compiler = createRevive();
compiler.soljson = soljson;
const standardJsonInput =
{
language: 'Solidity',
sources: {
'MyContract.sol': {
content: 'pragma solidity ^0.8.0; contract MyContract { function greet() public pure returns (string memory) { return \'Hello\'; } }',
},
},
settings: { optimizer: { enabled: false } }
};
compiler.writeToStdin(JSON.stringify(standardJsonInput));
compiler.callMain(['--standard-json']);
// Collect output
const stdout = compiler.readFromStdout();
const stderr = compiler.readFromStderr();
if (stderr) { console.error(stderr); process.exit(1); }
let out = JSON.parse(stdout);
let bytecode = out.contracts['MyContract.sol']['MyContract'].evm.bytecode.object
console.log(bytecode);
if(!bytecode.startsWith('50564d')) { process.exit(1); }
"
- name: Compress Artifact
run: |
mkdir -p resolc-wasm32-unknown-emscripten
mv ./target/wasm32-unknown-emscripten/release/resolc.js ./resolc-wasm32-unknown-emscripten/
mv ./target/wasm32-unknown-emscripten/release/resolc.wasm ./resolc-wasm32-unknown-emscripten/
mv ./target/wasm32-unknown-emscripten/release/resolc_web.js ./resolc-wasm32-unknown-emscripten/
- uses: actions/upload-artifact@v4
with:
name: resolc-wasm32-unknown-emscripten
path: resolc-wasm32-unknown-emscripten/*
retention-days: 1
create-release:
if: startsWith(github.ref_name, 'v')
needs: [check-version-changed, build-wasm]
runs-on: macos-14
environment: tags
steps:
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Create macOS Fat Binary
run: |
lipo resolc-aarch64-apple-darwin resolc-x86_64-apple-darwin -create -output resolc-universal-apple-darwin
- name: Make Executable
run: |
chmod +x resolc-x86_64-unknown-linux-musl
chmod +x resolc-universal-apple-darwin
- name: Create sha-256 checksum
run: |
shasum -a 256 resolc-x86_64-unknown-linux-musl > checksums.txt
shasum -a 256 resolc-universal-apple-darwin >> checksums.txt
shasum -a 256 resolc-x86_64-pc-windows-msvc.exe >> checksums.txt
shasum -a 256 resolc.js >> checksums.txt
shasum -a 256 resolc.wasm >> checksums.txt
shasum -a 256 resolc_web.js >> checksums.txt
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.REVIVE_RELEASE_APP_ID }}
private-key: ${{ secrets.REVIVE_RELEASE_APP_KEY }}
- name: create-release
uses: softprops/action-gh-release@v2
with:
body: |
## Changelog
${{ needs.check-version-changed.outputs.RELEASE_NOTES }}
## Note for macOS Users
The macOS binary is unsigned and it needs to be made runnable using `xattr -c resolc-universal-apple-darwin`.
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
prerelease: true
token: ${{ steps.app-token.outputs.token }}
target_commitish: ${{ github.sha }}
files: |
resolc-x86_64-unknown-linux-musl
resolc-universal-apple-darwin
resolc-x86_64-pc-windows-msvc.exe
resolc.js
resolc.wasm
resolc_web.js
checksums.txt
npm-release:
needs: [create-release]
runs-on: macos-14
environment: tags
steps:
- uses: actions/checkout@v4
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Set Up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
- run: npm ci -w js/resolc
- name: Build
run: |
cp -f resolc.{wasm,js} js/resolc/src/resolc
npm -w js/resolc run build
- name: Set version
run: npm -w js/resolc version --no-git-tag-version ${{github.event.release.tag_name}}
- name: npm pack
run: npm -w js/resolc pack
- uses: actions/upload-artifact@v4
with:
name: npm_package
path: "parity-resolc-*.tgz"
- uses: octokit/request-action@bbedc70b1981e610d89f1f8de88311a1fc02fb83
with:
route: POST /repos/paritytech/npm_publish_automation/actions/workflows/publish.yml/dispatches
ref: main
inputs: '${{ format(''{{ "artifact_name": "npm_package", "repo": "{0}", "run_id": "{1}" }}'', github.repository, github.run_id) }}'
env:
GITHUB_TOKEN: ${{ secrets.NPM_PUBLISH_AUTOMATION_TOKEN }}
+55
View File
@@ -0,0 +1,55 @@
name: Build
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
env:
CARGO_TERM_COLOR: always
jobs:
build-ubuntu-x86:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install solc
run: |
mkdir -p solc
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.26/solc-static-linux
chmod +x solc/solc
echo "$(pwd)/solc/" >> $GITHUB_PATH
- name: Install LLVM
run: |
curl -sSL --output llvm.tar.xz https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.4/clang+llvm-18.1.4-x86_64-linux-gnu-ubuntu-18.04.tar.xz
tar Jxf llvm.tar.xz
mv clang+llvm-18.1.4-x86_64-linux-gnu-ubuntu-18.04 llvm18/
echo "$(pwd)/llvm18/bin" >> $GITHUB_PATH
- name: Install apt dependencies
run: |
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt update
sudo apt install -y libtinfo5 ethereum
- name: Format
run: make format
- name: Clippy
run: make clippy
- name: Test cargo workspace
run: make test-workspace
- name: Test CLI
run: make test-cli
- uses: actions/upload-artifact@v4
with:
name: ${{ github.job }}-resolc
path: ./target/release/resolc
retention-days: 1
-45
View File
@@ -1,45 +0,0 @@
name: Test LLVM Builder
on:
pull_request:
branches: ["main"]
types: [opened, synchronize]
paths:
- 'LLVM.lock'
- 'crates/llvm-builder/**'
- '.github/workflows/test-llvm-builder.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
test:
strategy:
matrix:
runner: [parity-large, macos-14, windows-2022]
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
# without this it will override our rust flags
rustflags: ""
cache-key: ${{ matrix.runner }}
- name: Install Dependencies
if: matrix.runner == 'parity-large'
run: |
sudo apt update && sudo apt-get install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl
- name: Install Dependencies
if: matrix.runner == 'macos-14'
run: |
brew install ninja
- name: Test
run: make test-llvm-builder
env:
RUST_LOG: trace
-103
View File
@@ -1,103 +0,0 @@
name: Test Wasm Version
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
types: [opened, synchronize]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
REVIVE_WASM_INSTALL_DIR: ${{ github.workspace }}/target/wasm32-unknown-emscripten/release
jobs:
build:
runs-on: ubuntu-24.04
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
target: wasm32-unknown-emscripten
# without this it will override our rust flags
rustflags: ""
- name: Download Host LLVM
uses: ./.github/actions/get-llvm
with:
target: x86_64-unknown-linux-gnu
- name: Download Wasm LLVM
uses: ./.github/actions/get-llvm
with:
target: wasm32-unknown-emscripten
- name: Install emsdk
uses: ./.github/actions/get-emsdk
- name: Set LLVM Environment Variables
run: |
echo "LLVM_SYS_181_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
echo "REVIVE_LLVM_TARGET_PREFIX=$(pwd)/llvm-wasm32-unknown-emscripten" >> $GITHUB_ENV
- name: Build Revive
run: |
source emsdk/emsdk_env.sh
make install-wasm
- uses: actions/upload-artifact@v4
with:
name: revive-wasm
path: |
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc.js
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc.wasm
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc_web.js
retention-days: 1
test:
needs: build
strategy:
matrix:
os: ["ubuntu-24.04", "macos-14", "windows-2022"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Create Target Directory
run: mkdir -p ${{ env.REVIVE_WASM_INSTALL_DIR }}
- name: Download Artifact
uses: actions/download-artifact@v4
with:
name: revive-wasm
path: ${{ env.REVIVE_WASM_INSTALL_DIR }}
- name: Set Up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
- name: Install Node Packages
run: npm install
- name: Test emscripten
run: |
echo "Running tests for ${{ matrix.os }}"
npm run test:wasm
- name: Test @parity/resolc
run: |
echo "Running tests for ${{ matrix.os }}"
npm run -w js/resolc test
- name: Run Playwright tests
run: |
cd js/emscripten
npx playwright install --with-deps
npx playwright test
-57
View File
@@ -1,57 +0,0 @@
name: Test
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
types: [opened, synchronize]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
test:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
# without this it will override our rust flags
rustflags: ""
- name: Install Solc
uses: ./.github/actions/get-solc
- name: Download LLVM
uses: ./.github/actions/get-llvm
with:
target: x86_64-unknown-linux-gnu
- name: Set LLVM Environment Variables
run: |
echo "LLVM_SYS_181_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
- name: Install Geth
run: |
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt update
sudo apt install -y ethereum
- name: Machete
uses: bnjbvr/cargo-machete@v0.7.1
- name: Format
run: make format
- name: Clippy
run: make clippy
- name: Test cargo workspace
run: make test-workspace
- name: Test CLI
run: make test-cli
+3 -8
View File
@@ -1,6 +1,4 @@
/target
/js/resolc/dist
target-llvm
*.dot
.vscode/
.DS_Store
@@ -8,14 +6,11 @@ target-llvm
/*.yul
/*.ll
/*.s
/llvm*
/llvm-project
/llvm18.0
node_modules
artifacts
tmp
package-lock.json
/*.html
/build
soljson.js
test-results
playwright-report
.cache
emsdk
-6
View File
@@ -1,6 +0,0 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": false
}
-197
View File
@@ -1,197 +0,0 @@
# Changelog
## Unreleased
This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
### Added
### Changed
### Fixed
## v0.1.0-dev.14
This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
### Added
- The `revive-runner` helper utility binary which helps to run contracts locally without a blockchain node.
- Allow configuration of the EVM heap memory size and stack size via CLI flags and JSON input settings.
### Changed
- The default PVM stack memory size was increased from 16kb to 32kb.
### Fixed
- Constructors avoid storing zero sized immutable data on exit.
## v0.1.0-dev.13
This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
### Added
- Support for solc v0.8.29
- Decouples the solc JSON-input-output type definitions from the Solidity fronted and expose them via a dedicated crate.
- `--supported-solc-versions` for `resolc` binary to return a `semver` range of supported `solc` versions.
- Support for passing LLVM command line options via the prcoess input or providing one or more `--llvm-arg='..'` resolc CLI flag. This allows more fine-grained control over the LLVM backend configuration.
### Changed
- Storage keys and values are big endian. This was a pre-mature optimization because for the contract itself it this is a no-op and thus not observable. However we should consider the storage layout as part of the contract ABI. The endianness of transient storage values are still kept as-is.
- Running `resolc` using webkit is no longer supported.
### Fixed
- A missing byte swap for the create2 salt value.
## v0.1.0-dev.12
This is a development pre-release.
Supported `polkadot-sdk` rev: `21f6f0705e53c15aa2b8a5706b208200447774a9`
### Added
- Per file output selection for `--standard-json` mode.
- The `ir` output selection option for `--standard-json` mode.
### Changed
- Improved code size: Large contracts compile to smaller code blobs when enabling aggressive size optimizations (`-Oz`).
### Fixed
## v0.1.0-dev.11
This is a development pre-release.
Supported `polkadot-sdk` rev: `274a781e8ca1a9432c7ec87593bd93214abbff50`
### Added
### Changed
### Fixed
- A bug causing incorrect loads from the emulated EVM linear memory.
- A missing integer truncate after switching to 64bit.
## v0.1.0-dev.10
This is a development pre-release.
Supported `polkadot-sdk` rev: `274a781e8ca1a9432c7ec87593bd93214abbff50`
### Added
- Support for the `coinbase` opcode.
- The resolc web JS version.
### Changed
- Missing the `--overwrite` flag emits an error instead of a warning.
- The `resolc` executable prints the help by default.
- Removed support for legacy EVM assembly (EVMLA) translation.
- integration: identify cached code blobs on source code to fix potential confusions.
- Setting base, include or allow paths in emscripten is now a hard error.
- Employ a heuristic to detect `address.transfer` and `address.send` calls.
If detected, the re-entrant call flag is not set and 0 deposit limit is endowed.
### Fixed
- Solidity: Add the solc `--libraries` files to sources.
- A data race in tests.
- Fix `broken pipe` errors.
- llvm-builder: Allow warnings.
- solidity: Fix the custom compiler warning messages.
## v0.1.0-dev.9
This is a development pre-release.
### Added
### Changed
- Syscalls with more than 6 arguments now pack them into registers.
### Fixed
- Remove reloading of the resolc.js file (fix issue with relative path in web worker)
## v0.1.0-dev.8
This is a development pre-release.
### Added
- The `revive-llvm-builder` crate with the `revive-llvm` helper utility for streamlined management of the LLVM framework dependency.
- Initial support for running `resolc` in the browser.
### Changed
- Suported contracts runtime is polkadot-sdk git version `d62a90c8c729acd98c7e9a5cab9803b8b211ffc5`.
- The minimum supported Rust version is `1.81.0`.
- Error out early instead of invoking `solc` with invalid base or include path flags.
### Fixed
- Decouple the LLVM target dependency from the LLVM host dependency.
- Do not error out if no files and no errors were produced. This aligns resolc closer to solc.
- Fixes input normalization in the Wasm version.
## v0.1.0-dev.7
This is a development pre-release.
### Added
- Implement the `GASPRICE` opcode.
- Implement the `BASEFEE` opcode.
- Implement the `GASLIMIT` opcode.
### Changed
- The `GAS` opcode now returns the remaining `ref_time`.
- Contracts can now be supplied call data input of arbitrary size.
- Some syscalls now return the value in a register, slightly improving emitted contract code.
- Calls forward maximum weight limits instead of 0, anticipating a change in polkadot-sdk where weight limits of 0 no longer interprets as uncapped limit.
### Fixed
- A linker bug which was preventing certain contracts from linking with the PVM linker.
- JS: Fix encoding conversion from JS string (UTF-16) to UTF-8.
- The git commit hash slug is always displayed in the version string.
## v0.1.0-dev.6
This is a development pre-release.
# Added
- Implement the `BLOCKHASH` opcode.
- Implement delegate calls.
- Implement the `GASPRICE` opcode. Currently hard-coded to return `1`.
- The ELF shared object contract artifact is dumped into the debug output directory.
- Initial support for emitting debug info (opt in via the `-g` flag)
# Changed
- resolc now emits 64bit PolkaVM blobs, reducing contract code size and execution time.
- The RISC-V bit-manipulation target feature (`zbb`) is enabled.
# Fixed
- Compilation to Wasm (for usage in node and web browsers)
## v0.1.0-dev.5
This is development pre-release.
# Added
- Implement the `CODESIZE` and `EXTCODESIZE` opcodes.
# Changed
- Include the full revive version in the contract metadata.
# Fixed
## v0.1.0-dev-4
This is development pre-release.
# Added
- Support the `ORIGIN` opcode.
# Changed
- Update polkavm to `v0.14.0`.
- Enable the `a`, `fast-unaligned-access` and `xtheadcondmov` LLVM target features, decreasing the code size for some contracts.
# Fixed
Generated
+1306 -3083
View File
File diff suppressed because it is too large Load Diff
+46 -54
View File
@@ -3,82 +3,74 @@ resolver = "2"
members = ["crates/*"]
[workspace.package]
version = "0.1.0-dev.14"
version = "0.1.0"
authors = [
"Cyrill Leutwiler <cyrill@parity.io>",
"Parity Technologies <admin@parity.io>",
]
license = "MIT/Apache-2.0"
edition = "2021"
repository = "https://github.com/paritytech/revive"
rust-version = "1.81.0"
repository = "https://github.com/xermicus/revive"
[workspace.dependencies]
revive-benchmarks = { version = "0.1.0-dev.14", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0-dev.14", path = "crates/builtins" }
revive-common = { version = "0.1.0-dev.14", path = "crates/common" }
revive-differential = { version = "0.1.0-dev.14", path = "crates/differential" }
revive-integration = { version = "0.1.0-dev.14", path = "crates/integration" }
revive-linker = { version = "0.1.0-dev.14", path = "crates/linker" }
lld-sys = { version = "0.1.0-dev.14", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0-dev.14", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.1.0-dev.14", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0-dev.14", path = "crates/runner" }
revive-solc-json-interface = { version = "0.1.0-dev.14", path = "crates/solc-json-interface" }
revive-solidity = { version = "0.1.0-dev.14", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0-dev.14", path = "crates/stdlib" }
revive-build-utils = { version = "0.1.0-dev.14", path = "crates/build-utils" }
revive-benchmarks = { version = "0.1.0", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0", path = "crates/builtins" }
revive-common = { version = "0.1.0", path = "crates/common" }
revive-differential = { version = "0.1.0", path = "crates/differential" }
revive-integration = { version = "0.1.0", path = "crates/integration" }
revive-linker = { version = "0.1.0", path = "crates/linker" }
lld-sys = { version = "0.1.0", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.1.0", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0", path = "crates/runner" }
revive-solidity = { version = "0.1.0", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0", path = "crates/stdlib" }
hex = "0.4.3"
cc = "1.2"
libc = "0.2.169"
tempfile = "3.17"
hex = "0.4"
petgraph = "0.6"
cc = "1.0"
libc = "0.2"
tempfile = "3.8"
anyhow = "1.0"
semver = { version = "1.0", features = ["serde"] }
itertools = "0.14"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["arbitrary_precision"] }
semver = { version = "1.0", features = [ "serde" ] }
itertools = "0.12"
serde = { version = "1.0", features = [ "derive" ] }
serde_json = { version = "1.0", features = [ "arbitrary_precision" ] }
regex = "1.10"
once_cell = "1.20"
num = "0.4.3"
once_cell = "1.19"
num = "0.4"
sha1 = "0.10"
sha2 = "0.10"
sha3 = "0.10"
thiserror = "2.0"
which = "7.0"
md5 = "0.7"
colored = "2.1"
thiserror = "1.0"
which = "5.0"
path-slash = "0.2"
rayon = "1.8"
clap = { version = "4", default-features = false, features = ["derive"] }
polkavm-common = "0.21.0"
polkavm-linker = "0.21.0"
polkavm-disassembler = "0.21.0"
polkavm = "0.21.0"
alloy-primitives = { version = "0.8.21", features = ["serde"] }
alloy-sol-types = "0.8.21"
alloy-genesis = "0.11.1"
alloy-serde = "0.11.1"
env_logger = { version = "0.11.6", default-features = false }
serde_stacker = "0.1.11"
criterion = { version = "0.5.1", features = ["html_reports"] }
log = { version = "0.4.25" }
git2 = { version = "0.20.0", default-features = false }
downloader = "0.2.8"
flate2 = "1.0.35"
fs_extra = "1.3.0"
num_cpus = "1"
tar = "0.4"
toml = "0.8"
assert_cmd = "2.0"
assert_fs = "1.1"
rand = "0.8"
polkavm-common = "0.10"
polkavm-linker = "0.10"
polkavm-disassembler = "0.10"
polkavm = "0.10"
alloy-primitives = { version = "0.8", features = ["serde"] }
alloy-sol-types = "0.8"
alloy-genesis = "0.3"
alloy-serde = "0.3"
env_logger = { version = "0.10.0", default-features = false }
serde_stacker = "0.1"
criterion = { version = "0.5", features = ["html_reports"] }
log = { version = "0.4" }
# polkadot-sdk and friends
codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" }
scale-info = { version = "2.11.6", default-features = false }
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "c29e72a8628835e34deb6aa7db9a78a2e4eabcee" }
scale-info = { version = "2.11.1", default-features = false }
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "d7b575338b2c647e04fc48bfbe00ea8f492fb580" }
# llvm
[workspace.dependencies.inkwell]
git = "https://github.com/TheDan64/inkwell.git"
rev = "7b410298b6a93450adaa90b1841d5805a3038f12"
version = "0.5"
default-features = false
features = ["serde", "llvm18-0", "no-libffi-linking", "target-riscv"]
-32
View File
@@ -1,32 +0,0 @@
FROM rust:1.84.0 AS llvm-builder
WORKDIR /opt/revive
RUN apt update && \
apt upgrade -y && \
apt install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl
COPY . .
RUN make install-llvm-builder
RUN revive-llvm --target-env musl clone
RUN revive-llvm --target-env musl build --llvm-projects lld --llvm-projects clang
FROM messense/rust-musl-cross@sha256:68b86bc7cb2867259e6b233415a665ff4469c28b57763e78c3bfea1c68091561 AS resolc-builder
WORKDIR /opt/revive
RUN apt update && \
apt upgrade -y && \
apt install -y pkg-config
COPY . .
COPY --from=llvm-builder /opt/revive/target-llvm /opt/revive/target-llvm
ENV LLVM_SYS_181_PREFIX=/opt/revive/target-llvm/musl/target-final
RUN make install-bin
FROM alpine:latest
ADD https://github.com/ethereum/solidity/releases/download/v0.8.28/solc-static-linux /usr/bin/solc
COPY --from=resolc-builder /root/.cargo/bin/resolc /usr/bin/resolc
RUN apk add --no-cache libc6-compat
RUN chmod +x /usr/bin/solc
-3
View File
@@ -1,3 +0,0 @@
url = "https://github.com/llvm/llvm-project.git"
branch = "release/18.x"
ref = "3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff"
+19 -59
View File
@@ -1,59 +1,18 @@
.PHONY: \
install \
install-bin \
install-npm \
install-wasm \
install-llvm-builder \
install-llvm \
install-revive-runner \
format \
clippy \
machete \
test \
test-integration \
test-solidity \
test-workspace \
test-cli \
test-wasm \
test-llvm-builder
bench \
bench-pvm \
bench-evm \
clean
.PHONY: install format test test-solidity test-cli test-integration test-workspace clean docs docs-build
install: install-bin install-npm
install-bin:
cargo install --locked --path crates/solidity
cargo install --path crates/solidity
install-npm:
npm install && npm fund
install-wasm: install-npm
cargo build --target wasm32-unknown-emscripten -p revive-solidity --release --no-default-features
npm run build:package
install-llvm-builder:
cargo install --path crates/llvm-builder
install-llvm: install-llvm-builder
revive-llvm clone
revive-llvm build --llvm-projects lld --llvm-projects clang
install-revive-runner:
cargo install --path crates/runner --no-default-features --locked
format:
cargo fmt --all --check
clippy:
cargo clippy --all-features --workspace --tests --benches -- --deny warnings
machete:
cargo install cargo-machete
cargo machete
test: format clippy machete test-cli test-workspace install-revive-runner
test: format clippy test-cli test-workspace
cargo test --workspace
test-integration: install-bin
cargo test --package revive-integration
@@ -62,22 +21,11 @@ test-solidity: install
cargo test --package revive-solidity
test-workspace: install
cargo test --workspace --exclude revive-llvm-builder
cargo test --workspace
test-cli: install
npm run test:cli
test-wasm: install-wasm
npm run test:wasm
test-llvm-builder:
@echo "warning: the llvm-builder tests will take many hours"
cargo test --package revive-llvm-builder -- --test-threads=1
bench: install-bin
cargo criterion --all --all-features --message-format=json \
| criterion-table > crates/benchmarks/BENCHMARKS.md
bench-pvm: install-bin
cargo criterion --bench execute --features bench-pvm-interpreter --message-format=json \
| criterion-table > crates/benchmarks/PVM.md
@@ -86,10 +34,22 @@ bench-evm: install-bin
cargo criterion --bench execute --features bench-evm --message-format=json \
| criterion-table > crates/benchmarks/EVM.md
bench: install-bin
cargo criterion --all --all-features --message-format=json \
| criterion-table > crates/benchmarks/BENCHMARKS.md
clippy:
cargo clippy --all-features --workspace --tests --benches
docs: docs-build
mdbook serve --open docs/
docs-build:
mdbook test docs/ && mdbook build docs/
clean:
cargo clean ; \
revive-llvm clean ; \
rm -rf node_modules ; \
rm -rf crates/solidity/src/tests/cli-tests/artifacts ; \
cargo uninstall revive-solidity ; \
cargo uninstall revive-llvm-builder ;
rm -f package-lock.json
+13 -86
View File
@@ -1,111 +1,38 @@
![CI](https://github.com/paritytech/revive/actions/workflows/test.yml/badge.svg)
[![Docs](https://img.shields.io/badge/Docs-contracts.polkadot.io-brightgreen.svg)](https://contracts.polkadot.io/revive_compiler/)
![CI](https://github.com/xermicus/revive/actions/workflows/rust.yml/badge.svg)
# revive
YUL recompiler to LLVM, targetting RISC-V on [PolkaVM](https://github.com/koute/polkavm).
YUL and EVM assembly recompiler to LLVM, targetting RISC-V on [PolkaVM](https://github.com/koute/polkavm).
Visit [contracts.polkadot.io](https://contracts.polkadot.io) to learn more about contracts on Polkadot!
[Frontend](https://github.com/matter-labs/era-compiler-solidity) and [code generator](https://github.com/matter-labs/era-compiler-llvm-context) are based of ZKSync `zksolc`.
## Status
This is experimental software in active development and not ready just yet for production usage. Please do report any compiler related issues or missing features that are [not yet known to us](https://contracts.polkadot.io/known_issues/) here.
This is experimental software in active development and not ready just yet for production usage.
Discussion around the development is hosted on the [Polkadot Forum](https://forum.polkadot.network/t/contracts-update-solidity-on-polkavm/6949#a-new-solidity-compiler-1).
## Installation
Please consult [the documentation](https://contracts.polkadot.io/revive_compiler/installation) for installation instructions.
## Building from source
Building revive requires a [stable Rust installation](https://rustup.rs/) and a C++ toolchain for building [LLVM](https://github.com/llvm/llvm-project) on your system.
### LLVM
`revive` depends on a custom build of LLVM `v18.1.8` with the RISC-V _embedded_ target, including the `compiler-rt` builtins. You can either download a build from our releases (recommended for older hardware) or build it from source.
<details>
<summary>Download from our LLVM releases</summary>
Download the [latest LLVM build](https://github.com/paritytech/revive/releases?q=LLVM+binaries+release&expanded=true) from our releases.
> **MacOS** users need to clear the `downloaded` attribute from all binaries after extracting the archive:
> ```sh
> xattr -rc </path/to/the/extracted/archive>/target-llvm/gnu/target-final/bin/*
> ```
After extracting the archive, point `$LLVM_SYS_181_PREFIX` to it:
```sh
export LLVM_SYS_181_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/target-final
```
</details>
<details>
<summary>Building from source</summary>
Use the provided [revive-llvm](crates/llvm-builder/README.md) utility to compile a compatible LLVM build locally and point `$LLVM_SYS_181_PREFIX` to the installation afterwards.
The `Makefile` provides a shortcut target to obtain a compatible LLVM build:
```sh
make install-llvm
export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final
```
</details>
### The `resolc` Solidity frontend
To build the `resolc` Solidity frontend executable, make sure you have obtained a compatible LLVM build and did export the `LLVM_SYS_181_PREFIX` environment variable pointing to it (see [above](#LLVM)).
`resolc` depends on the [solc](https://github.com/ethereum/solidity) binary installed on your system.
To install the `resolc` Solidity frontend executable:
```sh
```bash
bash build-llvm.sh
export PATH=${PWD}/llvm18.0/bin:$PATH
make install-bin
resolc --version
```
### Cross-compilation to Wasm
### LLVM
Cross-compile the `resolc.js` frontend executable to Wasm for running it in a Node.js or browser environment. The `REVIVE_LLVM_TARGET_PREFIX` environment variable is used to control the target environment LLVM dependency.
`revive` requires a build of LLVM 18.1.4 or later including `compiler-rt`. Use the provided [build-llvm.sh](build-llvm.sh) build script to compile a compatible LLVM build locally in `$PWD/llvm18.0` (don't forget to add that to `$PATH` afterwards).
<details>
<summary>Instructions for cross-compilation to wasm32-unknown-emscripten</summary>
```sh
# Build the host LLVM dependency with PolkaVM target support
make install-llvm
export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final
# Build the target LLVM dependency with PolkaVM target support
revive-llvm --target-env emscripten clone
source emsdk/emsdk_env.sh
revive-llvm --target-env emscripten build --llvm-projects lld
export REVIVE_LLVM_TARGET_PREFIX=${PWD}/target-llvm/emscripten/target-final
# Build the resolc frontend executable
make install-wasm
make test-wasm
```
</details>
## Development
### Development
Please consult the [Makefile](Makefile) targets to learn how to run tests and benchmarks.
Ensure that your branch passes `make test` locally when submitting a pull request.
### Design overview
See the [relevant section in our documentation](https://contracts.polkadot.io/revive_compiler/architecture) to learn more about how the compiler works.
[Frontend](https://github.com/matter-labs/era-compiler-solidity) and [code generator](https://github.com/matter-labs/era-compiler-llvm-context) are based of ZKSync `zksolc` (the project started as a fork of the era compiler).
### Tests
Before running the tests, ensure that Geth (Go Ethereum) is installed on your system. Follow the installation guide here: [Installing Geth](https://geth.ethereum.org/docs/getting-started/installing-geth).
Once Geth is installed, you can run the tests using the following command:
```sh
make test
```
## Design overview
`revive` uses [solc](https://github.com/ethereum/solidity/), the Ethereum Solidity compiler, as the [Solidity frontend](crates/solidity/src/lib.rs) to process smart contracts written in Solidity. The YUL IR code (or legacy EVM assembly as a fallback for older `solc` versions) emitted by `solc` is then translated to LLVM IR, targetting [Polkadots `revive` pallet](https://docs.rs/pallet-revive/latest/pallet_revive/trait.SyscallDoc.html).
-21
View File
@@ -1,21 +0,0 @@
# Release checklist
Prior to the first stable release we neither have formal release processes nor do we follow a fixed release schedule.
To create a new pre-release:
1. Create a release PR which updates the `-dev.X` versions in the workspace `Cargo.toml` and updates the `CHANGELOG.md` accordingly.
2. If the CI passes, merge the release PR.
3. Push a tag that has the same `-dev.X` version as in `Cargo.toml`
4. The release workflow will attempt to build and publish a new pre-release if the latest tag does match the cargo package version.
5. Wait for the `Release` workflow to finish. It should create the pre-release with the same `-dev.X` name.
6. Check that pre-release was created on the [Releases page](https://github.com/paritytech/revive/releases) with all artifacts.
7. After the release is published, another workflow should start automatically and update json files in https://github.com/paritytech/resolc-bin. Check the changes.
8. Update the [contract-docs](https://github.com/paritytech/contract-docs/) accordingly
# LLVM release
To create a new LLVM release, run "Release LLVM" workflow. Use current LLVM version as parameter, e.g. `18.1.8`.
Version suffix will be resolved automatically.
The workflows will create new GitHub release, and upload LLVM binaries.
Next release of resolc will use newly created binaries.
-1
View File
@@ -1 +0,0 @@
https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/SECURITY.md
-30
View File
@@ -1,30 +0,0 @@
# Known issues
The following is known and we are either working on it or it is a hard limitation. Please do not open a new issue.
## Release
`0.1.0-dev-2`
## Missing features
- [Libraries with public functions are not supported](https://github.com/paritytech/revive/issues/91)
- [Automatic import resolution is not supported](https://github.com/paritytech/revive/issues/98)
- The emulated EVM linear contract memory is limited to 64kb in size. Will be fixed with support for metered dynamic memory.
- [The contract calldata is currently limited to 1kb in size](https://github.com/paritytech/revive/issues/57)
- [EIP-4844 opcodes are not supported](https://github.com/paritytech/revive/issues/64)
- [Delegate calls are not supported](https://github.com/paritytech/revive/issues/67)
- [The `blockhash` opcode is not supported](https://github.com/paritytech/revive/issues/61)
- [The `extcodesize` opcode is not supported](https://github.com/paritytech/revive/issues/58)
- [The `origin` opcode is not supported](https://github.com/paritytech/revive/issues/59)
- [Gas limits for contract calls are ignored](https://github.com/paritytech/revive/issues/60)
- [Gas related opcodes are not supported](https://github.com/paritytech/revive/issues/60)
- IPFS metadata hashes are not supported
- [Compiled contract artifacts can exceed the pallet static memory limit and fail to deploy](https://github.com/paritytech/revive/issues/96).
- [Transfers to inexistant accounts will fail if the transferred value lies below the ED.](https://github.com/paritytech/revive/issues/83) Will be fixed in the pallet to make the ED completely transparent for contracts.
## Wontfix
Please consult our documentation to learn more about Solidity and EVM features likely to remain unsupported (and why they will not be supported).
TODO: Insert link to the relevant documentation section.
Executable
+92
View File
@@ -0,0 +1,92 @@
#!/usr/bin/env bash
set -euo pipefail
INSTALL_DIR="${PWD}/llvm18.0"
mkdir -p ${INSTALL_DIR}
# Clone LLVM 18 (any revision after commit bd32aaa is supposed to work)
if [ ! -d "llvm-project" ]; then
git clone --depth 1 --branch release/18.x https://github.com/llvm/llvm-project.git
fi
# Build LLVM, clang
LLVM_SRC_PREFIX=${PWD}/llvm-project
LLVM_SRC_DIR=${LLVM_SRC_PREFIX}/llvm
LLVM_BUILD_DIR=${PWD}/build/llvm
if [ ! -d ${LLVM_BUILD_DIR} ] ; then
mkdir -p ${LLVM_BUILD_DIR}
fi
cmake -G Ninja \
-S ${LLVM_SRC_DIR} \
-B ${LLVM_BUILD_DIR} \
-DLLVM_ENABLE_ASSERTIONS=On \
-DLLVM_ENABLE_TERMINFO=Off \
-DLLVM_ENABLE_LIBXML2=Off \
-DLLVM_ENABLE_ZLIB=Off \
-DLLVM_ENABLE_PROJECTS='clang;lld' \
-DLLVM_TARGETS_TO_BUILD='RISCV' \
-DLLVM_ENABLE_ZSTD=Off \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}
cmake --build ${LLVM_BUILD_DIR}
cmake --install ${LLVM_BUILD_DIR}
# Build compiler builtins
COMPILER_RT_SRC_DIR=${LLVM_SRC_PREFIX}/compiler-rt
COMPILER_RT_BUILD_DIR=${PWD}/build/compiler-rt
if [ ! -d ${COMPILER_RT_BUILD_DIR} ] ; then
mkdir -p ${COMPILER_RT_BUILD_DIR}
fi
build_compiler_rt() {
case "$1" in
64) TARGET_ABI=lp64e ;;
32) TARGET_ABI=ilp32e ;;
*) exit -1
esac
CFLAGS="--target=riscv${1} -march=rv${1}em -mabi=${TARGET_ABI} -mcpu=generic-rv${1} -nostdlib -nodefaultlibs"
cmake -G Ninja \
-S ${COMPILER_RT_SRC_DIR} \
-B ${COMPILER_RT_BUILD_DIR} \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} \
-DCOMPILER_RT_BUILD_BUILTINS=ON \
-DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
-DCOMPILER_RT_BUILD_MEMPROF=OFF \
-DCOMPILER_RT_BUILD_PROFILE=OFF \
-DCOMPILER_RT_BUILD_SANITIZERS=OFF \
-DCOMPILER_RT_BUILD_XRAY=OFF \
-DCMAKE_C_COMPILER=${INSTALL_DIR}/bin/clang \
-DCMAKE_C_COMPILER_TARGET=riscv${1} \
-DCMAKE_ASM_COMPILER_TARGET=riscv${1} \
-DCMAKE_CXX_COMPILER_TARGET=riscv${1} \
-DCMAKE_C_TARGET_BITS=riscv${1} \
-DCMAKE_ASM_TARGET_BITS=riscv${1} \
-DCMAKE_AR=${INSTALL_DIR}/bin/llvm-ar \
-DCMAKE_NM=${INSTALL_DIR}/bin/llvm-nm \
-DCMAKE_RANLIB=${INSTALL_DIR}/bin/llvm-ranlib \
-DCOMPILER_RT_BAREMETAL_BUILD=ON \
-DLLVM_CONFIG_PATH=${INSTALL_DIR}/bin/llvm-config \
-DCMAKE_C_FLAGS="${CFLAGS}" \
-DCMAKE_ASM_FLAGS="${CFLAGS}" \
-DCOMPILER_RT_TEST_COMPILER=${INSTALL_DIR}/bin/clang \
-DCMAKE_CXX_FLAGS="${CFLAGS}" \
-DCMAKE_SYSTEM_NAME=unknown \
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON
cmake --build ${COMPILER_RT_BUILD_DIR}
cmake --install ${COMPILER_RT_BUILD_DIR}
}
build_compiler_rt 32
build_compiler_rt 64
echo ""
echo "success"
echo "add this directory to your PATH: ${INSTALL_DIR}/bin/"
+28 -28
View File
@@ -15,58 +15,58 @@
### Baseline
| | `EVM` | `PVMInterpreter` |
|:--------|:-------------------------|:-------------------------------- |
| **`0`** | `10.08 us` (✅ **1.00x**) | `10.32 us` (**1.02x slower**) |
| | `EVM` | `PVMInterpreter` |
|:--------|:------------------------|:-------------------------------- |
| **`0`** | `5.97 us` (✅ **1.00x**) | `27.04 us` (*4.53x slower*) |
### OddPorduct
| | `EVM` | `PVMInterpreter` |
|:-------------|:--------------------------|:-------------------------------- |
| **`10000`** | `3.60 ms` (✅ **1.00x**) | `1.57 ms` (🚀 **2.28x faster**) |
| **`100000`** | `34.72 ms` (✅ **1.00x**) | `14.82 ms` (🚀 **2.34x faster**) |
| **`300000`** | `105.01 ms` (✅ **1.00x**) | `44.11 ms` (🚀 **2.38x faster**) |
| **`10000`** | `4.26 ms` (✅ **1.00x**) | `2.88 ms` ( **1.48x faster**) |
| **`100000`** | `42.37 ms` (✅ **1.00x**) | `28.35 ms` ( **1.49x faster**) |
| **`300000`** | `127.88 ms` (✅ **1.00x**) | `88.43 ms` ( **1.45x faster**) |
### TriangleNumber
| | `EVM` | `PVMInterpreter` |
|:-------------|:-------------------------|:-------------------------------- |
| **`10000`** | `2.43 ms` (✅ **1.00x**) | `1.12 ms` (🚀 **2.17x faster**) |
| **`100000`** | `24.20 ms` (✅ **1.00x**) | `10.86 ms` (🚀 **2.23x faster**) |
| **`360000`** | `88.69 ms` (✅ **1.00x**) | `38.46 ms` (🚀 **2.31x faster**) |
| | `EVM` | `PVMInterpreter` |
|:-------------|:--------------------------|:-------------------------------- |
| **`10000`** | `2.85 ms` (✅ **1.00x**) | `2.37 ms` ( **1.20x faster**) |
| **`100000`** | `27.85 ms` (✅ **1.00x**) | `23.01 ms` ( **1.21x faster**) |
| **`360000`** | `103.01 ms` (✅ **1.00x**) | `83.66 ms` ( **1.23x faster**) |
### FibonacciRecursive
| | `EVM` | `PVMInterpreter` |
|:---------|:--------------------------|:--------------------------------- |
| **`12`** | `144.17 us` (✅ **1.00x**) | `150.85 us` (**1.05x slower**) |
| **`16`** | `938.71 us` (✅ **1.00x**) | `922.11 us` (✅ **1.02x faster**) |
| **`20`** | `6.54 ms` (✅ **1.00x**) | `6.20 ms` (**1.05x faster**) |
| **`24`** | `45.73 ms` (✅ **1.00x**) | `41.98 ms` (**1.09x faster**) |
| **`12`** | `195.19 us` (✅ **1.00x**) | `333.53 us` (*1.71x slower*) |
| **`16`** | `1.22 ms` (✅ **1.00x**) | `1.97 ms` (❌ *1.62x slower*) |
| **`20`** | `8.14 ms` (✅ **1.00x**) | `13.20 ms` (*1.62x slower*) |
| **`24`** | `55.09 ms` (✅ **1.00x**) | `88.56 ms` (*1.61x slower*) |
### FibonacciIterative
| | `EVM` | `PVMInterpreter` |
|:----------|:-------------------------|:-------------------------------- |
| **`64`** | `23.00 us` (✅ **1.00x**) | `31.88 us` (❌ *1.39x slower*) |
| **`128`** | `35.28 us` (✅ **1.00x**) | `42.43 us` (❌ *1.20x slower*) |
| **`256`** | `60.12 us` (✅ **1.00x**) | `61.20 us` (**1.02x slower**) |
| | `EVM` | `PVMInterpreter` |
|:----------|:-------------------------|:--------------------------------- |
| **`64`** | `33.39 us` (✅ **1.00x**) | `86.02 us` (❌ *2.58x slower*) |
| **`128`** | `52.91 us` (✅ **1.00x**) | `126.38 us` (❌ *2.39x slower*) |
| **`256`** | `82.33 us` (✅ **1.00x**) | `208.74 us` (*2.54x slower*) |
### FibonacciBinet
| | `EVM` | `PVMInterpreter` |
|:----------|:-------------------------|:-------------------------------- |
| **`64`** | `23.01 us` (✅ **1.00x**) | `47.74 us` (❌ *2.07x slower*) |
| **`128`** | `25.44 us` (✅ **1.00x**) | `49.67 us` (❌ *1.95x slower*) |
| **`256`** | `28.66 us` (✅ **1.00x**) | `53.01 us` (❌ *1.85x slower*) |
| | `EVM` | `PVMInterpreter` |
|:----------|:-------------------------|:--------------------------------- |
| **`64`** | `32.29 us` (✅ **1.00x**) | `161.75 us` (❌ *5.01x slower*) |
| **`128`** | `36.02 us` (✅ **1.00x**) | `172.59 us` (❌ *4.79x slower*) |
| **`256`** | `41.21 us` (✅ **1.00x**) | `185.30 us` (❌ *4.50x slower*) |
### SHA1
| | `EVM` | `PVMInterpreter` |
|:----------|:--------------------------|:--------------------------------- |
| **`1`** | `135.87 us` (✅ **1.00x**) | `243.75 us` (❌ *1.79x slower*) |
| **`64`** | `258.45 us` (✅ **1.00x**) | `355.70 us` (❌ *1.38x slower*) |
| **`512`** | `1.10 ms` (✅ **1.00x**) | `1.09 ms` (**1.01x faster**) |
| **`1`** | `160.17 us` (✅ **1.00x**) | `403.46 us` (❌ *2.52x slower*) |
| **`64`** | `286.69 us` (✅ **1.00x**) | `479.79 us` (❌ *1.67x slower*) |
| **`512`** | `1.18 ms` (✅ **1.00x**) | `1.37 ms` (*1.16x slower*) |
---
Made with [criterion-table](https://github.com/nu11ptr/criterion-table)
+1 -1
View File
@@ -46,7 +46,7 @@ fn group<'error, M>(c: &'error mut Criterion<M>, group_name: &str) -> BenchmarkG
where
M: Measurement,
{
c.benchmark_group(group_name)
return c.benchmark_group(group_name);
}
fn bench_baseline(c: &mut Criterion) {
-14
View File
@@ -1,14 +0,0 @@
# Generated by Cargo
# will have compiled files and executables
/target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# IDE
/.idea/
/.vscode/
-15
View File
@@ -1,15 +0,0 @@
[package]
name = "revive-build-utils"
version.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
authors = [
"Cyrill Leutwiler <cyrill@parity.io>",
]
description = "Shared build utilities of the revive compiler"
[lib]
doctest = false
[dependencies]
-10
View File
@@ -1,10 +0,0 @@
# revive: Compiler Common
## License
This library is distributed under the terms of either
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.
-48
View File
@@ -1,48 +0,0 @@
//! The compiler build utilities library.
/// The revive LLVM host dependency directory prefix environment variable.
pub const REVIVE_LLVM_HOST_PREFIX: &str = "LLVM_SYS_181_PREFIX";
/// The revive LLVM target dependency directory prefix environment variable.
pub const REVIVE_LLVM_TARGET_PREFIX: &str = "REVIVE_LLVM_TARGET_PREFIX";
/// Constructs a path to the LLVM tool `name`.
///
/// Respects the [`REVIVE_LLVM_HOST_PREFIX`] environment variable.
pub fn llvm_host_tool(name: &str) -> std::path::PathBuf {
std::env::var_os(REVIVE_LLVM_HOST_PREFIX)
.map(Into::<std::path::PathBuf>::into)
.unwrap_or_else(|| {
panic!(
"install LLVM using the revive-llvm builder and export {REVIVE_LLVM_HOST_PREFIX}",
)
})
.join("bin")
.join(name)
}
/// Returns the LLVM lib dir.
///
/// Respects the [`REVIVE_LLVM_HOST_PREFIX`] environment variable.
pub fn llvm_lib_dir() -> std::path::PathBuf {
std::path::PathBuf::from(llvm_config("--libdir").trim())
}
/// Returns the LLVM CXX compiler flags.
///
/// Respects the [`REVIVE_LLVM_HOST_PREFIX`] environment variable.
pub fn llvm_cxx_flags() -> String {
llvm_config("--cxxflags")
}
/// Execute the `llvm-config` utility respecting the [`REVIVE_LLVM_HOST_PREFIX`] environment variable.
fn llvm_config(arg: &str) -> String {
let llvm_config = llvm_host_tool("llvm-config");
let output = std::process::Command::new(&llvm_config)
.arg(arg)
.output()
.unwrap_or_else(|error| panic!("`{} {arg}` failed: {error}", llvm_config.display()));
String::from_utf8(output.stdout)
.unwrap_or_else(|_| panic!("output of `{} {arg}` should be utf8", llvm_config.display()))
}
+4 -2
View File
@@ -8,5 +8,7 @@ authors.workspace = true
build = "build.rs"
description = "compiler builtins for the revive compiler"
[build-dependencies]
revive-build-utils = { workspace = true }
[features]
riscv-64 = []
[dependencies]
+14 -18
View File
@@ -1,34 +1,30 @@
use std::{env, fs, io::Read, path::Path, process::Command};
#[cfg(not(feature = "riscv-64"))]
pub const BUILTINS_ARCHIVE_FILE: &str = "libclang_rt.builtins-riscv32.a";
#[cfg(feature = "riscv-64")]
pub const BUILTINS_ARCHIVE_FILE: &str = "libclang_rt.builtins-riscv64.a";
fn main() {
println!(
"cargo:rerun-if-env-changed={}",
revive_build_utils::REVIVE_LLVM_HOST_PREFIX
);
let llvm_config = revive_build_utils::llvm_host_tool("llvm-config");
let mut llvm_lib_dir = String::new();
Command::new(&llvm_config)
.arg("--libdir")
Command::new("llvm-config")
.args(["--libdir"])
.output()
.unwrap_or_else(|_| {
panic!(
"{} should be able to provide LD path",
llvm_config.display()
)
})
.expect("llvm-config should be able to provide LD path")
.stdout
.as_slice()
.read_to_string(&mut llvm_lib_dir)
.expect("llvm-config output should be utf8");
let lib_path = revive_build_utils::llvm_lib_dir()
.join("unknown")
let mut lib_path = std::path::PathBuf::from(llvm_lib_dir.trim())
.join("linux")
.join(BUILTINS_ARCHIVE_FILE);
let archive = fs::read(&lib_path).expect("clang builtins not found");
println!("cargo:rerun-if-env-changed={}", lib_path.display());
if !lib_path.exists() {
lib_path = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
.join(BUILTINS_ARCHIVE_FILE);
}
let archive = fs::read(lib_path).expect("clang builtins not found");
let out_dir = env::var_os("OUT_DIR").expect("has OUT_DIR");
let archive_path = Path::new(&out_dir).join(BUILTINS_ARCHIVE_FILE);
Binary file not shown.
Binary file not shown.
+3
View File
@@ -13,6 +13,9 @@ description = "Shared constants of the revive compiler"
[lib]
doctest = false
[features]
riscv-64 = []
[dependencies]
anyhow = { workspace = true }
serde = { workspace = true, features = ["derive"] }
+1 -1
View File
@@ -20,7 +20,7 @@ pub const BIT_LENGTH_ETH_ADDRESS: usize =
pub const BIT_LENGTH_WORD: usize = crate::byte_length::BYTE_LENGTH_WORD * BIT_LENGTH_BYTE;
/// Bit length of the runtime value type.
pub const BIT_LENGTH_VALUE: usize = BIT_LENGTH_WORD;
pub const BIT_LENGTH_VALUE: usize = crate::byte_length::BYTE_LENGTH_VALUE * BIT_LENGTH_BYTE;
/// Bit length of thre runimte block number type.
pub const BIT_LENGTH_BLOCK_NUMBER: usize =
+6 -3
View File
@@ -6,12 +6,15 @@ pub const BYTE_LENGTH_BYTE: usize = 1;
/// The x86 word byte-length.
pub const BYTE_LENGTH_X32: usize = 4;
/// Native stack alignment size in bytes
#[cfg(not(feature = "riscv-64"))]
pub const BYTE_LENGTH_STACK_ALIGN: usize = 4;
#[cfg(feature = "riscv-64")]
pub const BYTE_LENGTH_STACK_ALIGN: usize = 8;
/// The x86_64 word byte-length.
pub const BYTE_LENGTH_X64: usize = 8;
/// EVM native stack alignment size in bytes
pub const BYTE_LENGTH_STACK_ALIGN: usize = 32;
/// The ETH address byte-length.
pub const BYTE_LENGTH_ETH_ADDRESS: usize = 20;
+6 -3
View File
@@ -12,6 +12,12 @@ pub static EXTENSION_ABI: &str = "abi";
/// The Yul IR file extension.
pub static EXTENSION_YUL: &str = "yul";
/// The EVM legacy assembly IR file extension.
pub static EXTENSION_EVMLA: &str = "evmla";
/// The Ethereal IR file extension.
pub static EXTENSION_ETHIR: &str = "ethir";
/// The EVM file extension.
pub static EXTENSION_EVM: &str = "evm";
@@ -35,6 +41,3 @@ pub static EXTENSION_POLKAVM_ASSEMBLY: &str = "pvmasm";
/// The PolkaVM bytecode file extension.
pub static EXTENSION_POLKAVM_BINARY: &str = "pvm";
/// The ELF shared object file extension.
pub static EXTENSION_SHARED_OBJECT: &str = "so";
+4 -21
View File
@@ -1,6 +1,6 @@
{
"config": {
"chainId": 420420420,
"chainId": 1,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
@@ -16,16 +16,9 @@
"shanghaiTime": 0,
"cancunTime": 0,
"terminalTotalDifficulty": 0,
"terminalTotalDifficultyPassed": true,
"blobSchedule": {
"cancun": {
"target": 3,
"max": 6,
"baseFeeUpdateFraction": 3338477
}
}
"terminalTotalDifficultyPassed": true
},
"coinbase": "0xffffffffffffffffffffffffffffffffffffffff",
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x20000",
"extraData": "",
"gasLimit": "0xffffffff",
@@ -33,15 +26,5 @@
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00",
"alloc": {
"0101010101010101010101010101010101010101": {
"balance": "1000000000"
},
"0202020202020202020202020202020202020202": {
"balance": "1000000000"
},
"0303030303030303030303030303030303030303": {
"balance": "1000000000"
}
}
"alloc": {}
}
+5 -5
View File
@@ -40,7 +40,7 @@ const EXECUTABLE_ARGS_BENCH: [&str; 6] = [
"-",
];
const GAS_USED_MARKER: &str = "EVM gas used:";
const REVERT_MARKER: &str = " error: ";
const REVERT_MARKER: &str = "error: execution reverted";
/// The geth EVM state dump structure
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
@@ -100,9 +100,10 @@ pub struct EvmOutput {
impl EvmOutput {
/// Return if there was no error found.
///
/// Panics if the gas used is zero as this indicates nothing was run.
/// Panics if the gas used is zero as this indicates nothing was run, i.e.
/// there was no receiving account but still no error is reported.
pub fn run_success(&self) -> bool {
assert_ne!(self.gas_used, U256::ZERO, "nothing was executed: {self:?}");
assert_ne!(self.gas_used, U256::ZERO, "nothing was executed");
self.error.is_none()
}
}
@@ -413,7 +414,7 @@ impl Evm {
let stderr = str::from_utf8(output.stderr.as_slice())
.unwrap_or_else(|err| panic!("{EXECUTABLE_NAME} stderr failed to parse: {err}"));
let mut log: EvmLog = format!("{stdout}{stderr}").as_str().into();
let mut log: EvmLog = stdout.into();
log.stderr = stderr.into();
if self.bench {
log.parse_gas_used_from_bench();
@@ -557,7 +558,6 @@ allocated bytes: 3711"#;
}
#[test]
#[ignore] // https://github.com/ethereum/go-ethereum/issues/30778
fn bench_flipper() {
let log_runtime = Evm::default()
.code_blob(EVM_BIN_RUNTIME_FIXTURE.as_bytes().to_vec())
+6 -1
View File
@@ -8,14 +8,19 @@ authors.workspace = true
description = "revive compiler integration test cases"
[dependencies]
polkavm = { workspace = true }
alloy-primitives = { workspace = true }
alloy-sol-types = { workspace = true }
hex = { workspace = true }
env_logger = { workspace = true }
log = { workspace = true }
serde_json = { workspace = true }
revive-solidity = { workspace = true }
revive-runner = { workspace = true }
revive-differential = { workspace = true }
revive-llvm-context = { workspace = true }
revive-common = { workspace = true }
revive-runner = { workspace = true }
[dev-dependencies]
sha1 = { workspace = true }
+8 -8
View File
@@ -1,10 +1,10 @@
{
"Baseline": 939,
"Computation": 2282,
"DivisionArithmetics": 8849,
"ERC20": 18308,
"Events": 1640,
"FibonacciIterative": 1497,
"Flipper": 2099,
"SHA1": 8243
"Baseline": 878,
"Computation": 4305,
"DivisionArithmetics": 39774,
"ERC20": 53405,
"Events": 1693,
"FibonacciIterative": 2917,
"Flipper": 3570,
"SHA1": 32557
}
@@ -1,33 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
contract Predicted {
uint public salt;
constructor(uint _salt) {
salt = _salt;
}
}
contract AddressPredictor {
constructor(uint _salt, bytes memory _bytecode) payable {
address deployed = address(new Predicted{salt: bytes32(_salt)}(_salt));
address predicted = predictAddress(_salt, _bytecode);
assert(deployed == predicted);
}
function predictAddress(
uint _foo,
bytes memory _bytecode
) public view returns (address predicted) {
bytes32 addr = keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
bytes32(_foo),
keccak256(abi.encodePacked(_bytecode, abi.encode(_foo)))
)
);
predicted = address(uint160(uint(addr)));
}
}
-81
View File
@@ -1,81 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "BalanceReceiver"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Balance"
}
},
"value": 24
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "1c8d16b30000000000000000000000000303030303030303030303030303030303030303000000000000000000000000000000000000000000000000000000000000000a"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "6ada15d90000000000000000000000000303030303030303030303030303030303030303000000000000000000000000000000000000000000000000000000000000000a"
}
}
]
}
*/
contract BalanceReceiver {
constructor() payable {}
fallback() external payable {}
}
contract Balance {
constructor() payable {
// 0 to EOA
transfer_to(payable(address(0xdeadbeef)), 0);
send_to(payable(address(0xdeadbeef)), 0);
// 1 to EOA
transfer_to(payable(address(0xcafebabe)), 1);
send_to(payable(address(0xcafebabe)), 1);
BalanceReceiver balanceReceiver = new BalanceReceiver();
// 0 to contract
transfer_to(payable(address(balanceReceiver)), 0);
send_to(payable(address(balanceReceiver)), 0);
// 1 to contract
transfer_to(payable(address(balanceReceiver)), 1);
send_to(payable(address(balanceReceiver)), 1);
}
function transfer_to(address payable _dest, uint _amount) public payable {
_dest.transfer(_amount);
}
function send_to(address payable _dest, uint _amount) public payable {
require(_dest.send(_amount));
}
}
-31
View File
@@ -1,31 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "BaseFee"
}
}
}
},
{
"VerifyCall": {
"success": true
}
}
]
}
*/
contract BaseFee {
constructor() payable {
assert(block.basefee == 0);
}
}
@@ -1,33 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "BlockHash"
}
},
"data": "4545454545454545454545454545454545454545454545454545454545454545"
}
}
]
}
*/
contract BlockHash {
constructor(bytes32 expected) payable {
assert(blockhash(0) == expected);
assert(blockhash(1) == 0);
assert(
blockhash(
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
) == 0
);
}
}
+16 -20
View File
@@ -7,10 +7,10 @@ pragma solidity ^0.8;
"differential": true,
"actions": [
{
"Upload": {
"Instantiate": {
"code": {
"Solidity": {
"contract": "Callee"
"contract": "Call"
}
}
}
@@ -19,40 +19,36 @@ pragma solidity ^0.8;
"Instantiate": {
"code": {
"Solidity": {
"contract": "Caller"
"contract": "Call"
}
},
"value": 123
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
"Instantiated": 1
},
"data": "5a6535fc00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004cafebabe00000000000000000000000000000000000000000000000000000000"
"data": "1b8b921d0000000000000000000000001c81a61a407017c58397a47d2ab28191b9b8ec9b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000050102030405000000000000000000000000000000000000000000000000000000"
}
}
]
}
*/
contract Callee {
contract Call {
function value_transfer(address payable destination) public payable {
destination.transfer(msg.value);
}
function echo(bytes memory payload) public pure returns (bytes memory) {
return payload;
}
receive() external payable {}
}
contract Caller {
constructor() payable {
Callee callee = new Callee();
payable(address(callee)).transfer(msg.value);
}
function call(bytes memory payload) public returns (bytes memory) {
Callee callee = new Callee();
return callee.echo(payload);
function call(
address callee,
bytes memory payload
) public pure returns (bytes memory) {
return Call(callee).echo(payload);
}
}
-27
View File
@@ -1,27 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Coinbase"
}
}
}
}
]
}
*/
contract Coinbase {
constructor() payable {
address coinbase = address(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF);
assert(block.coinbase == coinbase);
}
}
-16
View File
@@ -30,14 +30,6 @@ pragma solidity ^0.8;
},
"data": "fc9c8d39"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "3af973b1"
}
}
]
}
@@ -51,12 +43,4 @@ contract Context {
function caller() public view returns (address ret) {
ret = msg.sender;
}
function chain_id() public view returns (uint) {
uint256 id;
assembly {
id := chainid()
}
return id;
}
}
+6 -57
View File
@@ -1,64 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "CreateA"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "CreateB"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"value": 10000
}
},
{
"Call": {
"dest": {
"Instantiated": 0
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
}
}
}
]
}
*/
pragma solidity ^0.8.24;
contract CreateA {
constructor() payable {}
address creator;
constructor() payable {
creator = msg.sender;
}
}
contract CreateB {
-50
View File
@@ -1,50 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "CreateA"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "CreateB"
}
},
"value": 100000
}
}
]
}
*/
contract CreateA {
constructor() payable {}
}
contract CreateB {
constructor() payable {
bytes32 salt = hex"ff";
try new CreateA{salt: salt}() returns (CreateA) {} catch {
revert("the first instantiation should succeed");
}
try new CreateA{salt: salt}() returns (CreateA) {} catch {
return;
}
revert("the second instantiation should have failed");
}
}
+11 -13
View File
@@ -4,32 +4,30 @@ pragma solidity ^0.8.24;
/* runner.json
{
"differential": true,
"actions": [
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "TestSha3"
}
}
}
"Instantiate": {}
},
{
"Call": {
"dest": {
"Instantiated": 0
"Instantiated": 0
},
"data": "f9fbd5540000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c68656c6c6f20776f726c64210000000000000000000000000000000000000000"
}
},
{
"VerifyCall": {
"success": true,
"output": "57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6"
}
}
]
}
*/
contract TestSha3 {
function test(string memory _pre) external payable returns (bytes32) {
bytes32 hash = keccak256(bytes(_pre));
return bytes32(uint(hash) + 1);
function test(string memory _pre) external payable returns (bytes32 hash) {
hash = keccak256(bytes(_pre));
}
}
-84
View File
@@ -1,84 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "Logic"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Tester"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"value": 123,
"data": "6466414b0000000000000000000000000000000000000000000000000000000000000020"
}
}
]
}
*/
contract Logic {
// NOTE: storage layout must be the same as contract Tester
uint256 public num;
address public sender;
uint256 public value;
uint public immutable multiplier = 4;
event DidSetVars();
function setVars(uint256 _num) public payable returns (uint256) {
num = _num * multiplier;
sender = msg.sender;
value = msg.value;
emit DidSetVars();
return _num;
}
}
contract Tester {
uint256 public num;
address public sender;
uint256 public value;
uint public immutable multiplier = 2;
function setVars(uint256 _num) public payable returns (bool, bytes memory) {
Logic impl = new Logic();
// Tester's storage is set, Logic is not modified.
(bool success, bytes memory data) = address(impl).delegatecall(
abi.encodeWithSignature("setVars(uint256)", _num)
);
assert(success);
assert(impl.num() == 0);
assert(impl.sender() == address(0));
assert(impl.value() == 0);
assert(num == _num * 4);
assert(sender == msg.sender);
assert(value == msg.value);
return (success, data);
}
}
@@ -1,38 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "DelegateCaller"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "e466c6c9"
}
}
]
}
*/
contract DelegateCaller {
function delegateNoContract() external returns (bool) {
address testAddress = 0x0000000000000000000000000000000000000000;
(bool success, ) = testAddress.delegatecall(
abi.encodeWithSignature("test()")
);
return success;
}
}
+4 -43
View File
@@ -4,27 +4,11 @@ pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "ERC20"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "ERC20Tester"
}
}
}
}
]
{
"Instantiate": {}
}
]
}
*/
@@ -98,26 +82,3 @@ contract ERC20 is IERC20 {
emit Transfer(msg.sender, address(0), amount);
}
}
contract ERC20Tester {
constructor() {
address BOB = address(0xffffffffffffffffffffffffffffffffffffff);
ERC20 token = new ERC20();
assert(token.decimals() == 18);
token.mint(300);
assert(token.balanceOf(address(this)) == 300);
token.transfer(BOB, 100);
assert(token.balanceOf(address(this)) == 200);
assert(token.balanceOf(BOB) == 100);
token.approve(address(this), 100);
token.transferFrom(address(this), BOB, 100);
assert(token.balanceOf(BOB) == 200);
assert(token.balanceOf(address(this)) == 100);
token.burn(100);
assert(token.balanceOf(address(this)) == 0);
}
}
+7 -3
View File
@@ -22,7 +22,12 @@ pragma solidity ^0.8;
},
"data": "4d43bec90000000000000000000000000000000000000000000000000000000000000000"
}
},
}
]
}
*/
/* TODO when pallet_revive accepts Solidity event topics
{
"Call": {
"dest": {
@@ -31,8 +36,7 @@ pragma solidity ^0.8;
"data": "4d43bec9000000000000000000000000000000000000000000000000000000000000007b"
}
}
]
}
*/
contract Events {
-12
View File
@@ -14,16 +14,4 @@ contract ExtCode {
ret := codesize()
}
}
function ExtCodeHash(address who) public view returns (bytes32 ret) {
assembly {
ret := extcodehash(who)
}
}
function CodeHash() public view returns (bytes32 ret) {
assembly {
ret := extcodehash(address())
}
}
}
@@ -1,42 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "FunctionPointer"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "26121ff0"
}
}
]
}
*/
contract FunctionPointer {
bool public flag = false;
function f0() public {
flag = true;
}
function f() public returns (bool) {
function() internal x = f0;
x();
return flag;
}
}
@@ -1,36 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "FunctionType"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b8c9d365"
}
}
]
}
*/
contract FunctionType {
uint public immutable x = 42;
function h() public view returns (function() external view returns (uint)) {
return this.x;
}
}
-32
View File
@@ -1,32 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "GasLeft"
}
}
}
},
{
"VerifyCall": {
"success": true
}
}
]
}
*/
contract GasLeft {
constructor() payable {
assert(gasleft() > gasleft());
assert(gasleft() > 0 && gasleft() < 0xffffffffffffffff);
}
}
-31
View File
@@ -1,31 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "GasLimit"
}
}
}
},
{
"VerifyCall": {
"success": true
}
}
]
}
*/
contract GasLimit {
constructor() payable {
assert(block.gaslimit == 2000000000000);
}
}
-31
View File
@@ -1,31 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "GasPrice"
}
}
}
},
{
"VerifyCall": {
"success": true
}
}
]
}
*/
contract GasPrice {
constructor() payable {
assert(tx.gasprice == 1000);
}
}
@@ -1,63 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "ImmutablesTester"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Immutables"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
}
}
}
]
}
*/
contract ImmutablesTester {
// Read should work in the runtime code
uint public immutable foo;
// Read should work in the runtime code
uint public immutable bar;
// Read should work in the runtime code
uint public immutable zoo;
// Assign and read should work in the constructor
constructor(uint _foo) payable {
foo = _foo;
bar = foo + 1;
zoo = bar + 2;
assert(zoo == _foo + 3);
}
}
contract Immutables {
fallback() external {
ImmutablesTester tester = new ImmutablesTester(127);
assert(tester.foo() == 127);
assert(tester.bar() == tester.foo() + 1);
assert(tester.zoo() == tester.bar() + 2);
}
}
-52
View File
@@ -1,52 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.29;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "LayoutAt"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "a7a0d537"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "15393349"
}
}
]
}
*/
contract LayoutAt layout at 0xDEADBEEF + 0xCAFEBABE {
uint[3] public something;
constructor() payable {
something[0] = 1337;
something[1] = 42;
something[2] = 69;
}
function slotOfSomething() public pure returns (uint ret) {
assembly {
ret := something.slot
}
}
}
@@ -1,51 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "MCopyOverlap"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "afdce848"
}
}
]
}
*/
function copy(
uint dstOffset,
uint srcOffset,
uint length
) pure returns (bytes memory out) {
out = hex"2222222222222222333333333333333344444444444444445555555555555555"
hex"6666666666666666777777777777777788888888888888889999999999999999"
hex"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccdddddddddddddddd";
assembly {
mcopy(
add(add(out, 0x20), dstOffset),
add(add(out, 0x20), srcOffset),
length
)
}
}
contract MCopyOverlap {
function mcopy_to_right_overlap() public pure returns (bytes memory) {
return copy(0x20, 0x10, 0x30);
}
}
-40
View File
@@ -1,40 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "MLoad"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "e2179b8e"
}
}
]
}
*/
contract MLoad {
constructor() payable {
assert(g() == 0);
}
function g() public payable returns (uint m) {
assembly {
m := mload(0)
}
}
}
+12 -1
View File
@@ -4,7 +4,6 @@ pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
@@ -24,6 +23,12 @@ pragma solidity ^0.8;
"data": "f016832c"
}
},
{
"VerifyCall": {
"success": true,
"output": "0000000000000000000000000000000000000000000000000000000000000060"
}
},
{
"Call": {
"dest": {
@@ -31,6 +36,12 @@ pragma solidity ^0.8;
},
"data": "f4a63aa5"
}
},
{
"VerifyCall": {
"success": true,
"output": "0000000000000000000000000000000000000000000000000000000000000084"
}
}
]
}
@@ -1,53 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "Callee"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "ReturnDataOob"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
}
}
}
]
}
*/
contract Callee {
function echo(bytes memory payload) public pure returns (bytes memory) {
return payload;
}
}
contract ReturnDataOob {
fallback() external {
new Callee().echo(hex"1234");
assembly {
let pos := mload(64)
let size := add(returndatasize(), 1)
returndatacopy(pos, 0, size)
}
}
}
-75
View File
@@ -1,75 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Send"
}
},
"value": 211
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "1c8d16b30000000000000000000000000303030303030303030303030303030303030303000000000000000000000000000000000000000000000000000000000000000a"
}
},
{
"VerifyCall": {
"success": true
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "fb9e8d050000000000000000000000000000000000000000000000000000000000000001"
}
},
{
"VerifyCall": {
"success": false
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "fb9e8d050000000000000000000000000000000000000000000000000000000000000000"
}
},
{
"VerifyCall": {
"success": false
}
}
]
}
*/
contract Send {
constructor() payable {}
function transfer_self(uint _amount) public payable {
transfer_to(payable(address(this)), _amount);
}
function transfer_to(address payable _dest, uint _amount) public payable {
if (_dest.send(_amount)) {}
}
fallback() external {}
receive() external payable {}
}
+1 -17
View File
@@ -22,14 +22,6 @@ pragma solidity ^0.8;
},
"data": "fabc9efaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "558b9f9bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
}
]
}
@@ -38,18 +30,10 @@ pragma solidity ^0.8;
contract Storage {
function transient(uint value) public returns (uint ret) {
assembly {
let slot := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
let slot := 123
tstore(slot, value)
let success := call(0, 0, 0, 0, 0, 0, 0)
ret := tload(slot)
}
}
function persistent(uint value) public returns (uint ret) {
assembly {
let slot := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
sstore(slot, value)
ret := sload(slot)
}
}
}
@@ -1,54 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "TransactionOrigin"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "TransactionTester"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "f8a8fd6d"
}
}
]
}
*/
contract TransactionTester {
constructor() payable {
assert(tx.origin == new TransactionOrigin().test());
}
function test() public payable returns (address ret) {
ret = tx.origin;
}
}
contract TransactionOrigin {
function test() public payable returns (address ret) {
assert(msg.sender != tx.origin);
ret = tx.origin;
}
}
-75
View File
@@ -1,75 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Transfer"
}
},
"value": 211
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "1c8d16b30000000000000000000000000303030303030303030303030303030303030303000000000000000000000000000000000000000000000000000000000000000a"
}
},
{
"VerifyCall": {
"success": true
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "fb9e8d050000000000000000000000000000000000000000000000000000000000000001"
}
},
{
"VerifyCall": {
"success": false
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "fb9e8d050000000000000000000000000000000000000000000000000000000000000000"
}
},
{
"VerifyCall": {
"success": false
}
}
]
}
*/
contract Transfer {
constructor() payable {}
function transfer_self(uint _amount) public payable {
transfer_to(payable(address(this)), _amount);
}
function transfer_to(address payable _dest, uint _amount) public payable {
_dest.transfer(_amount);
}
fallback() external {}
receive() external payable {}
}
+4 -33
View File
@@ -5,18 +5,8 @@ pragma solidity ^0.8;
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "ValueTester"
}
}
}
},
{
"Instantiate": {
"value": 1024,
"code": {
"Solidity": {
"contract": "Value"
@@ -29,7 +19,6 @@ pragma solidity ^0.8;
"dest": {
"Instantiated": 0
},
"value": 123,
"data": "3fa4f245"
}
}
@@ -37,30 +26,12 @@ pragma solidity ^0.8;
}
*/
contract ValueTester {
constructor() payable {}
function balance_self() public view returns (uint ret) {
ret = address(this).balance;
}
}
contract Value {
constructor() payable {
ValueTester tester = new ValueTester{value: msg.value}();
// own account
assert(address(this).balance == 0);
// tester account
assert(address(tester).balance == msg.value);
assert(tester.balance_self() == msg.value);
// non-existant account
assert(address(0xdeadbeef).balance == 0);
}
function value() public payable returns (uint ret) {
ret = msg.value;
}
function balance_of(address _address) public view returns (uint ret) {
ret = _address.balance;
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ pragma solidity ^0.8;
"Instantiated": 0
},
"key": "0000000000000000000000000000000000000000000000000000000000000000",
"expected": "0000000000000000000000000000000000000000000000000000000000000001"
"expected": "0100000000000000000000000000000000000000000000000000000000000000"
}
},
{
+10 -85
View File
@@ -1,7 +1,6 @@
use alloy_primitives::{Address, Bytes, I256, U256};
use alloy_sol_types::{sol, SolCall, SolConstructor};
use revive_llvm_context::OptimizerSettings;
use revive_solidity::test_utils::*;
#[derive(Clone)]
@@ -157,20 +156,6 @@ case!("DivisionArithmetics.sol", DivisionArithmetics, sdivCall, division_arithme
case!("DivisionArithmetics.sol", DivisionArithmetics, modCall, division_arithmetics_mod, n: U256, d: U256);
case!("DivisionArithmetics.sol", DivisionArithmetics, smodCall, division_arithmetics_smod, n: I256, d: I256);
sol!(
contract Send {
function transfer_self(uint _amount) public payable;
}
);
case!("Send.sol", Send, transfer_selfCall, send_self, amount: U256);
sol!(
contract Transfer {
function transfer_self(uint _amount) public payable;
}
);
case!("Transfer.sol", Transfer, transfer_selfCall, transfer_self, amount: U256);
sol!(
contract MStore8 {
function mStore8(uint value) public pure returns (uint256 word);
@@ -193,16 +178,10 @@ sol!(
function ExtCodeSize(address who) public view returns (uint ret);
function CodeSize() public pure returns (uint ret);
function ExtCodeHash(address who) public view returns (bytes32 ret);
function CodeHash() public view returns (bytes32 ret);
}
);
case!("ExtCode.sol", ExtCode, ExtCodeSizeCall, ext_code_size, address: Address);
case!("ExtCode.sol", ExtCode, CodeSizeCall, code_size,);
case!("ExtCode.sol", ExtCode, ExtCodeHashCall, ext_code_hash, address: Address);
case!("ExtCode.sol", ExtCode, CodeHashCall, code_hash,);
sol!(
contract MCopy {
@@ -230,11 +209,9 @@ case!("Call.sol", "Call", vec![], call_constructor);
sol!(
contract Value {
function balance_of(address _address) public view returns (uint ret);
function balance_self() public view returns (uint ret);
}
);
case!("Value.sol", Value, balance_ofCall, value_balance_of, address: Address);
case!("Value.sol", Value, balance_selfCall, value_balance_self,);
sol!(
contract Bitwise {
@@ -250,19 +227,8 @@ sol!(
);
case!("Storage.sol", Storage, transientCall, storage_transient, value: U256);
sol!(
contract Predicted {
constructor(uint _foo);
}
contract AddressPredictor {
constructor(uint _foo, bytes memory _bytecode) payable;
}
);
case!("AddressPredictor.sol", Predicted, constructorCall, predicted_constructor, salt: U256);
case!("AddressPredictor.sol", AddressPredictor, constructorCall, address_predictor_constructor, salt: U256, bytecode: Bytes);
impl Contract {
pub fn build(calldata: Vec<u8>, name: &'static str, code: &str) -> Self {
fn build(calldata: Vec<u8>, name: &'static str, code: &str) -> Self {
Self {
name,
evm_runtime: compile_evm_bin_runtime(name, code),
@@ -270,19 +236,11 @@ impl Contract {
calldata,
}
}
pub fn build_size_opt(calldata: Vec<u8>, name: &'static str, code: &str) -> Self {
Self {
name,
evm_runtime: compile_evm_bin_runtime(name, code),
pvm_runtime: compile_blob_with_options(name, code, true, OptimizerSettings::size()),
calldata,
}
}
}
#[cfg(test)]
mod tests {
use alloy_primitives::{Bytes, U256};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::{de::Deserialize, Serialize};
use std::{collections::BTreeMap, fs::File};
@@ -322,47 +280,14 @@ mod tests {
};
[
(|| {
Contract::build_size_opt(
vec![],
"Baseline",
include_str!("../contracts/Baseline.sol"),
)
}) as _,
(|| {
Contract::build_size_opt(
vec![],
"Flipper",
include_str!("../contracts/flipper.sol"),
)
}) as _,
(|| {
Contract::build_size_opt(
vec![],
"Computation",
include_str!("../contracts/Computation.sol"),
)
}) as _,
(|| {
Contract::build_size_opt(
vec![],
"FibonacciIterative",
include_str!("../contracts/Fibonacci.sol"),
)
}) as _,
(|| Contract::build_size_opt(vec![], "ERC20", include_str!("../contracts/ERC20.sol")))
as _,
(|| Contract::build_size_opt(vec![], "SHA1", include_str!("../contracts/SHA1.sol")))
as _,
(|| {
Contract::build_size_opt(
vec![],
"DivisionArithmetics",
include_str!("../contracts/DivisionArithmetics.sol"),
)
}) as _,
(|| Contract::build_size_opt(vec![], "Events", include_str!("../contracts/Events.sol")))
as _,
Contract::baseline as fn() -> Contract,
Contract::flipper as fn() -> Contract,
(|| Contract::odd_product(0)) as fn() -> Contract,
(|| Contract::fib_iterative(U256::ZERO)) as fn() -> Contract,
Contract::erc20 as fn() -> Contract,
(|| Contract::sha1(Bytes::new())) as fn() -> Contract,
(|| Contract::division_arithmetics_div(U256::ZERO, U256::ZERO)) as fn() -> Contract,
(|| Contract::event(U256::ZERO)) as fn() -> Contract,
]
.into_par_iter()
.map(extract_code_size)
+141 -268
View File
@@ -6,10 +6,6 @@ use SpecsAction::*;
use crate::cases::Contract;
/// Parameters:
/// - The function name of the test
/// - The contract name to fill in empty code based on the file path
/// - The contract source file
macro_rules! test_spec {
($test_name:ident, $contract_name:literal, $source_file:literal) => {
#[test]
@@ -30,36 +26,14 @@ test_spec!(hash_keccak_256, "TestSha3", "Crypto.sol");
test_spec!(erc20, "ERC20", "ERC20.sol");
test_spec!(computation, "Computation", "Computation.sol");
test_spec!(msize, "MSize", "MSize.sol");
test_spec!(transferred_value, "Value", "Value.sol");
test_spec!(sha1, "SHA1", "SHA1.sol");
test_spec!(block, "Block", "Block.sol");
test_spec!(mcopy, "MCopy", "MCopy.sol");
test_spec!(mcopy_overlap, "MCopyOverlap", "MCopyOverlap.sol");
test_spec!(events, "Events", "Events.sol");
test_spec!(storage, "Storage", "Storage.sol");
test_spec!(mstore8, "MStore8", "MStore8.sol");
test_spec!(address, "Context", "Context.sol");
test_spec!(value, "Value", "Value.sol");
test_spec!(create, "CreateB", "Create.sol");
test_spec!(call, "Caller", "Call.sol");
test_spec!(balance, "Balance", "Balance.sol");
test_spec!(return_data_oob, "ReturnDataOob", "ReturnDataOob.sol");
test_spec!(immutables, "Immutables", "Immutables.sol");
test_spec!(transaction, "Transaction", "Transaction.sol");
test_spec!(block_hash, "BlockHash", "BlockHash.sol");
test_spec!(delegate, "Delegate", "Delegate.sol");
test_spec!(gas_price, "GasPrice", "GasPrice.sol");
test_spec!(gas_left, "GasLeft", "GasLeft.sol");
test_spec!(gas_limit, "GasLimit", "GasLimit.sol");
test_spec!(base_fee, "BaseFee", "BaseFee.sol");
test_spec!(coinbase, "Coinbase", "Coinbase.sol");
test_spec!(create2, "CreateB", "Create2.sol");
test_spec!(transfer, "Transfer", "Transfer.sol");
test_spec!(send, "Send", "Send.sol");
test_spec!(function_pointer, "FunctionPointer", "FunctionPointer.sol");
test_spec!(mload, "MLoad", "MLoad.sol");
test_spec!(delegate_no_contract, "DelegateCaller", "DelegateCaller.sol");
test_spec!(function_type, "FunctionType", "FunctionType.sol");
test_spec!(layout_at, "LayoutAt", "LayoutAt.sol");
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
vec![Instantiate {
@@ -71,6 +45,7 @@ fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
path: Some(path.into()),
contract: contract.to_string(),
solc_optimizer: None,
pipeline: None,
},
data: vec![],
salt: OptionalHex::default(),
@@ -246,271 +221,169 @@ fn signed_remainder() {
data: Contract::division_arithmetics_smod(n, d).calldata,
})
}
}
run_differential(actions);
/*
#[test]
fn events() {
assert_success(&Contract::event(U256::ZERO), true);
assert_success(&Contract::event(U256::from(123)), true);
}
#[test]
fn ext_code_hash() {
let mut actions = instantiate("contracts/ExtCode.sol", "ExtCode");
fn balance() {
let (_, output) = assert_success(&Contract::value_balance_of(Default::default()), false);
// First do contract instantiation to figure out address and code hash
let results = Specs {
actions: actions.clone(),
..Default::default()
let expected = U256::ZERO;
let received = U256::from_be_slice(&output.data);
assert_eq!(expected, received);
let expected = U256::from(54589);
let (mut state, address) = State::new_deployed(Contract::value_balance_of(Default::default()));
state.accounts_mut().get_mut(&address).unwrap().value = expected;
let contract = Contract::value_balance_of(address);
let (_, output) = state
.transaction()
.with_default_account(&contract.pvm_runtime)
.calldata(contract.calldata)
.call();
assert_eq!(ReturnFlags::Success, output.flags);
let received = U256::from_be_slice(&output.data);
assert_eq!(expected, received)
}
#[test]
fn create2() {
let mut state = State::default();
let contract_a = Contract::create_a();
state.upload_code(&contract_a.pvm_runtime);
let contract = Contract::create_b();
let (state, output) = state
.transaction()
.with_default_account(&contract.pvm_runtime)
.calldata(contract.calldata)
.call();
assert_eq!(output.flags, ReturnFlags::Success);
assert_eq!(state.accounts().len(), 2);
for address in state.accounts().keys() {
if *address != Transaction::default_address() {
let derived_address = Transaction::default_address().create2(
B256::from(U256::from(1)),
keccak256(&contract_a.pvm_runtime).0,
);
assert_eq!(*address, derived_address);
}
}
.run();
let (addr, code_hash) = match results.first().cloned() {
Some(CallResult::Instantiate {
result, code_hash, ..
}) => (result.result.unwrap().addr, code_hash),
_ => panic!("instantiate contract failed"),
};
}
// code hash of itself
actions.push(Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::code_hash().calldata,
});
actions.push(VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(code_hash.as_bytes().to_vec()),
gas_consumed: None,
}));
#[test]
fn create2_failure() {
let mut state = State::default();
let contract_a = Contract::create_a();
state.upload_code(&contract_a.pvm_runtime);
// code hash for a given contract address
actions.push(Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_hash(Address::from(addr.to_fixed_bytes())).calldata,
});
actions.push(VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(code_hash.as_bytes().to_vec()),
gas_consumed: None,
}));
let contract = Contract::create_b();
let (state, output) = state
.transaction()
.with_default_account(&contract.pvm_runtime)
.calldata(contract.calldata.clone())
.call();
// EOA returns fixed hash
actions.push(Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_hash(Address::from(CHARLIE.to_fixed_bytes())).calldata,
});
actions.push(VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(
hex!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").to_vec(),
),
gas_consumed: None,
}));
assert_eq!(output.flags, ReturnFlags::Success);
// non-existing account
actions.push(Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_hash(Address::from([8u8; 20])).calldata,
});
actions.push(VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from([0u8; 32].to_vec()),
gas_consumed: None,
}));
// The address already exists, which should cause the contract to revert
Specs {
actions,
..Default::default()
let (_, output) = state
.transaction()
.with_default_account(&contract.pvm_runtime)
.calldata(contract.calldata)
.call();
assert_eq!(output.flags, ReturnFlags::Revert);
}
#[test]
fn create_with_value() {
let mut state = State::default();
state.upload_code(&Contract::create_a().pvm_runtime);
let amount = U256::from(123);
let contract = Contract::create_b();
let (state, output) = state
.transaction()
.with_default_account(&contract.pvm_runtime)
.callvalue(amount)
.call();
assert_eq!(output.flags, ReturnFlags::Success);
assert_eq!(state.accounts().len(), 2);
for (address, account) in state.accounts() {
if *address == Transaction::default_address() {
assert_eq!(account.value, U256::ZERO);
} else {
assert_eq!(account.value, amount);
}
}
.run();
}
#[test]
fn ext_code_size() {
let alice = Address::from(ALICE.0);
let own_address = alice.create(0);
let baseline_address = alice.create2([0u8; 32], keccak256(Contract::baseline().pvm_runtime));
let contract = Contract::ext_code_size(Transaction::default_address());
let (_, output) = assert_success(&contract, false);
let received = U256::from_be_slice(&output.data);
let expected = U256::from(contract.pvm_runtime.len());
assert_eq!(received, expected);
let own_code_size = U256::from(
Contract::ext_code_size(Default::default())
.pvm_runtime
.len(),
);
let baseline_code_size = U256::from(Contract::baseline().pvm_runtime.len());
Specs {
actions: vec![
// Instantiate the test contract
instantiate("contracts/ExtCode.sol", "ExtCode").remove(0),
// Instantiate the baseline contract
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Solidity {
path: Some("contracts/Baseline.sol".into()),
contract: "Baseline".to_string(),
solc_optimizer: None,
},
data: vec![],
salt: OptionalHex::from([0; 32]),
},
// Alice is not a contract and returns a code size of 0
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(alice).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from([0u8; 32].to_vec()),
gas_consumed: None,
}),
// Unknown address returns a code size of 0
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(Address::from([0xff; 20])).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from([0u8; 32].to_vec()),
gas_consumed: None,
}),
// Own address via extcodesize returns own code size
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(own_address).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(own_code_size.to_be_bytes::<32>().to_vec()),
gas_consumed: None,
}),
// Own address via codesize returns own code size
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::code_size().calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(own_code_size.to_be_bytes::<32>().to_vec()),
gas_consumed: None,
}),
// Baseline address returns the baseline code size
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(baseline_address).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(baseline_code_size.to_be_bytes::<32>().to_vec()),
gas_consumed: None,
}),
],
..Default::default()
}
.run();
let contract = Contract::ext_code_size(Default::default());
let (_, output) = assert_success(&contract, false);
let received = U256::from_be_slice(&output.data);
let expected = U256::ZERO;
assert_eq!(received, expected);
}
#[test]
#[should_panic(expected = "ReentranceDenied")]
fn send_denies_reentrancy() {
let value = 1000;
Specs {
actions: vec![
instantiate("contracts/Send.sol", "Send").remove(0),
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::send_self(U256::from(value)).calldata,
},
],
differential: false,
..Default::default()
}
.run();
fn code_size() {
let contract = Contract::code_size();
let (_, output) = assert_success(&contract, false);
let expected = U256::from(contract.pvm_runtime.len());
let received = U256::from_be_slice(&output.data);
assert_eq!(expected, received);
}
#[test]
#[should_panic(expected = "ReentranceDenied")]
fn transfer_denies_reentrancy() {
let value = 1000;
Specs {
actions: vec![
instantiate("contracts/Transfer.sol", "Transfer").remove(0),
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::transfer_self(U256::from(value)).calldata,
},
],
differential: false,
..Default::default()
}
.run();
fn value_transfer() {
// Succeeds in remix (shanghai) but traps the interpreter
let (state, _) = assert_success(&Contract::call_value_transfer(Default::default()), false);
assert_eq!(state.accounts().len(), 2);
assert!(state.accounts().get(&Address::default()).is_some());
}
#[test]
fn create2_salt() {
let salt = U256::from(777);
let predicted = Contract::predicted_constructor(salt).pvm_runtime;
let predictor = Contract::address_predictor_constructor(salt, predicted.clone().into());
Specs {
actions: vec![
Upload {
origin: TestAddress::Alice,
code: Code::Bytes(predicted),
storage_deposit_limit: None,
},
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Bytes(predictor.pvm_runtime),
data: predictor.calldata,
salt: OptionalHex::default(),
},
],
differential: false,
..Default::default()
}
.run();
fn echo() {
let (state, address) = State::new_deployed(Contract::call_constructor());
let expected = vec![1, 2, 3, 4, 5];
let contract = Contract::call_call(address, expected.clone());
let (_, output) = state
.transaction()
.with_default_account(&contract.pvm_runtime)
.calldata(contract.calldata)
.call();
assert_eq!(output.flags, ReturnFlags::Success);
let received = alloy_primitives::Bytes::abi_decode(&output.data, true)
.unwrap()
.to_vec();
assert_eq!(expected, received);
}
*/
+5
View File
@@ -7,9 +7,14 @@ repository.workspace = true
authors.workspace = true
description = "revive compiler linker utils"
[features]
riscv-64 = []
[dependencies]
inkwell = { workspace = true }
tempfile = { workspace = true }
polkavm-linker = { workspace = true }
polkavm-common = { workspace = true }
libc = { workspace = true }
anyhow = { workspace = true }
+16 -5
View File
@@ -8,7 +8,14 @@ SECTIONS {
.text : { KEEP(*(.text.polkavm_export)) *(.text .text.*) }
}"#;
#[cfg(not(feature = "riscv-64"))]
const BUILTINS_ARCHIVE_FILE: &str = "libclang_rt.builtins-riscv32.a";
#[cfg(feature = "riscv-64")]
const BUILTINS_ARCHIVE_FILE: &str = "libclang_rt.builtins-riscv64.a";
#[cfg(not(feature = "riscv-64"))]
const BUILTINS_LIB_NAME: &str = "clang_rt.builtins-riscv32";
#[cfg(feature = "riscv-64")]
const BUILTINS_LIB_NAME: &str = "clang_rt.builtins-riscv64";
fn invoke_lld(cmd_args: &[&str]) -> bool {
@@ -22,10 +29,9 @@ fn invoke_lld(cmd_args: &[&str]) -> bool {
unsafe { LLDELFLink(args.as_ptr(), args.len()) == 0 }
}
pub fn polkavm_linker<T: AsRef<[u8]>>(code: T, strip_binary: bool) -> anyhow::Result<Vec<u8>> {
fn polkavm_linker<T: AsRef<[u8]>>(code: T) -> anyhow::Result<Vec<u8>> {
let mut config = polkavm_linker::Config::default();
config.set_strip(strip_binary);
config.set_optimize(true);
config.set_strip(true);
polkavm_linker::program_from_elf(config, code.as_ref())
.map_err(|reason| anyhow::anyhow!("polkavm linker failed: {}", reason))
@@ -52,11 +58,11 @@ pub fn link<T: AsRef<[u8]>>(input: T) -> anyhow::Result<Vec<u8>> {
let ld_args = [
"ld.lld",
"--lto=full",
"--error-limit=0",
"--relocatable",
"--emit-relocs",
"--no-relax",
"--unique",
"--gc-sections",
"--library-path",
dir.path().to_str().expect("should be utf8"),
@@ -72,5 +78,10 @@ pub fn link<T: AsRef<[u8]>>(input: T) -> anyhow::Result<Vec<u8>> {
return Err(anyhow::anyhow!("ld.lld failed"));
}
Ok(fs::read(&output_path)?)
if env::var("PVM_LINKER_DUMP_SO").is_ok() {
fs::copy(&output_path, "/tmp/out.so")?;
};
let blob = fs::read(&output_path)?;
polkavm_linker(blob)
}
-1
View File
@@ -13,4 +13,3 @@ libc = { workspace = true }
[build-dependencies]
cc = { workspace = true }
revive-build-utils = { workspace = true }
+17 -76
View File
@@ -1,16 +1,17 @@
fn set_rustc_link_flags() {
let llvm_lib_path = match std::env::var(revive_build_utils::REVIVE_LLVM_TARGET_PREFIX) {
Ok(path) => std::path::PathBuf::from(path).join("lib"),
_ => revive_build_utils::llvm_lib_dir(),
};
fn llvm_config(arg: &str) -> String {
let output = std::process::Command::new("llvm-config")
.args([arg])
.output()
.unwrap_or_else(|_| panic!("`llvm-config {arg}` failed"));
println!(
"cargo:rustc-link-search=native={}",
llvm_lib_path.to_string_lossy()
);
String::from_utf8(output.stdout)
.unwrap_or_else(|_| panic!("output of `llvm-config {arg}` should be utf8"))
}
fn set_rustc_link_flags() {
println!("cargo:rustc-link-search=native={}", llvm_config("--libdir"));
for lib in [
// These are required by ld.lld
"lldELF",
"lldCommon",
"lldMachO",
@@ -21,82 +22,22 @@ fn set_rustc_link_flags() {
"LLVMTargetParser",
"LLVMBinaryFormat",
"LLVMDemangle",
// The `llvm-sys` crate relies on `llvm-config` to obtain a list of required LLVM libraries
// during the build process. This works well in typical native environments, where `llvm-config`
// can accurately list the necessary libraries.
// However, when cross-compiling to WebAssembly using Emscripten, `llvm-config` fails to recognize
// JavaScript-based libraries, making it necessary to manually inject the required dependencies.
"LLVMRISCVDisassembler",
"LLVMRISCVAsmParser",
"LLVMRISCVCodeGen",
"LLVMRISCVDesc",
"LLVMRISCVInfo",
"LLVMExecutionEngine",
"LLVMOption",
"LLVMMCDisassembler",
"LLVMPasses",
"LLVMHipStdPar",
"LLVMCFGuard",
"LLVMCoroutines",
"LLVMipo",
"LLVMVectorize",
"LLVMInstrumentation",
"LLVMFrontendOpenMP",
"LLVMFrontendOffloading",
"LLVMGlobalISel",
"LLVMAsmPrinter",
"LLVMSelectionDAG",
"LLVMCodeGen",
"LLVMTarget",
"LLVMObjCARCOpts",
"LLVMCodeGenTypes",
"LLVMIRPrinter",
"LLVMScalarOpts",
"LLVMInstCombine",
"LLVMAggressiveInstCombine",
"LLVMTransformUtils",
"LLVMBitWriter",
"LLVMAnalysis",
"LLVMProfileData",
"LLVMDebugInfoDWARF",
"LLVMObject",
"LLVMMCParser",
"LLVMIRReader",
"LLVMAsmParser",
"LLVMMC",
"LLVMDebugInfoCodeView",
"LLVMBitReader",
"LLVMRemarks",
"LLVMBitstreamReader",
] {
println!("cargo:rustc-link-lib=static={lib}");
}
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
let target_env = std::env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
if target_os == "linux" {
if target_env == "musl" {
println!("cargo:rustc-link-lib=static=c++");
} else {
println!("cargo:rustc-link-lib=dylib=stdc++");
}
#[cfg(target_os = "linux")]
{
println!("cargo:rustc-link-lib=dylib=stdc++");
println!("cargo:rustc-link-lib=tinfo");
}
}
fn main() {
println!(
"cargo:rerun-if-env-changed={}",
revive_build_utils::REVIVE_LLVM_HOST_PREFIX
);
println!(
"cargo:rerun-if-env-changed={}",
revive_build_utils::REVIVE_LLVM_TARGET_PREFIX
);
revive_build_utils::llvm_cxx_flags()
llvm_config("--cxxflags")
.split_whitespace()
.fold(&mut cc::Build::new(), |builder, flag| builder.flag(flag))
.warnings(false)
.flag("-Wno-unused-parameter")
.cpp(true)
.file("src/linker.cpp")
.compile("liblinker.a");
-39
View File
@@ -1,39 +0,0 @@
[package]
name = "revive-llvm-builder"
description = "revive LLVM compiler framework builder"
authors = [
"Oleksandr Zarudnyi <a.zarudnyy@matterlabs.dev>",
"Anton Baliasnikov <aba@matterlabs.dev>",
"Cyrill Leutwiler <cyrill@parity.io>",
]
version.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
[[bin]]
name = "revive-llvm"
path = "src/revive_llvm/main.rs"
[lib]
doctest = false
[dependencies]
clap = { workspace = true, features = ["help", "std", "derive"] }
anyhow = { workspace = true }
serde = { workspace = true, features = [ "derive" ] }
toml = { workspace = true }
num_cpus = { workspace = true }
fs_extra = { workspace = true }
path-slash = { workspace = true }
regex = { workspace = true }
downloader = { workspace = true }
tar = { workspace = true }
flate2 = { workspace = true }
env_logger = { workspace = true }
log = { workspace = true }
which = { workspace = true }
[dev-dependencies]
assert_cmd = { workspace = true }
assert_fs = { workspace = true }
-132
View File
@@ -1,132 +0,0 @@
# revive LLVM builder
Parity fork of the [Matter Labs zksync LLVM builder](https://github.com/matter-labs/era-compiler-llvm-builder) helper utility for compiling [revive](https://github.com/paritytech/revive) compatible LLVM builds.
## Installation and usage
The LLVM compiler framework for revive must be built with our tool called `revive-llvm`.
This is because the revive compiler has requirements not fullfilled in upstream builds:
- Special builds for compiling the frontend into statically linked ELF binaries and also Wasm executables
- The RISC-V target (the PolkaVM target)
- The compiler-rt builtins for the PolkaVM target
- We want to leave the assertions always on
- Various other specific configurations and optimization may be applied
Obtain a compatible build for your host platform from the release section of this repository (TODO). Alternatively follow below steps to get a custom build:
<details>
<summary>1. Install the system prerequisites.</summary>
* Linux (Debian):
Install the following packages:
```shell
apt install cmake ninja-build curl git libssl-dev pkg-config clang lld
```
* Linux (Arch):
Install the following packages:
```shell
pacman -Syu which cmake ninja curl git pkg-config clang lld
```
* MacOS:
* Install the [HomeBrew](https://brew.sh) package manager.
* Install the following packages:
```shell
brew install cmake ninja coreutils
```
* Install your choice of a recent LLVM/[Clang](https://clang.llvm.org) compiler, e.g. via [Xcode](https://developer.apple.com/xcode/), [Apples Command Line Tools](https://developer.apple.com/library/archive/technotes/tn2339/_index.html), or your preferred package manager.
</details>
<details>
<summary>2. Install Rust.</summary>
* Follow the latest [official instructions](https://www.rust-lang.org/tools/install:
```shell
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
. ${HOME}/.cargo/env
```
> Currently we are not pinned to any specific version of Rust, so just install the latest stable build for your platform.
</details>
<details>
<summary>3. Install the revive LLVM framework builder.</summary>
* Install the builder using `cargo`:
```shell
cargo install --git https://github.com/paritytech/revive-llvm-builder --force --locked
```
> The builder is not the LLVM framework itself, but a tool that clones its repository and runs a sequence of build commands. By default it is installed in `~/.cargo/bin/`, which is recommended to be added to your `$PATH`.
</details>
<details>
<summary>4. (Optional) Create the `LLVM.lock` file.</summary>
* The `LLVM.lock` dictates the LLVM source tree being used.
A default `./LLVM.lock` pointing to the release used for development is already provided.
</details>
<details>
<summary>5. Build LLVM.</summary>
* Clone and build the LLVM framework using the `revive-llvm` tool.
The clang and lld projects are required for the `resolc` Solidity frontend executable; they are enabled by default. LLVM assertions are also enabled by default.
```shell
revive-llvm clone
revive-llvm build --llvm-projects lld --llvm-projects clang
```
Build artifacts end up in the `./target-llvm/gnu/target-final/` directory by default.
The `gnu` directory depends on the supported archticture and will either be `gnu`, `musl` or `emscripten`.
You now need to export the final target directory `$LLVM_SYS_181_PREFIX`: `export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final`
If built with the `--enable-tests` option, test tools will be in the `./target-llvm/gnu/build-final/` directory, along with copies of the build artifacts. For all supported build options, run `revive-llvm build --help`.
</details>
## Supported target architectures
The following target platforms are supported:
- Linux GNU (x86)
- Linux MUSL (x86)
- MacOS (aarch64)
- Windows GNU (x86)
- Emscripten (wasm32)
<details>
<summary>Building for MUSL</summary>
* Via a musl build we can build revive into fully static ELF binaries.
Which is desirable for reproducible Solidity contracts builds.
The resulting binary is also very portable, akin to the`solc` frontend binary distribution.
Clone and build the LLVM framework using the `revive-llvm` tool:
```shell
revive-llvm --target-env musl clone
revive-llvm --target-env musl build --enable-assertions --llvm-projects clang --llvm-projects lld
```
</details>
<details>
<summary>Building for Emscripten</summary>
* Via an emsdk build we can run revive in the browser and on node.js.
Clone and build the LLVM framework using the `revive-llvm` tool:
```shell
revive-llvm --target-env emscripten clone
revive-llvm --target-env emscripten build --enable-assertions --llvm-projects clang --llvm-projects lld
```
</details>
-39
View File
@@ -1,39 +0,0 @@
//! The revive LLVM build type.
/// The revive LLVM build type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuildType {
/// The debug build.
Debug,
/// The release build.
Release,
/// The release with debug info build.
RelWithDebInfo,
/// The minimal size release build.
MinSizeRel,
}
impl std::str::FromStr for BuildType {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"Debug" => Ok(Self::Debug),
"Release" => Ok(Self::Release),
"RelWithDebInfo" => Ok(Self::RelWithDebInfo),
"MinSizeRel" => Ok(Self::MinSizeRel),
value => Err(format!("Unsupported build type: `{}`", value)),
}
}
}
impl std::fmt::Display for BuildType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Debug => write!(f, "Debug"),
Self::Release => write!(f, "Release"),
Self::RelWithDebInfo => write!(f, "RelWithDebInfo"),
Self::MinSizeRel => write!(f, "MinSizeRel"),
}
}
}
-163
View File
@@ -1,163 +0,0 @@
//! Utilities for compiling the LLVM compiler-rt builtins.
use crate::utils::path_windows_to_unix as to_unix;
use std::{env::consts::EXE_EXTENSION, process::Command};
/// Static CFLAGS variable passed to the compiler building the compiler-rt builtins.
const C_FLAGS: [&str; 6] = [
"--target=riscv64",
"-march=rv64emac",
"-mabi=lp64e",
"-mcpu=generic-rv64",
"-nostdlib",
"-nodefaultlibs",
];
/// Static CMAKE arguments for building the compiler-rt builtins.
const CMAKE_STATIC_ARGS: [&str; 14] = [
"-DCOMPILER_RT_BUILD_BUILTINS='On'",
"-DCOMPILER_RT_BUILD_LIBFUZZER='Off'",
"-DCOMPILER_RT_BUILD_MEMPROF='Off'",
"-DCOMPILER_RT_BUILD_PROFILE='Off'",
"-DCOMPILER_RT_BUILD_SANITIZERS='Off'",
"-DCOMPILER_RT_BUILD_XRAY='Off'",
"-DCOMPILER_RT_DEFAULT_TARGET_ONLY='On'",
"-DCOMPILER_RT_BAREMETAL_BUILD='On'",
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=1",
"-DCMAKE_EXPORT_COMPILE_COMMANDS='On'",
"-DCMAKE_SYSTEM_NAME='unknown'",
"-DCMAKE_C_COMPILER_TARGET='riscv64'",
"-DCMAKE_ASM_COMPILER_TARGET='riscv64'",
"-DCMAKE_CXX_COMPILER_TARGET='riscv64'",
];
/// Dynamic cmake arguments for building the compiler-rt builtins.
fn cmake_dynamic_args(
build_type: crate::BuildType,
target_env: crate::target_env::TargetEnv,
) -> anyhow::Result<[String; 13]> {
let llvm_compiler_rt_target = crate::LLVMPath::llvm_target_compiler_rt()?;
// The Emscripten target needs to use the host LLVM tools.
let llvm_target_host = if target_env == crate::target_env::TargetEnv::Emscripten {
crate::LLVMPath::llvm_build_host()?
} else {
crate::LLVMPath::llvm_target_final()?
};
let mut clang_path = llvm_target_host.to_path_buf();
clang_path.push("bin/clang");
clang_path.set_extension(EXE_EXTENSION);
let mut clangxx_path = llvm_target_host.to_path_buf();
clangxx_path.push("bin/clang++");
clangxx_path.set_extension(EXE_EXTENSION);
let mut llvm_config_path = llvm_target_host.to_path_buf();
llvm_config_path.push("bin/llvm-config");
llvm_config_path.set_extension(EXE_EXTENSION);
let mut ar_path = llvm_target_host.to_path_buf();
ar_path.push("bin/llvm-ar");
ar_path.set_extension(EXE_EXTENSION);
let mut nm_path = llvm_target_host.to_path_buf();
nm_path.push("bin/llvm-nm");
nm_path.set_extension(EXE_EXTENSION);
let mut ranlib_path = llvm_target_host.to_path_buf();
ranlib_path.push("bin/llvm-ranlib");
ranlib_path.set_extension(EXE_EXTENSION);
let mut linker_path = llvm_target_host.to_path_buf();
linker_path.push("bin/ld.lld");
linker_path.set_extension(EXE_EXTENSION);
Ok([
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
llvm_compiler_rt_target.to_string_lossy().as_ref(),
),
format!("-DCMAKE_BUILD_TYPE='{build_type}'"),
format!(
"-DCOMPILER_RT_TEST_COMPILER='{}'",
clang_path.to_string_lossy()
),
format!("-DCMAKE_C_FLAGS='{}'", C_FLAGS.join(" ")),
format!("-DCMAKE_ASM_FLAGS='{}'", C_FLAGS.join(" ")),
format!("-DCMAKE_CXX_FLAGS='{}'", C_FLAGS.join(" ")),
format!(
"-DCMAKE_C_COMPILER='{}'",
to_unix(clang_path.clone())?.display()
),
format!("-DCMAKE_ASM_COMPILER='{}'", to_unix(clang_path)?.display()),
format!(
"-DCMAKE_CXX_COMPILER='{}'",
to_unix(clangxx_path)?.display()
),
format!("-DCMAKE_AR='{}'", to_unix(ar_path)?.display()),
format!("-DCMAKE_NM='{}'", to_unix(nm_path)?.display()),
format!("-DCMAKE_RANLIB='{}'", to_unix(ranlib_path)?.display()),
format!(
"-DLLVM_CONFIG_PATH='{}'",
llvm_config_path.to_string_lossy()
),
])
}
/// Build the compiler-rt builtins library.
pub fn build(
build_type: crate::BuildType,
target_env: crate::target_env::TargetEnv,
default_target: Option<crate::TargetTriple>,
extra_args: &[String],
ccache_variant: Option<crate::ccache_variant::CcacheVariant>,
sanitizer: Option<crate::sanitizer::Sanitizer>,
) -> anyhow::Result<()> {
log::info!("building compiler-rt for rv64emac");
crate::utils::check_presence("cmake")?;
crate::utils::check_presence("ninja")?;
let llvm_module_compiler_rt = crate::LLVMPath::llvm_module_compiler_rt()?;
let llvm_compiler_rt_build = crate::LLVMPath::llvm_build_compiler_rt()?;
crate::utils::command(
std::process::Command::new("cmake")
.args([
"-S",
llvm_module_compiler_rt.to_string_lossy().as_ref(),
"-B",
llvm_compiler_rt_build.to_string_lossy().as_ref(),
"-G",
"Ninja",
])
.args(CMAKE_STATIC_ARGS)
.args(cmake_dynamic_args(build_type, target_env)?)
.args(extra_args)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
))
.args(crate::platforms::shared::shared_build_opts_default_target(
default_target,
))
.args(crate::platforms::shared::shared_build_opts_sanitizers(
sanitizer,
)),
"LLVM compiler-rt building cmake",
)?;
crate::utils::command(
Command::new("cmake").args([
"--build",
llvm_compiler_rt_build.to_string_lossy().as_ref(),
"--target",
"install",
"--config",
build_type.to_string().as_str(),
]),
"Building",
)?;
Ok(())
}
-31
View File
@@ -1,31 +0,0 @@
//! Compiler cache variants.
/// The list compiler cache variants to be used as constants.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CcacheVariant {
/// Standard ccache.
Ccache,
/// Mozilla's sccache.
Sccache,
}
impl std::str::FromStr for CcacheVariant {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"ccache" => Ok(Self::Ccache),
"sccache" => Ok(Self::Sccache),
value => Err(format!("Unsupported ccache variant: `{}`", value)),
}
}
}
impl std::fmt::Display for CcacheVariant {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Ccache => write!(f, "ccache"),
Self::Sccache => write!(f, "sccache"),
}
}
}
-340
View File
@@ -1,340 +0,0 @@
//! The revive LLVM builder library.
pub mod build_type;
pub mod builtins;
pub mod ccache_variant;
pub mod llvm_path;
pub mod llvm_project;
pub mod lock;
pub mod platforms;
pub mod sanitizer;
pub mod target_env;
pub mod target_triple;
pub mod utils;
pub use self::build_type::BuildType;
pub use self::llvm_path::LLVMPath;
pub use self::lock::Lock;
pub use self::platforms::Platform;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
use std::process::Command;
pub use target_env::TargetEnv;
pub use target_triple::TargetTriple;
/// Executes the LLVM repository cloning.
pub fn clone(lock: Lock, deep: bool, target_env: TargetEnv) -> anyhow::Result<()> {
utils::check_presence("git")?;
if target_env == TargetEnv::Emscripten {
utils::install_emsdk()?;
}
let destination_path = PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE);
if destination_path.exists() {
log::warn!(
"LLVM repository directory {} already exists, falling back to checkout",
destination_path.display()
);
return checkout(lock, false);
}
let mut clone_args = vec!["clone", "--branch", lock.branch.as_str()];
if !deep {
clone_args.push("--depth");
clone_args.push("1");
}
utils::command(
Command::new("git")
.args(clone_args)
.arg(lock.url.as_str())
.arg(destination_path.to_string_lossy().as_ref()),
"LLVM repository cloning",
)?;
if let Some(r#ref) = lock.r#ref {
utils::command(
Command::new("git")
.args(["checkout", r#ref.as_str()])
.current_dir(destination_path.to_string_lossy().as_ref()),
"LLVM repository commit checking out",
)?;
}
Ok(())
}
/// Executes the checkout of the specified branch.
pub fn checkout(lock: Lock, force: bool) -> anyhow::Result<()> {
let destination_path = PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE);
utils::command(
Command::new("git")
.current_dir(destination_path.as_path())
.args(["fetch", "--all", "--tags"]),
"LLVM repository data fetching",
)?;
if force {
utils::command(
Command::new("git")
.current_dir(destination_path.as_path())
.args(["clean", "-d", "-x", "--force"]),
"LLVM repository cleaning",
)?;
}
utils::command(
Command::new("git")
.current_dir(destination_path.as_path())
.args(["checkout", "--force", lock.branch.as_str()]),
"LLVM repository data pulling",
)?;
if let Some(r#ref) = lock.r#ref {
let mut checkout_command = Command::new("git");
checkout_command.current_dir(destination_path.as_path());
checkout_command.arg("checkout");
if force {
checkout_command.arg("--force");
}
checkout_command.arg(r#ref);
utils::command(&mut checkout_command, "LLVM repository checking out")?;
}
Ok(())
}
/// Executes the building of the LLVM framework for the platform determined by the cfg macro.
/// Since cfg is evaluated at compile time, overriding the platform with a command-line
/// argument is not possible. So for cross-platform testing, comment out all but the
/// line to be tested, and perhaps also checks in the platform-specific build method.
#[allow(clippy::too_many_arguments)]
pub fn build(
build_type: BuildType,
target_env: TargetEnv,
targets: HashSet<Platform>,
llvm_projects: HashSet<llvm_project::LLVMProject>,
enable_rtti: bool,
default_target: Option<TargetTriple>,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<ccache_variant::CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<sanitizer::Sanitizer>,
enable_valgrind: bool,
) -> anyhow::Result<()> {
log::trace!("build type: {:?}", build_type);
log::trace!("target env: {:?}", target_env);
log::trace!("targets: {:?}", targets);
log::trace!("llvm projects: {:?}", llvm_projects);
log::trace!("enable rtti: {:?}", enable_rtti);
log::trace!("default target: {:?}", default_target);
log::trace!("eneable tests: {:?}", enable_tests);
log::trace!("enable_coverage: {:?}", enable_coverage);
log::trace!("extra args: {:?}", extra_args);
log::trace!("sanitzer: {:?}", sanitizer);
log::trace!("enable valgrind: {:?}", enable_valgrind);
if !PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE).exists() {
log::error!(
"LLVM project source directory {} does not exist (run `revive-llvm --target-env {} clone`)",
LLVMPath::DIRECTORY_LLVM_SOURCE,
target_env
)
}
std::fs::create_dir_all(llvm_path::DIRECTORY_LLVM_TARGET.get().unwrap())?;
if cfg!(target_arch = "x86_64") {
if cfg!(target_os = "linux") {
if target_env == TargetEnv::MUSL {
platforms::x86_64_linux_musl::build(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
enable_valgrind,
)?;
} else if target_env == TargetEnv::GNU {
platforms::x86_64_linux_gnu::build(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
enable_valgrind,
)?;
} else if target_env == TargetEnv::Emscripten {
platforms::wasm32_emscripten::build(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
enable_valgrind,
)?;
} else {
anyhow::bail!("Unsupported target environment for x86_64 and Linux");
}
} else if cfg!(target_os = "macos") {
platforms::x86_64_macos::build(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
)?;
} else if cfg!(target_os = "windows") {
platforms::x86_64_windows_msvc::build(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
)?;
} else {
anyhow::bail!("Unsupported target OS for x86_64");
}
} else if cfg!(target_arch = "aarch64") {
if cfg!(target_os = "linux") {
if target_env == TargetEnv::MUSL {
platforms::aarch64_linux_musl::build(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
enable_valgrind,
)?;
} else if target_env == TargetEnv::GNU {
platforms::aarch64_linux_gnu::build(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
enable_valgrind,
)?;
} else {
anyhow::bail!("Unsupported target environment for aarch64 and Linux");
}
} else if cfg!(target_os = "macos") {
if target_env == TargetEnv::Emscripten {
platforms::wasm32_emscripten::build(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
enable_valgrind,
)?;
} else {
platforms::aarch64_macos::build(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
)?;
}
} else {
anyhow::bail!("Unsupported target OS for aarch64");
}
} else {
anyhow::bail!("Unsupported target architecture");
}
crate::builtins::build(
build_type,
target_env,
default_target,
extra_args,
ccache_variant,
sanitizer,
)?;
Ok(())
}
/// Executes the build artifacts cleaning.
pub fn clean() -> anyhow::Result<()> {
let remove_if_exists = |path: &Path| {
if !path.exists() {
return Ok(());
}
log::info!("deleting {}", path.display());
std::fs::remove_dir_all(path)
};
remove_if_exists(
llvm_path::DIRECTORY_LLVM_TARGET
.get()
.expect("target_env is always set because of the default value")
.parent()
.expect("target_env parent directory is target-llvm"),
)?;
remove_if_exists(&PathBuf::from(LLVMPath::DIRECTORY_EMSDK_SOURCE))?;
remove_if_exists(&PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE))?;
remove_if_exists(&PathBuf::from(LLVMPath::DIRECTORY_LLVM_HOST_SOURCE))?;
Ok(())
}
-151
View File
@@ -1,151 +0,0 @@
//! The revive LLVM builder constants.
use std::path::PathBuf;
use std::sync::OnceLock;
pub static DIRECTORY_LLVM_TARGET: OnceLock<PathBuf> = OnceLock::new();
/// The LLVM path resolver.
pub struct LLVMPath {}
impl LLVMPath {
/// The LLVM source directory.
pub const DIRECTORY_LLVM_SOURCE: &'static str = "./llvm/";
/// The LLVM host source directory for stage 1 of multistage MUSL and Emscripten builds.
///
/// We use upstream LLVM anyways; re-use the same tree for host and target builds.
pub const DIRECTORY_LLVM_HOST_SOURCE: &'static str = Self::DIRECTORY_LLVM_SOURCE;
/// The Emscripten SDK source directory.
pub const DIRECTORY_EMSDK_SOURCE: &'static str = "./emsdk/";
/// Returns the path to the `llvm` stage 1 host LLVM source module directory.
pub fn llvm_host_module_llvm() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(Self::DIRECTORY_LLVM_HOST_SOURCE);
path.push("llvm");
crate::utils::absolute_path(path).inspect(|absolute_path| {
log::debug!(
"llvm stage 1 host llvm source module: {}",
absolute_path.display()
)
})
}
/// Returns the path to the `llvm` LLVM source module directory.
pub fn llvm_module_llvm() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(Self::DIRECTORY_LLVM_SOURCE);
path.push("llvm");
crate::utils::absolute_path(path)
.inspect(|absolute_path| log::debug!("llvm source module: {}", absolute_path.display()))
}
/// Returns the path to the MUSL source.
pub fn musl_source(name: &str) -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(DIRECTORY_LLVM_TARGET.get().unwrap());
path.push(name);
crate::utils::absolute_path(path)
.inspect(|absolute_path| log::debug!("musl source: {}", absolute_path.display()))
}
/// Returns the path to the MUSL build directory.
pub fn musl_build(source_directory: &str) -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(DIRECTORY_LLVM_TARGET.get().unwrap());
path.push(source_directory);
path.push("build");
crate::utils::absolute_path(path)
.inspect(|absolute_path| log::debug!("musl build: '{}'", absolute_path.display()))
}
/// Returns the path to the LLVM CRT build directory.
pub fn llvm_build_crt() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(DIRECTORY_LLVM_TARGET.get().unwrap());
path.push("build-crt");
crate::utils::absolute_path(path)
.inspect(|absolute_path| log::debug!("llvm build crt: {}", absolute_path.display()))
}
/// Returns the path to the LLVM host build directory.
pub fn llvm_build_host() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(DIRECTORY_LLVM_TARGET.get().unwrap());
path.push("build-host");
crate::utils::absolute_path(path)
.inspect(|absolute_path| log::debug!("llvm build host: {}", absolute_path.display()))
}
/// Returns the path to the LLVM final build directory.
pub fn llvm_build_final() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(DIRECTORY_LLVM_TARGET.get().unwrap());
path.push("build-final");
crate::utils::absolute_path(path)
.inspect(|absolute_path| log::debug!("llvm build final: {}", absolute_path.display()))
}
/// Returns the path to the MUSL target directory.
pub fn musl_target() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(DIRECTORY_LLVM_TARGET.get().unwrap());
path.push("target-musl");
crate::utils::absolute_path(path)
.inspect(|absolute_path| log::debug!("musl target: {}", absolute_path.display()))
}
/// Returns the path to the LLVM CRT target directory.
pub fn llvm_target_crt() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(DIRECTORY_LLVM_TARGET.get().unwrap());
path.push("target-crt");
crate::utils::absolute_path(path)
.inspect(|absolute_path| log::debug!("llvm crt target: {}", absolute_path.display()))
}
/// Returns the path to the LLVM host target directory.
pub fn llvm_target_host() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(DIRECTORY_LLVM_TARGET.get().unwrap());
path.push("target-host");
crate::utils::absolute_path(path)
.inspect(|absolute_path| log::debug!("llvm host target: {}", absolute_path.display()))
}
/// Returns the path to the LLVM final target directory.
pub fn llvm_target_final() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(DIRECTORY_LLVM_TARGET.get().unwrap());
path.push("target-final");
crate::utils::absolute_path(path)
.inspect(|absolute_path| log::debug!("llvm final target: {}", absolute_path.display()))
}
/// Returns the path to the LLVM compiler builtin target directory.
pub fn llvm_module_compiler_rt() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(Self::DIRECTORY_LLVM_SOURCE);
path.push("compiler-rt");
crate::utils::absolute_path(path).inspect(|absolute_path| {
log::debug!("compiler-rt source dir: {}", absolute_path.display())
})
}
/// Returns the path to the LLVM compiler-rt target directory.
pub fn llvm_target_compiler_rt() -> anyhow::Result<PathBuf> {
Self::llvm_target_final()
}
/// Returns the path to the LLVM compiler-rt build directory.
pub fn llvm_build_compiler_rt() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(DIRECTORY_LLVM_TARGET.get().unwrap());
path.push("build-compiler-rt");
crate::utils::absolute_path(path).inspect(|absolute_path| {
log::debug!("llvm compiler-rt build: {}", absolute_path.display())
})
}
/// Returns the path to the LLVM target final bin path.
///
pub fn llvm_target_final_bin(
target_env: crate::target_env::TargetEnv,
) -> anyhow::Result<PathBuf> {
let mut path = Self::llvm_target_final()?;
path.push("bin");
path.push(format!("{target_env}"));
crate::utils::absolute_path(path).inspect(|absolute_path| {
log::debug!("llvm target final bin: {}", absolute_path.display())
})
}
}
-39
View File
@@ -1,39 +0,0 @@
//! The LLVM projects to enable during the build.
/// The list of LLVM projects used as constants.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LLVMProject {
/// The Clang compiler.
CLANG,
/// LLD, the LLVM linker.
LLD,
/// The LLVM debugger.
LLDB,
/// The MLIR compiler.
MLIR,
}
impl std::str::FromStr for LLVMProject {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value.to_lowercase().as_str() {
"clang" => Ok(Self::CLANG),
"lld" => Ok(Self::LLD),
"lldb" => Ok(Self::LLDB),
"mlir" => Ok(Self::MLIR),
value => Err(format!("Unsupported LLVM project to enable: `{}`", value)),
}
}
}
impl std::fmt::Display for LLVMProject {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::CLANG => write!(f, "clang"),
Self::LLD => write!(f, "lld"),
Self::LLDB => write!(f, "lldb"),
Self::MLIR => write!(f, "mlir"),
}
}
}
-37
View File
@@ -1,37 +0,0 @@
//! The revive LLVM builder lock file.
use anyhow::Context;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use serde::Deserialize;
use serde::Serialize;
/// The default lock file location.
pub const LLVM_LOCK_DEFAULT_PATH: &str = "LLVM.lock";
/// The lock file data.
///
/// This file describes the exact reference of the LLVM framework.
#[derive(Debug, Deserialize, Serialize)]
pub struct Lock {
/// The LLVM repository URL.
pub url: String,
/// The LLVM repository branch.
pub branch: String,
/// The LLVM repository commit reference.
pub r#ref: Option<String>,
}
impl TryFrom<&PathBuf> for Lock {
type Error = anyhow::Error;
fn try_from(path: &PathBuf) -> Result<Self, Self::Error> {
let mut config_str = String::new();
let mut config_file =
File::open(path).with_context(|| format!("Error opening {:?} file", path))?;
config_file.read_to_string(&mut config_str)?;
Ok(toml::from_str(&config_str)?)
}
}
@@ -1,111 +0,0 @@
//! The revive LLVM arm64 `linux-gnu` builder.
use std::collections::HashSet;
use std::process::Command;
use crate::build_type::BuildType;
use crate::ccache_variant::CcacheVariant;
use crate::llvm_path::LLVMPath;
use crate::llvm_project::LLVMProject;
use crate::platforms::Platform;
use crate::sanitizer::Sanitizer;
use crate::target_triple::TargetTriple;
/// The building sequence.
#[allow(clippy::too_many_arguments)]
pub fn build(
build_type: BuildType,
targets: HashSet<Platform>,
llvm_projects: HashSet<LLVMProject>,
enable_rtti: bool,
default_target: Option<TargetTriple>,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<Sanitizer>,
enable_valgrind: bool,
) -> anyhow::Result<()> {
crate::utils::check_presence("cmake")?;
crate::utils::check_presence("clang")?;
crate::utils::check_presence("clang++")?;
crate::utils::check_presence("lld")?;
crate::utils::check_presence("ninja")?;
let llvm_module_llvm = LLVMPath::llvm_module_llvm()?;
let llvm_build_final = LLVMPath::llvm_build_final()?;
let llvm_target_final = LLVMPath::llvm_target_final()?;
crate::utils::command(
Command::new("cmake")
.args([
"-S",
llvm_module_llvm.to_string_lossy().as_ref(),
"-B",
llvm_build_final.to_string_lossy().as_ref(),
"-G",
"Ninja",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
llvm_target_final.to_string_lossy().as_ref(),
)
.as_str(),
format!("-DCMAKE_BUILD_TYPE='{build_type}'").as_str(),
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
format!(
"-DLLVM_TARGETS_TO_BUILD='{}'",
targets
.into_iter()
.map(|platform| platform.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
format!(
"-DLLVM_ENABLE_PROJECTS='{}'",
llvm_projects
.into_iter()
.map(|project| project.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
"-DLLVM_USE_LINKER='lld'",
])
.args(crate::platforms::shared::shared_build_opts_default_target(
default_target,
))
.args(crate::platforms::shared::shared_build_opts_tests(
enable_tests,
))
.args(crate::platforms::shared::shared_build_opts_coverage(
enable_coverage,
))
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::SHARED_BUILD_OPTS_NOT_MUSL)
.args(crate::platforms::shared::shared_build_opts_werror(
crate::target_env::TargetEnv::GNU,
))
.args(extra_args)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
))
.args(crate::platforms::shared::shared_build_opts_assertions(
enable_assertions,
))
.args(crate::platforms::shared::shared_build_opts_rtti(
enable_rtti,
))
.args(crate::platforms::shared::shared_build_opts_sanitizers(
sanitizer,
))
.args(crate::platforms::shared::shared_build_opts_valgrind(
enable_valgrind,
)),
"LLVM building cmake",
)?;
crate::utils::ninja(llvm_build_final.as_ref())?;
Ok(())
}
@@ -1,394 +0,0 @@
//! The revive LLVM arm64 `linux-musl` builder.
use crate::build_type::BuildType;
use crate::ccache_variant::CcacheVariant;
use crate::llvm_path::LLVMPath;
use crate::llvm_project::LLVMProject;
use crate::platforms::Platform;
use crate::sanitizer::Sanitizer;
use crate::target_triple::TargetTriple;
use std::collections::HashSet;
use std::path::Path;
use std::process::Command;
/// The building sequence.
#[allow(clippy::too_many_arguments)]
pub fn build(
build_type: BuildType,
targets: HashSet<Platform>,
llvm_projects: HashSet<LLVMProject>,
enable_rtti: bool,
default_target: Option<TargetTriple>,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<Sanitizer>,
enable_valgrind: bool,
) -> anyhow::Result<()> {
crate::utils::check_presence("cmake")?;
crate::utils::check_presence("clang")?;
crate::utils::check_presence("clang++")?;
crate::utils::check_presence("lld")?;
crate::utils::check_presence("ninja")?;
let musl_name = "musl-1.2.3";
let musl_build = LLVMPath::musl_build(musl_name)?;
let musl_target = LLVMPath::musl_target()?;
let llvm_module_llvm = LLVMPath::llvm_module_llvm()?;
let llvm_host_module_llvm = LLVMPath::llvm_host_module_llvm()?;
let llvm_build_crt = LLVMPath::llvm_build_crt()?;
let llvm_target_crt = LLVMPath::llvm_target_crt()?;
let llvm_build_host = LLVMPath::llvm_build_host()?;
let llvm_target_host = LLVMPath::llvm_target_host()?;
let llvm_build_final = LLVMPath::llvm_build_final()?;
let llvm_target_final = LLVMPath::llvm_target_final()?;
if !LLVMPath::musl_source(musl_name)?.exists() {
crate::utils::download_musl(musl_name)?;
}
crate::platforms::shared::build_musl(musl_build.as_path(), musl_target.as_path())?;
build_crt(
targets.clone(),
llvm_host_module_llvm.as_path(),
llvm_build_crt.as_path(),
llvm_target_crt.as_path(),
ccache_variant,
)?;
build_host(
llvm_host_module_llvm.as_path(),
llvm_build_host.as_path(),
llvm_target_host.as_path(),
musl_target.as_path(),
llvm_target_crt.as_path(),
ccache_variant,
)?;
build_target(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
llvm_module_llvm.as_path(),
llvm_build_final.as_path(),
llvm_target_final.as_path(),
musl_target.as_path(),
llvm_target_host.as_path(),
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
enable_valgrind,
)?;
Ok(())
}
///
/// The `crt` building sequence.
///
fn build_crt(
mut targets: HashSet<Platform>,
source_directory: &Path,
build_directory: &Path,
target_directory: &Path,
ccache_variant: Option<CcacheVariant>,
) -> anyhow::Result<()> {
targets.insert(Platform::AArch64);
crate::utils::command(
Command::new("cmake")
.args([
"-S",
source_directory.to_string_lossy().as_ref(),
"-B",
build_directory.to_string_lossy().as_ref(),
"-G",
"Ninja",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
target_directory.to_string_lossy()
)
.as_str(),
"-DCMAKE_BUILD_TYPE='Release'",
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
"-DLLVM_ENABLE_PROJECTS='compiler-rt'",
format!("-DLLVM_TARGETS_TO_BUILD='{}'", Platform::AArch64).as_str(),
"-DLLVM_DEFAULT_TARGET_TRIPLE='aarch64-unknown-linux-musl'",
"-DLLVM_BUILD_TESTS='Off'",
"-DLLVM_BUILD_RUNTIMES='Off'",
"-DLLVM_BUILD_UTILS='Off'",
"-DLLVM_INCLUDE_TESTS='Off'",
"-DLLVM_INCLUDE_RUNTIMES='Off'",
"-DLLVM_INCLUDE_UTILS='Off'",
"-DCOMPILER_RT_DEFAULT_TARGET_ARCH='aarch64'",
"-DCOMPILER_RT_BUILD_CRT='On'",
"-DCOMPILER_RT_BUILD_BUILTINS='On'",
"-DCOMPILER_RT_BUILD_SANITIZERS='Off'",
"-DCOMPILER_RT_BUILD_XRAY='Off'",
"-DCOMPILER_RT_BUILD_LIBFUZZER='Off'",
"-DCOMPILER_RT_BUILD_PROFILE='Off'",
"-DCOMPILER_RT_BUILD_MEMPROF='Off'",
"-DCOMPILER_RT_BUILD_ORC='Off'",
])
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
)),
"CRT building cmake",
)?;
crate::utils::command(
Command::new("ninja")
.arg("-C")
.arg(build_directory)
.arg("install-crt"),
"CRT building ninja",
)?;
Ok(())
}
///
/// The host toolchain building sequence.
///
fn build_host(
source_directory: &Path,
build_directory: &Path,
target_directory: &Path,
musl_target_directory: &Path,
crt_target_directory: &Path,
ccache_variant: Option<CcacheVariant>,
) -> anyhow::Result<()> {
crate::utils::command(
Command::new("cmake")
.args([
"-S",
source_directory.to_string_lossy().as_ref(),
"-B",
build_directory.to_string_lossy().as_ref(),
"-G",
"Ninja",
format!(
"-DDEFAULT_SYSROOT='{}'",
musl_target_directory.to_string_lossy()
)
.as_str(),
"-DLINKER_SUPPORTS_COLOR_DIAGNOSTICS=0",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
target_directory.to_string_lossy()
)
.as_str(),
"-DCMAKE_BUILD_TYPE='Release'",
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
"-DCLANG_DEFAULT_CXX_STDLIB='libc++'",
"-DCLANG_DEFAULT_RTLIB='compiler-rt'",
"-DLLVM_DEFAULT_TARGET_TRIPLE='aarch64-unknown-linux-musl'",
"-DLLVM_TARGETS_TO_BUILD='AArch64'",
"-DLLVM_BUILD_TESTS='Off'",
"-DLLVM_BUILD_UTILS='Off'",
"-DLLVM_INCLUDE_TESTS='Off'",
"-DLLVM_INCLUDE_UTILS='Off'",
"-DLLVM_ENABLE_PROJECTS='clang;lld'",
"-DLLVM_ENABLE_RUNTIMES='compiler-rt;libcxx;libcxxabi;libunwind'",
"-DLIBCXX_CXX_ABI='libcxxabi'",
"-DLIBCXX_HAS_MUSL_LIBC='On'",
"-DLIBCXX_ENABLE_SHARED='Off'",
"-DLIBCXX_ENABLE_STATIC='On'",
"-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY='On'",
"-DLIBCXXABI_ENABLE_SHARED='Off'",
"-DLIBCXXABI_ENABLE_STATIC='On'",
"-DLIBCXXABI_ENABLE_STATIC_UNWINDER='On'",
"-DLIBCXXABI_USE_LLVM_UNWINDER='On'",
"-DLIBCXXABI_USE_COMPILER_RT='On'",
"-DLIBUNWIND_ENABLE_STATIC='On'",
"-DLIBUNWIND_ENABLE_SHARED='Off'",
"-DCOMPILER_RT_BUILD_CRT='On'",
"-DCOMPILER_RT_BUILD_SANITIZERS='Off'",
"-DCOMPILER_RT_BUILD_XRAY='Off'",
"-DCOMPILER_RT_BUILD_LIBFUZZER='Off'",
"-DCOMPILER_RT_BUILD_PROFILE='On'",
"-DCOMPILER_RT_BUILD_MEMPROF='Off'",
"-DCOMPILER_RT_BUILD_ORC='Off'",
"-DCOMPILER_RT_DEFAULT_TARGET_ARCH='aarch64'",
"-DCOMPILER_RT_DEFAULT_TARGET_ONLY='On'",
])
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
)),
"LLVM host building cmake",
)?;
let mut crt_lib_directory = crt_target_directory.to_path_buf();
crt_lib_directory.push("lib/");
let mut build_lib_directory = build_directory.to_path_buf();
build_lib_directory.push("lib/");
let copy_options = fs_extra::dir::CopyOptions {
overwrite: true,
copy_inside: true,
content_only: true,
..Default::default()
};
fs_extra::dir::copy(crt_lib_directory, build_lib_directory, &copy_options)?;
crate::utils::command(
Command::new("ninja")
.arg("-C")
.arg(build_directory)
.arg("install"),
"LLVM host building ninja",
)?;
Ok(())
}
///
/// The target toolchain building sequence.
///
#[allow(clippy::too_many_arguments)]
fn build_target(
build_type: BuildType,
targets: HashSet<Platform>,
llvm_projects: HashSet<LLVMProject>,
enable_rtti: bool,
default_target: Option<TargetTriple>,
source_directory: &Path,
build_directory: &Path,
target_directory: &Path,
musl_target_directory: &Path,
host_target_directory: &Path,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<Sanitizer>,
enable_valgrind: bool,
) -> anyhow::Result<()> {
let mut clang_path = host_target_directory.to_path_buf();
clang_path.push("bin/clang");
let mut clang_cxx_path = host_target_directory.to_path_buf();
clang_cxx_path.push("bin/clang++");
crate::utils::command(
Command::new("cmake")
.args([
"-S",
source_directory.to_string_lossy().as_ref(),
"-B",
build_directory.to_string_lossy().as_ref(),
"-G",
"Ninja",
"-DBUILD_SHARED_LIBS='Off'",
"-DLINKER_SUPPORTS_COLOR_DIAGNOSTICS=0",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
target_directory.to_string_lossy()
)
.as_str(),
format!("-DCMAKE_BUILD_TYPE='{build_type}'").as_str(),
format!("-DCMAKE_C_COMPILER='{}'", clang_path.to_string_lossy()).as_str(),
format!(
"-DCMAKE_CXX_COMPILER='{}'",
clang_cxx_path.to_string_lossy()
)
.as_str(),
"-DCMAKE_FIND_LIBRARY_SUFFIXES='.a'",
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=1",
"-DCMAKE_EXE_LINKER_FLAGS='-fuse-ld=lld -static'",
format!(
"-DLLVM_TARGETS_TO_BUILD='{}'",
targets
.into_iter()
.map(|platform| platform.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
format!(
"-DLLVM_ENABLE_PROJECTS='{}'",
llvm_projects
.into_iter()
.map(|project| project.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
])
.args(crate::platforms::shared::shared_build_opts_default_target(
default_target,
))
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::SHARED_BUILD_OPTS_NOT_MUSL)
.args(crate::platforms::shared::shared_build_opts_werror(
crate::target_env::TargetEnv::MUSL,
))
.args(crate::platforms::shared::shared_build_opts_tests(
enable_tests,
))
.args(crate::platforms::shared::shared_build_opts_coverage(
enable_coverage,
))
.args(extra_args)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
))
.args(crate::platforms::shared::shared_build_opts_assertions(
enable_assertions,
))
.args(crate::platforms::shared::shared_build_opts_rtti(
enable_rtti,
))
.args(crate::platforms::shared::shared_build_opts_sanitizers(
sanitizer,
))
.args(crate::platforms::shared::shared_build_opts_valgrind(
enable_valgrind,
)),
"LLVM target building cmake",
)?;
crate::utils::ninja(build_directory)?;
let mut musl_lib_directory = musl_target_directory.to_path_buf();
musl_lib_directory.push("lib/");
let mut host_lib_directory = host_target_directory.to_path_buf();
host_lib_directory.push("lib/aarch64-unknown-linux-musl/");
let mut target_lib_directory = target_directory.to_path_buf();
target_lib_directory.push("lib/");
let copy_options = fs_extra::dir::CopyOptions {
overwrite: true,
copy_inside: true,
content_only: true,
..Default::default()
};
fs_extra::dir::copy(
musl_lib_directory,
target_lib_directory.as_path(),
&copy_options,
)?;
fs_extra::dir::copy(
host_lib_directory,
target_lib_directory.as_path(),
&copy_options,
)?;
Ok(())
}
@@ -1,105 +0,0 @@
//! The revive LLVM arm64 `macos-aarch64` builder.
use std::collections::HashSet;
use std::process::Command;
use crate::build_type::BuildType;
use crate::ccache_variant::CcacheVariant;
use crate::llvm_path::LLVMPath;
use crate::llvm_project::LLVMProject;
use crate::platforms::Platform;
use crate::sanitizer::Sanitizer;
use crate::target_triple::TargetTriple;
/// The building sequence.
#[allow(clippy::too_many_arguments)]
pub fn build(
build_type: BuildType,
targets: HashSet<Platform>,
llvm_projects: HashSet<LLVMProject>,
enable_rtti: bool,
default_target: Option<TargetTriple>,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<Sanitizer>,
) -> anyhow::Result<()> {
crate::utils::check_presence("cmake")?;
crate::utils::check_presence("ninja")?;
let llvm_module_llvm = LLVMPath::llvm_module_llvm()?;
let llvm_build_final = LLVMPath::llvm_build_final()?;
let llvm_target_final = LLVMPath::llvm_target_final()?;
crate::utils::command(
Command::new("cmake")
.args([
"-S",
llvm_module_llvm.to_string_lossy().as_ref(),
"-B",
llvm_build_final.to_string_lossy().as_ref(),
"-G",
"Ninja",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
llvm_target_final.to_string_lossy().as_ref(),
)
.as_str(),
format!("-DCMAKE_BUILD_TYPE='{build_type}'").as_str(),
format!(
"-DLLVM_TARGETS_TO_BUILD='{}'",
targets
.into_iter()
.map(|platform| platform.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
format!(
"-DLLVM_ENABLE_PROJECTS='{}'",
llvm_projects
.into_iter()
.map(|project| project.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
"-DCMAKE_OSX_DEPLOYMENT_TARGET='11.0'",
])
.args(crate::platforms::shared::shared_build_opts_default_target(
default_target,
))
.args(crate::platforms::shared::shared_build_opts_tests(
enable_tests,
))
.args(crate::platforms::shared::shared_build_opts_coverage(
enable_coverage,
))
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::SHARED_BUILD_OPTS_NOT_MUSL)
.args(crate::platforms::shared::shared_build_opts_werror(
crate::target_env::TargetEnv::GNU,
))
.args(extra_args)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
))
.args(crate::platforms::shared::shared_build_opts_assertions(
enable_assertions,
))
.args(crate::platforms::shared::shared_build_opts_rtti(
enable_rtti,
))
.args(crate::platforms::shared::macos_build_opts_ignore_dupicate_libs_warnings())
.args(crate::platforms::shared::shared_build_opts_sanitizers(
sanitizer,
)),
"LLVM building cmake",
)?;
crate::utils::ninja(llvm_build_final.as_ref())?;
Ok(())
}
-45
View File
@@ -1,45 +0,0 @@
//! The revive LLVM builder platforms.
pub mod aarch64_linux_gnu;
pub mod aarch64_linux_musl;
pub mod aarch64_macos;
pub mod shared;
pub mod wasm32_emscripten;
pub mod x86_64_linux_gnu;
pub mod x86_64_linux_musl;
pub mod x86_64_macos;
pub mod x86_64_windows_msvc;
use std::str::FromStr;
/// The list of platforms used as constants.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Platform {
/// The native X86 platform.
X86,
/// The native AArch64 platform.
AArch64,
/// The PolkaVM RISC-V platform.
PolkaVM,
}
impl FromStr for Platform {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"PolkaVM" => Ok(Self::PolkaVM),
value => Err(format!("Unsupported platform: `{}`", value)),
}
}
}
impl std::fmt::Display for Platform {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::X86 => write!(f, "X86"),
Self::AArch64 => write!(f, "AArch64"),
Self::PolkaVM => write!(f, "RISCV"),
}
}
}
-226
View File
@@ -1,226 +0,0 @@
//! The shared options for building various platforms.
use crate::ccache_variant::CcacheVariant;
use crate::sanitizer::Sanitizer;
use crate::target_env::TargetEnv;
use crate::target_triple::TargetTriple;
use std::path::Path;
use std::process::Command;
/// The build options shared by all platforms.
pub const SHARED_BUILD_OPTS: [&str; 21] = [
"-DPACKAGE_VENDOR='Parity Technologies'",
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=1",
"-DLLVM_BUILD_DOCS='Off'",
"-DLLVM_INCLUDE_DOCS='Off'",
"-DLLVM_INCLUDE_BENCHMARKS='Off'",
"-DLLVM_INCLUDE_EXAMPLES='Off'",
"-DLLVM_ENABLE_DOXYGEN='Off'",
"-DLLVM_ENABLE_SPHINX='Off'",
"-DLLVM_ENABLE_OCAMLDOC='Off'",
"-DLLVM_ENABLE_ZLIB='Off'",
"-DLLVM_ENABLE_ZSTD='Off'",
"-DLLVM_ENABLE_LIBXML2='Off'",
"-DLLVM_ENABLE_BINDINGS='Off'",
"-DLLVM_ENABLE_TERMINFO='Off'",
"-DLLVM_ENABLE_LIBEDIT='Off'",
"-DLLVM_ENABLE_LIBPFM='Off'",
"-DCMAKE_EXPORT_COMPILE_COMMANDS='On'",
"-DPython3_FIND_REGISTRY='LAST'", // Use Python version from $PATH, not from registry
"-DBUG_REPORT_URL='https://github.com/paritytech/contract-issues/issues/'",
"-DCLANG_ENABLE_ARCMT='Off'",
"-DCLANG_ENABLE_STATIC_ANALYZER='Off'",
];
/// The build options shared by all platforms except MUSL.
pub const SHARED_BUILD_OPTS_NOT_MUSL: [&str; 4] = [
"-DLLVM_OPTIMIZED_TABLEGEN='On'",
"-DLLVM_BUILD_RUNTIME='Off'",
"-DLLVM_BUILD_RUNTIMES='Off'",
"-DLLVM_INCLUDE_RUNTIMES='Off'",
];
/// The shared build options to treat warnings as errors.
///
/// Disabled because it makes the build very brittle.
pub fn shared_build_opts_werror(_target_env: TargetEnv) -> Vec<String> {
vec!["-DLLVM_ENABLE_WERROR='Off'".to_string()]
}
/// The build options to set the default target.
pub fn shared_build_opts_default_target(target: Option<TargetTriple>) -> Vec<String> {
match target {
Some(target) => vec![format!(
"-DLLVM_DEFAULT_TARGET_TRIPLE='{}'",
target.to_string()
)],
None => vec![format!(
"-DLLVM_DEFAULT_TARGET_TRIPLE='{}'",
TargetTriple::PolkaVM
)],
}
}
/// The `musl` building sequence.
pub fn build_musl(build_directory: &Path, target_directory: &Path) -> anyhow::Result<()> {
std::fs::create_dir_all(build_directory)?;
std::fs::create_dir_all(target_directory)?;
crate::utils::command(
Command::new("../configure")
.current_dir(build_directory)
.arg(format!("--prefix={}", target_directory.to_string_lossy()))
.arg(format!(
"--syslibdir={}/lib/",
target_directory.to_string_lossy()
))
.arg("--enable-wrapper='clang'"),
"MUSL configuring",
)?;
crate::utils::command(
Command::new("make")
.current_dir(build_directory)
.arg("-j")
.arg(num_cpus::get().to_string()),
"MUSL building",
)?;
crate::utils::command(
Command::new("make")
.current_dir(build_directory)
.arg("install"),
"MUSL installing",
)?;
let mut include_directory = target_directory.to_path_buf();
include_directory.push("include/");
let mut asm_include_directory = include_directory.clone();
asm_include_directory.push("asm/");
std::fs::create_dir_all(asm_include_directory.as_path())?;
let mut types_header_path = asm_include_directory.clone();
types_header_path.push("types.h");
let copy_options = fs_extra::dir::CopyOptions {
overwrite: true,
copy_inside: true,
..Default::default()
};
fs_extra::dir::copy("/usr/include/linux", include_directory, &copy_options)?;
let copy_options = fs_extra::dir::CopyOptions {
overwrite: true,
copy_inside: true,
content_only: true,
..Default::default()
};
fs_extra::dir::copy(
"/usr/include/asm-generic",
asm_include_directory,
&copy_options,
)?;
crate::utils::command(
Command::new("sed")
.arg("-i")
.arg("s/asm-generic/asm/")
.arg(types_header_path),
"types_header asm signature replacement",
)?;
Ok(())
}
/// The build options to enable assertions.
pub fn shared_build_opts_assertions(enabled: bool) -> Vec<String> {
vec![format!(
"-DLLVM_ENABLE_ASSERTIONS='{}'",
if enabled { "On" } else { "Off" },
)]
}
/// The build options to build with RTTI support.
pub fn shared_build_opts_rtti(enabled: bool) -> Vec<String> {
vec![format!(
"-DLLVM_ENABLE_RTTI='{}'",
if enabled { "On" } else { "Off" },
)]
}
/// The build options to enable sanitizers.
pub fn shared_build_opts_sanitizers(sanitizer: Option<Sanitizer>) -> Vec<String> {
match sanitizer {
Some(sanitizer) => vec![format!("-DLLVM_USE_SANITIZER='{}'", sanitizer)],
None => vec![],
}
}
/// The build options to enable Valgrind for LLVM regression tests.
pub fn shared_build_opts_valgrind(enabled: bool) -> Vec<String> {
if enabled {
vec!["-DLLVM_LIT_ARGS='-sv --vg --vg-leak'".to_owned()]
} else {
vec![]
}
}
/// The LLVM tests build options shared by all platforms.
pub fn shared_build_opts_tests(enabled: bool) -> Vec<String> {
vec![
format!(
"-DLLVM_BUILD_UTILS='{}'",
if enabled { "On" } else { "Off" },
),
format!(
"-DLLVM_BUILD_TESTS='{}'",
if enabled { "On" } else { "Off" },
),
format!(
"-DLLVM_INCLUDE_UTILS='{}'",
if enabled { "On" } else { "Off" },
),
format!(
"-DLLVM_INCLUDE_TESTS='{}'",
if enabled { "On" } else { "Off" },
),
]
}
/// The code coverage build options shared by all platforms.
pub fn shared_build_opts_coverage(enabled: bool) -> Vec<String> {
vec![format!(
"-DLLVM_BUILD_INSTRUMENTED_COVERAGE='{}'",
if enabled { "On" } else { "Off" },
)]
}
/// Use of compiler cache (ccache) to speed up the build process.
pub fn shared_build_opts_ccache(ccache_variant: Option<CcacheVariant>) -> Vec<String> {
match ccache_variant {
Some(ccache_variant) => vec![
format!(
"-DCMAKE_C_COMPILER_LAUNCHER='{}'",
ccache_variant.to_string()
),
format!(
"-DCMAKE_CXX_COMPILER_LAUNCHER='{}'",
ccache_variant.to_string()
),
],
None => vec![],
}
}
/// Ignore duplicate libraries warnings for MacOS with XCode>=15.
pub fn macos_build_opts_ignore_dupicate_libs_warnings() -> Vec<String> {
let xcode_version =
crate::utils::get_xcode_version().unwrap_or(crate::utils::XCODE_MIN_VERSION);
if xcode_version >= crate::utils::XCODE_VERSION_15 {
vec![
"-DCMAKE_EXE_LINKER_FLAGS='-Wl,-no_warn_duplicate_libraries'".to_owned(),
"-DCMAKE_SHARED_LINKER_FLAGS='-Wl,-no_warn_duplicate_libraries'".to_owned(),
]
} else {
vec![]
}
}
@@ -1,224 +0,0 @@
//! The revive LLVM `wasm32_unknown_emscripten` builder.
//!
//! Cross-compiling LLVM for Emscripten requires llvm-tblgen, clang-tblgen and llvm-config.
use std::{collections::HashSet, path::Path, process::Command};
/// The building sequence.
#[allow(clippy::too_many_arguments)]
pub fn build(
build_type: crate::BuildType,
targets: HashSet<crate::Platform>,
llvm_projects: HashSet<crate::llvm_project::LLVMProject>,
enable_rtti: bool,
default_target: Option<crate::TargetTriple>,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<crate::ccache_variant::CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<crate::sanitizer::Sanitizer>,
enable_valgrind: bool,
) -> anyhow::Result<()> {
crate::utils::check_presence("cmake")?;
crate::utils::check_presence("ninja")?;
crate::utils::check_presence("emsdk")?;
crate::utils::check_presence("clang")?;
crate::utils::check_presence("clang++")?;
if cfg!(target_os = "linux") {
crate::utils::check_presence("lld")?;
}
let llvm_module_llvm = crate::LLVMPath::llvm_module_llvm()?;
let llvm_host_module_llvm = crate::LLVMPath::llvm_host_module_llvm()?;
let llvm_build_host = crate::LLVMPath::llvm_build_host()?;
let llvm_target_host = crate::LLVMPath::llvm_target_host()?;
let llvm_build_final = crate::LLVMPath::llvm_build_final()?;
let llvm_target_final = crate::LLVMPath::llvm_target_final()?;
build_host(
llvm_host_module_llvm.as_path(),
llvm_build_host.as_path(),
llvm_target_host.as_path(),
ccache_variant,
)?;
build_target(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
llvm_module_llvm.as_path(),
llvm_build_final.as_path(),
llvm_target_final.as_path(),
llvm_target_host.as_path(),
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
enable_valgrind,
)?;
Ok(())
}
/// The host toolchain building sequence.
fn build_host(
source_directory: &Path,
build_directory: &Path,
target_directory: &Path,
ccache_variant: Option<crate::ccache_variant::CcacheVariant>,
) -> anyhow::Result<()> {
log::info!("building the LLVM Emscripten host utilities");
crate::utils::command(
Command::new("cmake")
.args([
"-S",
source_directory.to_string_lossy().as_ref(),
"-B",
build_directory.to_string_lossy().as_ref(),
"-G",
"Ninja",
"-DLINKER_SUPPORTS_COLOR_DIAGNOSTICS=0",
&format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
target_directory.to_string_lossy()
),
"-DLLVM_BUILD_SHARED_LIBS='Off'",
"-DCMAKE_BUILD_TYPE='Release'",
&format!(
"-DLLVM_TARGETS_TO_BUILD='WebAssembly;{}'",
crate::Platform::PolkaVM
),
"-DLLVM_ENABLE_PROJECTS='clang;lld'",
])
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::SHARED_BUILD_OPTS_NOT_MUSL)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
)),
"LLVM host building cmake config",
)?;
crate::utils::ninja(build_directory)?;
Ok(())
}
/// The target toolchain building sequence.
#[allow(clippy::too_many_arguments)]
fn build_target(
build_type: crate::BuildType,
targets: HashSet<crate::Platform>,
llvm_projects: HashSet<crate::llvm_project::LLVMProject>,
enable_rtti: bool,
default_target: Option<crate::TargetTriple>,
source_directory: &Path,
build_directory: &Path,
target_directory: &Path,
host_target_directory: &Path,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<crate::ccache_variant::CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<crate::sanitizer::Sanitizer>,
enable_valgrind: bool,
) -> anyhow::Result<()> {
let mut llvm_tblgen_path = host_target_directory.to_path_buf();
llvm_tblgen_path.push("bin/llvm-tblgen");
let mut clang_tblgen_path = host_target_directory.to_path_buf();
clang_tblgen_path.push("bin/clang-tblgen");
crate::utils::command(
Command::new("emcmake")
.env("EMCC_DEBUG", "2")
.env("CXXFLAGS", "-Dwait4=__syscall_wait4")
.env("LDFLAGS", "-lnodefs.js -s NO_INVOKE_RUN=1 -s EXIT_RUNTIME=1 -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_RUNTIME_METHODS=FS,callMain,NODEFS -s MODULARIZE=1 -s WASM_BIGINT=1 -s ALLOW_TABLE_GROWTH=1 -s NODEJS_CATCH_EXIT=0 -sDYNAMIC_EXECUTION=0")
.arg("cmake")
.args([
"-S",
source_directory.to_string_lossy().as_ref(),
"-B",
build_directory.to_string_lossy().as_ref(),
"-G",
"Ninja",
"-DLINKER_SUPPORTS_COLOR_DIAGNOSTICS=0",
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=1",
// Enable thin LTO but emscripten has various issues with it.
// FIXME: https://github.com/paritytech/revive/issues/148
//"-DLLVM_ENABLE_LTO='Thin'",
//"-DCMAKE_EXE_LINKER_FLAGS='-Wl,-u,htons -Wl,-u,htonl -Wl,-u,fileno -Wl,-u,ntohs'",
&format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
target_directory.to_string_lossy()
),
&format!("-DCMAKE_BUILD_TYPE='{build_type}'"),
&format!(
"-DLLVM_TARGETS_TO_BUILD='{}'",
targets
.into_iter()
.map(|platform| platform.to_string())
.collect::<Vec<String>>()
.join(";")
),
&format!(
"-DLLVM_ENABLE_PROJECTS='{}'",
llvm_projects
.into_iter()
.map(|project| project.to_string())
.collect::<Vec<String>>()
.join(";")
),
"-DLLVM_BUILD_SHARED_LIBS='Off'",
"-DLLVM_ENABLE_DUMP='Off'",
"-DLLVM_ENABLE_EXPENSIVE_CHECKS='Off'",
"-DLLVM_ENABLE_BACKTRACES='Off'",
"-DLLVM_ENABLE_BACKTRACES='Off'",
"-DLLVM_ENABLE_THREADS='Off'",
"-DLLVM_BUILD_TOOLS='Off'",
&format!("-DLLVM_TABLEGEN='{}'", llvm_tblgen_path.to_string_lossy()),
&format!("-DCLANG_TABLEGEN='{}'", clang_tblgen_path.to_string_lossy()),
])
.args(crate::platforms::shared::shared_build_opts_default_target(
default_target,
))
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::SHARED_BUILD_OPTS_NOT_MUSL)
.args(crate::platforms::shared::shared_build_opts_werror(crate::target_env::TargetEnv::Emscripten))
.args(crate::platforms::shared::shared_build_opts_tests(
enable_tests,
))
.args(crate::platforms::shared::shared_build_opts_coverage(
enable_coverage,
))
.args(extra_args)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
))
.args(crate::platforms::shared::shared_build_opts_assertions(
enable_assertions,
))
.args(crate::platforms::shared::shared_build_opts_rtti(
enable_rtti,
))
.args(crate::platforms::shared::shared_build_opts_sanitizers(
sanitizer,
))
.args(crate::platforms::shared::shared_build_opts_valgrind(
enable_valgrind,
)),
"LLVM target building cmake",
)?;
crate::utils::ninja(build_directory)?;
Ok(())
}
@@ -1,111 +0,0 @@
//! The revive LLVM amd64 `linux-gnu` builder.
use std::collections::HashSet;
use std::process::Command;
use crate::build_type::BuildType;
use crate::ccache_variant::CcacheVariant;
use crate::llvm_path::LLVMPath;
use crate::llvm_project::LLVMProject;
use crate::platforms::Platform;
use crate::sanitizer::Sanitizer;
use crate::target_triple::TargetTriple;
/// The building sequence.
#[allow(clippy::too_many_arguments)]
pub fn build(
build_type: BuildType,
targets: HashSet<Platform>,
llvm_projects: HashSet<LLVMProject>,
enable_rtti: bool,
default_target: Option<TargetTriple>,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<Sanitizer>,
enable_valgrind: bool,
) -> anyhow::Result<()> {
crate::utils::check_presence("cmake")?;
crate::utils::check_presence("clang")?;
crate::utils::check_presence("clang++")?;
crate::utils::check_presence("lld")?;
crate::utils::check_presence("ninja")?;
let llvm_module_llvm = LLVMPath::llvm_module_llvm()?;
let llvm_build_final = LLVMPath::llvm_build_final()?;
let llvm_target_final = LLVMPath::llvm_target_final()?;
crate::utils::command(
Command::new("cmake")
.args([
"-S",
llvm_module_llvm.to_string_lossy().as_ref(),
"-B",
llvm_build_final.to_string_lossy().as_ref(),
"-G",
"Ninja",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
llvm_target_final.to_string_lossy().as_ref(),
)
.as_str(),
format!("-DCMAKE_BUILD_TYPE='{build_type}'").as_str(),
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
format!(
"-DLLVM_TARGETS_TO_BUILD='{}'",
targets
.into_iter()
.map(|platform| platform.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
format!(
"-DLLVM_ENABLE_PROJECTS='{}'",
llvm_projects
.into_iter()
.map(|project| project.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
"-DLLVM_USE_LINKER='lld'",
])
.args(crate::platforms::shared::shared_build_opts_default_target(
default_target,
))
.args(crate::platforms::shared::shared_build_opts_tests(
enable_tests,
))
.args(crate::platforms::shared::shared_build_opts_coverage(
enable_coverage,
))
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
))
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::SHARED_BUILD_OPTS_NOT_MUSL)
.args(crate::platforms::shared::shared_build_opts_werror(
crate::target_env::TargetEnv::GNU,
))
.args(extra_args)
.args(crate::platforms::shared::shared_build_opts_assertions(
enable_assertions,
))
.args(crate::platforms::shared::shared_build_opts_rtti(
enable_rtti,
))
.args(crate::platforms::shared::shared_build_opts_sanitizers(
sanitizer,
))
.args(crate::platforms::shared::shared_build_opts_valgrind(
enable_valgrind,
)),
"LLVM building cmake",
)?;
crate::utils::ninja(llvm_build_final.as_ref())?;
Ok(())
}
@@ -1,394 +0,0 @@
//! The revive LLVM amd64 `linux-musl` builder.
use std::collections::HashSet;
use std::path::Path;
use std::process::Command;
use crate::build_type::BuildType;
use crate::ccache_variant::CcacheVariant;
use crate::llvm_path::LLVMPath;
use crate::llvm_project::LLVMProject;
use crate::platforms::Platform;
use crate::sanitizer::Sanitizer;
use crate::target_triple::TargetTriple;
/// The building sequence.
#[allow(clippy::too_many_arguments)]
pub fn build(
build_type: BuildType,
targets: HashSet<Platform>,
llvm_projects: HashSet<LLVMProject>,
enable_rtti: bool,
default_target: Option<TargetTriple>,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<Sanitizer>,
enable_valgrind: bool,
) -> anyhow::Result<()> {
log::info!("building for target x86_64_linux_musl");
crate::utils::check_presence("cmake")?;
crate::utils::check_presence("clang")?;
crate::utils::check_presence("clang++")?;
crate::utils::check_presence("lld")?;
crate::utils::check_presence("ninja")?;
let musl_name = "musl-1.2.3";
let musl_build = LLVMPath::musl_build(musl_name)?;
let musl_target = LLVMPath::musl_target()?;
let llvm_module_llvm = LLVMPath::llvm_module_llvm()?;
let llvm_host_module_llvm = LLVMPath::llvm_host_module_llvm()?;
let llvm_build_crt = LLVMPath::llvm_build_crt()?;
let llvm_target_crt = LLVMPath::llvm_target_crt()?;
let llvm_build_host = LLVMPath::llvm_build_host()?;
let llvm_target_host = LLVMPath::llvm_target_host()?;
let llvm_build_final = LLVMPath::llvm_build_final()?;
let llvm_target_final = LLVMPath::llvm_target_final()?;
if !LLVMPath::musl_source(musl_name)?.exists() {
crate::utils::download_musl(musl_name)?;
}
crate::platforms::shared::build_musl(musl_build.as_path(), musl_target.as_path())?;
build_crt(
targets.clone(),
llvm_host_module_llvm.as_path(),
llvm_build_crt.as_path(),
llvm_target_crt.as_path(),
ccache_variant,
)?;
build_host(
llvm_host_module_llvm.as_path(),
llvm_build_host.as_path(),
llvm_target_host.as_path(),
musl_target.as_path(),
llvm_target_crt.as_path(),
ccache_variant,
)?;
build_target(
build_type,
targets,
llvm_projects,
enable_rtti,
default_target,
llvm_module_llvm.as_path(),
llvm_build_final.as_path(),
llvm_target_final.as_path(),
musl_target.as_path(),
llvm_target_host.as_path(),
enable_tests,
enable_coverage,
extra_args,
ccache_variant,
enable_assertions,
sanitizer,
enable_valgrind,
)?;
Ok(())
}
/// The `crt` building sequence.
fn build_crt(
mut targets: HashSet<Platform>,
source_directory: &Path,
build_directory: &Path,
target_directory: &Path,
ccache_variant: Option<CcacheVariant>,
) -> anyhow::Result<()> {
targets.insert(Platform::X86);
crate::utils::command(
Command::new("cmake")
.args([
"-S",
source_directory.to_string_lossy().as_ref(),
"-B",
build_directory.to_string_lossy().as_ref(),
"-G",
"Ninja",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
target_directory.to_string_lossy()
)
.as_str(),
"-DCMAKE_BUILD_TYPE='Release'",
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
"-DLLVM_ENABLE_PROJECTS='compiler-rt'",
format!("-DLLVM_TARGETS_TO_BUILD='{}'", Platform::X86).as_str(),
"-DLLVM_DEFAULT_TARGET_TRIPLE='x86_64-pc-linux-musl'",
"-DLLVM_BUILD_TESTS='Off'",
"-DLLVM_BUILD_RUNTIMES='Off'",
"-DLLVM_BUILD_UTILS='Off'",
"-DLLVM_INCLUDE_TESTS='Off'",
"-DLLVM_INCLUDE_RUNTIMES='Off'",
"-DLLVM_INCLUDE_UTILS='Off'",
"-DCOMPILER_RT_DEFAULT_TARGET_ARCH='x86_64'",
"-DCOMPILER_RT_BUILD_CRT='On'",
"-DCOMPILER_RT_BUILD_SANITIZERS='Off'",
"-DCOMPILER_RT_BUILD_XRAY='Off'",
"-DCOMPILER_RT_BUILD_LIBFUZZER='Off'",
"-DCOMPILER_RT_BUILD_PROFILE='Off'",
"-DCOMPILER_RT_BUILD_MEMPROF='Off'",
"-DCOMPILER_RT_BUILD_ORC='Off'",
])
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
)),
"CRT building cmake",
)?;
crate::utils::command(
Command::new("ninja")
.arg("-C")
.arg(build_directory)
.arg("install-crt"),
"CRT building ninja",
)?;
Ok(())
}
/// The host toolchain building sequence.
fn build_host(
source_directory: &Path,
build_directory: &Path,
target_directory: &Path,
musl_target_directory: &Path,
crt_target_directory: &Path,
ccache_variant: Option<CcacheVariant>,
) -> anyhow::Result<()> {
crate::utils::command(
Command::new("cmake")
.args([
"-S",
source_directory.to_string_lossy().as_ref(),
"-B",
build_directory.to_string_lossy().as_ref(),
"-G",
"Ninja",
format!(
"-DDEFAULT_SYSROOT='{}'",
musl_target_directory.to_string_lossy()
)
.as_str(),
"-DLINKER_SUPPORTS_COLOR_DIAGNOSTICS=0",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
target_directory.to_string_lossy()
)
.as_str(),
"-DCMAKE_BUILD_TYPE='Release'",
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
"-DCLANG_DEFAULT_CXX_STDLIB='libc++'",
"-DCLANG_DEFAULT_RTLIB='compiler-rt'",
"-DLLVM_DEFAULT_TARGET_TRIPLE='x86_64-pc-linux-musl'",
"-DLLVM_TARGETS_TO_BUILD='X86'",
"-DLLVM_BUILD_TESTS='Off'",
"-DLLVM_BUILD_UTILS='Off'",
"-DLLVM_INCLUDE_TESTS='Off'",
"-DLLVM_INCLUDE_UTILS='Off'",
"-DLLVM_ENABLE_PROJECTS='clang;lld'",
"-DLLVM_ENABLE_RUNTIMES='compiler-rt;libcxx;libcxxabi;libunwind'",
"-DLIBCXX_CXX_ABI='libcxxabi'",
"-DLIBCXX_HAS_MUSL_LIBC='On'",
"-DLIBCXX_ENABLE_SHARED='Off'",
"-DLIBCXX_ENABLE_STATIC='On'",
"-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY='On'",
"-DLIBCXXABI_ENABLE_SHARED='Off'",
"-DLIBCXXABI_ENABLE_STATIC='On'",
"-DLIBCXXABI_ENABLE_STATIC_UNWINDER='On'",
"-DLIBCXXABI_USE_LLVM_UNWINDER='On'",
"-DLIBCXXABI_USE_COMPILER_RT='On'",
"-DLIBUNWIND_ENABLE_STATIC='On'",
"-DLIBUNWIND_ENABLE_SHARED='Off'",
"-DCOMPILER_RT_BUILD_CRT='On'",
"-DCOMPILER_RT_BUILD_SANITIZERS='Off'",
"-DCOMPILER_RT_BUILD_XRAY='Off'",
"-DCOMPILER_RT_BUILD_LIBFUZZER='Off'",
"-DCOMPILER_RT_BUILD_PROFILE='On'",
"-DCOMPILER_RT_BUILD_MEMPROF='Off'",
"-DCOMPILER_RT_BUILD_ORC='Off'",
"-DCOMPILER_RT_DEFAULT_TARGET_ARCH='x86_64'",
"-DCOMPILER_RT_DEFAULT_TARGET_ONLY='On'",
"-DLIBCLANG_BUILD_STATIC='On'",
"-DBUILD_SHARED_LIBS='Off'",
])
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
)),
"LLVM host building cmake",
)?;
let mut crt_lib_directory = crt_target_directory.to_path_buf();
crt_lib_directory.push("lib/");
let mut build_lib_directory = build_directory.to_path_buf();
build_lib_directory.push("lib/");
let copy_options = fs_extra::dir::CopyOptions {
overwrite: true,
copy_inside: true,
content_only: true,
..Default::default()
};
fs_extra::dir::copy(crt_lib_directory, build_lib_directory, &copy_options)?;
crate::utils::command(
Command::new("ninja")
.arg("-C")
.arg(build_directory)
.arg("install"),
"LLVM host building ninja",
)?;
Ok(())
}
/// The target toolchain building sequence.
#[allow(clippy::too_many_arguments)]
fn build_target(
build_type: BuildType,
targets: HashSet<Platform>,
llvm_projects: HashSet<LLVMProject>,
enable_rtti: bool,
default_target: Option<TargetTriple>,
source_directory: &Path,
build_directory: &Path,
target_directory: &Path,
musl_target_directory: &Path,
host_target_directory: &Path,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<Sanitizer>,
enable_valgrind: bool,
) -> anyhow::Result<()> {
let mut clang_path = host_target_directory.to_path_buf();
clang_path.push("bin/clang");
let mut clang_cxx_path = host_target_directory.to_path_buf();
clang_cxx_path.push("bin/clang++");
crate::utils::command(
Command::new("cmake")
.args([
"-S",
source_directory.to_string_lossy().as_ref(),
"-B",
build_directory.to_string_lossy().as_ref(),
"-G",
"Ninja",
"-DBUILD_SHARED_LIBS='Off'",
"-DLIBCLANG_BUILD_STATIC='On'",
"-DLLVM_BUILD_STATIC='On'",
"-DLINKER_SUPPORTS_COLOR_DIAGNOSTICS=0",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
target_directory.to_string_lossy()
)
.as_str(),
format!("-DCMAKE_BUILD_TYPE='{build_type}'").as_str(),
format!("-DCMAKE_C_COMPILER='{}'", clang_path.to_string_lossy()).as_str(),
format!(
"-DCMAKE_CXX_COMPILER='{}'",
clang_cxx_path.to_string_lossy()
)
.as_str(),
"-DCMAKE_FIND_LIBRARY_SUFFIXES='.a'",
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=1",
"-DCMAKE_EXE_LINKER_FLAGS='-fuse-ld=lld -static'",
format!(
"-DLLVM_TARGETS_TO_BUILD='{}'",
targets
.into_iter()
.map(|platform| platform.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
format!(
"-DLLVM_ENABLE_PROJECTS='{}'",
llvm_projects
.into_iter()
.map(|project| project.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
])
.args(crate::platforms::shared::shared_build_opts_default_target(
default_target,
))
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::SHARED_BUILD_OPTS_NOT_MUSL)
.args(crate::platforms::shared::shared_build_opts_werror(
crate::target_env::TargetEnv::MUSL,
))
.args(crate::platforms::shared::shared_build_opts_tests(
enable_tests,
))
.args(crate::platforms::shared::shared_build_opts_coverage(
enable_coverage,
))
.args(extra_args)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
))
.args(crate::platforms::shared::shared_build_opts_assertions(
enable_assertions,
))
.args(crate::platforms::shared::shared_build_opts_rtti(
enable_rtti,
))
.args(crate::platforms::shared::shared_build_opts_sanitizers(
sanitizer,
))
.args(crate::platforms::shared::shared_build_opts_valgrind(
enable_valgrind,
)),
"LLVM target building cmake",
)?;
crate::utils::ninja(build_directory)?;
let mut musl_lib_directory = musl_target_directory.to_path_buf();
musl_lib_directory.push("lib/");
let mut host_lib_directory = host_target_directory.to_path_buf();
host_lib_directory.push("lib/x86_64-pc-linux-musl/");
let mut target_lib_directory = target_directory.to_path_buf();
target_lib_directory.push("lib/");
let copy_options = fs_extra::dir::CopyOptions {
overwrite: true,
copy_inside: true,
content_only: true,
..Default::default()
};
fs_extra::dir::copy(
musl_lib_directory,
target_lib_directory.as_path(),
&copy_options,
)?;
fs_extra::dir::copy(
host_lib_directory,
target_lib_directory.as_path(),
&copy_options,
)?;
Ok(())
}
@@ -1,105 +0,0 @@
//! The revive LLVM amd64 `macos` builder.
use std::collections::HashSet;
use std::process::Command;
use crate::build_type::BuildType;
use crate::ccache_variant::CcacheVariant;
use crate::llvm_path::LLVMPath;
use crate::llvm_project::LLVMProject;
use crate::platforms::Platform;
use crate::sanitizer::Sanitizer;
use crate::target_triple::TargetTriple;
/// The building sequence.
#[allow(clippy::too_many_arguments)]
pub fn build(
build_type: BuildType,
targets: HashSet<Platform>,
llvm_projects: HashSet<LLVMProject>,
enable_rtti: bool,
default_target: Option<TargetTriple>,
enable_tests: bool,
enable_coverage: bool,
extra_args: &[String],
ccache_variant: Option<CcacheVariant>,
enable_assertions: bool,
sanitizer: Option<Sanitizer>,
) -> anyhow::Result<()> {
crate::utils::check_presence("cmake")?;
crate::utils::check_presence("ninja")?;
let llvm_module_llvm = LLVMPath::llvm_module_llvm()?;
let llvm_build_final = LLVMPath::llvm_build_final()?;
let llvm_target_final = LLVMPath::llvm_target_final()?;
crate::utils::command(
Command::new("cmake")
.args([
"-S",
llvm_module_llvm.to_string_lossy().as_ref(),
"-B",
llvm_build_final.to_string_lossy().as_ref(),
"-G",
"Ninja",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
llvm_target_final.to_string_lossy().as_ref(),
)
.as_str(),
format!("-DCMAKE_BUILD_TYPE='{build_type}'").as_str(),
format!(
"-DLLVM_TARGETS_TO_BUILD='{}'",
targets
.into_iter()
.map(|platform| platform.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
format!(
"-DLLVM_ENABLE_PROJECTS='{}'",
llvm_projects
.into_iter()
.map(|project| project.to_string())
.collect::<Vec<String>>()
.join(";")
)
.as_str(),
"-DCMAKE_OSX_DEPLOYMENT_TARGET='11.0'",
])
.args(crate::platforms::shared::shared_build_opts_default_target(
default_target,
))
.args(crate::platforms::shared::shared_build_opts_tests(
enable_tests,
))
.args(crate::platforms::shared::shared_build_opts_coverage(
enable_coverage,
))
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::SHARED_BUILD_OPTS_NOT_MUSL)
.args(crate::platforms::shared::shared_build_opts_werror(
crate::target_env::TargetEnv::GNU,
))
.args(extra_args)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
))
.args(crate::platforms::shared::shared_build_opts_assertions(
enable_assertions,
))
.args(crate::platforms::shared::shared_build_opts_rtti(
enable_rtti,
))
.args(crate::platforms::shared::macos_build_opts_ignore_dupicate_libs_warnings())
.args(crate::platforms::shared::shared_build_opts_sanitizers(
sanitizer,
)),
"LLVM building cmake",
)?;
crate::utils::ninja(llvm_build_final.as_ref())?;
Ok(())
}

Some files were not shown because too many files have changed in this diff Show More