diff --git a/.github/actions/setup-rust/action.yml b/.github/actions/setup-rust/action.yml new file mode 100644 index 0000000..6681080 --- /dev/null +++ b/.github/actions/setup-rust/action.yml @@ -0,0 +1,29 @@ +name: Setup Rust +description: Setup Rust with specified toolchain, target and components. +inputs: + toolchain: + description: 'Toolchain' + default: stable + required: true + target: + description: 'Target' + required: true + components: + description: 'Components' + required: true + +runs: + using: composite + steps: + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ inputs.toolchain }} + target: ${{ inputs.target }} + components: ${{ inputs.components }} + + - name: Install rust matcher + run: echo "::add-matcher::.github/actions/setup-rust/rust.json" + shell: bash + + - uses: Swatinem/rust-cache@v1.3.0 diff --git a/.github/actions/setup-rust/rust.json b/.github/actions/setup-rust/rust.json new file mode 100644 index 0000000..dbc4c79 --- /dev/null +++ b/.github/actions/setup-rust/rust.json @@ -0,0 +1,31 @@ +{ + "problemMatcher": [ + { + "owner": "rust", + "pattern": [ + { + "regexp": "^(warning|warn|error)(\\[(.*)\\])?: (.*)$", + "severity": 1, + "message": 4, + "code": 3 + }, + { + "regexp": "^([\\s->=]*(.*):(\\d*):(\\d*)|.*)$", + "file": 2, + "line": 3, + "column": 4 + } + ] + }, + { + "owner": "cross-rs", + "pattern": [ + { + "regexp": "^\\[cross\\] (warning|error): (.*)$", + "severity": 1, + "message": 2 + } + ] + } + ] +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..aaa521b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,71 @@ +on: + pull_request: + workflow_dispatch: + push: + branches: [main, staging, trying] + tags: + - "v*.*.*" + +name: CI + +env: + CARGO_NET_RETRY: 3 + CARGO_HTTP_CHECK_REVOKE: false + +jobs: + shellcheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Run ShellCheck + uses: azohra/shell-linter@v0.3.0 + + build: + name: Build Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/setup-rust + + - name: Get Changed Files + id: files + uses: Ana06/get-changed-files@v2.1.0 + with: + # use JSON so we don't have to worry about filenames with spaces + format: 'json' + filter: 'docker/Dockerfile.*' + + - name: Validate Changed Images + id: images + run: | + set -x + set -e + # read modified files + readarray -t added_modified < <(jq -r '.[]' <<<'${{ steps.files.outputs.added_modified }}') + names=() + for path in "${added_modified[@]}"; do + filename=$(basename "${path}") + if [[ "${filename}" == Dockerfile.*linux* ]]; then + names+=("${filename/Dockerfile./}") + fi + done + count=${#names[@]} + + # only run if we have any modified targets + if [[ "${count}" -ne "0" ]]; then + echo "Building and testing images for ${names}" + + # get and build cross to build our docker images + home="${PWD}" + td="$(mktemp -d)" + cd "${td}" + git clone https://github.com/cross-rs/cross/ "${td}" + cargo build -p xtask + + # copy over our project and build our docker images + cp -a "${home}"/* docker/cross-toolchains/ + python3 -m pip install toml --user + echo "${names}" + docker/cross-toolchains/run_ci_tests.py "${names}" + fi diff --git a/docker/darwin-entry.sh b/docker/darwin-entry.sh index 4b8882e..289d8ee 100755 --- a/docker/darwin-entry.sh +++ b/docker/darwin-entry.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# shellcheck disable=SC2086 set -e diff --git a/docker/darwin-symlink.sh b/docker/darwin-symlink.sh index 0a0efd9..efb509a 100755 --- a/docker/darwin-symlink.sh +++ b/docker/darwin-symlink.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# shellcheck disable=SC2016 +# shellcheck disable=SC2012,SC2016 set -x set -euo pipefail @@ -7,7 +7,7 @@ set -euo pipefail main() { # create a symlink to our sysroot to make it accessible in the dockerfile local sdk_version - sdk_version=$(ls /opt/osxcross/SDK) + sdk_version=$(ls -t -1 /opt/osxcross/SDK | head -1) ln -s "/opt/osxcross/SDK/${sdk_version}" "/opt/osxcross/SDK/latest" rm "${0}" diff --git a/docker/darwin.sh b/docker/darwin.sh index 4236e24..021a817 100755 --- a/docker/darwin.sh +++ b/docker/darwin.sh @@ -7,6 +7,7 @@ set -eo pipefail . lib.sh if [[ "${MACOS_SDK_FILE}" == "nonexistent" ]] && [[ -z "${MACOS_SDK_URL}" ]]; then + # shellcheck disable=SC2016 echo 'Must set the environment variable `MACOS_SDK_FILE` or `MACOS_SDK_URL`.' 1>&2 exit 1 fi diff --git a/docker/ios-entry.sh b/docker/ios-entry.sh index 775ed70..a62c8d6 100755 --- a/docker/ios-entry.sh +++ b/docker/ios-entry.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# shellcheck disable=SC2012,SC2086 set -e diff --git a/docker/ios-symlink.sh b/docker/ios-symlink.sh index 8b03fc3..d1be5f2 100755 --- a/docker/ios-symlink.sh +++ b/docker/ios-symlink.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# shellcheck disable=SC2016 +# shellcheck disable=SC2012,SC2016 set -x set -euo pipefail @@ -7,7 +7,7 @@ set -euo pipefail main() { # create a symlink to our sysroot to make it accessible in the dockerfile local sdk_version - sdk_version=$(ls /opt/cctools/SDK) + sdk_version=$(ls -t -1 /opt/cctools/SDK | head -1) ln -s "/opt/cctools/SDK/${sdk_version}" "/opt/cctools/SDK/latest" rm "${0}" diff --git a/docker/ios.sh b/docker/ios.sh index 8014c69..78dbdfb 100755 --- a/docker/ios.sh +++ b/docker/ios.sh @@ -3,6 +3,7 @@ # https://github.com/tpoechtrager/cctools-port/tree/master/usage_examples/ios_toolchain # This code is public domain # https://github.com/tpoechtrager/cctools-port/issues/21#issuecomment-223382676 +# shellcheck disable=SC2012 set -x set -eo pipefail @@ -11,6 +12,7 @@ set -eo pipefail . lib.sh if [[ "${IOS_SDK_FILE}" == "nonexistent" ]] && [[ -z "${IOS_SDK_URL}" ]]; then + # shellcheck disable=SC2016 echo 'Must set the environment variable `IOS_SDK_FILE` or `IOS_SDK_URL`.' 1>&2 exit 1 fi @@ -95,8 +97,6 @@ main() { # now, need to get our metadata, and move the SDK to the output dir mkdir -p "${install_dir}" mv SDK "${sdk_dir}" - local syslib - syslib=$(find "${sdk_dir}" -name libSystem.dylib -o -name libSystem.tbd | head -n1) local wrapper_sdkdir pushd "${sdk_dir}" wrapper_sdkdir=$(echo iPhoneOS*sdk | head -n1) @@ -146,6 +146,7 @@ main() { ln -sf "${clang}" "${clang}"++ # need a fake wrapper for xcrun, which is used by `cc`. + # shellcheck disable=SC2016 echo '#!/usr/bin/env sh echo "${SDKROOT}" ' > "${install_dir}/bin/xcrun" diff --git a/docker/msvc-wine-symlink.sh b/docker/msvc-wine-symlink.sh index 3a3cd27..cac90dd 100755 --- a/docker/msvc-wine-symlink.sh +++ b/docker/msvc-wine-symlink.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# shellcheck disable=SC2016 +# shellcheck disable=SC2012,SC2016 set -x set -euo pipefail @@ -19,7 +19,7 @@ main() { # create a symlink to our sysroot to make it accessible in the dockerfile local msvc_version - msvc_version=$(ls /opt/msvc/vc/tools/msvc/) + msvc_version=$(ls -t -1 /opt/msvc/vc/tools/msvc/ | head -1) ln -s "/opt/msvc/vc/tools/msvc/${msvc_version}" "/opt/msvc/vc/tools/msvc/latest" rm "${0}" diff --git a/run_ci_tests.py b/run_ci_tests.py new file mode 100755 index 0000000..bdae317 --- /dev/null +++ b/run_ci_tests.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 + +import argparse +import os +import subprocess +import toml + +HOME = os.path.dirname(os.path.realpath(__file__)) + +def main(): + parser = argparse.ArgumentParser(prog='CI') + parser.add_argument('names', nargs='+') + parser.add_argument('-e', '--engine', help='the container engine to use') + parser.add_argument( + '-v', + '--verbose', + action='store_true', + help='print verbose diagnostic output', + ) + args = parser.parse_args() + if args.engine is None: + args.engine = os.environ.get('CROSS_CONTAINER_ENGINE', 'docker') + + with open(os.path.join(HOME, 'targets.toml')) as file: + matrix = toml.loads(file.read()) + matrix = {i['name']: i for i in matrix['target']} + + for name in args.names: + target = matrix[name] + command = [ + 'cargo', + 'build-docker-image', + name, + '--engine', + args.engine, + '--tag', + 'main' + ] + if args.verbose: + command.append('--verbose') + print(f'Running build command "{" ".join(command)}"') + subprocess.run(command, check=True) + + # add our environment and run our tests + env = dict(os.environ) + cross_env = {} + key = f'CROSS_TARGET_{target["target"].upper().replace("-", "_")}_IMAGE' + image = f'ghcr.io/cross-rs/{target["target"]}:main' + cross_env[key] = image + cross_env['TARGET'] = target['target'] + cross_env['CROSS_CONTAINER_ENGINE'] = args.engine + for key in ('cpp', 'dylib', 'std', 'build-std', 'run', 'runners'): + value = target.get(key) + if value: + key = key.upper().replace('-', '_') + if value is True: + value = '1' + cross_env[key] = value + env.update(cross_env) + if args.verbose: + print(f'Running test command with env of "{cross_env}"') + subprocess.run(['ci/test.sh'], env=env, check=True) + +if __name__ == '__main__': + main() diff --git a/targets.toml b/targets.toml new file mode 100644 index 0000000..e81b268 --- /dev/null +++ b/targets.toml @@ -0,0 +1,109 @@ +# This is similar to cross's `targets.toml`, and it's meant to be both +# information and used in CI. + +[[target]] +name = "aarch64-apple-darwin-cross" +target = "aarch64-apple-darwin" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true + +[[target]] +name = "i686-apple-darwin-cross" +target = "i686-apple-darwin" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true + +[[target]] +name = "x86_64-apple-darwin-cross" +target = "x86_64-apple-darwin" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true + +[[target]] +name = "aarch64-apple-ios" +target = "aarch64-apple-ios-cross" +os = "ubuntu-latest" +dylib = true +std = true + +[[target]] +name = "aarch64-pc-windows-msvc-cross" +target = "aarch64-pc-windows-msvc" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true +run = true + +[[target]] +name = "i686-pc-windows-msvc-cross" +target = "i686-pc-windows-msvc" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true +run = true + +[[target]] +name = "thumbv7a-pc-windows-msvc-cross" +target = "thumbv7a-pc-windows-msvc" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true +run = true + +[[target]] +name = "x86_64-pc-windows-msvc-cross" +target = "x86_64-pc-windows-msvc" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true +run = true + +[[target]] +name = "aarch64_be-unknown-linux-gnu-cross" +target = "aarch64_be-unknown-linux-gnu" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true +run = true +build-std = true + +[[target]] +name = "s390x-unknown-linux-gnu-cross" +target = "s390x-unknown-linux-gnu" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true +run = true +runners = "qemu-user qemu-system" + +[[target]] +name = "thumbv7neon-unknown-linux-musleabihf-cross" +target = "thumbv7neon-unknown-linux-musleabihf" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true +run = true +build-std = true + +[[target]] +name = "x86_64-unknown-linux-gnu-sde-cross" +target = "x86_64-unknown-linux-gnu" +os = "ubuntu-latest" +cpp = true +dylib = true +std = true +run = true +runners = "native"