diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..bd8940d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,40 @@ +{ + "name": "xvec C++ Toolchain", + "image": "ghcr.io/intel/xvec-toolchain:latest", + "containerUser": "root", + "remoteEnv": { + "CC": "icx", + "CXX": "icpx" + }, + "runArgs": [ + "--cap-add=SYS_PTRACE", + "--security-opt=seccomp=unconfined" + ], + "postCreateCommand": "bash -lc 'git --version && cmake --version && ccmake --version && clangd --version && doxygen --version && mrdocs --version && sde64 -help >/dev/null'", + "customizations": { + "vscode": { + "extensions": [ + "llvm-vs-code-extensions.vscode-clangd", + "ms-vscode.cmake-tools", + "ms-vscode.cpptools", + "xaver.clang-format", + "twxs.cmake", + "streetsidesoftware.code-spell-checker" + ], + "settings": { + "C_Cpp.intelliSenseEngine": "disabled", + "clangd.path": "/usr/bin/clangd", + "clangd.arguments": [ + "--background-index", + "--clang-tidy" + ], + "cmake.generator": "Unix Makefiles", + "cmake.buildDirectory": "${workspaceFolder}/build", + "cmake.configureEnvironment": { + "CC": "icx", + "CXX": "icpx" + } + } + } + } +} diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f1e071b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,21 @@ +.git +.devcontainer/* +!.devcontainer/devcontainer.json +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +Thumbs.db +cmake-build-*/ +build/ +out/ +bin/ +docs/doxygen/ +*.o +*.obj +*.a +*.so +*.so.* +*.dylib +*.dll +*.exe diff --git a/.github/workflows/toolchain-image.yml b/.github/workflows/toolchain-image.yml new file mode 100644 index 0000000..1763b94 --- /dev/null +++ b/.github/workflows/toolchain-image.yml @@ -0,0 +1,115 @@ +name: Toolchain image + +on: + pull_request: + paths: + - Dockerfile + - .dockerignore + - .devcontainer/devcontainer.json + - .vscode/extensions.json + - .github/workflows/toolchain-image.yml + - docs/development-container.md + - README.md + - third-party-programs.txt + push: + branches: [main] + paths: + - Dockerfile + - .dockerignore + - .devcontainer/devcontainer.json + - .vscode/extensions.json + - .github/workflows/toolchain-image.yml + - docs/development-container.md + - README.md + - third-party-programs.txt + workflow_dispatch: + +permissions: + contents: read + packages: none + +concurrency: + group: toolchain-image-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: Validate dev-container metadata + run: | + python - <<'PY' + import json + from pathlib import Path + + root = Path(".") + for rel in [".devcontainer/devcontainer.json", ".vscode/extensions.json"]: + json.loads((root / rel).read_text()) + + doc = (root / "docs/development-container.md").read_text() + readme = (root / "README.md").read_text() + third_party = (root / "third-party-programs.txt").read_text() + assert "ghcr.io/intel/xvec-toolchain:latest" in doc + assert "docs/development-container.md" in readme + assert "Intel(R) Software Development Emulator" in third_party + PY + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build toolchain image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64 + cache-from: type=gha + cache-to: type=gha,mode=max + provenance: true + sbom: true + + publish: + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: build + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v7 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/intel/xvec-toolchain + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=ref,event=branch + type=sha,format=short + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and publish toolchain image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + provenance: true + sbom: true diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..e6f2364 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "ms-vscode-remote.remote-containers" + ] +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..60ba2a2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,210 @@ +FROM ubuntu:24.04 + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +ARG DEBIAN_FRONTEND=noninteractive +ARG HTTP_PROXY +ARG HTTPS_PROXY +ARG NO_PROXY +ARG http_proxy +ARG https_proxy +ARG no_proxy +ARG TARGETARCH +ARG MRDOCS_VERSION=2026.9.4 +ARG MRDOCS_SHA256=be1fbbc516233fe7cc87f66c735b9dbbd23e4bcfadfda705503daac5b6f42ed8 +ARG INTEL_SDE_VERSION=10.13.1-2026-07-28 +ARG INTEL_SDE_SHA256=94e97d623fec54385686e1e7ba65ebc9941748c05ee451423948334892bf2b50 + +LABEL org.opencontainers.image.title="xvec C++ toolchain" \ + org.opencontainers.image.description="Containerized C++ development environment for intel/xvec" \ + org.opencontainers.image.source="https://github.com/intel/xvec" \ + org.opencontainers.image.url="https://github.com/intel/xvec" \ + org.opencontainers.image.documentation="https://github.com/intel/xvec/blob/main/docs/development-container.md" \ + org.opencontainers.image.licenses="Apache-2.0 WITH LLVM-exception" + +ENV MRDOCS_ROOT=/opt/mrdocs +ENV INTEL_SDE_ROOT=/opt/intel-sde +ENV ONEAPI_ROOT=/opt/intel/oneapi +ENV PATH="${MRDOCS_ROOT}/bin:${INTEL_SDE_ROOT}:${ONEAPI_ROOT}/compiler/latest/bin:${PATH}" + +RUN target_arch="${TARGETARCH:-$(dpkg --print-architecture)}" \ + && if [[ "${target_arch}" != "amd64" ]]; then \ + echo "This image supports only linux/amd64 because Intel SDE is x86-64-only." >&2; \ + exit 1; \ + fi + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ca-certificates \ + cmake \ + cmake-curses-gui \ + curl \ + doxygen \ + git \ + gnupg \ + graphviz \ + libboost-test-dev \ + make \ + software-properties-common \ + xz-utils \ + && rm -rf /var/lib/apt/lists/* + +RUN export NO_PROXY= no_proxy= \ + && install -d -m 0755 /etc/apt/keyrings \ + && curl --fail --show-error --location --retry 3 \ + https://apt.llvm.org/llvm-snapshot.gpg.key \ + -o /tmp/llvm.key \ + && gpg --batch --yes --dearmor \ + -o /etc/apt/keyrings/llvm.gpg \ + /tmp/llvm.key \ + && echo "deb [signed-by=/etc/apt/keyrings/llvm.gpg] https://apt.llvm.org/noble/ llvm-toolchain-noble-20 main" \ + > /etc/apt/sources.list.d/llvm.list \ + && add-apt-repository -y ppa:ubuntu-toolchain-r/test \ + && curl --fail --show-error --location --retry 3 \ + https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \ + -o /tmp/intel-oneapi.key \ + && gpg --batch --yes --dearmor \ + -o /etc/apt/keyrings/oneapi-archive-keyring.gpg \ + /tmp/intel-oneapi.key \ + && echo "deb [signed-by=/etc/apt/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" \ + > /etc/apt/sources.list.d/oneapi.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + clang-20 \ + clangd-20 \ + clang-format-20 \ + clang-tidy-20 \ + gcc-16 \ + g++-16 \ + intel-oneapi-compiler-dpcpp-cpp \ + lldb-20 \ + && test -x /usr/bin/clang++-20 \ + && update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-16 160 \ + && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-16 160 \ + && update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-16 160 \ + && update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-16 160 \ + && update-alternatives --install /usr/bin/clang clang /usr/bin/clang-20 200 \ + && update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-20 200 \ + && update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-20 200 \ + && update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-20 200 \ + && update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-20 200 \ + && update-alternatives --install /usr/bin/lldb lldb /usr/bin/lldb-20 200 \ + && test -x /opt/intel/oneapi/compiler/latest/bin/icx \ + && test -x /opt/intel/oneapi/compiler/latest/bin/icpx \ + && test -f /opt/intel/oneapi/compiler/latest/env/vars.sh \ + && ln -sf /opt/intel/oneapi/compiler/latest/env/vars.sh /etc/profile.d/20-intel-oneapi-compiler.sh \ + && printf '%s\n' '#!/bin/bash' \ + 'export LD_LIBRARY_PATH="/opt/intel/oneapi/compiler/latest/lib:/opt/intel/oneapi/compiler/latest/lib/x64:/opt/intel/oneapi/compiler/latest/opt/compiler/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"' \ + 'exec "$@"' \ + > /usr/local/bin/xvec-entrypoint \ + && printf '%s\n' '#!/bin/bash' \ + 'source /opt/intel/oneapi/compiler/latest/env/vars.sh >/dev/null' \ + 'exec "$@"' \ + > /usr/local/bin/intel-oneapi-compiler-wrapper \ + && printf '%s\n' '#!/bin/bash' \ + 'exec /usr/local/bin/intel-oneapi-compiler-wrapper /opt/intel/oneapi/compiler/latest/bin/icx "$@"' \ + > /usr/local/bin/icx \ + && printf '%s\n' '#!/bin/bash' \ + 'exec /usr/local/bin/intel-oneapi-compiler-wrapper /opt/intel/oneapi/compiler/latest/bin/icpx "$@"' \ + > /usr/local/bin/icpx \ + && chmod 0755 /usr/local/bin/xvec-entrypoint /usr/local/bin/intel-oneapi-compiler-wrapper /usr/local/bin/icx /usr/local/bin/icpx \ + && rm -f /tmp/llvm.key /tmp/intel-oneapi.key \ + && rm -rf /var/lib/apt/lists/* + +RUN export NO_PROXY= no_proxy= \ + && install -d -m 0755 "${MRDOCS_ROOT}" \ + && curl --fail --show-error --location --retry 3 \ + "https://github.com/cppalliance/mrdocs/releases/download/${MRDOCS_VERSION}/MrDocs-${MRDOCS_VERSION}-Linux.tar.gz" \ + -o /tmp/mrdocs.tar.gz \ + && echo "${MRDOCS_SHA256} /tmp/mrdocs.tar.gz" | sha256sum --check \ + && tar --extract --gzip \ + --file=/tmp/mrdocs.tar.gz \ + --directory="${MRDOCS_ROOT}" \ + --strip-components=1 \ + && rm -f /tmp/mrdocs.tar.gz + +RUN export NO_PROXY= no_proxy= \ + && if [[ "$(dpkg --print-architecture)" != "amd64" ]]; then \ + echo "Intel SDE requires an x86-64/amd64 image." >&2; \ + exit 1; \ + fi \ + && curl --fail --show-error --location --retry 3 \ + "https://downloadmirror.intel.com/924984/sde-external-${INTEL_SDE_VERSION}-lin.tar.xz" \ + -o /tmp/intel-sde.tar.xz \ + && echo "${INTEL_SDE_SHA256} /tmp/intel-sde.tar.xz" | sha256sum --check \ + && install -d -m 0755 "${INTEL_SDE_ROOT}" \ + && tar --extract --xz \ + --file=/tmp/intel-sde.tar.xz \ + --directory="${INTEL_SDE_ROOT}" \ + --strip-components=1 \ + && rm -f /tmp/intel-sde.tar.xz \ + && test -x "${INTEL_SDE_ROOT}/sde64" \ + && test -x "${INTEL_SDE_ROOT}/xed64" \ + && find "${INTEL_SDE_ROOT}" -maxdepth 2 -type f \ + \( -iname 'LICENSE*' -o -iname 'third-party-programs.txt' \) \ + | grep -q . \ + && ln -sf "${INTEL_SDE_ROOT}/sde64" /usr/local/bin/sde \ + && ln -sf "${INTEL_SDE_ROOT}/sde64" /usr/local/bin/sde64 \ + && ln -sf "${INTEL_SDE_ROOT}/xed64" /usr/local/bin/xed \ + && ln -sf "${INTEL_SDE_ROOT}/xed64" /usr/local/bin/xed64 + +RUN cat <<'EOF' >/tmp/boost_test.cpp +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE xvec_boost_test_smoke +#include + +BOOST_AUTO_TEST_CASE(smoke) +{ + BOOST_TEST(true); +} +EOF + +RUN cat <<'EOF' >/tmp/icpx_smoke.cpp +#include + +int main() +{ + int value = 0; +#pragma omp parallel reduction(+:value) + value += 1; + return value > 0 ? 0 : 1; +} +EOF + +RUN test -x "$(command -v gcc)" \ + && test -x "$(command -v g++)" \ + && test -x "$(command -v cc)" \ + && test -x "$(command -v c++)" \ + && test -x "$(command -v clang)" \ + && test -x "$(command -v clang++)" \ + && test -x "$(command -v clangd)" \ + && test -x "$(command -v clang-format)" \ + && test -x "$(command -v clang-tidy)" \ + && test -x "$(command -v lldb)" \ + && test -x "$(command -v icx)" \ + && test -x "$(command -v icpx)" \ + && cmake --version >/dev/null \ + && ccmake --version >/dev/null \ + && make --version >/dev/null \ + && git --version >/dev/null \ + && curl --version >/dev/null \ + && doxygen --version >/dev/null \ + && dot -V >/dev/null 2>&1 \ + && mrdocs --version >/dev/null \ + && g++ -std=c++20 /tmp/boost_test.cpp -lboost_unit_test_framework -o /tmp/boost_test \ + && /tmp/boost_test --log_level=test_suite \ + && icpx -std=c++20 -fopenmp /tmp/icpx_smoke.cpp -o /tmp/icpx_smoke \ + && LD_LIBRARY_PATH="/opt/intel/oneapi/compiler/latest/lib:/opt/intel/oneapi/compiler/latest/lib/x64:/opt/intel/oneapi/compiler/latest/opt/compiler/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}" /tmp/icpx_smoke \ + && test -x "$(command -v sde)" \ + && test -x "$(command -v sde64)" \ + && test -x "$(command -v xed)" \ + && test -x "$(command -v xed64)" \ + && find "${INTEL_SDE_ROOT}" -maxdepth 2 -type f \ + \( -iname 'LICENSE*' -o -iname 'third-party-programs.txt' \) \ + | grep -q . \ + && test "$(gcc -dumpversion | cut -d. -f1)" = "16" \ + && test "$(clang -dumpversion | cut -d. -f1)" = "20" \ + && rm -f /tmp/boost_test.cpp /tmp/boost_test /tmp/icpx_smoke.cpp /tmp/icpx_smoke + +ENTRYPOINT ["/usr/local/bin/xvec-entrypoint"] +CMD ["/bin/bash"] diff --git a/README.md b/README.md index 9aabff9..c1b492f 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,10 @@ The full documentation includes the API reference, guides, and worked examples: The documentation is generated from the source using Doxygen and published from the `main` branch. +For the containerized development environment, GHCR toolchain image, and VS Code +Dev Containers workflow, see +[docs/development-container.md](docs/development-container.md). + ## Releases and compatibility The `main` branch contains the latest development version. It is continuously diff --git a/docs/development-container.md b/docs/development-container.md new file mode 100644 index 0000000..1816be0 --- /dev/null +++ b/docs/development-container.md @@ -0,0 +1,123 @@ +# Development container and toolchain image + +The repository includes a containerized C++ development environment for xvec. +The image definition lives in the repository `Dockerfile`, and GitHub Actions can +publish the resulting image as `ghcr.io/intel/xvec-toolchain:latest`. + +## Build the image with Docker + +### Behind the corporate proxy + +Use the tested build command below when external LLVM, Intel, and GitHub +downloads must go through a corporate proxy: + +```bash +sudo docker build --no-cache --progress=plain \ + --build-arg HTTP_PROXY="${HTTP_PROXY:-$http_proxy}" \ + --build-arg HTTPS_PROXY="${HTTPS_PROXY:-$https_proxy}" \ + --build-arg http_proxy="${http_proxy:-$HTTP_PROXY}" \ + --build-arg https_proxy="${https_proxy:-$HTTPS_PROXY}" \ + --build-arg NO_PROXY= \ + --build-arg no_proxy= \ + -t xvec-toolchain:latest . +``` + +Both uppercase and lowercase variables are supplied because different tools and +build environments consult different spellings. Both `NO_PROXY` and `no_proxy` +are explicitly cleared so the external LLVM, Intel, and GitHub hosts do not +bypass the proxy unexpectedly. Do not bake proxy values into the image with +`ENV`; keep them as per-build inputs. + +### Without a proxy + +For normal internet-connected systems, a simpler build is sufficient: + +```bash +sudo docker build --progress=plain -t xvec-toolchain:latest . +``` + +## Run Docker manually + +Bind-mount the checkout so the container can access the source tree: + +```bash +sudo docker run --rm -it \ + --mount type=bind,source="$PWD",target=/workspace \ + --workdir /workspace \ + xvec-toolchain:latest +``` + +Intel SDE is already installed in the image. The extra runtime options below are +permissions for SDE and Pin-based tracing, not installation steps: + +```bash +sudo docker run --rm -it \ + --cap-add=SYS_PTRACE \ + --security-opt seccomp=unconfined \ + --mount type=bind,source="$PWD",target=/workspace \ + --workdir /workspace \ + xvec-toolchain:latest +``` + +Example SDE invocation: + +```bash +sde64 -spr -- ./my-program +``` + +## Use the toolchain image in VS Code locally + +1. Install Docker and Visual Studio Code. +2. Install the Dev Containers extension + (`ms-vscode-remote.remote-containers`). +3. Clone this repository locally and open the repository folder in VS Code. +4. If the GHCR package is private, authenticate before reopening in the + container. For example: + + ```bash + gh auth token | docker login ghcr.io --username USERNAME --password-stdin + ``` + +5. Run **Dev Containers: Reopen in Container** from the Command Palette. + +When VS Code opens the dev container, it automatically bind-mounts the +repository workspace. You do not need to add a manual Docker `--mount` option in +that workflow. The first image pull can be large, but subsequent container +starts reuse the cached image and layers that already exist on the local system. + +After changes to the image or dev-container definition, use **Dev Containers: +Rebuild Container** or **Reopen in Container** again to pick up the update. + +The default build directory is `build/`. Configure and build with CMake or +`ccmake`: + +```bash +cmake -S test -B build -DCMAKE_CXX_COMPILER="${CXX:-icpx}" +cmake --build build --parallel +``` + +To adjust cache entries interactively, run `ccmake -S test -B build`. + +The dev container defaults to the Intel oneAPI DPC++/C++ compiler +(`CC=icx`, `CXX=icpx`). To choose a different compiler, set `CC` and `CXX` +before configuring a fresh build directory. Typical examples are +`gcc`/`g++` or `clang`/`clang++`. + +The image is built only for `linux/amd64` because Intel SDE is distributed for +x86-64 Linux. Codespaces can consume the same dev-container definition, but SDE +or Pin-based tracing may still be limited by nested or otherwise restricted +runtime environments even though the binaries are installed in the image. + +## GHCR image information + +The published image name is: + +```text +ghcr.io/intel/xvec-toolchain:latest +``` + +The `.github/workflows/toolchain-image.yml` workflow validates pull requests by +building the image without publishing it. Pushes to `main` publish `latest`, +branch, and commit-SHA tags through GHCR. Access to the package depends on the +repository or package visibility settings; users may need to authenticate to +pull the image when the package is private. diff --git a/third-party-programs.txt b/third-party-programs.txt index 5323165..706242a 100644 --- a/third-party-programs.txt +++ b/third-party-programs.txt @@ -40,3 +40,26 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- + +2. MrDocs + Redistributed in the xvec development container image from the official + prebuilt Linux release available at + https://github.com/cppalliance/mrdocs/releases. + Upstream project: https://github.com/cppalliance/mrdocs + License: Apache License v2.0 with LLVM Exceptions + +------------------------------------------------------------------------------- + +3. Intel(R) Software Development Emulator (Intel(R) SDE) + Included in the xvec development container image for x86-64 development and + test workflows. + Download source used by the image build: + https://downloadmirror.intel.com/924984/sde-external-10.13.1-2026-07-28-lin.tar.xz + License and redistribution terms are supplied by Intel with the downloaded + package and preserved in the extracted image contents. Mirrored copies of the + bundled SDE license materials indicate that redistribution of the unmodified + package may be allowed when notices are reproduced, but the exact pinned + release terms should still be confirmed with Intel or legal counsel before + making any published image broadly accessible. + +-------------------------------------------------------------------------------