diff --git a/.clang-format b/.clang-format index a3ebb75c1d..bffce04a3e 100644 --- a/.clang-format +++ b/.clang-format @@ -5,7 +5,7 @@ AlignAfterOpenBracket: DontAlign AlignConsecutiveBitFields: true # AlignConsecutiveDeclarations: false AlignConsecutiveMacros: true -# AlignEscapedNewlines: Right +AlignEscapedNewlines: DontAlign # AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: false diff --git a/.env b/.env index e3ca2ae9f0..cf3ae699c0 100644 --- a/.env +++ b/.env @@ -2,7 +2,7 @@ # MetaCall Library by Parra Studios # Docker image infrastructure for MetaCall. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,4 +23,4 @@ COMPOSE_PROJECT_NAME='metacall' # Configure default variables METACALL_PATH=/usr/local/metacall METACALL_BUILD_TYPE=relwithdebinfo -METACALL_BASE_IMAGE=debian:bookworm-slim # debian:bullseye-slim # ubuntu:jammy # alpine:3.17 +METACALL_BASE_IMAGE=debian:trixie-slim # debian:bookworm-slim # ubuntu:noble # ubuntu:jammy # alpine:3.17 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index bb7fc31237..ea802c726b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,7 +1,17 @@ # Contributing When contributing to this repository, please first discuss the change you wish to make via issue, -email, or any other method with the owners of this repository before making a change. +email, or any other method with the owners of this repository before making a change. Here is an examplary process you can follow to create an issue on MetaCall: + +1. Identify a problem or a possible addition to Metacall codebase/operation
+for instance: ```pre-commit-clang-format not working on windows...``` +2. Then go to the necessary MetaCall gitHub repository and click on the "Issues" tab at the top of the page. Indicate your issue's interest by tagging it as a bug report, custom issue, documentation, feature, or discussion.
+in this case: ```metacall/core``` +3. Type in a title and description for your issue. Be as detailed as possible, including any error messages or steps to reproduce the issue. Image example:
+![issue image](https://user-images.githubusercontent.com/93955843/220493308-0ce3f101-6957-43fb-96d1-7a730ccf304c.PNG) + +4. You can assign the issue to yourself, add labels or a milestone to it, and attach files if necessary. +5. Submit the newly created issue and start working on a solution by creating a fork of the repository.
(Here to issue used for explanation) Please note we have a [Code of Conduct](/.github/CODE_OF_CONDUCT.md), please follow it in all your interactions with the project. diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 2d0bd44cce..67a684cd07 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -28,10 +28,46 @@ jobs: steps: - name: Check out the repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Prepare MacOS Installation + if: matrix.os == 'macos-latest' + run: | + echo "Uninstall CMake" + brew uninstall --force cmake + + echo "Uninstall NodeJS and NPM" + npm uninstall npm -g + rm -rf /usr/local/lib/node_modules/npm + + echo "Uninstall Ruby" + brew uninstall --force --ignore-dependencies ruby + brew cleanup -s ruby + brew cleanup --prune-prefix + RUBY_FRAMEWORK_DIR=$(xcrun --sdk macosx --show-sdk-path)/System/Library/Frameworks/Ruby.framework + sudo rm -rf $RUBY_FRAMEWORK_DIR + + echo "Uninstall Go" + brew uninstall --force go + brew autoremove + sudo rm -rf /usr/local/Cellar/go + sudo rm -rf /usr/local/go + sudo rm -rf /usr/local/opt/go + sudo rm -rf /etc/paths.d/go + sudo rm -rf /usr/local/bin/go + sudo rm -rf /usr/local/bin/gofmt + + echo "Uninstall Java" + sudo rm -rf /Library/Java/JavaVirtualMachines/* + sudo rm -rf /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin + sudo rm -rf /Library/PreferencePanes/JavaControlPanel.prefPane + unset JAVA_HOME + + echo "Export XCode SDK Root" + echo "SDKROOT=$(xcrun --sdk macosx --show-sdk-path)" >> $GITHUB_ENV + # TODO: Add support for NetCore Bench - name: Set up the environment run: | @@ -52,12 +88,10 @@ jobs: - name: Build working-directory: ./build - # TODO: Remove the disable option for fork safe once funchook problem is solved run: | if [ "$(uname)" == "Darwin" ]; then . .env fi - cmake -DOPTION_FORK_SAFE=OFF .. bash ../tools/metacall-build.sh $METACALL_BUILD_OPTIONS env: METACALL_BUILD_OPTIONS: release benchmarks @@ -66,14 +100,6 @@ jobs: if: ${{ github.event_name != 'pull_request' }} run: python3 ./tools/metacall-benchmarks-merge.py ./build/benchmarks - # Download previous benchmark result from cache (if exists) - - name: Download previous benchmark data - uses: actions/cache@v1 - if: ${{ github.event_name != 'pull_request' }} - with: - path: ./cache - key: ${{ matrix.os }}-benchmark - - name: Store benchmark result uses: benchmark-action/github-action-benchmark@v1 if: ${{ github.event_name != 'pull_request' }} @@ -82,31 +108,30 @@ jobs: tool: 'googlecpp' output-file-path: ./build/benchmarks/metacall-benchmarks.json # Access token to deploy GitHub Pages branch - github-token: "" + github-token: ${{ secrets.BENCHMARKS_PUSH_TOKEN }} # Disable push and deploy GitHub pages branch automatically auto-push: false - skip-fetch-gh-pages: true + # Github Pages repository name + gh-repository: github.com/metacall/core-benchmarks # Github Pages branch name - gh-pages-branch: ${{ github.head_ref || github.ref_name }} + gh-pages-branch: main # Output directory - benchmark-data-dir-path: bench/${{ matrix.os }} - # Where the previous data file is stored - external-data-json-path: ./cache/metacall-benchmarks.json + benchmark-data-dir-path: ./${{ matrix.os }} - # Upload benchmark artifacts - - name: Upload benchmark artifact - uses: actions/upload-artifact@master + - name: Push benchmark result if: ${{ github.event_name != 'pull_request' }} - with: - name: ${{ matrix.os }}-benchmark - path: ./bench/ + run: | + cd benchmark-data-repository + git push https://$REPO_KEY@github.com/metacall/core-benchmarks.git + env: + REPO_KEY: ${{secrets.BENCHMARKS_PUSH_TOKEN}} benchmark-windows: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [windows-2019] + os: [windows-2022, windows-2025] env: LTTNG_UST_REGISTER_TIMEOUT: 0 @@ -115,7 +140,7 @@ jobs: steps: - name: Check out the repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -150,14 +175,6 @@ jobs: if: ${{ github.event_name != 'pull_request' }} run: python3 ./tools/metacall-benchmarks-merge.py ./build/benchmarks - # Download previous benchmark result from cache (if exists) - - name: Download previous benchmark data - uses: actions/cache@v1 - if: ${{ github.event_name != 'pull_request' }} - with: - path: ./cache - key: ${{ matrix.os }}-benchmark - - name: Store benchmark result uses: benchmark-action/github-action-benchmark@v1 if: ${{ github.event_name != 'pull_request' }} @@ -166,70 +183,20 @@ jobs: tool: 'googlecpp' output-file-path: ./build/benchmarks/metacall-benchmarks.json # Access token to deploy GitHub Pages branch - github-token: "" + github-token: ${{ secrets.BENCHMARKS_PUSH_TOKEN }} # Disable push and deploy GitHub pages branch automatically auto-push: false - skip-fetch-gh-pages: true + # Github Pages repository name + gh-repository: github.com/metacall/core-benchmarks # Github Pages branch name - gh-pages-branch: ${{ github.head_ref || github.ref_name }} + gh-pages-branch: main # Output directory - benchmark-data-dir-path: bench/${{ matrix.os }} - # Where the previous data file is stored - external-data-json-path: ./cache/metacall-benchmarks.json + benchmark-data-dir-path: ./${{ matrix.os }} - # Upload benchmark artifacts - - name: Upload benchmark artifact - uses: actions/upload-artifact@master + - name: Push benchmark result if: ${{ github.event_name != 'pull_request' }} - with: - name: ${{ matrix.os }}-benchmark - path: ./bench/ - - # This job will merge all benchmarks into one artifact - benchmark-upload: - runs-on: ubuntu-latest - if: ${{ github.event_name != 'pull_request' }} - needs: [benchmark-unix, benchmark-windows] - steps: - # Ubuntu - - uses: actions/download-artifact@master - with: - name: ubuntu-latest-benchmark - path: ./bench/ - - # MacOS - - uses: actions/download-artifact@master - with: - name: macos-latest-benchmark - path: ./bench/ - - # Windows - - uses: actions/download-artifact@master - with: - name: windows-2019-benchmark - path: ./bench/ - - # Upload benchmark website artifacts - - name: Upload benchmark artifact - uses: actions/upload-pages-artifact@v2 - with: - path: ./bench/ - name: benchmarks - - benchmark-deploy: - runs-on: ubuntu-latest - if: ${{ github.event_name != 'pull_request' }} - needs: [benchmark-upload] - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - permissions: - contents: read - pages: write - id-token: write - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v2 - with: - artifact_name: benchmarks + run: | + cd benchmark-data-repository + git push https://${REPO_KEY}@github.com/metacall/core-benchmarks.git + env: + REPO_KEY: ${{secrets.BENCHMARKS_PUSH_TOKEN}} diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 8f7233c39c..243d5b2355 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -11,7 +11,7 @@ jobs: name: Formatting Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Run clang-format style check for C/C++. uses: jidicula/clang-format-action@v4.9.0 with: diff --git a/.github/workflows/docker-hub.yml b/.github/workflows/docker-hub.yml index 2f6df6cb96..34267338aa 100644 --- a/.github/workflows/docker-hub.yml +++ b/.github/workflows/docker-hub.yml @@ -1,13 +1,11 @@ -name: Build and Push Docker Image +name: Build and Push Docker Image for Multiple Architectures on: - # To enable manual triggering of this workflow - workflow_dispatch: - - # Trigger for pushes to master and tags + pull_request: push: branches: - master + - develop tags: - 'v*.*.*' @@ -16,38 +14,201 @@ concurrency: cancel-in-progress: true env: - IMAGE_NAME: index.docker.io/metacall/core + DOCKER_REGISTRY: index.docker.io + DOCKER_USERNAME: metacall + IMAGE_NAME: core + BUILDKIT_VERSION: 0.13.0 + + # TODO: Tests failing + # - linux/s390x + # TODO: Detour not supported, needs to patch GOT instead of PLT + # - linux/mips64le + # - linux/mips64 + PLATFORM_LIST: > + [ + "linux/amd64", + "linux/amd64/v2", + "linux/amd64/v3", + "linux/386", + "linux/arm64", + "linux/riscv64", + "linux/ppc64le", + "linux/arm/v7", + "linux/arm/v6", + "linux/loong64" + ] jobs: - build: + matrix: + name: Generate Platform List runs-on: ubuntu-latest + outputs: + platform_list: ${{ steps.generate_platform_list.outputs.platform_list }} + steps: + - name: Generate platform list + id: generate_platform_list + run: | + set -exuo pipefail + PLATFORM_STRING=$(cat <> $GITHUB_ENV + echo "::set-output name=platform_list::$PLATFORM_LIST" + + build: name: Build + runs-on: ubuntu-latest + needs: matrix + strategy: + fail-fast: false + matrix: + platform: ${{ fromJSON(needs.matrix.outputs.platform_list) }} + steps: - - name: Checkout the code - uses: actions/checkout@v2 + - name: Checkout Repository + uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Login to DockerHub - run: docker login -u "${{ secrets.DOCKER_HUB_USERNAME }}" -p "${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}" + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 - - name: Pull MetaCall Docker Images - run: bash ./docker-compose.sh pull + - name: Set up Docker BuildX + uses: docker/setup-buildx-action@v3 + with: + version: v${{ env.BUILDKIT_VERSION }} + + - name: Login to Docker Hub + # Only run when master or when tagging a version + if: (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) && github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Build MetaCall Docker Images - run: bash ./docker-compose.sh build + env: + METACALL_PLATFORM: ${{ matrix.platform }} + DOCKER_BUILDKIT: 1 + run: | + ./docker-compose.sh platform + + - name: Run Tests + env: + DOCKER_BUILDKIT: 1 + run: | + set -exuo pipefail + docker image inspect ${DOCKER_USERNAME}/${IMAGE_NAME}:cli --format='{{.Os}}/{{.Architecture}}' + cat < Dockerfile.test + FROM ${DOCKER_USERNAME}/${IMAGE_NAME}:cli + RUN apt-get update && apt-get install -y file + RUN file /usr/local/bin/metacallcli && ldd /usr/local/bin/metacallcli + RUN echo "console.log('0123456789abcdef')" > script.js + RUN metacallcli script.js | tee output.txt + RUN grep 0123456789abcdef output.txt + EOF + + docker buildx build --progress=plain --platform ${{ matrix.platform }} -f Dockerfile.test -t test-image . + + - name: Tag & Push Platform Images + # Only run when master or when tagging a version + if: (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) && github.event_name != 'pull_request' + run: | + platform_tag=$(echo "${{ matrix.platform }}" | tr '/' '-') + for tag in "deps" "dev" "runtime" "cli"; do + docker tag \ + ${DOCKER_USERNAME}/${IMAGE_NAME}:${tag} \ + ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-${platform_tag} + + echo "Pushing image for tag: ${tag} with platform: ${platform_tag}" + docker push ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-${platform_tag} + done - # TODO: Build with alpine and provide multiple tags (debian & alpine) once all tests pass - - name: Push MetaCall Docker Image to DockerHub + manifest: + name: Create and Push Manifest Lists + needs: [matrix, build] + # Only run when master or when tagging a version + if: (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) && github.event_name != 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Create and Push Manifest Lists run: | - if [[ "${{ github.ref == 'refs/heads/master' }}" = true ]]; then - bash ./docker-compose.sh push - elif [[ "${{ contains(github.ref, 'refs/tags/') }}" = true ]]; then - bash ./docker-compose.sh version - else - echo "Failed to push the docker images" - exit 1 + set -exuo pipefail + + tags=("deps" "dev" "runtime" "cli") + platforms=($(echo '${{ needs.matrix.outputs.platform_list }}' | jq -r '.[]')) + + echo "Create all the tags by platform" + + for tag in "${tags[@]}"; do + echo "Creating manifest for tag: $tag" + platform_tags="" + for platform in "${platforms[@]}"; do + platform_tag=$(echo "${platform}" | tr '/' '-') + platform_tags="${platform_tags} ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-${platform_tag}" + done + echo "Creating manifest with tags: ${platform_tags}" + docker manifest create ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:${tag} ${platform_tags} --amend + docker manifest push ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:${tag} + done + + echo "Create the latest tag" + + cli_platform_tags="" + for platform in ${platforms[@]}"; do + platform_tag=$(echo "${platform}" | tr '/' '-') + cli_platform_tags="${cli_platform_tags} ${DOCKER_USERNAME}/${IMAGE_NAME}:cli-${platform_tag}" + done + docker manifest create ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:latest ${cli_platform_tags} --amend + docker manifest push ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:latest + + if [[ "${{ startsWith(github.ref, 'refs/tags/') }}" = true ]]; then + VERSION=${GITHUB_REF#refs/tags/v} + + echo "Create the version ${VERSION} tag" + + for tag in "${tags[@]}"; do + platform_tags="" + for platform in "${platforms[@]}"; do + platform_tag=$(echo "${platform}" | tr '/' '-') + platform_tags="${platform_tags} ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-${platform_tag}" + done + docker manifest create ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:${VERSION}-${tag} ${platform_tags} --amend + docker manifest push ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:${VERSION}-${tag} + done fi - - name: Logout from DockerHub - run: docker logout + cleanup: + name: Cleanup Platform Specific Tags + needs: [matrix, build, manifest] + runs-on: ubuntu-latest + if: always() + steps: + - name: Remove Platform-Specific Tags + run: | + set -exuo pipefail + + tags=("deps" "dev" "runtime" "cli") + platforms=($(echo '${{ needs.matrix.outputs.platform_list }}' | jq -r '.[]')) + + for tag in "${tags[@]}"; do + for platform in "${platforms[@]}"; do + platform_tag=$(echo "${platform}" | tr '/' '-') + tag_to_delete="${tag}-${platform_tag}" + + echo "Deleting tag: ${tag_to_delete}" + echo "https://hub.docker.com/v2/repositories/$%7BDOCKER_USERNAME%7D/$%7BIMAGE_NAME%7D/tags/$%7Btag_to_delete%7D/" + + curl -X DELETE \ + -H "Authorization: Bearer ${{ secrets.DOCKER_HUB_ACCESS_TOKEN_DELETE }}" \ + "https://hub.docker.com/v2/repositories/$%7BDOCKER_USERNAME%7D/$%7BIMAGE_NAME%7D/tags/$%7Btag_to_delete%7D/" + done + done diff --git a/.github/workflows/linux-sanitizer.yml b/.github/workflows/linux-sanitizer.yml deleted file mode 100644 index 6d24be34b6..0000000000 --- a/.github/workflows/linux-sanitizer.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Linux Sanitizer Test - -on: - workflow_dispatch: - pull_request: - push: - tags: - - 'v*.*.*' - branches: - - master - - develop - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - linux-sanitizer-gcc: - name: Linux GCC Sanitizer Test - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - image: ["debian:bookworm-slim", "debian:bullseye-slim", "ubuntu:jammy"] - sanitizer: [address-sanitizer, thread-sanitizer] # TODO: memory-sanitizer not supported by GCC - - env: - SANITIZER_SKIP_SUMMARY: 1 - - steps: - - name: Check out the repository - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Install, build and run thread sanitizer tests - run: ./docker-compose.sh test-${{ matrix.sanitizer }} - env: - METACALL_BUILD_TYPE: debug - METACALL_BASE_IMAGE: ${{ matrix.image }} diff --git a/.github/workflows/linux-test.yml b/.github/workflows/linux-test.yml index 434530c5b5..dd9af86734 100644 --- a/.github/workflows/linux-test.yml +++ b/.github/workflows/linux-test.yml @@ -22,16 +22,64 @@ jobs: fail-fast: false matrix: build: [debug, release] - image: ["debian:bookworm-slim", "debian:bullseye-slim", "ubuntu:jammy"] # TODO: "alpine:3.17" + image: ["debian:trixie-slim", "debian:bookworm-slim", "ubuntu:noble", "ubuntu:jammy"] # TODO: "alpine:3.17" steps: - name: Check out the repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Install, build and run tests + - name: Install, build and run tests (build) + run: ./docker-compose.sh build + env: + METACALL_BUILD_TYPE: ${{ matrix.build }} + METACALL_BASE_IMAGE: ${{ matrix.image }} + + - name: Install, build and run tests (test) run: ./docker-compose.sh test env: METACALL_BUILD_TYPE: ${{ matrix.build }} METACALL_BASE_IMAGE: ${{ matrix.image }} + + linux-sanitizer-test: + name: Linux GCC Sanitizer Test + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + image: ["debian:trixie-slim", "debian:bookworm-slim", "ubuntu:noble", "ubuntu:jammy"] + sanitizer: [address-sanitizer, thread-sanitizer] # TODO: memory-sanitizer not supported by GCC + + env: + SANITIZER_SKIP_SUMMARY: 1 + + steps: + - name: Check out the repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install, build and run thread sanitizer tests + run: ./docker-compose.sh test-${{ matrix.sanitizer }} + env: + METACALL_BUILD_TYPE: debug + METACALL_BASE_IMAGE: ${{ matrix.image }} + + linux-distributable: + name: Linux Distributable Dispatch + needs: [linux-test, linux-sanitizer-test] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master' + steps: + - name: Linux Workflow Dispatch + uses: convictional/trigger-workflow-and-wait@v1.6.1 + with: + owner: metacall + repo: distributable-linux + github_token: ${{ secrets.G_PERSONAL_ACCESS_TOKEN }} + workflow_file_name: ci.yml + wait_workflow: true + client_payload: '{"ref": "${{ github.head_ref || github.ref_name }}"}' + ref: master diff --git a/.github/workflows/macos-test.yml b/.github/workflows/macos-test.yml index 850808c4f3..520de15171 100644 --- a/.github/workflows/macos-test.yml +++ b/.github/workflows/macos-test.yml @@ -15,13 +15,14 @@ concurrency: cancel-in-progress: true jobs: - mac-test: + macos-test: name: MacOS Clang Test - runs-on: macos-latest + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: + os: [macos-13, macos-14, macos-15] options: [ {build: debug, sanitizer: without-sanitizer}, {build: debug, sanitizer: address-sanitizer}, @@ -30,16 +31,19 @@ jobs: ] env: - LTTNG_UST_REGISTER_TIMEOUT: 0 NUGET_XMLDOC_MODE: skip DOTNET_CLI_TELEMETRY_OPTOUT: "true" steps: - name: Check out the repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Uninstall CMake + run: | + brew uninstall --force cmake + - name: Uninstall NodeJS and NPM run: | npm uninstall npm -g @@ -47,8 +51,9 @@ jobs: - name: Uninstall Ruby run: | - brew uninstall --force ruby - brew autoremove + brew uninstall --force --ignore-dependencies ruby + brew cleanup -s ruby + brew cleanup --prune-prefix RUBY_FRAMEWORK_DIR=$(xcrun --sdk macosx --show-sdk-path)/System/Library/Frameworks/Ruby.framework sudo rm -rf $RUBY_FRAMEWORK_DIR @@ -69,11 +74,14 @@ jobs: sudo rm -rf /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin sudo rm -rf /Library/PreferencePanes/JavaControlPanel.prefPane unset JAVA_HOME + + - name: Export XCode SDK Root + run: echo "SDKROOT=$(xcrun --sdk macosx --show-sdk-path)" >> $GITHUB_ENV - name: Set up the environment run: sh ./tools/metacall-environment.sh $METACALL_INSTALL_OPTIONS env: - METACALL_INSTALL_OPTIONS: base python nodejs typescript java ruby wasm rpc file cobol go backtrace #netcore5 c rust rapidjson funchook swig pack # clangformat v8rep51 coverage + METACALL_INSTALL_OPTIONS: base python nodejs typescript java ruby wasm rpc file cobol go backtrace #netcore5 c rust rapidjson pack # clangformat v8rep51 coverage - name: Configure run: | @@ -85,10 +93,35 @@ jobs: - name: Build working-directory: ./build - # TODO: Remove the disable option for fork safe once funchook problem is solved run: | . .env - cmake -DOPTION_FORK_SAFE=OFF .. bash ../tools/metacall-build.sh $METACALL_BUILD_OPTIONS env: - METACALL_BUILD_OPTIONS: ${{ matrix.options.build }} tests + METACALL_BUILD_OPTIONS: ${{ matrix.options.build }} tests install + + macos-distributable: + name: MacOS Distributable Dispatch + needs: macos-test + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master' + steps: + - name: Homebrew Workflow Dispatch + uses: convictional/trigger-workflow-and-wait@v1.6.1 + with: + owner: metacall + repo: homebrew + github_token: ${{ secrets.G_PERSONAL_ACCESS_TOKEN }} + workflow_file_name: test.yml + wait_workflow: true + client_payload: '{"ref": "${{ github.head_ref || github.ref_name }}"}' + ref: main + - name: MacOS Workflow Dispatch + uses: convictional/trigger-workflow-and-wait@v1.6.1 + with: + owner: metacall + repo: distributable-macos + github_token: ${{ secrets.G_PERSONAL_ACCESS_TOKEN }} + workflow_file_name: ci.yml + wait_workflow: true + client_payload: '{"ref": "${{ github.head_ref || github.ref_name }}"}' + ref: master diff --git a/.github/workflows/release-nodejs.yml b/.github/workflows/release-nodejs.yml new file mode 100644 index 0000000000..da626217cc --- /dev/null +++ b/.github/workflows/release-nodejs.yml @@ -0,0 +1,26 @@ +name: Release NodeJS Package + +on: + push: + branches: [ master, develop ] + paths: + - 'source/ports/node_port/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + release: + name: Release NodeJS Port + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Release the port + working-directory: source/ports/node_port + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: ./upload.sh diff --git a/.github/workflows/release-python.yml b/.github/workflows/release-python.yml new file mode 100644 index 0000000000..a5f0c7de4f --- /dev/null +++ b/.github/workflows/release-python.yml @@ -0,0 +1,28 @@ +name: Release Python Package + +on: + push: + branches: [ master, develop ] + paths: + - 'source/ports/py_port/**' + +permissions: + id-token: write + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + release: + name: Release Python Port + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Release the port + working-directory: source/ports/py_port + run: ./upload.sh diff --git a/.github/workflows/release-rust.yml b/.github/workflows/release-rust.yml new file mode 100644 index 0000000000..d2a0c31a43 --- /dev/null +++ b/.github/workflows/release-rust.yml @@ -0,0 +1,66 @@ +name: Release Rust Crates + +on: + workflow_dispatch: + pull_request: + push: + branches: [ master, develop ] + paths: + - '.github/workflows/release-rust.yml' + - 'source/ports/rs_port/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + +jobs: + test: + name: Rust Port Tests + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] # TODO: , windows-latest] + steps: + - name: Check out the repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install MetaCall Unix + if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest' + run: curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | sh + - name: Install MetaCall Windows + if: matrix.os == 'windows-latest' + run: powershell -NoProfile -ExecutionPolicy Unrestricted -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; &([scriptblock]::Create((Invoke-WebRequest -UseBasicParsing 'https://raw.githubusercontent.com/metacall/install/master/install.ps1')))" + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + - name: Build the Rust Port + working-directory: source/ports/rs_port + run: cargo build --verbose + + - name: Test the Rust Port + working-directory: source/ports/rs_port + run: cargo test --verbose + + release: + name: Release Rust Port + runs-on: ubuntu-latest + needs: test + if: ${{ github.event_name != 'pull_request' }} + steps: + - name: Check out the repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Release the port + run: | + cd source/ports/rs_port + bash ./upload.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 413ff507a8..24f963c9e9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ concurrency: cancel-in-progress: true env: - GHR_VERSION: 0.12.0 + GHR_VERSION: 0.17.0 IMAGE_NAME: index.docker.io/metacall/core IMAGE_REGISTRY: index.docker.io ARTIFACTS_PATH: ./build-artifacts @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out the repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Pull the Docker images @@ -33,7 +33,7 @@ jobs: - name: Extract built artifacts run: bash ./docker-compose.sh pack - name: Upload built artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: built-artifacts path: ${{ env.ARTIFACTS_PATH }}/ @@ -44,11 +44,11 @@ jobs: needs: build steps: - name: Check out the repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 # To fetch all tags - name: Download built artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4.1.8 with: name: built-artifacts path: ${{ env.ARTIFACTS_PATH }}/ diff --git a/.github/workflows/windows-test.yml b/.github/workflows/windows-test.yml index d782881d90..3518e6d4db 100644 --- a/.github/workflows/windows-test.yml +++ b/.github/workflows/windows-test.yml @@ -17,11 +17,12 @@ concurrency: jobs: windows-test: name: Windows MSVC Test - runs-on: windows-2019 # TODO: Implement matrix with windows 2019 and 2022 + runs-on: windows-${{ matrix.os }} strategy: fail-fast: false matrix: + os: [2022, 2025] options: [ {build: debug, sanitizer: without-sanitizer}, {build: debug, sanitizer: address-sanitizer}, @@ -36,7 +37,7 @@ jobs: steps: - name: Check out the repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -48,7 +49,7 @@ jobs: - name: Set up the environment run: cmd.exe /c "powershell .\tools\metacall-environment.ps1 $Env:METACALL_INSTALL_OPTIONS" env: - METACALL_INSTALL_OPTIONS: python nodejs java ruby typescript wasm rpc file # netcore5 java c cobol rust rapidjson funchook swig pack # clangformat v8rep51 coverage + METACALL_INSTALL_OPTIONS: python nodejs java ruby typescript wasm rpc file # netcore5 java c cobol rust rapidjson pack # clangformat v8rep51 coverage - name: Configure run: | @@ -63,4 +64,21 @@ jobs: working-directory: ./build run: cmd.exe /c "powershell ..\tools\metacall-build.ps1 $Env:METACALL_BUILD_OPTIONS" env: - METACALL_BUILD_OPTIONS: ${{ matrix.options.build }} tests + METACALL_BUILD_OPTIONS: ${{ matrix.options.build }} tests install + + windows-distributable: + name: Windows Distributable Dispatch + needs: windows-test + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master' + steps: + - name: Windows Workflow Dispatch + uses: convictional/trigger-workflow-and-wait@v1.6.1 + with: + owner: metacall + repo: distributable-windows + github_token: ${{ secrets.G_PERSONAL_ACCESS_TOKEN }} + workflow_file_name: ci.yml + wait_workflow: true + client_payload: '{"ref": "${{ github.head_ref || github.ref_name }}"}' + ref: master diff --git a/.gitignore b/.gitignore index 9b833cae7b..f462998c4f 100644 --- a/.gitignore +++ b/.gitignore @@ -33,13 +33,6 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake -# Avoid ignoring build hooks -!hooks/build -!tools/deps/hooks/build -!tools/dev/hooks/build -!tools/runtime/hooks/build -!tools/cli/hooks/build - # Qt cache CMakeLists.txt.user CMakeLists.txt.user.* @@ -54,18 +47,21 @@ _open-project.bat _start-cmake-gui.bat _start-cmd.bat +# macOS files +.DS_Store + # Local config unix .localconfig # Visual Studio Code .vscode +# Clang files +.cache + # Linked dockerignore file in main context .dockerignore !tools/deps/.dockerignore !tools/dev/.dockerignore !tools/runtime/.dockerignore !tools/cli/.dockerignore - -# macOS files -.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index 18275d3ad3..f543559e6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ # MetaCall Library by Parra Studios # A library for providing a foreing function interface calls. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ # # CMake version -cmake_minimum_required(VERSION 3.14 FATAL_ERROR) +cmake_minimum_required(VERSION 3.15 FATAL_ERROR) # Include cmake modules @@ -173,12 +173,12 @@ include(CompileOptions) # if(OPTION_COVERAGE) - list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/coverage") - - set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE) - set(ENABLE_COVERAGE_ALL ON CACHE BOOL "Enable coverage build for all targets." FORCE) - - find_package(codecov) + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(WARNING "OPTION_COVERAGE requires to be build with -DCMAKE_BUILD_TYPE=Debug, skipping coverage") + set(OPTION_COVERAGE OFF) + else() + include(Coverage) + endif() endif() # @@ -195,7 +195,7 @@ if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr" OR "${CMAKE_INSTALL_PREFIX}" STREQU endif() # Installation paths -if(UNIX AND SYSTEM_DIR_INSTALL) +if(UNIX AND SYSTEM_DIR_INSTALL OR OPTION_BUILD_GUIX) # Install into the system (/usr/bin or /usr/local/bin) set(INSTALL_ROOT "share/${project}") # /usr/[local]/share/ set(INSTALL_CMAKE "share/${project}/cmake") # /usr/[local]/share//cmake @@ -241,6 +241,9 @@ else() endif() endif() +# Export compile commands +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + # # CTest configuration # @@ -257,14 +260,6 @@ add_subdirectory(source) add_subdirectory(docs) add_subdirectory(deploy) -# -# Coverage evaluation (must run after all targets) -# - -if(OPTION_COVERAGE) - coverage_evaluate() -endif() - # # Project configuration generation # diff --git a/Dockerfile b/Dockerfile index 8eeb02cd29..a81cfd453b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ # MetaCall Library by Parra Studios # Docker image infrastructure for MetaCall. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/LICENSE b/LICENSE index 5a00ce2141..d56ad81fad 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2016-2022 Vicente Eduardo Ferrer Garcia + Copyright 2016-2025 Vicente Eduardo Ferrer Garcia Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/NOTICE b/NOTICE index 64d3172e01..687413ccf2 100644 --- a/NOTICE +++ b/NOTICE @@ -19,9 +19,8 @@ All external code and licenses used by **METACALL** are always wrapped into plug - [2. Serials](#2-serials) - [2.1 RapidJSON](#21-rapidjson) - [3. Detours](#3-detours) - - [3.1 FuncHook](#31-funchook) + - [3.1 PLTHook](#31-plthook) - [4. Ports](#4-ports) - - [4.1 Swig](#41-swig) @@ -80,24 +79,10 @@ All external code and licenses used by **METACALL** are always wrapped into plug ## 3. Detours -### 3.1 FuncHook +### 3.1 PLTHook -| Software | License | -| :----------: | :-------------------------------------------------------------------------------------------------: | -| **FuncHook** | [GPLv2 or later with a GPL linking exception](https://github.com/kubo/funchook/blob/master/LICENSE) | +| Software | License | +| :----------: | :------------------------------------------------------------------------------------------: | +| **PLTHook** | [2-clause BSD-style license](https://github.com/metacall/plthook?tab=readme-ov-file#license) | ## 4. Ports - -### 4.1 Swig - -| Software | License | -| :------: | :-----: | -| **SWIG** | **∅** | - ->When SWIG is used as it is distributed by the SWIG developers, its output is not governed by SWIG's license (including the GPL). SWIG's output contains code from three sources: -> -> - code generated by SWIG, which is not governed by copyright; -> - code copied from the SWIG library which is permissively licensed to be redistributed without restriction; -> - code derived from the user's input, which may be governed by the license of the code supplied by the user. -> ->So, while the input supplied to SWIG may affect the license of SWIG's output (e.g. if the input code is licensed under a copyleft or proprietary license), SWIG's license does not affect the license of the output. This is consistent with the FSF's FAQ entries on this subject ([GPLOutput](http://www.gnu.org/licenses/gpl-faq.html#GPLOutput) and [WhatCaseIsOutputGPL](http://www.gnu.org/licenses/gpl-faq.html#WhatCaseIsOutputGPL)), because the SWIG code copied into the output by SWIG is not GPL-licensed. diff --git a/README.md b/README.md index 86c1cc33dd..8248f30942 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ sum(3, 4); // 7 metacall main.js ``` -**MetaCall** is a extensible, embeddable and interoperable cross-platform polyglot runtime. It supports NodeJS, Vanilla JavaScript, TypeScript, Python, Ruby, C#, Java, WASM, Go, C, C++, Rust, D, Cobol [and more](https://github.com/metacall/core/blob/develop/docs/README.md#2-language-support). +**MetaCall** is an extensible, embeddable, and interoperable cross-platform polyglot runtime. It supports NodeJS, Vanilla JavaScript, TypeScript, Python, Ruby, C#, Java, WASM, Go, C, C++, Rust, D, Cobol [and more](https://github.com/metacall/core/blob/develop/docs/README.md#2-language-support). ## Install diff --git a/VERSION b/VERSION index da2ac9c7e6..6f16bd3257 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.5 \ No newline at end of file +0.9.15 \ No newline at end of file diff --git a/cmake/CMakeDebug.cmake b/cmake/CMakeDebug.cmake index b11e8bab91..dd80a221b9 100644 --- a/cmake/CMakeDebug.cmake +++ b/cmake/CMakeDebug.cmake @@ -2,7 +2,7 @@ # CMake Debug Utilities by Parra Studios # CMake debugging utilities and inspection facilities. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/CheckCCompilerFlagStackSmashing.cmake b/cmake/CheckCCompilerFlagStackSmashing.cmake index 1c9c541978..ea31ed5d77 100644 --- a/cmake/CheckCCompilerFlagStackSmashing.cmake +++ b/cmake/CheckCCompilerFlagStackSmashing.cmake @@ -2,7 +2,7 @@ # Compiler checker for stack smashing flags by Parra Studios # Tests if a defined stack smashing security flag is available. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/CheckCXXCompilerFlagStackSmashing.cmake b/cmake/CheckCXXCompilerFlagStackSmashing.cmake index 83b6178393..9fa7f95891 100644 --- a/cmake/CheckCXXCompilerFlagStackSmashing.cmake +++ b/cmake/CheckCXXCompilerFlagStackSmashing.cmake @@ -2,7 +2,7 @@ # Compiler checker for stack smashing flags by Parra Studios # Tests if a defined stack smashing security flag is available. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/CompileOptions.cmake b/cmake/CompileOptions.cmake index f7cae28aa2..b3cd23a466 100644 --- a/cmake/CompileOptions.cmake +++ b/cmake/CompileOptions.cmake @@ -68,6 +68,47 @@ set(DEFAULT_INCLUDE_DIRECTORIES) # Libraries # +# Valgrind +if(OPTION_TEST_MEMORYCHECK) + set(MEMORYCHECK_COMPILE_DEFINITIONS + "__MEMORYCHECK__=1" + ) + + set(MEMORYCHECK_COMMAND_OPTIONS "--leak-check=full") + # set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --show-leak-kinds=all") + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --trace-children=yes") + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --show-reachable=yes") + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --track-origins=yes") + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --num-callers=100") + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --smc-check=all-non-file") # for JITs + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --suppressions=${CMAKE_SOURCE_DIR}/source/tests/memcheck/valgrind-dl.supp") + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --suppressions=${CMAKE_SOURCE_DIR}/source/tests/memcheck/valgrind-python.supp") + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --suppressions=${CMAKE_SOURCE_DIR}/source/tests/memcheck/valgrind-node.supp") + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --suppressions=${CMAKE_SOURCE_DIR}/source/tests/memcheck/valgrind-wasm.supp") + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --suppressions=${CMAKE_SOURCE_DIR}/source/tests/memcheck/valgrind-wasm.supp") + + # TODO: Implement automatic detection for valgrind suppressions and create a proper test suite for the CI + set(MEMORYCHECK_ADDITIONAL_SUPPRESSIONS + "/usr/lib/valgrind/python3.supp" + "/usr/lib/valgrind/debian.supp" + ) + + foreach(SUPPRESSION ${MEMORYCHECK_ADDITIONAL_SUPPRESSIONS}) + if(EXISTS "${SUPPRESSION}") + set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --suppressions=${SUPPRESSION}") + endif() + endforeach() + + # This is needed in order to allow valgrind to properly track malloc in Python + set(TESTS_MEMCHECK_ENVIRONMENT_VARIABLES + "PYTHONMALLOC=malloc" + ) +else() + set(MEMORYCHECK_COMPILE_DEFINITIONS) + set(MEMORYCHECK_COMMAND_OPTIONS) + set(TESTS_MEMCHECK_ENVIRONMENT_VARIABLES) +endif() + # ThreadSanitizer is incompatible with AddressSanitizer and LeakSanitizer if(OPTION_BUILD_THREAD_SANITIZER AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) set(SANITIZER_LIBRARIES -ltsan) @@ -89,12 +130,14 @@ elseif(OPTION_BUILD_ADDRESS_SANITIZER AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR set(TESTS_SANITIZER_ENVIRONMENT_VARIABLES "LSAN_OPTIONS=verbosity=1:log_threads=1:print_suppressions=false:suppressions=${CMAKE_SOURCE_DIR}/source/tests/sanitizer/lsan.supp" - # Specify use_sigaltstack=0 as CoreCLR uses own alternate stack for signal handlers (https://github.com/swgillespie/coreclr/commit/bec020aa466d08e49e007d0011b0e79f8f7c7a62) - # "ASAN_OPTIONS=use_sigaltstack=0:symbolize=1:alloc_dealloc_mismatch=0:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:fast_unwind_on_malloc=0" - # Specify handle_segv=0 and detect_leaks=0 for the JVM (https://blog.gypsyengineer.com/en/security/running-java-with-addresssanitizer.html) - # "ASAN_OPTIONS=detect_leaks=0:handle_segv=0:symbolize=1:alloc_dealloc_mismatch=0:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:fast_unwind_on_malloc=0" + # "ASAN_OPTIONS=handle_segv=0:symbolize=1:alloc_dealloc_mismatch=0:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:fast_unwind_on_malloc=0" + + # TODO: We should document each flag why is it used, because now we do not know what runtime has each requirement and why. + # Another option should be to separate by runtimes and only set up them on the ASAN tests that require them, + # because we do not need to disable all features on all tests, this may hide bugs in the core library for example. + # Specify use_sigaltstack=0 as CoreCLR uses own alternate stack for signal handlers (https://github.com/swgillespie/coreclr/commit/bec020aa466d08e49e007d0011b0e79f8f7c7a62) "ASAN_OPTIONS=use_sigaltstack=0:symbolize=1:alloc_dealloc_mismatch=0:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:fast_unwind_on_malloc=0" ) set(SANITIZER_COMPILE_DEFINITIONS @@ -106,6 +149,72 @@ else() set(SANITIZER_COMPILE_DEFINITIONS) endif() +function(find_sanitizer NAME LINK_OPTION) + string(TOUPPER "${NAME}" NAME_UPPER) + set(SANITIZER_PROGRAM_CODE "int main() {return 0;}") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sanitizer_locate.cpp" "${SANITIZER_PROGRAM_CODE}") + + try_compile( + STATUS + ${PROJECT_OUTPUT_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/sanitizer_locate.cpp + OUTPUT_VARIABLE SANITIZER_COMPILER_OUTPUT + LINK_OPTIONS ${LINK_OPTION} + COPY_FILE ${CMAKE_CURRENT_BINARY_DIR}/sanitizer_locate + ) + + if(NOT STATUS) + message(FATAL_ERROR "Could not find location for lib${NAME}: ${SANITIZER_COMPILER_OUTPUT}") + return() + endif() + + file(GET_RUNTIME_DEPENDENCIES + EXECUTABLES ${CMAKE_CURRENT_BINARY_DIR}/sanitizer_locate + RESOLVED_DEPENDENCIES_VAR SANITIZER_PROGRAM_LIBRARIES + ) + + foreach(DEPENDENCY IN LISTS SANITIZER_PROGRAM_LIBRARIES) + string(FIND "${DEPENDENCY}" "${NAME}" POSITION) + if(POSITION GREATER -1) + set(LIB${NAME_UPPER}_PATH "${DEPENDENCY}" PARENT_SCOPE) + return() + endif() + endforeach() +endfunction() + +if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + if(OPTION_BUILD_THREAD_SANITIZER) + find_sanitizer(tsan -fsanitize=thread) + set(SANITIZER_LIBRARIES_PATH + "${LIBTSAN_PATH}" + ) + elseif(OPTION_BUILD_MEMORY_SANITIZER) + set(SANITIZER_LIBRARIES_PATH) # TODO + elseif(OPTION_BUILD_ADDRESS_SANITIZER) + find_sanitizer(asan -fsanitize=address) + find_sanitizer(ubsan -fsanitize=undefined) + set(SANITIZER_LIBRARIES_PATH + "${LIBASAN_PATH}" + "${LIBUBSAN_PATH}" + ) + endif() +endif() + +if(SANITIZER_LIBRARIES_PATH) + if(PROJECT_OS_LINUX) + list(JOIN SANITIZER_LIBRARIES_PATH " " SANITIZER_LIBRARIES_PATH_JOINED) + set(TESTS_SANITIZER_PRELOAD_ENVIRONMENT_VARIABLES + "LD_PRELOAD=${SANITIZER_LIBRARIES_PATH_JOINED}" + ) + elseif(PROJECT_OS_FAMILY MATCHES "macos") + list(JOIN SANITIZER_LIBRARIES_PATH ":" SANITIZER_LIBRARIES_PATH_JOINED) + set(TESTS_SANITIZER_PRELOAD_ENVIRONMENT_VARIABLES + "DYLD_INSERT_LIBRARIES=${SANITIZER_LIBRARIES_PATH_JOINED}" + "DYLD_FORCE_FLAT_NAMESPACE=1" + ) + endif() +endif() + if((PROJECT_OS_WIN AND MSVC) OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # MSVC and Clang do not require to link manually the sanitizer libraries set(SANITIZER_LIBRARIES) @@ -136,6 +245,7 @@ set(DEFAULT_COMPILE_DEFINITIONS LOG_POLICY_FORMAT_PRETTY=${LOG_POLICY_FORMAT_PRETTY_VALUE} REFLECT_MEMORY_TRACKER=${REFLECT_MEMORY_TRACKER_VALUE} SYSTEM_${SYSTEM_NAME_UPPER} + ${MEMORYCHECK_COMPILE_DEFINITIONS} ${SANITIZER_COMPILE_DEFINITIONS} ) @@ -209,14 +319,14 @@ if(WIN32 AND MSVC) add_compile_options(/Oy) # TODO: Disable runtime checks (not compatible with O2) - # foreach(FLAG_VAR + # foreach(COMPILER_FLAGS # CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE # CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO # CMAKE_C_FLAGS CMAKE_C_FLAGS_RELEASE # CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO # ) - # string(REGEX REPLACE "/RTC[^ ]*" "" ${FLAG_VAR} "${${FLAG_VAR}}") - # endforeach(FLAG_VAR) + # string(REGEX REPLACE "/RTC[^ ]*" "" ${COMPILER_FLAGS} "${${COMPILER_FLAGS}}") + # endforeach(COMPILER_FLAGS) if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") # Enable debug symbols @@ -227,7 +337,6 @@ if(WIN32 AND MSVC) # Sanitizers if(OPTION_BUILD_THREAD_SANITIZER AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) add_compile_options(/fsanitize=thread) - # add_compile_options(/fsanitize=undefined) add_link_options(/INCREMENTAL:NO) elseif(OPTION_BUILD_ADDRESS_SANITIZER AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) add_compile_options(/fsanitize=address) @@ -238,6 +347,7 @@ if(WIN32 AND MSVC) add_compile_options(/fsanitize=leak) add_link_options(/INCREMENTAL:NO) endif() + endif() if (PROJECT_OS_FAMILY MATCHES "unix" OR PROJECT_OS_FAMILY MATCHES "macos") @@ -317,6 +427,55 @@ if (PROJECT_OS_FAMILY MATCHES "unix" OR PROJECT_OS_FAMILY MATCHES "macos") endif() endif() +macro(check_symbol_executable symbol binary_path result_var) + if(WIN32) + find_program(DUMPBIN_EXECUTABLE dumpbin) + if(NOT DUMPBIN_EXECUTABLE) + message(FATAL_ERROR "Trying to find symbol ${symbol} in ${binary_path} but dumpbin was not found") + endif() + execute_process( + COMMAND ${DUMPBIN_EXECUTABLE} /symbols ${binary_path} + OUTPUT_VARIABLE dumpbin_output + RESULT_VARIABLE dumpbin_result + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(FIND "${dumpbin_output}" symbol SYMBOL_FOUND) + if(NOT SYMBOL_FOUND EQUAL -1) + set(${result_var} TRUE PARENT_SCOPE) + else() + set(${result_var} FALSE PARENT_SCOPE) + endif() + else() + find_program(NM_EXECUTABLE nm) + if(NM_EXECUTABLE) + execute_process( + COMMAND ${NM_EXECUTABLE} -D ${binary_path} + OUTPUT_VARIABLE nm_output + RESULT_VARIABLE nm_result + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(FIND "${nm_output}" symbol SYMBOL_FOUND) + if(NOT SYMBOL_FOUND EQUAL -1) + set(${result_var} TRUE PARENT_SCOPE) + else() + set(${result_var} FALSE PARENT_SCOPE) + endif() + else() + message(FATAL_ERROR "Trying to find symbol ${symbol} in ${binary_path} but nm was not found") + endif() + endif() +endmacro() + +function(check_asan_executable binary_path result_var) + check_symbol_executable("__asan_init" "${binary_path}" ${result_var}) +endfunction() + +function(check_tsan_executable binary_path result_var) + check_symbol_executable("__tsan_init" "${binary_path}" ${result_var}) +endfunction() + # # Linker options # diff --git a/cmake/Coverage.cmake b/cmake/Coverage.cmake new file mode 100644 index 0000000000..4a15b0efcb --- /dev/null +++ b/cmake/Coverage.cmake @@ -0,0 +1,48 @@ +# +# Coverage CMake support by Parra Studios +# Cross-compiler code coverage utility. +# +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if(NOT OPTION_COVERAGE) + return() +endif() + +include(CTest) + +if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") +endif() + +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") +endif() + +if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage") +endif() + +if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR + "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -fprofile-instr-generate -fcoverage-mapping") +endif() + +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-elide-constructors -fprofile-instr-generate -fcoverage-mapping") +endif() diff --git a/cmake/FindCobol.cmake b/cmake/FindCobol.cmake index a1fd13103b..c85a5cb466 100644 --- a/cmake/FindCobol.cmake +++ b/cmake/FindCobol.cmake @@ -2,7 +2,7 @@ # CMake Find GNU/Cobol by Parra Studios # CMake script to find GNU/Cobol compiler and runtime. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindCoreCLR.cmake b/cmake/FindCoreCLR.cmake index 62bda548cd..884d3c1132 100644 --- a/cmake/FindCoreCLR.cmake +++ b/cmake/FindCoreCLR.cmake @@ -2,7 +2,7 @@ # CMake Find CoreCLR NET Engine by Parra Studios # CMake script to find CoreCLR NET Engine. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -24,8 +24,6 @@ # CORECLR_LIBRARIES - List of CoreCLR libraries # CORECLR_CGINFO - List of CoreCLR libraries - - # Prevent vervosity if already included if(CORECLR_FOUND) set(CORECLR_FIND_QUIETLY TRUE) diff --git a/cmake/FindDotNET.cmake b/cmake/FindDotNET.cmake index f71040876e..57c2d4dc95 100644 --- a/cmake/FindDotNET.cmake +++ b/cmake/FindDotNET.cmake @@ -2,7 +2,7 @@ # CMake Find Dot NET Engine by Parra Studios # CMake script to find DotNET Engine. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindGBench.cmake b/cmake/FindGBench.cmake index cf8ac278bd..74eacb0b8a 100644 --- a/cmake/FindGBench.cmake +++ b/cmake/FindGBench.cmake @@ -2,7 +2,7 @@ # CMake Find Google Benchmark by Parra Studios # CMake script to find Google Benchmark library. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindJulia.cmake b/cmake/FindJulia.cmake index c8b004c063..bf3c30d3b8 100644 --- a/cmake/FindJulia.cmake +++ b/cmake/FindJulia.cmake @@ -2,7 +2,7 @@ # CMake Find Julia Runtime by Parra Studios # CMake script to find Julia runtime. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindLibClang.cmake b/cmake/FindLibClang.cmake index c33d930368..bbf4d2c25f 100644 --- a/cmake/FindLibClang.cmake +++ b/cmake/FindLibClang.cmake @@ -2,7 +2,7 @@ # CMake Find Clang library by Parra Studios # CMake script to find Clang C API library. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -34,7 +34,7 @@ option(LibClang_CMAKE_DEBUG "Print paths for debugging LibClang dependencies." O if(LibClang_FIND_VERSION) set(LibClang_VERSION_LIST ${LibClang_FIND_VERSION}) else() - set(LibClang_VERSION_LIST 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8) + set(LibClang_VERSION_LIST 17 16 15 14 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8) endif() macro(_libclang_generate_search_paths template result) diff --git a/cmake/FindLibFFI.cmake b/cmake/FindLibFFI.cmake index 8600a17549..313925b13e 100644 --- a/cmake/FindLibFFI.cmake +++ b/cmake/FindLibFFI.cmake @@ -2,7 +2,7 @@ # CMake Find Foreing Function Interface library by Parra Studios # CMake script to find FFI library. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindLibGit2.cmake b/cmake/FindLibGit2.cmake new file mode 100644 index 0000000000..cb1c0cf0a1 --- /dev/null +++ b/cmake/FindLibGit2.cmake @@ -0,0 +1,82 @@ +# +# CMake Find LibGit2 Library by Parra Studios +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia +# + +# Find libgit2 library and include paths +# +# LibGit2_FOUND - True if LibGit2 was found +# LibGit2_INCLUDE_DIR - LibGit2 headers path +# LibGit2_VERSION - LibGit2 version +# LibGit2_VERSION_MAJOR - LibGit2 major version +# LibGit2_VERSION_MINOR - LibGit2 minor version +# LibGit2_VERSION_REVISION - LibGit2 patch version +# LibGit2_LIBRARY - LibGit2 shared library +# LibGit2_LIBRARY_DIR - LibGit2 shared library folder +# + +# Prevent vervosity if already included +if(LibGit2_LIBRARY) + set(LibGit2_FIND_QUIETLY TRUE) +endif() + +# Include package manager +include(FindPackageHandleStandardArgs) + +# Find via PkgConfig +find_package(PkgConfig QUIET) +pkg_check_modules(PKG_GIT2 QUIET libgit2) + +if(NOT PKG_GIT2_FOUND) + return() +endif() + +if(NOT LibGit2_DEFINITIONS) + set(LibGit2_DEFINITIONS ${PKG_GIT2_CFLAGS_OTHER}) +endif() + +if(NOT LibGit2_INCLUDE_DIR) + find_path(LibGit2_INCLUDE_DIR + NAMES git2.h + HINTS ${PKG_GIT2_INCLUDE_DIRS} + ) +endif() + +if(NOT LibGit2_VERSION AND LibGit2_INCLUDE_DIR) + file(STRINGS "${LibGit2_INCLUDE_DIR}/git2/version.h" LibGit2_VERSION_MAJOR REGEX "^#define LIBGIT2_VER_MAJOR +([0-9]+)") + string(REGEX MATCH "([0-9]+)$" LibGit2_VERSION_MAJOR "${LibGit2_VERSION_MAJOR}") + + file(STRINGS "${LibGit2_INCLUDE_DIR}/git2/version.h" LibGit2_VERSION_MINOR REGEX "^#define LIBGIT2_VER_MINOR +([0-9]+)") + string(REGEX MATCH "([0-9]+)$" LibGit2_VERSION_MINOR "${LibGit2_VERSION_MINOR}") + + file(STRINGS "${LibGit2_INCLUDE_DIR}/git2/version.h" LibGit2_VERSION_REVISION REGEX "^#define LIBGIT2_VER_REVISION +([0-9]+)") + string(REGEX MATCH "([0-9]+)$" LibGit2_VERSION_REVISION "${LibGit2_VERSION_REVISION}") + + set(LibGit2_VERSION "${LibGit2_VERSION_MAJOR}.${LibGit2_VERSION_MINOR}.${LibGit2_VERSION_REVISION}") +endif() + +if(NOT LibGit2_LIBRARY) + find_library(LibGit2_LIBRARY + NAMES git2 + HINTS ${PKG_GIT2_LIBRARY_DIRS} + ) +endif() + +set(LibGit2_LIBRARIES ${LibGit2_LIBRARY}) +set(LibGit2_INCLUDE_DIRS ${LibGit2_INCLUDE_DIR}) +get_filename_component(LibGit2_LIBRARY_DIR ${LibGit2_LIBRARY} DIRECTORY) + +# Define package +find_package_handle_standard_args(LibGit2 + FOUND_VAR + LibGit2_FOUND + REQUIRED_VARS + LibGit2_LIBRARY + LibGit2_LIBRARY_DIR + LibGit2_INCLUDE_DIR + LibGit2_INCLUDE_DIRS + VERSION_VAR + LibGit2_VERSION +) + +mark_as_advanced(LibGit2_LIBRARY LibGit2_LIBRARY_DIR LibGit2_INCLUDE_DIR) diff --git a/cmake/FindLibTCC.cmake b/cmake/FindLibTCC.cmake index fea97d2b81..83c2e4ac59 100644 --- a/cmake/FindLibTCC.cmake +++ b/cmake/FindLibTCC.cmake @@ -2,7 +2,7 @@ # CMake Find Tiny C Compiler library by Parra Studios # CMake script to find TCC library. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindMetaCall.cmake b/cmake/FindMetaCall.cmake index 2728f242a6..f974e9509d 100644 --- a/cmake/FindMetaCall.cmake +++ b/cmake/FindMetaCall.cmake @@ -2,7 +2,7 @@ # CMake Find MetaCall library by Parra Studios # CMake script to find and include MetaCall library for development. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindNPM.cmake b/cmake/FindNPM.cmake index c98a5d23aa..2a61990e25 100644 --- a/cmake/FindNPM.cmake +++ b/cmake/FindNPM.cmake @@ -2,7 +2,7 @@ # CMake Find NPM by Parra Studios # CMake script to find NodeJS Package Manager. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindNodeJS.cmake b/cmake/FindNodeJS.cmake index f369a40b52..6cea42bf48 100644 --- a/cmake/FindNodeJS.cmake +++ b/cmake/FindNodeJS.cmake @@ -1,6 +1,6 @@ # # CMake Find NodeJS JavaScript Runtime by Parra Studios -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Find NodeJS executable and include paths @@ -289,10 +289,17 @@ if(NodeJS_INCLUDE_DIR) # Get node module version find_file(NodeJS_VERSION_FILE_PATH node_version.h PATHS ${NodeJS_INCLUDE_DIR} - PATH_SUFFIXES ${NodeJS_INCLUDE_SUFFIXES} DOC "NodeJS JavaScript Version Header" ) + if(NOT NodeJS_VERSION_FILE_PATH) + find_file(NodeJS_VERSION_FILE_PATH node_version.h + PATHS ${NodeJS_INCLUDE_DIR} + PATH_SUFFIXES ${NodeJS_INCLUDE_SUFFIXES} + DOC "NodeJS JavaScript Version Header" + ) + endif() + if(NodeJS_VERSION_FILE_PATH) file(READ ${NodeJS_VERSION_FILE_PATH} NodeJS_VERSION_FILE) @@ -367,21 +374,30 @@ if(NodeJS_MODULE_VERSION) if(NOT NodeJS_BUILD_FROM_SOURCE) message(STATUS "Searching NodeJS library version ${NodeJS_MODULE_VERSION}") - if(WIN32) - set(NodeJS_LIBRARY_PATH "C:/Program Files/nodejs") - else() - set(NodeJS_LIBRARY_PATH "/usr/local/lib") - endif() - - set(NodeJS_SYSTEM_LIBRARY_PATH "/lib/x86_64-linux-gnu" "/usr/lib/x86_64-linux-gnu") # TODO: Add others - # Find library find_library(NodeJS_LIBRARY NAMES ${NodeJS_LIBRARY_NAMES} - PATHS ${NodeJS_LIBRARY_PATH} ${NodeJS_SYSTEM_LIBRARY_PATH} + HINTS ${NodeJS_PATHS} + PATH_SUFFIXES lib DOC "NodeJS JavaScript Runtime Library" ) + if(NOT NodeJS_LIBRARY) + if(WIN32) + set(NodeJS_LIBRARY_PATH "C:/Program Files/nodejs") + else() + set(NodeJS_LIBRARY_PATH "/usr/local/lib" "/usr/lib") + endif() + + set(NodeJS_SYSTEM_LIBRARY_PATH "/lib/x86_64-linux-gnu" "/usr/lib/x86_64-linux-gnu") # TODO: Add others + + find_library(NodeJS_LIBRARY + NAMES ${NodeJS_LIBRARY_NAMES} + PATHS ${NodeJS_LIBRARY_PATH} ${NodeJS_SYSTEM_LIBRARY_PATH} + DOC "NodeJS JavaScript Runtime Library" + ) + endif() + if(NodeJS_LIBRARY) message(STATUS "NodeJS Library Found") endif() @@ -437,7 +453,9 @@ if(NOT NodeJS_LIBRARY) endif() # Check for Visual Studio Version and configure the build command - if(MSVC_VERSION GREATER 1916) + if(MSVC_VERSION GREATER_EQUAL 1930) + set(NodeJS_MSVC_VER vs2022) + elseif(MSVC_VERSION GREATER_EQUAL 1920) set(NodeJS_MSVC_VER vs2019) elseif(MSVC_VERSION GREATER 1900) set(NodeJS_MSVC_VER vs2017) @@ -489,9 +507,7 @@ if(NOT NodeJS_LIBRARY) # Copy library to MetaCall output path execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_OUTPUT_DIR}) - file(COPY ${NodeJS_COMPILE_PATH}/${NodeJS_LIBRARY_NAME} DESTINATION ${PROJECT_OUTPUT_DIR}) - - message(STATUS "Install NodeJS shared library") + file(COPY "${NodeJS_COMPILE_PATH}/${NodeJS_LIBRARY_NAME}" DESTINATION ${PROJECT_OUTPUT_DIR}) endif() else() message(STATUS "Configure NodeJS shared library") @@ -500,7 +516,9 @@ if(NOT NodeJS_LIBRARY) set(BUILD_ICU_FLAGS "--without-intl") else() # Select the ICU library depending on the NodeJS version - if("${NodeJS_VERSION_MAJOR}" GREATER_EQUAL "18") + if("${NodeJS_VERSION_MAJOR}" GREATER_EQUAL "20") + set(ICU_URL "https://github.com/unicode-org/icu/releases/download/release-73-1/icu4c-73_1-src.zip") + elseif("${NodeJS_VERSION_MAJOR}" GREATER_EQUAL "18") set(ICU_URL "https://github.com/unicode-org/icu/releases/download/release-72-1/icu4c-72_1-src.zip") elseif("${NodeJS_VERSION_MAJOR}" GREATER_EQUAL "16") set(ICU_URL "https://github.com/unicode-org/icu/releases/download/release-69-1/icu4c-69_1-src.zip") @@ -514,6 +532,17 @@ if(NOT NodeJS_LIBRARY) set(ICU_URL "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-src.zip") endif() + # Workaround for configure bug: ERROR: Could not load deps/icu/source/common/unicode/uvernum.h - is ICU installed? + if("${NodeJS_VERSION_MAJOR}" GREATER_EQUAL "18") + set(NodeJS_ICU_DOWNLOAD_FILE "${NodeJS_BASE_PATH}/icu4c-src.zip") + file(DOWNLOAD ${ICU_URL} "${NodeJS_ICU_DOWNLOAD_FILE}") + execute_process( + WORKING_DIRECTORY "${NodeJS_OUTPUT_PATH}/deps" + COMMAND ${CMAKE_COMMAND} -E tar xzf "${NodeJS_ICU_DOWNLOAD_FILE}" + ) + set(ICU_URL "${NodeJS_OUTPUT_PATH}/deps/icu") + endif() + # Workaround for OpenSSL bug: https://github.com/metacall/core/issues/223 if(APPLE) set(ICU_ENV_VAR ${CMAKE_COMMAND} -E env PYTHONHTTPSVERIFY=0) @@ -530,45 +559,59 @@ if(NOT NodeJS_LIBRARY) set(NodeJS_PREFIX) endif() + set(BUILD_DEBUG) + set(BUILD_DEBUG_ASAN) + set(BUILD_DEBUG_ASAN_OPTIONS) + if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(BUILD_DEBUG "--debug") + set(BUILD_DEBUG --debug) if(OPTION_BUILD_ADDRESS_SANITIZER) - set(BUILD_DEBUG "${BUILD_DEBUG} --enable-asan") + set(BUILD_DEBUG_ASAN --enable-asan) + + if("${NodeJS_VERSION_MAJOR}" GREATER_EQUAL "20") + set(BUILD_DEBUG_ASAN_OPTIONS ${CMAKE_COMMAND} -E env ASAN_OPTIONS=detect_container_overflow=0) + endif() endif() - else() - set(BUILD_DEBUG) endif() - execute_process(COMMAND ${ICU_ENV_VAR} sh -c "./configure ${NodeJS_PREFIX} ${BUILD_ICU_FLAGS} --shared ${BUILD_DEBUG}" WORKING_DIRECTORY "${NodeJS_OUTPUT_PATH}") + execute_process( + WORKING_DIRECTORY "${NodeJS_OUTPUT_PATH}" + COMMAND ${ICU_ENV_VAR} ./configure ${NodeJS_PREFIX} ${BUILD_ICU_FLAGS} --shared ${BUILD_DEBUG} ${BUILD_DEBUG_ASAN} + ) message(STATUS "Build NodeJS shared library") + # Create build output directory + execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${NodeJS_OUTPUT_PATH}/out) + include(ProcessorCount) ProcessorCount(N) - if(NOT N EQUAL 0) - execute_process(COMMAND sh -c "make -j${N} -C out BUILDTYPE=${CMAKE_BUILD_TYPE} V=1" WORKING_DIRECTORY "${NodeJS_OUTPUT_PATH}") + if(N GREATER 1) + execute_process( + WORKING_DIRECTORY "${NodeJS_OUTPUT_PATH}" + COMMAND ${BUILD_DEBUG_ASAN_OPTIONS} make -j${N} -C ${NodeJS_OUTPUT_PATH}/out BUILDTYPE=${CMAKE_BUILD_TYPE} V=1 + ) else() - execute_process(COMMAND sh -c "make -C out BUILDTYPE=${CMAKE_BUILD_TYPE} V=1" WORKING_DIRECTORY "${NodeJS_OUTPUT_PATH}") + execute_process( + WORKING_DIRECTORY "${NodeJS_OUTPUT_PATH}" + COMMAND ${BUILD_DEBUG_ASAN_OPTIONS} make -C ${NodeJS_OUTPUT_PATH}/out BUILDTYPE=${CMAKE_BUILD_TYPE} V=1 + ) endif() - - message(STATUS "Install NodeJS shared library") - - execute_process(COMMAND sh -c "make install" WORKING_DIRECTORY "${NodeJS_OUTPUT_PATH}") endif() endif() # Set up the compile path in case of prefix is specified if(NOT WIN32 AND NOT MSVC AND NodeJS_INSTALL_PREFIX) - set(NodeJS_COMPILE_PATH "${NodeJS_INSTALL_PREFIX}/lib") + set(NodeJS_COMPILE_PREFIX_PATH "${NodeJS_INSTALL_PREFIX}/lib") endif() # Find compiled library find_library(NodeJS_LIBRARY NAMES ${NodeJS_LIBRARY_NAMES} - PATHS ${NodeJS_COMPILE_PATH} + PATHS ${NodeJS_COMPILE_PATH} ${NodeJS_COMPILE_PREFIX_PATH} DOC "NodeJS JavaScript Runtime Library" NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH @@ -576,6 +619,8 @@ if(NOT NodeJS_LIBRARY) if(NOT NodeJS_LIBRARY) message(FATAL_ERROR "NodeJS library not found and it could not be built from source") + else() + set(NodeJS_BUILD_FROM_SOURCE TRUE) endif() endif() diff --git a/cmake/FindPatchelf.cmake b/cmake/FindPatchelf.cmake index 84d6a28393..044cd412d0 100644 --- a/cmake/FindPatchelf.cmake +++ b/cmake/FindPatchelf.cmake @@ -2,7 +2,7 @@ # CMake Find Patchelf by Parra Studios # CMake script to find Patchelf executable. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindRapidJSON.cmake b/cmake/FindRapidJSON.cmake index eb5fb5fd49..26b0d6b1e1 100644 --- a/cmake/FindRapidJSON.cmake +++ b/cmake/FindRapidJSON.cmake @@ -2,7 +2,7 @@ # CMake Find RapidJSON by Parra Studios # CMake script to find RapidJSON library. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindRust.cmake b/cmake/FindRust.cmake index 32579029aa..c9ef316aa2 100644 --- a/cmake/FindRust.cmake +++ b/cmake/FindRust.cmake @@ -2,7 +2,7 @@ # CMake Find Rust by Parra Studios # CMake script to find Rust compiler and tools. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindSpiderMonkey.cmake b/cmake/FindSpiderMonkey.cmake index 60cea0f418..a952c9e4e9 100644 --- a/cmake/FindSpiderMonkey.cmake +++ b/cmake/FindSpiderMonkey.cmake @@ -2,7 +2,7 @@ # CMake Find Mozilla SpiderMonkey JavaScript Engine by Parra Studios # CMake script to find Mozilla SpiderMonkey Javascript Engine. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindV8.cmake b/cmake/FindV8.cmake index c7875b5094..aedb8a8d7d 100644 --- a/cmake/FindV8.cmake +++ b/cmake/FindV8.cmake @@ -2,7 +2,7 @@ # CMake Find V8 Google JavaScript Engine by Parra Studios # CMake script to find V8 JavaScript Engine. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindWasmtime.cmake b/cmake/FindWasmtime.cmake index 964a8e7922..bf086293a9 100644 --- a/cmake/FindWasmtime.cmake +++ b/cmake/FindWasmtime.cmake @@ -1,6 +1,6 @@ # # CMake Find Wasmtime WebAssembly Runtime by Parra Studios -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Find Wasmtime library and include paths diff --git a/cmake/FindZig.cmake b/cmake/FindZig.cmake new file mode 100644 index 0000000000..cb2764032c --- /dev/null +++ b/cmake/FindZig.cmake @@ -0,0 +1,47 @@ +# +# CMake Find Zig by Parra Studios +# CMake script to find Zig compiler and tools. +# +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Find Zig executables and paths +# +# Zig_FOUND - True if Zig was found +# Zig_COMPILER_EXECUTABLE - Zig compiler executable path + +# Options +# +# Zig_CMAKE_DEBUG - Print the debug information and all constants values + +option(Zig_CMAKE_DEBUG "Show full output of the Zig related commands for debugging." OFF) + +find_program(Zig_COMPILER_EXECUTABLE zig +) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(Zig + FOUND_VAR Zig_FOUND +) + +mark_as_advanced( + Zig_FOUND + Zig_COMPILER_EXECUTABLE +) + +if(Zig_CMAKE_DEBUG) + message(STATUS "Zig_COMPILER_EXECUTABLE: ${Zig_COMPILER_EXECUTABLE}") +endif() diff --git a/cmake/InstallGBench.cmake b/cmake/InstallGBench.cmake index 5e0a69123d..ccf3073d7a 100644 --- a/cmake/InstallGBench.cmake +++ b/cmake/InstallGBench.cmake @@ -2,7 +2,7 @@ # CMake Install Google Benchmark by Parra Studios # CMake script to install Google Benchmark library. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/InstallGTest.cmake b/cmake/InstallGTest.cmake index 7c867827f8..45fdf569c9 100644 --- a/cmake/InstallGTest.cmake +++ b/cmake/InstallGTest.cmake @@ -2,7 +2,7 @@ # CMake Install Google Test by Parra Studios # CMake script to install Google Test library. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ if(NOT GTEST_FOUND OR USE_BUNDLED_GTEST) if(NOT GTEST_VERSION OR USE_BUNDLED_GTEST) - set(GTEST_VERSION 1.11.0) + set(GTEST_VERSION 1.16.0) endif() find_package(Threads REQUIRED) @@ -35,10 +35,22 @@ if(NOT GTEST_FOUND OR USE_BUNDLED_GTEST) set(GTEST_DISABLE_PTHREADS OFF) endif() + if(MSVC AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) + if(OPTION_BUILD_THREAD_SANITIZER) + set(SANITIZER_FLAGS -DCMAKE_CXX_FLAGS=/fsanitize=thread -DCMAKE_C_FLAGS=/fsanitize=thread) + endif() + if(OPTION_BUILD_ADDRESS_SANITIZER) + set(SANITIZER_FLAGS -DCMAKE_CXX_FLAGS=/fsanitize=address -DCMAKE_C_FLAGS=/fsanitize=address) + endif() + if(OPTION_BUILD_MEMORY_SANITIZER) + set(SANITIZER_FLAGS -DCMAKE_CXX_FLAGS="/fsanitize=memory /fsanitize=leak" -DCMAKE_C_FLAGS="/fsanitize=memory /fsanitize=leak") + endif() + endif() + # Import Google Test Framework ExternalProject_Add(google-test-depends GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-${GTEST_VERSION} + GIT_TAG v${GTEST_VERSION} CMAKE_ARGS -Dgtest_build_samples=OFF -Dgtest_build_tests=OFF @@ -48,6 +60,7 @@ if(NOT GTEST_FOUND OR USE_BUNDLED_GTEST) -DINSTALL_GTEST=OFF -DBUILD_GMOCK=ON -Dgmock_build_tests=OFF + ${SANITIZER_FLAGS} PREFIX "${CMAKE_CURRENT_BINARY_DIR}" UPDATE_COMMAND "" INSTALL_COMMAND "" @@ -65,17 +78,11 @@ if(NOT GTEST_FOUND OR USE_BUNDLED_GTEST) set(GTEST_LIB_SUFFIX "lib") set(GTEST_LIBS_DIR "${binary_dir}/lib/${CMAKE_BUILD_TYPE}") set(GMOCK_LIBS_DIR "${binary_dir}/lib/${CMAKE_BUILD_TYPE}") - if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(GTEST_LIB_DEBUG "d") - else() - set(GTEST_LIB_DEBUG "") - endif() else() set(GTEST_LIB_PREFIX "lib") set(GTEST_LIB_SUFFIX "a") set(GTEST_LIBS_DIR "${binary_dir}/lib") set(GMOCK_LIBS_DIR "${binary_dir}/lib") - set(GTEST_LIB_DEBUG "") endif() # Define Paths @@ -85,11 +92,11 @@ if(NOT GTEST_FOUND OR USE_BUNDLED_GTEST) ) set(GTEST_LIBRARY - "${GTEST_LIBS_DIR}/${GTEST_LIB_PREFIX}gtest${GTEST_LIB_DEBUG}.${GTEST_LIB_SUFFIX}" + "${GTEST_LIBS_DIR}/${GTEST_LIB_PREFIX}gtest.${GTEST_LIB_SUFFIX}" ) set(GMOCK_LIBRARY - "${GMOCK_LIBS_DIR}/${GTEST_LIB_PREFIX}gmock${GTEST_LIB_DEBUG}.${GTEST_LIB_SUFFIX}" + "${GMOCK_LIBS_DIR}/${GTEST_LIB_PREFIX}gmock.${GTEST_LIB_SUFFIX}" ) set(GTEST_LIBRARIES diff --git a/cmake/InstallLibTCC.cmake b/cmake/InstallLibTCC.cmake index 52ffff18bc..23a780e264 100644 --- a/cmake/InstallLibTCC.cmake +++ b/cmake/InstallLibTCC.cmake @@ -2,7 +2,7 @@ # CMake Install Tiny C Compiler by Parra Studios # CMake script to install TCC library. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ if(PROJECT_OS_FAMILY STREQUAL unix) if(OPTION_BUILD_MUSL) set(LIBTCC_CONFIGURE ./configure --prefix=${LIBTCC_INSTALL_PREFIX} ${LIBTCC_DEBUG} --disable-static --config-musl) else() - set(LIBTCC_CONFIGURE ./configure --prefix=${LIBTCC_INSTALL_PREFIX} ${LIBTCC_DEBUG} --disable-static --with-libgcc --with-selinux) + set(LIBTCC_CONFIGURE ./configure --prefix=${LIBTCC_INSTALL_PREFIX} ${LIBTCC_DEBUG} --disable-static --with-selinux) endif() elseif(PROJECT_OS_FAMILY STREQUAL macos) # TODO: --disable-static is not working on MacOS, this should be reported or further investigated @@ -84,10 +84,10 @@ elseif(PROJECT_OS_FAMILY STREQUAL macos) # AddressSanitizer can not provide additional info. # SUMMARY: AddressSanitizer: BUS (libsystem_c.dylib:x86_64+0x3647db0f) in off32 - set(LIBTCC_CONFIGURE ./configure --prefix=${LIBTCC_INSTALL_PREFIX} ${LIBTCC_DEBUG} --enable-cross) # --disable-static + set(LIBTCC_CONFIGURE ./configure --prefix=${LIBTCC_INSTALL_PREFIX} ${LIBTCC_DEBUG}) # --disable-static elseif(PROJECT_OS_FAMILY STREQUAL win32) if(PROJECT_OS_NAME STREQUAL MinGW) - set(LIBTCC_CONFIGURE ./configure --prefix=${LIBTCC_INSTALL_PREFIX} ${LIBTCC_DEBUG} --config-mingw32 --disable-static --with-libgcc --with-selinux) + set(LIBTCC_CONFIGURE ./configure --prefix=${LIBTCC_INSTALL_PREFIX} ${LIBTCC_DEBUG} --config-mingw32 --disable-static) else() set(LIBTCC_CONFIGURE "") endif() @@ -125,7 +125,7 @@ else() endif() set(LIBTCC_TARGET libtcc-depends) -set(LIBTCC_COMMIT_SHA "afc1362") +set(LIBTCC_COMMIT_SHA "6ec4a10") if(PROJECT_OS_FAMILY STREQUAL macos) # TODO: --disable-static is not working on MacOS, this should be reported or further investigated, remove this when it is solved set(LIBTTC_LIBRARY_NAME "${CMAKE_STATIC_LIBRARY_PREFIX}tcc${CMAKE_STATIC_LIBRARY_SUFFIX}") @@ -146,7 +146,7 @@ set(LIBTTC_RUNTIME_FILES ExternalProject_Add(${LIBTCC_TARGET} DOWNLOAD_NAME tinycc.tar.gz URL https://github.com/metacall/tinycc/archive/${LIBTCC_COMMIT_SHA}.tar.gz - URL_MD5 5582b17ee5848aeec28bee13773843f7 + URL_MD5 1d25d1a07a39c6d6671b7221d5286dc1 CONFIGURE_COMMAND ${LIBTCC_CONFIGURE} BUILD_COMMAND ${LIBTCC_BUILD} BUILD_IN_SOURCE true diff --git a/cmake/InstallPatchelf.cmake b/cmake/InstallPatchelf.cmake index 98ecc4ca08..72b44a952d 100644 --- a/cmake/InstallPatchelf.cmake +++ b/cmake/InstallPatchelf.cmake @@ -2,7 +2,7 @@ # CMake Find Patchelf by Parra Studios # CMake script to find Patchelf executable. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/InstallRapidJSON.cmake b/cmake/InstallRapidJSON.cmake index 9aa784c580..f90dfc4a4e 100644 --- a/cmake/InstallRapidJSON.cmake +++ b/cmake/InstallRapidJSON.cmake @@ -2,7 +2,7 @@ # CMake Install RapidJSON by Parra Studios # CMake script to install RapidJSON library. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -24,25 +24,21 @@ if(NOT RAPIDJSON_FOUND OR USE_BUNDLED_RAPIDJSON) if(NOT RAPIDJSON_VERSION OR USE_BUNDLED_RAPIDJSON) - set(RAPIDJSON_VERSION 232389d) - set(RAPIDJSON_URL_MD5 577d3495a07b66fcd4a2866c93831bc4) + set(RAPIDJSON_VERSION 24b5e7a8b27f42fa16b96fc70aade9106cf7102f) endif() ExternalProject_Add(rapid-json-depends - DOWNLOAD_NAME RapidJSON-${RAPIDJSON_VERSION}.tar.gz - URL https://github.com/Tencent/rapidjson/archive/${RAPIDJSON_VERSION}.tar.gz - URL_MD5 ${RAPIDJSON_URL_MD5} - CMAKE_ARGS - -DCMAKE_INSTALL_PREFIX= - -DRAPIDJSON_BUILD_DOC=Off - -DRAPIDJSON_BUILD_EXAMPLES=Off - -DRAPIDJSON_BUILD_TESTS=Off - TEST_COMMAND "" + GIT_REPOSITORY "https://github.com/Tencent/rapidjson.git" + GIT_TAG "${RAPIDJSON_VERSION}" + BUILD_COMMAND "" + CONFIGURE_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" ) - ExternalProject_Get_Property(rapid-json-depends INSTALL_DIR) + ExternalProject_Get_Property(rapid-json-depends SOURCE_DIR) - set(RAPIDJSON_ROOT_DIR ${INSTALL_DIR}) + set(RAPIDJSON_ROOT_DIR ${SOURCE_DIR}) set(RAPIDJSON_INCLUDE_DIRS ${RAPIDJSON_ROOT_DIR}/include) set(RAPIDJSON_FOUND TRUE) diff --git a/cmake/Portability.cmake b/cmake/Portability.cmake index 5a0b4eecc5..556427b187 100644 --- a/cmake/Portability.cmake +++ b/cmake/Portability.cmake @@ -2,7 +2,7 @@ # Portability CMake support by Parra Studios # Cross-platform and architecture detection utility. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -146,11 +146,10 @@ set(PROJECT_ARCH_NAME ${CMAKE_SYSTEM_PROCESSOR}) # 32 or 64 bit Linux if(PROJECT_OS_LINUX) - if(${PROJECT_ARCH_NAME} STREQUAL "x86") + if (${PROJECT_ARCH_NAME} MATCHES "^(x86|i[3-6]86|x86_64)$" AND "${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") set(PROJECT_ARCH_32BIT TRUE BOOL INTERNAL) - endif() - - if(${PROJECT_ARCH_NAME} MATCHES "(x86_64)|(amd64)|(AMD64)") + set(PROJECT_ARCH_X86 TRUE BOOL INTERNAL) + elseif(${PROJECT_ARCH_NAME} MATCHES "(x86_64)|(amd64)|(AMD64)") set(PROJECT_ARCH_64BIT TRUE BOOL INTERNAL) set(PROJECT_ARCH_AMD64 TRUE BOOL INTERNAL) elseif(${PROJECT_ARCH_NAME} STREQUAL "aarch64") @@ -162,6 +161,7 @@ if(PROJECT_OS_LINUX) set(PROJECT_ARCH_64BIT TRUE BOOL INTERNAL) endif() + # Verify the architecture is correct if(PROJECT_ARCH_32BIT) if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4") message(STATUS "Linux ${PROJECT_ARCH_NAME} 32bit detected") @@ -183,7 +183,7 @@ endif() if(NOT PROJECT_ARCH_32BIT AND NOT PROJECT_ARCH_64BIT) if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4") message(STATUS "32bit architecture ${PROJECT_ARCH_NAME} detected") - set(PROJECT_ARCH_32BIT TRUE BOOL INTERNAL) + set(PROJECT_ARCH_32BIT TRUE BOOL INTERNAL) if(PROJECT_OS_WIN) set(WINXBITS Win32) @@ -191,7 +191,7 @@ if(NOT PROJECT_ARCH_32BIT AND NOT PROJECT_ARCH_64BIT) elseif("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") message(STATUS "64bit architecture ${PROJECT_ARCH_NAME} detected") - set(PROJECT_ARCH_64BIT TRUE BOOL INTERNAL) + set(PROJECT_ARCH_64BIT TRUE BOOL INTERNAL) if(PROJECT_OS_WIN) set(WINXBITS Win64) @@ -202,19 +202,6 @@ if(NOT PROJECT_ARCH_32BIT AND NOT PROJECT_ARCH_64BIT) endif() endif() -# Set the library directory suffix accordingly -#if(PROJECT_PROC_64BIT) -# # Set the install path to lib64 -# set(PROJECT_LIB_DIR "lib64") -# set(PROJECT_PLUGIN_DIR "lib64/${PROJECT_NAME}-${META_VERSION}") -#else(PROJECT_PROC_64BIT) -# set(PROJECT_LIB_DIR "lib") -# set(PROJECT_PLUGIN_DIR "lib/${PROJECT_NAME}-${META_VERSION}") -#endif() - -#message(STATUS "Installing Libraries to ${CMAKE_INSTALL_PREFIX}/${PROJECT_LIB_DIR}") -#message(STATUS "Installing Plugins to ${CMAKE_INSTALL_PREFIX}/${PROJECT_PLUGIN_DIR}") - # # Define the library path environment variable name # diff --git a/cmake/ScriptProject.cmake b/cmake/ScriptProject.cmake index 19aa2b9705..fb7d138355 100644 --- a/cmake/ScriptProject.cmake +++ b/cmake/ScriptProject.cmake @@ -2,7 +2,7 @@ # Script project generator by Parra Studios # Generates a script project embedded into CMake. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/SecurityFlags.cmake b/cmake/SecurityFlags.cmake index 15cc623eb4..b31ccbbf7d 100644 --- a/cmake/SecurityFlags.cmake +++ b/cmake/SecurityFlags.cmake @@ -2,7 +2,7 @@ # Compiler and linker options for hardening flags by Parra Studios # Enables hardening security flags if available. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/TestEnvironmentVariables.cmake b/cmake/TestEnvironmentVariables.cmake index 441e6baa04..1255f2bb46 100644 --- a/cmake/TestEnvironmentVariables.cmake +++ b/cmake/TestEnvironmentVariables.cmake @@ -2,7 +2,7 @@ # Test Environment Variables by Parra Studios # Utility for defining cross-platform environment variables in tests. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/Warnings.cmake b/cmake/Warnings.cmake index afc47ebfc4..23f057afd2 100644 --- a/cmake/Warnings.cmake +++ b/cmake/Warnings.cmake @@ -2,7 +2,7 @@ # Cross-compiler warning utility by Parra Studios # Utility to enable cross-compiler warnings. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -46,6 +46,7 @@ if(WARNINGS_ENABLED) # Define C compiler warning flags if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + # TODO: Uncomment the rest of the warnings, enable Weverything for clang add_compile_options(-Wall) add_compile_options(-Wextra) add_compile_options(-Wunused) @@ -85,7 +86,7 @@ if(WARNINGS_ENABLED) string(REPLACE "/W1" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") string(REPLACE "/W2" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") string(REPLACE "/W3" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4 /Wall") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4") # /Wall set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CTR_NONSTDC_NO_WARNINGS=1") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CTR_SECURE_NO_WARNINGS=1") set(WARNINGS_C_AVAILABLE 1) @@ -105,7 +106,7 @@ if(WARNINGS_ENABLED) string(REPLACE "/W1" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REPLACE "/W2" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REPLACE "/W3" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /Wall") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") # /Wall set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _CTR_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _CTR_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _CTR_NONSTDC_NO_WARNINGS=1") diff --git a/cmake/coverage/FindGcov.cmake b/cmake/coverage/FindGcov.cmake deleted file mode 100644 index 157fc88c6d..0000000000 --- a/cmake/coverage/FindGcov.cmake +++ /dev/null @@ -1,149 +0,0 @@ -# This file is part of CMake-codecov. -# -# Copyright (c) -# 2015-2017 RWTH Aachen University, Federal Republic of Germany -# -# See the LICENSE file in the package base directory for details -# -# Written by Alexander Haase, alexander.haase@rwth-aachen.de -# - - -# include required Modules -include(FindPackageHandleStandardArgs) - -# Search for gcov binary. -set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) -set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) - -get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) -foreach (LANG ${ENABLED_LANGUAGES}) - # Gcov evaluation is dependent on the used compiler. Check gcov support for - # each compiler that is used. If gcov binary was already found for this - # compiler, do not try to find it again. - if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN) - get_filename_component(COMPILER_PATH "${CMAKE_${LANG}_COMPILER}" PATH) - - if ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU") - # Some distributions like OSX (homebrew) ship gcov with the compiler - # version appended as gcov-x. To find this binary we'll build the - # suggested binary name with the compiler version. - string(REGEX MATCH "^[0-9]+" GCC_VERSION - "${CMAKE_${LANG}_COMPILER_VERSION}") - - find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov - HINTS ${COMPILER_PATH}) - - elseif ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Clang") - # Some distributions like Debian ship llvm-cov with the compiler - # version appended as llvm-cov-x.y. To find this binary we'll build - # the suggested binary name with the compiler version. - string(REGEX MATCH "^[0-9]+.[0-9]+" LLVM_VERSION - "${CMAKE_${LANG}_COMPILER_VERSION}") - - # llvm-cov prior version 3.5 seems to be not working with coverage - # evaluation tools, but these versions are compatible with the gcc - # gcov tool. - if(LLVM_VERSION VERSION_GREATER 3.4) - find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}" - "llvm-cov" HINTS ${COMPILER_PATH}) - mark_as_advanced(LLVM_COV_BIN) - - if (LLVM_COV_BIN) - find_program(LLVM_COV_WRAPPER "llvm-cov-wrapper" PATHS - ${CMAKE_MODULE_PATH}) - if (LLVM_COV_WRAPPER) - set(GCOV_BIN "${LLVM_COV_WRAPPER}" CACHE FILEPATH "") - - # set additional parameters - set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV - "LLVM_COV_BIN=${LLVM_COV_BIN}" CACHE STRING - "Environment variables for llvm-cov-wrapper.") - mark_as_advanced(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV) - endif () - endif () - endif () - - if (NOT GCOV_BIN) - # Fall back to gcov binary if llvm-cov was not found or is - # incompatible. This is the default on OSX, but may crash on - # recent Linux versions. - find_program(GCOV_BIN gcov HINTS ${COMPILER_PATH}) - endif () - endif () - - - if (GCOV_BIN) - set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN "${GCOV_BIN}" CACHE STRING - "${LANG} gcov binary.") - - if (NOT CMAKE_REQUIRED_QUIET) - message("-- Found gcov evaluation for " - "${CMAKE_${LANG}_COMPILER_ID}: ${GCOV_BIN}") - endif() - - unset(GCOV_BIN CACHE) - endif () - endif () -endforeach () - -# Add a new global target for all gcov targets. This target could be used to -# generate the gcov files for the whole project instead of calling -gcov -# for each target. -if (NOT TARGET gcov) - add_custom_target(gcov) -endif (NOT TARGET gcov) - -# This function will add gcov evaluation for target . Only sources of -# this target will be evaluated and no dependencies will be added. It will call -# Gcov on any source file of once and store the gcov file in the same -# directory. -function (add_gcov_target TNAME) - set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) - - # We don't have to check, if the target has support for coverage, thus this - # will be checked by add_coverage_target in Findcoverage.cmake. Instead we - # have to determine which gcov binary to use. - get_target_property(TSOURCES ${TNAME} SOURCES) - set(SOURCES "") - set(TCOMPILER "") - foreach (FILE ${TSOURCES}) - codecov_path_of_source(${FILE} FILE) - if (NOT "${FILE}" STREQUAL "") - codecov_lang_of_source(${FILE} LANG) - if (NOT "${LANG}" STREQUAL "") - list(APPEND SOURCES "${FILE}") - set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) - endif () - endif () - endforeach () - - # If no gcov binary was found, coverage data can't be evaluated. - if (NOT GCOV_${TCOMPILER}_BIN) - message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") - return() - endif () - - set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") - set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") - - set(BUFFER "") - foreach(FILE ${SOURCES}) - get_filename_component(FILE_PATH "${TDIR}/${FILE}" PATH) - - # call gcov - add_custom_command(OUTPUT ${TDIR}/${FILE}.gcov - COMMAND ${GCOV_ENV} ${GCOV_BIN} ${TDIR}/${FILE}.gcno > /dev/null - DEPENDS ${TNAME} ${TDIR}/${FILE}.gcno - WORKING_DIRECTORY ${FILE_PATH} - ) - - list(APPEND BUFFER ${TDIR}/${FILE}.gcov) - endforeach() - - # add target for gcov evaluation of - add_custom_target(${TNAME}-gcov DEPENDS ${BUFFER}) - - # add evaluation target to the global gcov target. - add_dependencies(gcov ${TNAME}-gcov) -endfunction (add_gcov_target) diff --git a/cmake/coverage/FindLcov.cmake b/cmake/coverage/FindLcov.cmake deleted file mode 100644 index beb925ae06..0000000000 --- a/cmake/coverage/FindLcov.cmake +++ /dev/null @@ -1,354 +0,0 @@ -# This file is part of CMake-codecov. -# -# Copyright (c) -# 2015-2017 RWTH Aachen University, Federal Republic of Germany -# -# See the LICENSE file in the package base directory for details -# -# Written by Alexander Haase, alexander.haase@rwth-aachen.de -# - - -# configuration -set(LCOV_DATA_PATH "${CMAKE_BINARY_DIR}/lcov/data") -set(LCOV_DATA_PATH_INIT "${LCOV_DATA_PATH}/init") -set(LCOV_DATA_PATH_CAPTURE "${LCOV_DATA_PATH}/capture") -set(LCOV_HTML_PATH "${CMAKE_BINARY_DIR}/lcov/html") - - - - -# Search for Gcov which is used by Lcov. -find_package(Gcov) - - - - -# This function will add lcov evaluation for target . Only sources of -# this target will be evaluated and no dependencies will be added. It will call -# geninfo on any source file of once and store the info file in the same -# directory. -# -# Note: This function is only a wrapper to define this function always, even if -# coverage is not supported by the compiler or disabled. This function must -# be defined here, because the module will be exited, if there is no coverage -# support by the compiler or it is disabled by the user. -function (add_lcov_target TNAME) - if (LCOV_FOUND) - # capture initial coverage data - lcov_capture_initial_tgt(${TNAME}) - - # capture coverage data after execution - lcov_capture_tgt(${TNAME}) - endif () -endfunction (add_lcov_target) - - - - -# include required Modules -include(FindPackageHandleStandardArgs) - -# Search for required lcov binaries. -find_program(LCOV_BIN lcov) -find_program(GENINFO_BIN geninfo) -find_program(GENHTML_BIN genhtml) -find_package_handle_standard_args(lcov - REQUIRED_VARS LCOV_BIN GENINFO_BIN GENHTML_BIN -) - -# enable genhtml C++ demangeling, if c++filt is found. -set(GENHTML_CPPFILT_FLAG "") -find_program(CPPFILT_BIN c++filt) -if (NOT CPPFILT_BIN STREQUAL "") - set(GENHTML_CPPFILT_FLAG "--demangle-cpp") -endif (NOT CPPFILT_BIN STREQUAL "") - -# enable no-external flag for lcov, if available. -if (GENINFO_BIN AND NOT DEFINED GENINFO_EXTERN_FLAG) - set(FLAG "") - execute_process(COMMAND ${GENINFO_BIN} --help OUTPUT_VARIABLE GENINFO_HELP) - string(REGEX MATCH "external" GENINFO_RES "${GENINFO_HELP}") - if (GENINFO_RES) - set(FLAG "--no-external") - endif () - - set(GENINFO_EXTERN_FLAG "${FLAG}" - CACHE STRING "Geninfo flag to exclude system sources.") -endif () - -# If Lcov was not found, exit module now. -if (NOT LCOV_FOUND) - return() -endif (NOT LCOV_FOUND) - - - - -# Create directories to be used. -file(MAKE_DIRECTORY ${LCOV_DATA_PATH_INIT}) -file(MAKE_DIRECTORY ${LCOV_DATA_PATH_CAPTURE}) - -set(LCOV_REMOVE_PATTERNS "") - -# This function will merge lcov files to a single target file. Additional lcov -# flags may be set with setting LCOV_EXTRA_FLAGS before calling this function. -function (lcov_merge_files OUTFILE ...) - # Remove ${OUTFILE} from ${ARGV} and generate lcov parameters with files. - list(REMOVE_AT ARGV 0) - - # Generate merged file. - string(REPLACE "${CMAKE_BINARY_DIR}/" "" FILE_REL "${OUTFILE}") - add_custom_command(OUTPUT "${OUTFILE}.raw" - COMMAND cat ${ARGV} > ${OUTFILE}.raw - DEPENDS ${ARGV} - COMMENT "Generating ${FILE_REL}" - ) - - add_custom_command(OUTPUT "${OUTFILE}" - COMMAND ${LCOV_BIN} --quiet -a ${OUTFILE}.raw --output-file ${OUTFILE} - --base-directory ${PROJECT_SOURCE_DIR} ${LCOV_EXTRA_FLAGS} - COMMAND ${LCOV_BIN} --quiet -r ${OUTFILE} ${LCOV_REMOVE_PATTERNS} - --output-file ${OUTFILE} ${LCOV_EXTRA_FLAGS} - DEPENDS ${OUTFILE}.raw - COMMENT "Post-processing ${FILE_REL}" - ) -endfunction () - - - - -# Add a new global target to generate initial coverage reports for all targets. -# This target will be used to generate the global initial info file, which is -# used to gather even empty report data. -if (NOT TARGET lcov-capture-init) - add_custom_target(lcov-capture-init) - set(LCOV_CAPTURE_INIT_FILES "" CACHE INTERNAL "") -endif (NOT TARGET lcov-capture-init) - - -# This function will add initial capture of coverage data for target , -# which is needed to get also data for objects, which were not loaded at -# execution time. It will call geninfo for every source file of once and -# store the info file in the same directory. -function (lcov_capture_initial_tgt TNAME) - # We don't have to check, if the target has support for coverage, thus this - # will be checked by add_coverage_target in Findcoverage.cmake. Instead we - # have to determine which gcov binary to use. - get_target_property(TSOURCES ${TNAME} SOURCES) - set(SOURCES "") - set(TCOMPILER "") - foreach (FILE ${TSOURCES}) - codecov_path_of_source(${FILE} FILE) - if (NOT "${FILE}" STREQUAL "") - codecov_lang_of_source(${FILE} LANG) - if (NOT "${LANG}" STREQUAL "") - list(APPEND SOURCES "${FILE}") - set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) - endif () - endif () - endforeach () - - # If no gcov binary was found, coverage data can't be evaluated. - if (NOT GCOV_${TCOMPILER}_BIN) - message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") - return() - endif () - - set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") - set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") - - - set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) - set(GENINFO_FILES "") - foreach(FILE ${SOURCES}) - # generate empty coverage files - set(OUTFILE "${TDIR}/${FILE}.info.init") - list(APPEND GENINFO_FILES ${OUTFILE}) - - add_custom_command(OUTPUT ${OUTFILE} COMMAND ${GCOV_ENV} ${GENINFO_BIN} - --quiet --base-directory ${PROJECT_SOURCE_DIR} --initial - --gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE} - ${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcno - DEPENDS ${TNAME} - COMMENT "Capturing initial coverage data for ${FILE}" - ) - endforeach() - - # Concatenate all files generated by geninfo to a single file per target. - set(OUTFILE "${LCOV_DATA_PATH_INIT}/${TNAME}.info") - set(LCOV_EXTRA_FLAGS "--initial") - lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) - add_custom_target(${TNAME}-capture-init ALL DEPENDS ${OUTFILE}) - - # add geninfo file generation to global lcov-geninfo target - add_dependencies(lcov-capture-init ${TNAME}-capture-init) - set(LCOV_CAPTURE_INIT_FILES "${LCOV_CAPTURE_INIT_FILES}" - "${OUTFILE}" CACHE INTERNAL "" - ) -endfunction (lcov_capture_initial_tgt) - - -# This function will generate the global info file for all targets. It has to be -# called after all other CMake functions in the root CMakeLists.txt file, to get -# a full list of all targets that generate coverage data. -function (lcov_capture_initial) - # Skip this function (and do not create the following targets), if there are - # no input files. - if ("${LCOV_CAPTURE_INIT_FILES}" STREQUAL "") - return() - endif () - - # Add a new target to merge the files of all targets. - set(OUTFILE "${LCOV_DATA_PATH_INIT}/all_targets.info") - lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_INIT_FILES}) - add_custom_target(lcov-geninfo-init ALL DEPENDS ${OUTFILE} - lcov-capture-init - ) -endfunction (lcov_capture_initial) - - - - -# Add a new global target to generate coverage reports for all targets. This -# target will be used to generate the global info file. -if (NOT TARGET lcov-capture) - add_custom_target(lcov-capture) - set(LCOV_CAPTURE_FILES "" CACHE INTERNAL "") -endif (NOT TARGET lcov-capture) - - -# This function will add capture of coverage data for target , which is -# needed to get also data for objects, which were not loaded at execution time. -# It will call geninfo for every source file of once and store the info -# file in the same directory. -function (lcov_capture_tgt TNAME) - # We don't have to check, if the target has support for coverage, thus this - # will be checked by add_coverage_target in Findcoverage.cmake. Instead we - # have to determine which gcov binary to use. - get_target_property(TSOURCES ${TNAME} SOURCES) - set(SOURCES "") - set(TCOMPILER "") - foreach (FILE ${TSOURCES}) - codecov_path_of_source(${FILE} FILE) - if (NOT "${FILE}" STREQUAL "") - codecov_lang_of_source(${FILE} LANG) - if (NOT "${LANG}" STREQUAL "") - list(APPEND SOURCES "${FILE}") - set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) - endif () - endif () - endforeach () - - # If no gcov binary was found, coverage data can't be evaluated. - if (NOT GCOV_${TCOMPILER}_BIN) - message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") - return() - endif () - - set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") - set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") - - - set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) - set(GENINFO_FILES "") - foreach(FILE ${SOURCES}) - # Generate coverage files. If no .gcda file was generated during - # execution, the empty coverage file will be used instead. - set(OUTFILE "${TDIR}/${FILE}.info") - list(APPEND GENINFO_FILES ${OUTFILE}) - - add_custom_command(OUTPUT ${OUTFILE} - COMMAND test -f "${TDIR}/${FILE}.gcda" - && ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory - ${PROJECT_SOURCE_DIR} --gcov-tool ${GCOV_BIN} - --output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG} - ${TDIR}/${FILE}.gcda - || cp ${OUTFILE}.init ${OUTFILE} - DEPENDS ${TNAME} ${TNAME}-capture-init - COMMENT "Capturing coverage data for ${FILE}" - ) - endforeach() - - # Concatenate all files generated by geninfo to a single file per target. - set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/${TNAME}.info") - lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) - add_custom_target(${TNAME}-geninfo DEPENDS ${OUTFILE}) - - # add geninfo file generation to global lcov-capture target - add_dependencies(lcov-capture ${TNAME}-geninfo) - set(LCOV_CAPTURE_FILES "${LCOV_CAPTURE_FILES}" "${OUTFILE}" CACHE INTERNAL - "" - ) - - # Add target for generating html output for this target only. - file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/${TNAME}) - add_custom_target(${TNAME}-genhtml - COMMAND ${GENHTML_BIN} --quiet --sort --prefix ${PROJECT_SOURCE_DIR} - --baseline-file ${LCOV_DATA_PATH_INIT}/${TNAME}.info - --output-directory ${LCOV_HTML_PATH}/${TNAME} - --title "${CMAKE_PROJECT_NAME} - target ${TNAME}" - ${GENHTML_CPPFILT_FLAG} ${OUTFILE} - DEPENDS ${TNAME}-geninfo ${TNAME}-capture-init - ) -endfunction (lcov_capture_tgt) - - -# This function will generate the global info file for all targets. It has to be -# called after all other CMake functions in the root CMakeLists.txt file, to get -# a full list of all targets that generate coverage data. -function (lcov_capture) - # Skip this function (and do not create the following targets), if there are - # no input files. - if ("${LCOV_CAPTURE_FILES}" STREQUAL "") - return() - endif () - - # Add a new target to merge the files of all targets. - set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/all_targets.info") - lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_FILES}) - add_custom_target(lcov-geninfo DEPENDS ${OUTFILE} lcov-capture) - - # Add a new global target for all lcov targets. This target could be used to - # generate the lcov html output for the whole project instead of calling - # -geninfo and -genhtml for each target. It will also be - # used to generate a html site for all project data together instead of one - # for each target. - if (NOT TARGET lcov) - file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/all_targets) - add_custom_target(lcov - COMMAND ${GENHTML_BIN} --quiet --sort - --baseline-file ${LCOV_DATA_PATH_INIT}/all_targets.info - --output-directory ${LCOV_HTML_PATH}/all_targets - --title "${CMAKE_PROJECT_NAME}" --prefix "${PROJECT_SOURCE_DIR}" - ${GENHTML_CPPFILT_FLAG} ${OUTFILE} - DEPENDS lcov-geninfo-init lcov-geninfo - ) - endif () -endfunction (lcov_capture) - - - - -# Add a new global target to generate the lcov html report for the whole project -# instead of calling -genhtml for each target (to create an own report -# for each target). Instead of the lcov target it does not require geninfo for -# all targets, so you have to call -geninfo to generate the info files -# the targets you'd like to have in your report or lcov-geninfo for generating -# info files for all targets before calling lcov-genhtml. -file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/selected_targets) -if (NOT TARGET lcov-genhtml) - add_custom_target(lcov-genhtml - COMMAND ${GENHTML_BIN} - --quiet - --output-directory ${LCOV_HTML_PATH}/selected_targets - --title \"${CMAKE_PROJECT_NAME} - targets `find - ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name - \"all_targets.info\" -exec basename {} .info \\\;`\" - --prefix ${PROJECT_SOURCE_DIR} - --sort - ${GENHTML_CPPFILT_FLAG} - `find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name - \"all_targets.info\"` - ) -endif (NOT TARGET lcov-genhtml) diff --git a/cmake/coverage/Findcodecov.cmake b/cmake/coverage/Findcodecov.cmake deleted file mode 100644 index 5bacd950c1..0000000000 --- a/cmake/coverage/Findcodecov.cmake +++ /dev/null @@ -1,312 +0,0 @@ -# This file is part of CMake-codecov. -# -# Copyright (c) -# 2015-2017 RWTH Aachen University, Federal Republic of Germany -# -# See the LICENSE file in the package base directory for details -# -# Written by Alexander Haase, alexander.haase@rwth-aachen.de -# - -# Add an option to choose, if coverage should be enabled or not. If enabled -# marked targets will be build with coverage support and appropriate targets -# will be added. If disabled coverage will be ignored for *ALL* targets. -option(ENABLE_COVERAGE "Enable coverage build." OFF) - -# Add an option to choose, if coverage should be enabled for all targets, even -# those which are not explictly marked as coverage targets. If disabled, only -# targets added by add_coverage will be marked for coverage build. This option -# is only available, if coverage was enabled. -if (ENABLE_COVERAGE) - option(ENABLE_COVERAGE_ALL "Enable coverage build for all targets." OFF) -endif () - -set(COVERAGE_FLAG_CANDIDATES - # gcc and clang - "-O0 -g -fprofile-arcs -ftest-coverage" - - # gcc and clang fallback - "-O0 -g --coverage" -) - -# Add coverage support for target ${TNAME} and register target for coverage -# evaluation. If coverage is disabled or not supported, this function will -# simply do nothing. -# -# Note: This function is only a wrapper to define this function always, even if -# coverage is not supported by the compiler or disabled. This function must -# be defined here, because the module will be exited, if there is no coverage -# support by the compiler or it is disabled by the user. -function (add_coverage TNAME) - # only add coverage for target, if coverage is support and enabled. - if (ENABLE_COVERAGE) - foreach (TNAME ${ARGV}) - add_coverage_target(${TNAME}) - endforeach () - endif () -endfunction (add_coverage) - -# Add global target to gather coverage information after all targets have been -# added. Other evaluation functions could be added here, after checks for the -# specific module have been passed. -# -# Note: This function is only a wrapper to define this function always, even if -# coverage is not supported by the compiler or disabled. This function must -# be defined here, because the module will be exited, if there is no coverage -# support by the compiler or it is disabled by the user. -function (coverage_evaluate) - # add lcov evaluation - if (LCOV_FOUND) - lcov_capture_initial() - lcov_capture() - endif (LCOV_FOUND) -endfunction () - -# Exit this module, if coverage is disabled. add_coverage is defined before this -# return, so this module can be exited now safely without breaking any build- -# scripts. -if (NOT ENABLE_COVERAGE) - return() -endif () - -# Find the required flags foreach language. -set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) -set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) - -get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) -foreach (LANG ${ENABLED_LANGUAGES}) - # Coverage flags are not dependent on language, but the used compiler. So - # instead of searching flags foreach language, search flags foreach compiler - # used. - set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) - if (NOT COVERAGE_${COMPILER}_FLAGS) - foreach (FLAG ${COVERAGE_FLAG_CANDIDATES}) - if(NOT CMAKE_REQUIRED_QUIET) - message(STATUS "Try ${COMPILER} code coverage flag = [${FLAG}]") - endif() - - set(CMAKE_REQUIRED_FLAGS "${FLAG}") - unset(COVERAGE_FLAG_DETECTED CACHE) - - if (${LANG} STREQUAL "C") - include(CheckCCompilerFlag) - check_c_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) - - elseif (${LANG} STREQUAL "CXX") - include(CheckCXXCompilerFlag) - check_cxx_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) - - elseif (${LANG} STREQUAL "Fortran") - # CheckFortranCompilerFlag was introduced in CMake 3.x. To be - # compatible with older Cmake versions, we will check if this - # module is present before we use it. Otherwise we will define - # Fortran coverage support as not available. - include(CheckFortranCompilerFlag OPTIONAL - RESULT_VARIABLE INCLUDED) - if (INCLUDED) - check_fortran_compiler_flag("${FLAG}" - COVERAGE_FLAG_DETECTED) - elseif (NOT CMAKE_REQUIRED_QUIET) - message("-- Performing Test COVERAGE_FLAG_DETECTED") - message("-- Performing Test COVERAGE_FLAG_DETECTED - Failed" - " (Check not supported)") - endif () - endif() - - if (COVERAGE_FLAG_DETECTED) - set(COVERAGE_${COMPILER}_FLAGS "${FLAG}" - CACHE STRING "${COMPILER} flags for code coverage.") - mark_as_advanced(COVERAGE_${COMPILER}_FLAGS) - break() - else () - message(WARNING "Code coverage is not available for ${COMPILER}" - " compiler. Targets using this compiler will be " - "compiled without it.") - endif () - endforeach () - endif () -endforeach () - -set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE}) - -# Helper function to get the language of a source file. -function (codecov_lang_of_source FILE RETURN_VAR) - get_filename_component(FILE_EXT "${FILE}" EXT) - string(TOLOWER "${FILE_EXT}" FILE_EXT) - string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) - - get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) - foreach (LANG ${ENABLED_LANGUAGES}) - list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) - if (NOT ${TEMP} EQUAL -1) - set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) - return() - endif () - endforeach() - - set(${RETURN_VAR} "" PARENT_SCOPE) -endfunction () - -# Helper function to get the relative path of the source file destination path. -# This path is needed by FindGcov and FindLcov cmake files to locate the -# captured data. -function (codecov_path_of_source FILE RETURN_VAR) - string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _source ${FILE}) - - # If expression was found, SOURCEFILE is a generator-expression for an - # object library. Currently we found no way to call this function automatic - # for the referenced target, so it must be called in the directoryso of the - # object library definition. - if (NOT "${_source}" STREQUAL "") - set(${RETURN_VAR} "" PARENT_SCOPE) - return() - endif () - - string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" FILE "${FILE}") - if(IS_ABSOLUTE ${FILE}) - file(RELATIVE_PATH FILE ${CMAKE_CURRENT_SOURCE_DIR} ${FILE}) - endif() - - # get the right path for file - string(REPLACE ".." "__" PATH "${FILE}") - - set(${RETURN_VAR} "${PATH}" PARENT_SCOPE) -endfunction() - -# Add coverage support for target ${TNAME} and register target for coverage -# evaluation. -function(add_coverage_target TNAME) - # Check if all sources for target use the same compiler. If a target uses - # e.g. C and Fortran mixed and uses different compilers (e.g. clang and - # gfortran) this can trigger huge problems, because different compilers may - # use different implementations for code coverage. - get_target_property(TSOURCES ${TNAME} SOURCES) - set(TARGET_COMPILER "") - set(ADDITIONAL_FILES "") - foreach (FILE ${TSOURCES}) - # If expression was found, FILE is a generator-expression for an object - # library. Object libraries will be ignored. - string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) - if ("${_file}" STREQUAL "") - codecov_lang_of_source(${FILE} LANG) - if (LANG) - list(APPEND TARGET_COMPILER ${CMAKE_${LANG}_COMPILER_ID}) - - list(APPEND ADDITIONAL_FILES "${FILE}.gcno") - list(APPEND ADDITIONAL_FILES "${FILE}.gcda") - endif () - endif () - endforeach () - - list(REMOVE_DUPLICATES TARGET_COMPILER) - list(LENGTH TARGET_COMPILER NUM_COMPILERS) - - if (NUM_COMPILERS GREATER 1) - message(WARNING "Can't use code coverage for target ${TNAME}, because " - "it will be compiled by incompatible compilers. Target will be " - "compiled without code coverage.") - return() - elseif (NUM_COMPILERS EQUAL 0) - message(WARNING "Can't use code coverage for target ${TNAME}, because " - "it uses an unknown compiler. Target will be compiled without " - "code coverage.") - return() - elseif (NOT DEFINED "COVERAGE_${TARGET_COMPILER}_FLAGS") - # A warning has been printed before, so just return if flags for this - # compiler aren't available. - return() - endif() - - # enable coverage for target - set_property(TARGET ${TNAME} APPEND_STRING - PROPERTY COMPILE_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") - set_property(TARGET ${TNAME} APPEND_STRING - PROPERTY LINK_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") - - # Add gcov files generated by compiler to clean target. - set(CLEAN_FILES "") - foreach (FILE ${ADDITIONAL_FILES}) - codecov_path_of_source(${FILE} FILE) - list(APPEND CLEAN_FILES "CMakeFiles/${TNAME}.dir/${FILE}") - endforeach() - - set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES - "${CLEAN_FILES}") - - - add_gcov_target(${TNAME}) - add_lcov_target(${TNAME}) -endfunction(add_coverage_target) - -# If ENABLE_COVERAGE_ALL is enabled, overload add_executable and add_library -# functions, to add coverage support for *ALL* targets. The functions will call -# the overloaded functions first and then add_coverage. -if (ENABLE_COVERAGE_ALL) - function(add_executable ARGV) - # add executable - _add_executable(${ARGV}) - - get_target_property(TARGET_TYPE "${ARGV0}" TYPE) - - if(TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") - return() - endif() - - # check if target is supported for code coverage - get_target_property(TSOURCES ${ARGV0} SOURCES) - foreach (FILE ${TSOURCES}) - get_source_file_property(SLANG ${FILE} LANGUAGE) - if ((NOT ${SLANG} STREQUAL "C") AND (NOT ${SLANG} STREQUAL "CXX")) - # Target has source files that are not supported for code - # coverage. Do not add coverage for this target and print a - # warning. - message("-- Code coverage not supported for target ${ARGV0}") - return() - endif() - endforeach () - - get_target_property(ALIASED ${ARGV0} ALIASED_TARGET) - - if(NOT ALIASED) - # add coverage (if not alias and not interface) - add_coverage(${ARGV0}) - endif() - endfunction(add_executable) - - function(add_library ARGV) - # add library - _add_library(${ARGV}) - - get_target_property(TARGET_TYPE "${ARGV0}" TYPE) - - if(TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") - return() - endif() - - # check if target is supported for code coverage - get_target_property(TSOURCES ${ARGV0} SOURCES) - foreach (FILE ${TSOURCES}) - get_source_file_property(SLANG ${FILE} LANGUAGE) - if ((NOT ${SLANG} STREQUAL "C") AND (NOT ${SLANG} STREQUAL "CXX")) - # Target has source files that are not supported for code - # coverage. Do not add coverage for this target and print a - # warning. - message("-- Code coverage not supported for target ${ARGV0}") - return() - endif() - endforeach () - - get_target_property(ALIASED ${ARGV0} ALIASED_TARGET) - - if(NOT ALIASED) - # add coverage (if not alias) - add_coverage(${ARGV0}) - endif() - - endfunction(add_library) -endif () - -# Include modules for parsing the collected data and output it in a readable -# format (like gcov and lcov). -find_package(Gcov) -find_package(Lcov) diff --git a/cmake/coverage/LICENSE b/cmake/coverage/LICENSE deleted file mode 100644 index 7f786a8415..0000000000 --- a/cmake/coverage/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright 2015-2017 RWTH Aachen University, Federal Republic of Germany -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cmake/coverage/llvm-cov-wrapper b/cmake/coverage/llvm-cov-wrapper deleted file mode 100644 index a804898945..0000000000 --- a/cmake/coverage/llvm-cov-wrapper +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env sh - -# This file is part of CMake-codecov. -# -# Copyright (c) -# 2015-2017 RWTH Aachen University, Federal Republic of Germany -# -# See the LICENSE file in the package base directory for details -# -# Written by Alexander Haase, alexander.haase@rwth-aachen.de -# - -if [ -z "$LLVM_COV_BIN" ] -then - echo "LLVM_COV_BIN not set!" >& 2 - exit 1 -fi - - -# Get LLVM version to find out. -LLVM_VERSION=$($LLVM_COV_BIN -version | grep -i "LLVM version" \ - | sed "s/^\([A-Za-z ]*\)\([0-9]\).\([0-9]\).*$/\2.\3/g") - -if [ "$1" = "-v" ] -then - echo "llvm-cov-wrapper $LLVM_VERSION" - exit 0 -fi - - -if [ -n "$LLVM_VERSION" ] -then - MAJOR=$(echo $LLVM_VERSION | cut -d'.' -f1) - MINOR=$(echo $LLVM_VERSION | cut -d'.' -f2) - - if [ $MAJOR -eq 3 ] && [ $MINOR -le 4 ] - then - if [ -f "$1" ] - then - filename=$(basename "$1") - extension="${filename##*.}" - - case "$extension" in - "gcno") exec $LLVM_COV_BIN --gcno="$1" ;; - "gcda") exec $LLVM_COV_BIN --gcda="$1" ;; - esac - fi - fi - - if [ $MAJOR -eq 3 ] && [ $MINOR -le 5 ] - then - exec $LLVM_COV_BIN $@ - fi -fi - -exec $LLVM_COV_BIN gcov $@ diff --git a/deploy/packages/postinst b/deploy/packages/postinst index 8a6d524f7f..8ae7a6fa6c 100755 --- a/deploy/packages/postinst +++ b/deploy/packages/postinst @@ -4,7 +4,7 @@ # MetaCall Dependencies Bash Script by Parra Studios # Remove all packages and unused data from MetaCall building and testing. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/docker-compose.cache.yml b/docker-compose.cache.yml index cc7f584b29..63b1b455c7 100644 --- a/docker-compose.cache.yml +++ b/docker-compose.cache.yml @@ -2,7 +2,7 @@ # MetaCall Library by Parra Studios # Docker compose infrastructure for MetaCall. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/docker-compose.sh b/docker-compose.sh index 3d1ed0ad22..e254cb103e 100755 --- a/docker-compose.sh +++ b/docker-compose.sh @@ -4,7 +4,7 @@ # MetaCall Build Bash Script by Parra Studios # Build and install bash script utility for MetaCall. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -27,6 +27,16 @@ export DOCKER_BUILDKIT=1 export BUILDKIT_PROGRESS=plain export PROGRESS_NO_TRUNC=1 +# Check if docker compose command is available +if [ -x "$(command -v docker-compose)" ]; then + DOCKER_COMPOSE="docker-compose" +elif $(docker compose &>/dev/null) && [ $? -eq 0 ]; then + DOCKER_COMPOSE="docker compose" +else + echo "Docker Compose not installed, install it and re-run the script" + exit 1 +fi + # Pull MetaCall Docker Compose sub_pull() { if [ -z "$IMAGE_NAME" ]; then @@ -46,31 +56,31 @@ sub_pull() { # Build MetaCall Docker Compose (link manually dockerignore files) sub_build() { ln -sf tools/deps/.dockerignore .dockerignore - docker-compose -f docker-compose.yml build --force-rm deps + $DOCKER_COMPOSE -f docker-compose.yml build --force-rm deps ln -sf tools/dev/.dockerignore .dockerignore - docker-compose -f docker-compose.yml build --force-rm dev + $DOCKER_COMPOSE -f docker-compose.yml build --force-rm dev ln -sf tools/runtime/.dockerignore .dockerignore - docker-compose -f docker-compose.yml build --force-rm runtime + $DOCKER_COMPOSE -f docker-compose.yml build --force-rm runtime ln -sf tools/cli/.dockerignore .dockerignore - docker-compose -f docker-compose.yml build --force-rm cli + $DOCKER_COMPOSE -f docker-compose.yml build --force-rm cli } # Build MetaCall Docker Compose without cache (link manually dockerignore files) sub_rebuild() { ln -sf tools/deps/.dockerignore .dockerignore - docker-compose -f docker-compose.yml build --force-rm --no-cache deps + $DOCKER_COMPOSE -f docker-compose.yml build --force-rm --no-cache deps ln -sf tools/dev/.dockerignore .dockerignore - docker-compose -f docker-compose.yml build --force-rm --no-cache dev + $DOCKER_COMPOSE -f docker-compose.yml build --force-rm --no-cache dev ln -sf tools/runtime/.dockerignore .dockerignore - docker-compose -f docker-compose.yml build --force-rm --no-cache runtime + $DOCKER_COMPOSE -f docker-compose.yml build --force-rm --no-cache runtime ln -sf tools/cli/.dockerignore .dockerignore - docker-compose -f docker-compose.yml build --force-rm --no-cache cli + $DOCKER_COMPOSE -f docker-compose.yml build --force-rm --no-cache cli } # Build MetaCall Docker Compose for testing (link manually dockerignore files) @@ -81,14 +91,17 @@ sub_test() { # Disable build with sanitizer export METACALL_BUILD_SANITIZER= + # Disable build with coverage + export METACALL_BUILD_COVERAGE= + # Define build type export METACALL_BUILD_TYPE=${METACALL_BUILD_TYPE:-debug} ln -sf tools/deps/.dockerignore .dockerignore - docker-compose -f docker-compose.yml -f docker-compose.test.yml build --force-rm deps + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.test.yml build --force-rm deps ln -sf tools/dev/.dockerignore .dockerignore - docker-compose -f docker-compose.yml -f docker-compose.test.yml build --force-rm dev + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.test.yml build --force-rm dev } # Build MetaCall Docker Compose with Sanitizer for testing (link manually dockerignore files) @@ -99,18 +112,21 @@ sub_test_sanitizer() { # Enable build with sanitizer export METACALL_BUILD_SANITIZER=${METACALL_BUILD_SANITIZER:-address-sanitizer} + # Disable build with coverage + export METACALL_BUILD_COVERAGE= + # Define build type export METACALL_BUILD_TYPE=${METACALL_BUILD_TYPE:-debug} ln -sf tools/deps/.dockerignore .dockerignore - docker-compose -f docker-compose.yml -f docker-compose.test.yml build --force-rm deps + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.test.yml build --force-rm deps ln -sf tools/dev/.dockerignore .dockerignore if [ ! -z "${SANITIZER_SKIP_SUMMARY:-}" ]; then - docker-compose -f docker-compose.yml -f docker-compose.test.yml build --force-rm dev + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.test.yml build --force-rm dev else - docker-compose -f docker-compose.yml -f docker-compose.test.yml build --force-rm dev | tee /tmp/metacall-test-output + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.test.yml build --force-rm dev | tee /tmp/metacall-test-output # Retrieve all the summaries SUMMARY=$(grep "SUMMARY:" /tmp/metacall-test-output) @@ -142,6 +158,27 @@ sub_test_sanitizer() { fi } +# Build MetaCall Docker Compose for coverage (link manually dockerignore files) +sub_coverage() { + # Disable BuildKit as workaround due to log limits (TODO: https://github.com/docker/buildx/issues/484) + export DOCKER_BUILDKIT=0 + + # Disable build with sanitizer + export METACALL_BUILD_SANITIZER= + + # Disable build with coverage + export METACALL_BUILD_COVERAGE=coverage + + # Define build type + export METACALL_BUILD_TYPE=debug + + ln -sf tools/deps/.dockerignore .dockerignore + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.test.yml build --force-rm deps + + ln -sf tools/dev/.dockerignore .dockerignore + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.test.yml build --force-rm dev +} + # Build MetaCall Docker Compose with caching (link manually dockerignore files) sub_cache() { if [ -z "$IMAGE_REGISTRY" ]; then @@ -150,20 +187,56 @@ sub_cache() { fi ln -sf tools/deps/.dockerignore .dockerignore - docker-compose -f docker-compose.yml -f docker-compose.cache.yml build deps + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.cache.yml build deps + + ln -sf tools/dev/.dockerignore .dockerignore + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.cache.yml build dev + + ln -sf tools/runtime/.dockerignore .dockerignore + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.cache.yml build runtime + + ln -sf tools/cli/.dockerignore .dockerignore + $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.cache.yml build cli +} + +# Build MetaCall Docker Compose with multi-platform specifier (link manually dockerignore files) +sub_platform() { + if [ -z "$METACALL_PLATFORM" ]; then + echo "Error: METACALL_PLATFORM variable not defined" + exit 1 + fi + + # Initialize QEMU for Buildkit + docker run --rm --privileged tonistiigi/binfmt --install all + + # Debian in Docker Hub does not support LoongArch64 yet, let's use official LoongArch repository instead + if [ "$METACALL_PLATFORM" = "linux/loong64" ]; then + source .env + export METACALL_BASE_IMAGE="ghcr.io/loong64/${METACALL_BASE_IMAGE}" + fi + + # Generate the docker compose file with all .env variables substituted (bake seems not to support this) + $DOCKER_COMPOSE -f docker-compose.yml config &> docker-compose.bake.yml + + # Build with Bake, so the image can be loaded into local docker context + ln -sf tools/deps/.dockerignore .dockerignore + docker buildx bake -f docker-compose.bake.yml --set *.platform="${METACALL_PLATFORM}" --load deps ln -sf tools/dev/.dockerignore .dockerignore - docker-compose -f docker-compose.yml -f docker-compose.cache.yml build dev + docker buildx bake -f docker-compose.bake.yml --set *.platform="${METACALL_PLATFORM}" --load dev ln -sf tools/runtime/.dockerignore .dockerignore - docker-compose -f docker-compose.yml -f docker-compose.cache.yml build runtime + docker buildx bake -f docker-compose.bake.yml --set *.platform="${METACALL_PLATFORM}" --load runtime ln -sf tools/cli/.dockerignore .dockerignore - docker-compose -f docker-compose.yml -f docker-compose.cache.yml build cli + docker buildx bake -f docker-compose.bake.yml --set *.platform="${METACALL_PLATFORM}" --load cli + + # Delete temporal docker compose file + rm -rf docker-compose.bake.yml } # Push MetaCall Docker Compose -sub_push(){ +sub_push() { if [ -z "$IMAGE_NAME" ]; then echo "Error: IMAGE_NAME variable not defined" exit 1 @@ -191,7 +264,7 @@ sub_push(){ } # Version MetaCall Docker Compose -sub_version(){ +sub_version() { if [ -z "$IMAGE_NAME" ]; then echo "Error: IMAGE_NAME variable not defined" exit 1 @@ -221,7 +294,7 @@ sub_version(){ } # Pack MetaCall Docker Compose -sub_pack(){ +sub_pack() { if [ -z "$ARTIFACTS_PATH" ]; then echo "Error: ARTIFACTS_PATH variable not defined" exit 1 @@ -260,7 +333,9 @@ sub_help() { echo " test-address-sanitizer" echo " test-thread-sanitizer" echo " test-memory-sanitizer" + echo " coverage" echo " cache" + echo " platform" echo " push" echo " pack" echo "" @@ -291,9 +366,15 @@ case "$1" in export METACALL_BUILD_SANITIZER="memory-sanitizer" sub_test_sanitizer ;; + coverage) + sub_coverage + ;; cache) sub_cache ;; + platform) + sub_platform + ;; push) sub_push ;; diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 5b2784f5f6..5802aeef51 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -2,7 +2,7 @@ # MetaCall Library by Parra Studios # Docker compose infrastructure for MetaCall. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -24,10 +24,11 @@ services: image: metacall/core:deps build: args: - METACALL_INSTALL_OPTIONS: base python ruby netcore7 nodejs typescript file rpc wasm java c cobol go rust rapidjson funchook swig pack backtrace # clangformat v8rep51 coverage + METACALL_BUILD_TYPE: ${METACALL_BUILD_TYPE} + METACALL_INSTALL_OPTIONS: base python ruby netcore8 nodejs typescript file rpc wasm java c cobol go rust rapidjson pack backtrace sandbox ${METACALL_BUILD_COVERAGE} # clangformat v8rep51 dev: image: metacall/core:dev build: args: METACALL_BUILD_TYPE: ${METACALL_BUILD_TYPE} - METACALL_BUILD_OPTIONS: ${METACALL_BUILD_SANITIZER} python ruby netcore7 nodejs typescript file rpc wasm java c cobol go rust examples tests scripts ports install pack benchmarks # v8 coverage + METACALL_BUILD_OPTIONS: ${METACALL_BUILD_SANITIZER} python ruby netcore8 nodejs typescript file rpc wasm java c cobol go rust examples tests scripts ports install pack sandbox benchmarks ${METACALL_BUILD_COVERAGE} # v8 diff --git a/docker-compose.yml b/docker-compose.yml index 10fd23c33f..1c1997b138 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ # MetaCall Library by Parra Studios # Docker compose infrastructure for MetaCall. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,20 +17,20 @@ # limitations under the License. # -version: "3.7" - services: deps: image: metacall/core:deps container_name: metacall_core_deps build: + network: "host" context: . dockerfile: tools/deps/Dockerfile args: METACALL_BASE_IMAGE: $METACALL_BASE_IMAGE METACALL_PATH: $METACALL_PATH METACALL_TOOLS_PATH: $METACALL_PATH/tools - METACALL_INSTALL_OPTIONS: base python ruby nodejs typescript file rpc rapidjson funchook swig pack backtrace # clangformat v8rep51 coverage + METACALL_BUILD_TYPE: $METACALL_BUILD_TYPE + METACALL_INSTALL_OPTIONS: base python ruby nodejs typescript file rpc rapidjson pack backtrace # clangformat v8rep51 coverage environment: DEBIAN_FRONTEND: noninteractive # Work around https://github.com/dotnet/cli/issues/1582 until Docker releases a @@ -47,6 +47,7 @@ services: image: metacall/core:dev container_name: metacall_core_dev build: + network: "host" context: . dockerfile: tools/dev/Dockerfile args: @@ -63,15 +64,13 @@ services: CONFIGURATION_PATH: $METACALL_PATH/build/configurations/global.json SERIAL_LIBRARY_PATH: $METACALL_PATH/build DETOUR_LIBRARY_PATH: $METACALL_PATH/build - PORT_LIBRARY_PATH: $METACALL_PATH/build NODE_PATH: /usr/lib/node_modules - depends_on: - - deps runtime: image: metacall/core:runtime container_name: metacall_core_runtime build: + network: "host" context: . dockerfile: tools/runtime/Dockerfile args: @@ -88,15 +87,13 @@ services: CONFIGURATION_PATH: /usr/local/share/metacall/configurations/global.json SERIAL_LIBRARY_PATH: /usr/local/lib DETOUR_LIBRARY_PATH: /usr/local/lib - PORT_LIBRARY_PATH: /usr/local/lib NODE_PATH: /usr/local/lib/node_modules - depends_on: - - dev cli: image: metacall/core:cli container_name: metacall_core_cli build: + network: "host" context: . dockerfile: tools/cli/Dockerfile environment: @@ -109,8 +106,4 @@ services: CONFIGURATION_PATH: /usr/local/share/metacall/configurations/global.json SERIAL_LIBRARY_PATH: /usr/local/lib DETOUR_LIBRARY_PATH: /usr/local/lib - PORT_LIBRARY_PATH: /usr/local/lib NODE_PATH: /usr/local/lib/node_modules - depends_on: - - dev - - runtime diff --git a/docs/README.md b/docs/README.md index cec22b656d..55c101c5cd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -66,7 +66,7 @@ Use the [installer](https://github.com/metacall/install) and try [some examples] - [5.3.2.1 MetaCall](#5321-metacall) - [5.3.2.2 RapidJSON](#5322-rapidjson) - [5.3.3 Detours](#533-detours) - - [5.3.3.1 FuncHook](#5331-funchook) + - [5.3.3.1 PLTHook](#5331-plthook) - [5.4 Ports](#54-ports) - [5.5 Serialization](#55-serialization) - [5.6 Memory Layout](#56-memory-layout) @@ -93,7 +93,7 @@ The **METACALL** project started a long time ago when I was coding a [Game Engin ## 2. Language Support -This section describes all programming languages that **METACALL** supports. **METACALL** is offered through a C API. This means you can use it as a library to embed different runtimes into C. The **[Loaders](#21-loaders-backends)** are the ones that allow to call different functions from C. They are plugins (libraries) which **METACALL** loads and they have a common interface. They usually implement JITs, VMs or interpreters. On the other hand we have the **[Ports](#22-ports-frontends)** which are wrappers to the **METACALL** C API that expose the API to other languages. With the Python Loader we can execute calls to Python from C. With the Python Port we can install **METACALL** via `pip` and use it to call other languages from Python. The combination of both provides the opportunity for complete interoperability between virtually any two languages. +This section describes all programming languages that **METACALL** supports. **METACALL** is offered through a C API. This means you can use it as a library to embed different runtimes into C. The **[Loaders](#21-loaders-backends)** are the ones that allow to call different functions from C. They are plugins (libraries) that **METACALL** loads and they have a common interface. They usually implement JITs, VMs or interpreters. On the other hand we have the **[Ports](#22-ports-frontends)** which are wrappers to the **METACALL** C API that expose the API to other languages. With the Python Loader we can execute calls to Python from C. With the Python Port we can install **METACALL** via `pip` and use it to call other languages from Python. The combination of both provides the opportunity for complete interoperability between virtually any two languages. ### 2.1 Loaders (Backends) @@ -116,7 +116,7 @@ This section describes all programming languages that **METACALL** allows to loa | [Java](https://www.java.com) | [JVM](https://en.wikipedia.org/wiki/Java_virtual_machine) | **>=11** | java | | [WebAssembly](https://webassembly.org/) | [Wasmtime](https://github.com/bytecodealliance/wasmtime) | **>= 0.27 <= 8.0.1** | wasm | | [C]() | [libclang](https://clang.llvm.org/doxygen/group__CINDEX.html) - [Tiny C Compiler](https://bellard.org/tcc/) - [libffi](http://sourceware.org/libffi/) | **>=12** - **>=2021-10-30** - **>=3.2** | c | -| [Rust](https://www.rust-lang.org/) | [rustc](https://doc.rust-lang.org/rustc/what-is-rustc.html - [libffi](http://sourceware.org/libffi/) | **nightly-2021-12-04** | rs | +| [Rust](https://www.rust-lang.org/) | [rustc](https://doc.rust-lang.org/rustc/what-is-rustc.html) - [libffi](http://sourceware.org/libffi/) | **nightly-2021-12-04** | rs | - Languages and run-times under construction: @@ -156,17 +156,17 @@ Ports are the frontends to the **METACALL C API** from other languages. They all **METACALL** can be used in the following cases: -- Interconnect different technologies in the same project. It allows heterogeneous teams of developers to work on the same project in an isolated way and using different programming languages at the same time. +- Interconnect different technologies in the same project. It allows heterogeneous teams of developers to work on the same project in an isolated way and use different programming languages at the same time. -- Embedding programming languages in existing software. Game Engines, 3D Editors like [Blender](https://www.blender.org/), among others can take benefit of **METACALL** and extend the core functionality with higher level programming languages (aka scripting). +- Embedding programming languages in existing software. Game Engines and 3D Editors like [Blender](https://www.blender.org/), among others can take benefit of **METACALL** and extend the core functionality with higher level programming languages (aka scripting). - Function as a Service. **METACALL** can be used to implement efficient FaaS architectures. We are using it to implement our own FaaS (Function as a Service) **[https://metacall.io](https://metacall.io/)** based on **[Function Mesh](https://medium.com/@metacall/function-mesh-architecture-c0304ba4bad0)** pattern and high performance function scalability thanks to this library. -- Source code migrations. **METACALL** can wrap large and legacy codebases, and provide an agnostic way to work with the codebase in a new programming language. Eventually the code can be migrated in parts, without needing to create a new project or stop the production environment. Incremental changes can be done, solving the migration easily and with less time and effort. +- Source code migrations. **METACALL** can wrap large and legacy codebases, and provide an agnostic way to work with the codebase in a new programming language. Eventually the code can be migrated in parts, without needing to create a new project or stop the production environment. Incremental changes can be made, solving the migration easily and with less time and effort. - Porting low level libraries to high level languages transparently. With **METACALL** you can get rid of extension APIs like Python C API or NodeJS N-API. You can call low level libraries directly from your high level languages without making a wrapper in C or C++ for it. -As you can see, there are plenty of uses. **METACALL** introduces a new model of programming which allows a high interoperability between technologies. If you find any other use case just let us know about it with a Pull Request and we will add it to the list. +As you can see, there are plenty of uses. **METACALL** introduces a new model of programming which allows high interoperability between technologies. If you find any other use case just let us know about it with a Pull Request and we will add it to the list. ## 3.1 Known Projects Using MetaCall @@ -178,13 +178,13 @@ As you can see, there are plenty of uses. **METACALL** introduces a new model of ## 4.1 Installation -Prior to trying any of the examples, you must have **METACALL** installed in your system. To install **METACALL** you have the following options: +Before trying any of the examples, you must have **METACALL** installed in your system. To install **METACALL** you have the following options: - [Install precompiled tarball via shell script (downloads the tarball generated by Guix)](https://github.com/metacall/install). - [Build and install it manually](#6-build-system). - [Pull it from DockerHub](https://hub.docker.com/r/metacall/core). - [Install via Guix package manager](https://github.com/metacall/distributable/blob/master/source/metacall.scm) (needs to fix the commit of [Guix channels](https://github.com/metacall/distributable/blob/master/channels/channels.scm)). -- [Download precompiled tarball from Guix via Distributable Releases Assests](https://github.com/metacall/distributable/releases). +- [Download the precompiled tarball from Guix via Distributable Releases Assets](https://github.com/metacall/distributable/releases). - [ArchLinux AUR](https://github.com/metacall/aur). - [Homebrew](https://github.com/metacall/homebrew). - [Download precompiled tarball (.tar.gz) or Debian (.deb) / RPM (.rpm) installers via Core Releases Assets](https://github.com/metacall/core/releases). @@ -229,17 +229,17 @@ The environment variables are optional, in case you want to modify default paths #### 5.1.1 Design Decisions -- To provide an high level API with a simple UX and to be easy to understand. +- To provide a high level API with a simple UX and to be easy to understand. - To work in high performance environments. - To be as cross-platform as possible. -- To avoid to modify run-times directly or use the code inside **METACALL** in order to avoid maintaining them, or propagating security flaws or licenses into **METACALL**. +- To avoid modifying run-times directly or using the code inside **METACALL** to avoid maintaining them, or propagating security flaws or licenses into **METACALL**. -- To provide support for any embeddable programming language and to provide support for **METACALL** to be used form any programming language. +- To provide support for any embeddable programming language and to provide support for **METACALL** to be used from any programming language. -- All external code used into **METACALL** must be introduced by inversion of control in the plugin system, so that the core must not remain aware from what software is using. +- All external code used in **METACALL** must be introduced by inversion of control in the plugin system so that the core must not remain aware of what software is used. - All code developed in **METACALL** must be implemented in standalone libraries that can work by themselves in an isolated way (aka modules). @@ -251,17 +251,17 @@ The environment variables are optional, in case you want to modify default paths - [`detours`](/source/detours) implement the [`detour`](/source/detour) interface by using a plugin architecture. The current list of available detour plugins is the following one. - - [`funchook_detour`](/source/detours/funchook_detour) implemented by means of FuncHook library. + - [`plthook_detour`](/source/detours/plthook_detour) implemented by means of PLTHook library. - [`dynlink`](/source/dynlink) implements a cross-platform method to dynamically load libraries. It is used to dynamically load plugins into **METACALL**. -- [`environment`](/source/environment) implements an standard way to deal with environment variables. **METACALL** uses environment variables to define custom paths for plugins and scripts. +- [`environment`](/source/environment) implements a standard way to deal with environment variables. **METACALL** uses environment variables to define custom paths for plugins and scripts. - [`examples`](/source/examples) ... - [`filesystem`](/source/filesystem) provides an abstraction for operative system file system. -- [`format`](/source/format) provides an standard way for printing to standard input output for old C versions that does not support newest constructions. +- [`format`](/source/format) provides a standard way for printing to standard input output for old C versions that does not support newest constructions. - [`loader`](/source/loader) ... @@ -293,11 +293,11 @@ The environment variables are optional, in case you want to modify default paths The module that holds the representation of types, values and functions is called [`reflect`](/source/reflect) and it handles the abstraction of code loaded into **METACALL**. -**METACALL** uses reflection and introspection techniques to inspect the code loaded by the [`loaders`](/source/loaders) in order to interpret it and provide an higher abstraction of it. With this higher abstraction **METACALL** can easily inter-operate between languages transparently. +**METACALL** uses reflection and introspection techniques to inspect the code loaded by the [`loaders`](/source/loaders) in order to interpret it and provide a higher abstraction of it. With this higher abstraction **METACALL** can easily inter-operate between languages transparently. #### 5.2.1 Type System -**METACALL** implements an abstract type system which is a binary representation of the types supported by it. This means that **METACALL** can convert any type of a language to its own type system and back. Each loader is responsible of doing this conversions. +**METACALL** implements an abstract type system which is a binary representation of the types supported by it. This means that **METACALL** can convert any type of a language to its own type system and back. Each loader is responsible of doing these conversions. **METACALL** maintains most of the types of the languages but not all are supported. If new types are added they have to be implemented in the [`reflect`](/source/reflect) module and also in the [`loaders`](/source/loaders) and [`serials`](/source/serials) to fully support it. @@ -321,7 +321,7 @@ The module that holds the representation of types, values and functions is calle | Class | Defines properties and methods that are common to all objects | | Object | An instance of Class | -- Boolean is mostly represented by an integer value. There are languages that does not support it so it gets converted to a integer value in the memory layout. +- Boolean is mostly represented by an integer value. There are languages that does not support it so it gets converted to an integer value in the memory layout. - Integer and Floating Point values provide a complete abstraction to numerical types. Type sizes are preserved and the correct type is used when using any number. This depends on the internal implementation of the value by the run-time. Although there can be problems related to this. A `bignum` type from Ruby may overflow if it is too big when trying to convert it to a `float` type in C#. @@ -329,9 +329,9 @@ The module that holds the representation of types, values and functions is calle - Buffer represents a blob of raw memory (i.e. an array of bytes). This can be used to represent files as images or any other resources into memory. -- Array is implemented by means of array of values, which you can think it should be called _list_ instead. But as the memory layout is stored into a contiguous memory block of references to values, it is considered an array. +- Array is implemented using an array of values, which might lead one to ponder that it should be called _list_ instead. But as the memory layout is stored into a contiguous memory block of references to values, it is considered an array. -- Map implements an associative key value pair container. A map is implemented with an array of two sized elements array. Each element of the map is an array of size two, where the first element of it is always an String and the second element is a value of any type. +- Map implements an associative key value pair container. A map is implemented with an array of two sized elements array. Each element of the map is an array of size two, where the first element of it is always a String and the second element is a value of any type. - Pointer is an opaque value representing a raw reference to a memory block. Some languages allow to use references to memory and some others do not. This type is opaque because **METACALL** does not know what kind of concrete value represents it. The representation may be a complex type handled by the developer source code inside the run-time. @@ -347,7 +347,7 @@ When converting values between different types, if any potential number overflow The value model is implemented by means of object pool. Each value is a reference to a memory block allocated from a memory pool (which can be injected into **METACALL**). The references can be passed by value, this means **METACALL** copies the reference value instead of the data which this reference is pointing to, like most run-times do when managing their own values. -Each created value must be destroyed manually, otherwise it will lead to a memory leak. This only occurs when dealing with **METACALL** at C level. If **METACALL** is being used in an higher language through [`ports`](/source/ports), the developer does not have to care about memory management. +Each created value must be destroyed manually, otherwise it will lead to a memory leak. This only occurs when dealing with **METACALL** at C level. If **METACALL** is being used in a higher language through [`ports`](/source/ports), the developer does not have to care about memory management. The value memory layout is described in the following form. @@ -499,7 +499,7 @@ A loader must implement it to be considered a valid loader. #### 5.3.3 Detours -##### 5.3.3.1 FuncHook +##### 5.3.3.1 PLTHook ### 5.4 Ports @@ -555,7 +555,7 @@ Usually the developer is the same who does the fork, but it may be possible that ### 5.8 Threading Model -The threading model is still experimental. We are discovering the best ways of designing and implementing it, so it may vary over time. In another hand, at the moment of writing (check the commit history), there are some concerns that are already known and parts of the design that we have achieved thanks to NodeJS event loop nature. +The threading model is still experimental. We are discovering the best ways of designing and implementing it, so it may vary over time. At the moment of writing (check the commit history), there are some concerns that are already known and parts of the design already achieved thanks to the NodeJS event loop nature. The Node Loader is designed in a way in which the V8 instance is created in a new thread, and from there the event loop "blocks" that thread until the execution. Recent versions of N-API (since NodeJS 14.x) allow you to have control and reimplement your own event loop thanks to the new embedder API. But when this project started and NodeJS loader was implemented, only NodeJS 8.x exist. So the only option (without reimplementing part of NodeJS, because it goes against one design decisions of the project) was to use `node::Start`, a call that blocks your thread while executing the event loop. This also produces a lot of problems, because of lack of control over NodeJS, but they are not directly related to the thread model. @@ -663,11 +663,11 @@ It is possible to enable or disable concrete loaders, script, ports, serials or | Build Option Prefix | Build Option Suffix | | :-----------------------: | --------------------------------------------------------------------- | -| **OPTION*BUILD_LOADERS*** | `C` `JS` `CS` `MOCK` `PY` `JSM` `NODE` `RB` `FILE` | -| **OPTION*BUILD_SCRIPTS*** | `C` `CS` `JS` `NODE` `PY` `RB` `JAVA` | -| **OPTION*BUILD_SERIALS*** | `METACALL` `RAPID_JSON` | -| **OPTION*BUILD_DETOURS*** | `FUNCHOOK` | -| **OPTION*BUILD_PORTS*** | `CS` `CXX` `D` `GO` `JAVA` `JS` `LUA` `NODE` `PHP` `PL` `PY` `R` `RB` | +| **OPTION_BUILD_LOADERS_*** | `C` `JS` `CS` `MOCK` `PY` `JSM` `NODE` `RB` `FILE` | +| **OPTION_BUILD_SCRIPTS_*** | `C` `CS` `JS` `NODE` `PY` `RB` `JAVA` | +| **OPTION_BUILD_SERIALS_*** | `METACALL` `RAPID_JSON` | +| **OPTION_BUILD_DETOURS_*** | `PLTHOOK` | +| **OPTION_BUILD_PORTS_*** | `CS` `CXX` `D` `GO` `JAVA` `JS` `LUA` `NODE` `PHP` `PL` `PY` `R` `RB` | To format the entire C/C++ codebase use: @@ -679,27 +679,19 @@ Be aware that this target won't exist if clang-format was not installed when cma ### 6.2 Coverage -In order to run code coverage and obtain html reports use the following commands. Note, test must be run before executing code coverage. +In order to run code coverage and obtain html reports use the following commands (assuming you just clonned the repository): ```sh -make -make test -make -k gcov -make -k lcov -make -k lcov-genhtml +git clone https://github.com/metacall/core.git +mkdir core/build && cd core/build +cmake -DCMAKE_BUILD_TYPE=Debug -DOPTION_COVERAGE=On .. +make -j$(NPROC) +ctest +ctest -T Coverage +gcovr -r ../source/ . --html-details coverage.html ``` -The output reports will be generated in `${CMAKE_BINARY_DIR}/lcov/html/selected_targets` in html format. - -To obtain a report of a single `target` do: - -```sh -make -make test -make -gcov -make -geninfo -make -genhtml -``` +The output reports will be generated in `${CMAKE_BINARY_DIR}/coverage.html` in html format. ### 6.3 Debugging @@ -746,14 +738,14 @@ Click the button below. A workspace with all required environments will be creat ## 7. Platform Support -The following platforms and architectures have been tested an work correctly with all plugins of **METACALL**. +The following platforms and architectures have been tested and are known to work correctly with all plugins of **METACALL**. -| Operative System | Architecture | Compiler | -| :--------------: | :-----------------: | :---------: | -| **`ubuntu`** | **`amd64`** | **`gcc`** | -| **`debian`** | **`amd64`** | **`gcc`** | -| **`debian`** | **`amd64`** | **`clang`** | -| **`windows`** | **`x86`** **`x64`** | **`msvc`** | +| Operative System | Architecture | Compiler | +| :--------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :---------: | +| **`ubuntu`** | **`amd64`** | **`gcc`** | +| **`debian`** | **`amd64`** **`amd64/v2`** **`amd64/v3`** **`386`** **`arm64`** **`riscv64`** **`ppc64le`** **`arm/v7`** **`arm/v6`** **`loong64`** | **`gcc`** | +| **`macos`** | **`amd64`** **`arm64`** | **`clang`** | +| **`windows`** | **`x86`** **`x64`** | **`msvc`** | ### 7.1 Docker Support @@ -870,13 +862,14 @@ Where `script.js` is a script contained in host folder `$HOME/metacall` that wil | :-----------------: | :--------------------------------------------------: | | **`ubuntu-latest`** | https://metacall.github.io/core/bench/ubuntu-latest/ | | **`macos-latest`** | https://metacall.github.io/core/bench/macos-latest/ | -| **`windows-2019`** | https://metacall.github.io/core/bench/windows-2019/ | +| **`windows-2022`** | https://metacall.github.io/core/bench/windows-2022/ | +| **`windows-2025`** | https://metacall.github.io/core/bench/windows-2025/ | ## 9. License **METACALL** is licensed under **[Apache License Version 2.0](/LICENSE)**. -> Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia <> +> Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia <> > > Licensed under the Apache License, Version 2.0 (the "License"); > you may not use this file except in compliance with the License. diff --git a/metacall-config-version.cmake.in b/metacall-config-version.cmake.in index b1dbaaf9d9..a25c169f21 100644 --- a/metacall-config-version.cmake.in +++ b/metacall-config-version.cmake.in @@ -2,7 +2,7 @@ # MetaCall Library by Parra Studios # A library for providing a foreing function interface calls. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/metacall-config.cmake.in b/metacall-config.cmake.in index bed83cb4cb..eb193eed48 100644 --- a/metacall-config.cmake.in +++ b/metacall-config.cmake.in @@ -2,7 +2,7 @@ # MetaCall Library by Parra Studios # A library for providing a foreing function interface calls. # -# Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 96ce56f95b..b7c1e402b9 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -18,9 +18,6 @@ set(SERIAL_LIBRARY_PATH "@OUTPUT_DIRECTORY_DIR@" CACHE PATH "MetaCall serial lib # Export output detour plugin directory set(DETOUR_LIBRARY_PATH "@OUTPUT_DIRECTORY_DIR@" CACHE PATH "MetaCall detour library path") -# Export output port directory -set(PORT_LIBRARY_PATH "@OUTPUT_DIRECTORY_DIR@" CACHE PATH "MetaCall port library path") - # Add extra environment varible set(EXTRA_ENVIRONMENT_VARIABLES "" CACHE PATH "MetaCall extra environment variable") @@ -54,17 +51,13 @@ set(TESTS_DETOUR_ENVIRONMENT_VARIABLES "DETOUR_LIBRARY_PATH=${DETOUR_LIBRARY_PATH}" ) -set(TESTS_PORT_ENVIRONMENT_VARIABLES - "PORT_LIBRARY_PATH=${PORT_LIBRARY_PATH}" -) - set(TESTS_ENVIRONMENT_VARIABLES ${TESTS_LOADER_ENVIRONMENT_VARIABLES} ${TESTS_CONFIGURATION_ENVIRONMENT_VARIABLES} ${TESTS_SERIAL_ENVIRONMENT_VARIABLES} ${TESTS_DETOUR_ENVIRONMENT_VARIABLES} - ${TESTS_PORT_ENVIRONMENT_VARIABLES} ${TESTS_SANITIZER_ENVIRONMENT_VARIABLES} + ${TESTS_MEMCHECK_ENVIRONMENT_VARIABLES} ${EXTRA_ENVIRONMENT_VARIABLES} ) @@ -78,12 +71,13 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Default definitions # -add_definitions( - -DCONFIGURATION_INSTALL_PATH=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_DATA}/configurations/global.json\" - -DSERIAL_LIBRARY_INSTALL_PATH=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_SHARED}\" - -DLOADER_LIBRARY_INSTALL_PATH=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_SHARED}\" - -DDETOUR_LIBRARY_INSTALL_PATH=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_SHARED}\" - -DPORT_LIBRARY_INSTALL_PATH=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_SHARED}\" +set(DEFAULT_COMPILE_DEFINITIONS + ${DEFAULT_COMPILE_DEFINITIONS} + CONFIGURATION_INSTALL_PATH="${CMAKE_INSTALL_PREFIX}/${INSTALL_DATA}/configurations/global.json" + SERIAL_LIBRARY_INSTALL_PATH="${CMAKE_INSTALL_PREFIX}/${INSTALL_SHARED}" + LOADER_LIBRARY_INSTALL_PATH="${CMAKE_INSTALL_PREFIX}/${INSTALL_SHARED}" + DETOUR_LIBRARY_INSTALL_PATH="${CMAKE_INSTALL_PREFIX}/${INSTALL_SHARED}" + PORT_LIBRARY_INSTALL_PATH="${CMAKE_INSTALL_PREFIX}/${INSTALL_SHARED}" ) # diff --git a/source/adt/CMakeLists.txt b/source/adt/CMakeLists.txt index 122513f58a..6083509df2 100644 --- a/source/adt/CMakeLists.txt +++ b/source/adt/CMakeLists.txt @@ -164,7 +164,7 @@ target_compile_options(${target} # Linker options # -target_link_libraries(${target} +target_link_options(${target} PRIVATE PUBLIC diff --git a/source/adt/include/adt/adt.h b/source/adt/include/adt/adt.h index 7283a5c08d..040bd1fc50 100644 --- a/source/adt/include/adt/adt.h +++ b/source/adt/include/adt/adt.h @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/source/adt/include/adt/adt_bucket.h b/source/adt/include/adt/adt_bucket.h index 7053b2157c..4fb799f189 100644 --- a/source/adt/include/adt/adt_bucket.h +++ b/source/adt/include/adt/adt_bucket.h @@ -1,6 +1,6 @@ /* * Abstract Data Type Library by Parra Studios - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * A abstract data type library providing generic containers. * diff --git a/source/adt/include/adt/adt_comparable.h b/source/adt/include/adt/adt_comparable.h index 0ef2d082b0..54fc2d2b84 100644 --- a/source/adt/include/adt/adt_comparable.h +++ b/source/adt/include/adt/adt_comparable.h @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/source/adt/include/adt/adt_hash.h b/source/adt/include/adt/adt_hash.h index b275c9895a..3601d4676c 100644 --- a/source/adt/include/adt/adt_hash.h +++ b/source/adt/include/adt/adt_hash.h @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/source/adt/include/adt/adt_map.h b/source/adt/include/adt/adt_map.h index ef1b45ebc8..2a256463ed 100644 --- a/source/adt/include/adt/adt_map.h +++ b/source/adt/include/adt/adt_map.h @@ -1,6 +1,6 @@ /* * Abstract Data Type Library by Parra Studios - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * A abstract data type library providing generic containers. * @@ -51,6 +51,15 @@ typedef int (*map_cb_iterate)(map, map_key, map_value, map_cb_iterate_args); typedef struct map_iterator_type *map_iterator; +/* -- Member Data -- */ + +struct map_iterator_type +{ + map m; + size_t current_bucket; + size_t current_pair; +}; + /* -- Methods -- */ ADT_API map map_create(map_cb_hash hash_cb, map_cb_compare compare_cb); @@ -79,15 +88,15 @@ ADT_API int map_clear(map m); ADT_API void map_destroy(map m); -ADT_API map_iterator map_iterator_begin(map m); +ADT_API void map_iterator_begin(map_iterator it, map m); -ADT_API map_key map_iterator_get_key(map_iterator it); +ADT_API map_key map_iterator_key(map_iterator it); -ADT_API map_value map_iterator_get_value(map_iterator it); +ADT_API map_value map_iterator_value(map_iterator it); ADT_API void map_iterator_next(map_iterator it); -ADT_API int map_iterator_end(map_iterator *it); +ADT_API int map_iterator_end(map_iterator it); #ifdef __cplusplus } diff --git a/source/adt/include/adt/adt_set.h b/source/adt/include/adt/adt_set.h index 81140723b2..a662a90b8b 100644 --- a/source/adt/include/adt/adt_set.h +++ b/source/adt/include/adt/adt_set.h @@ -1,6 +1,6 @@ /* * Abstract Data Type Library by Parra Studios - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * A abstract data type library providing generic containers. * @@ -50,6 +50,15 @@ typedef int (*set_cb_iterate)(set, set_key, set_value, set_cb_iterate_args); typedef struct set_iterator_type *set_iterator; +/* -- Member Data -- */ + +struct set_iterator_type +{ + set s; + size_t current_bucket; + size_t current_pair; +}; + /* -- Methods -- */ ADT_API set set_create(set_cb_hash hash_cb, set_cb_compare compare_cb); @@ -80,15 +89,15 @@ ADT_API int set_clear(set s); ADT_API void set_destroy(set s); -ADT_API set_iterator set_iterator_begin(set s); +ADT_API void set_iterator_begin(set_iterator it, set s); -ADT_API set_key set_iterator_get_key(set_iterator it); +ADT_API set_key set_iterator_key(set_iterator it); -ADT_API set_value set_iterator_get_value(set_iterator it); +ADT_API set_value set_iterator_value(set_iterator it); ADT_API void set_iterator_next(set_iterator it); -ADT_API int set_iterator_end(set_iterator *it); +ADT_API int set_iterator_end(set_iterator it); #ifdef __cplusplus } diff --git a/source/adt/include/adt/adt_string.h b/source/adt/include/adt/adt_string.h index 903acbbd18..1b50369a8d 100644 --- a/source/adt/include/adt/adt_string.h +++ b/source/adt/include/adt/adt_string.h @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,13 +35,12 @@ extern "C" { /* -- Macros -- */ /* This is a temporary solution for safe strings, it can be improved in the future */ -#define string_copy(dest, src, dest_size) \ - do \ - { \ +#define string_copy(dest, src, dest_size) \ + do \ + { \ size_t __string_copy_length = strnlen(src, dest_size - 1); \ - memcpy(dest, src, __string_copy_length); \ - dest[__string_copy_length] = '\0'; \ - \ + memcpy(dest, src, __string_copy_length); \ + dest[__string_copy_length] = '\0'; \ } while (0) #ifdef __cplusplus diff --git a/source/adt/include/adt/adt_trie.h b/source/adt/include/adt/adt_trie.h index a867f7b08a..899e1f9296 100644 --- a/source/adt/include/adt/adt_trie.h +++ b/source/adt/include/adt/adt_trie.h @@ -1,6 +1,6 @@ /* * Abstract Data Type Library by Parra Studios - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * A abstract data type library providing generic containers. * diff --git a/source/adt/include/adt/adt_vector.h b/source/adt/include/adt/adt_vector.h index d839b2b8d4..d727171687 100644 --- a/source/adt/include/adt/adt_vector.h +++ b/source/adt/include/adt/adt_vector.h @@ -1,6 +1,6 @@ /* * Abstract Data Type Library by Parra Studios - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * A abstract data type library providing generic containers. * @@ -205,13 +205,11 @@ typedef struct vector_type *vector; * @param[in] type_name * Type of element to be modified */ -#define vector_set_const(v, position, constant, type_name) \ - do \ - { \ - type_name macro_vector_type_const_to_var = constant; \ - \ +#define vector_set_const(v, position, constant, type_name) \ + do \ + { \ + type_name macro_vector_type_const_to_var = constant; \ vector_set(v, position, ¯o_vector_type_const_to_var); \ - \ } while (0) /** @@ -228,13 +226,11 @@ typedef struct vector_type *vector; * @param[in] type_name * Type of element to be inserted */ -#define vector_push_back_const(v, constant, type_name) \ - do \ - { \ - type_name macro_vector_type_const_to_var = constant; \ - \ +#define vector_push_back_const(v, constant, type_name) \ + do \ + { \ + type_name macro_vector_type_const_to_var = constant; \ vector_push_back(v, ¯o_vector_type_const_to_var); \ - \ } while (0) /** @@ -251,13 +247,11 @@ typedef struct vector_type *vector; * @param[in] type_name * Type of element to be inserted */ -#define vector_push_front_const(v, constant, type_name) \ - do \ - { \ - type_name macro_vector_type_const_to_var = constant; \ - \ +#define vector_push_front_const(v, constant, type_name) \ + do \ + { \ + type_name macro_vector_type_const_to_var = constant; \ vector_push_front(v, ¯o_vector_type_const_to_var); \ - \ } while (0) /** @@ -279,13 +273,11 @@ typedef struct vector_type *vector; * @param[in] type_name * Type of element to be inserted */ -#define vector_insert_const(v, position, constant, type_name) \ - do \ - { \ - type_name macro_vector_type_const_to_var = constant; \ - \ +#define vector_insert_const(v, position, constant, type_name) \ + do \ + { \ + type_name macro_vector_type_const_to_var = constant; \ vector_insert(v, position, ¯o_vector_type_const_to_var); \ - \ } while (0) /* -- Methods -- */ diff --git a/source/adt/source/adt.c b/source/adt/source/adt.c index 376c9914dc..eeaf243223 100644 --- a/source/adt/source/adt.c +++ b/source/adt/source/adt.c @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ const char *adt_print_info(void) { static const char adt_info[] = "Abstract Data Type Library " METACALL_VERSION "\n" - "Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia \n" + "Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia \n" #ifdef ADT_STATIC_DEFINE "Compiled as static library type" diff --git a/source/adt/source/adt_bucket.c b/source/adt/source/adt_bucket.c index c24d193bf7..98f7398751 100644 --- a/source/adt/source/adt_bucket.c +++ b/source/adt/source/adt_bucket.c @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/source/adt/source/adt_comparable.c b/source/adt/source/adt_comparable.c index 38b6257a9d..037be1f9be 100644 --- a/source/adt/source/adt_comparable.c +++ b/source/adt/source/adt_comparable.c @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/source/adt/source/adt_hash.c b/source/adt/source/adt_hash.c index 69649ac9b1..2800af3b60 100644 --- a/source/adt/source/adt_hash.c +++ b/source/adt/source/adt_hash.c @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/source/adt/source/adt_map.c b/source/adt/source/adt_map.c index 5e4fd572e5..eb1768d0d9 100644 --- a/source/adt/source/adt_map.c +++ b/source/adt/source/adt_map.c @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,21 +42,6 @@ struct map_type map_cb_compare compare_cb; }; -struct map_iterator_type -{ - map m; - size_t current_bucket; - size_t current_pair; -}; - -struct map_contains_any_cb_iterator_type -{ - map m; - int result; -}; - -typedef struct map_contains_any_cb_iterator_type *map_contains_any_cb_iterator; - /* -- Methods -- */ map map_create(map_cb_hash hash_cb, map_cb_compare compare_cb) @@ -104,30 +89,38 @@ size_t map_size(map m) return 0; } -static int map_bucket_realloc_iterator(map m, map_key key, map_value value, map_cb_iterate_args args) +static int map_bucket_rehash(map m, map new_map) { - map new_map = (map)args; + size_t bucket_iterator, pair_iterator; - if (new_map != m && key != NULL && args != NULL) + for (bucket_iterator = 0; bucket_iterator < m->capacity; ++bucket_iterator) { - map_hash h = new_map->hash_cb(key); + bucket b = &m->buckets[bucket_iterator]; - size_t index = h % new_map->capacity; + if (b->pairs != NULL && b->count > 0) + { + for (pair_iterator = 0; pair_iterator < b->count; ++pair_iterator) + { + pair p = &b->pairs[pair_iterator]; - bucket b = &new_map->buckets[index]; + map_hash h = new_map->hash_cb(p->key); - if (bucket_insert(b, key, value) != 0) - { - log_write("metacall", LOG_LEVEL_ERROR, "Invalid map bucket realloc insertion"); - return 1; - } + size_t index = h % new_map->capacity; - ++new_map->count; + bucket new_bucket = &new_map->buckets[index]; - return 0; + if (bucket_insert(new_bucket, p->key, p->value) != 0) + { + log_write("metacall", LOG_LEVEL_ERROR, "Invalid map bucket realloc insertion"); + return 1; + } + + ++new_map->count; + } + } } - return 1; + return 0; } static int map_bucket_realloc(map m) @@ -160,8 +153,10 @@ static int map_bucket_realloc(map m) { size_t iterator; - map_iterate(m, &map_bucket_realloc_iterator, &new_map); + /* Rehash all the elements into the new map */ + map_bucket_rehash(m, &new_map); + /* Destroy all pairs from old map */ for (iterator = 0; iterator < m->capacity; ++iterator) { bucket b = &m->buckets[iterator]; @@ -172,6 +167,7 @@ static int map_bucket_realloc(map m) } } + /* Destroy all buckets from old map */ free(m->buckets); m->capacity = new_map.capacity; @@ -239,9 +235,9 @@ vector map_get(map m, map_key key) { if (m != NULL && key != NULL) { - map_hash hash = m->hash_cb(key); + map_hash h = m->hash_cb(key); - size_t index = hash % m->capacity; + size_t index = h % m->capacity; bucket b = &m->buckets[index]; @@ -255,9 +251,9 @@ int map_contains(map m, map_key key) { if (m != NULL && key != NULL) { - map_hash hash = m->hash_cb(key); + map_hash h = m->hash_cb(key); - size_t index = hash % m->capacity; + size_t index = h % m->capacity; bucket b = &m->buckets[index]; @@ -272,29 +268,29 @@ int map_contains(map m, map_key key) return 1; } -static int map_contains_any_cb_iterate(map m, map_key key, map_value value, map_cb_iterate_args args) -{ - map_contains_any_cb_iterator iterator = (map_contains_any_cb_iterator)args; - - (void)m; - (void)value; - - iterator->result = map_contains(iterator->m, key); - - /* Stop iteration if we found an element */ - return !iterator->result; -} - int map_contains_any(map dest, map src) { - struct map_contains_any_cb_iterator_type args; + size_t bucket_iterator, pair_iterator; - args.m = dest; - args.result = 1; + for (bucket_iterator = 0; bucket_iterator < src->capacity; ++bucket_iterator) + { + bucket b = &src->buckets[bucket_iterator]; - map_iterate(src, &map_contains_any_cb_iterate, (map_cb_iterate_args)&args); + if (b->pairs != NULL && b->count > 0) + { + for (pair_iterator = 0; pair_iterator < b->count; ++pair_iterator) + { + pair p = &b->pairs[pair_iterator]; - return args.result; + if (map_contains(dest, p->key) == 0) + { + return 0; + } + } + } + } + + return 1; } map_value map_remove(map m, map_key key) @@ -413,20 +409,27 @@ void map_iterate(map m, map_cb_iterate iterate_cb, map_cb_iterate_args args) } } -static int map_append_cb_iterate(map m, map_key key, map_value value, map_cb_iterate_args args) +int map_append(map dest, map src) { - map dest = (map)args; - - (void)m; + size_t bucket_iterator, pair_iterator; - return map_insert(dest, key, value); -} + for (bucket_iterator = 0; bucket_iterator < src->capacity; ++bucket_iterator) + { + bucket b = &src->buckets[bucket_iterator]; -int map_append(map dest, map src) -{ - map_cb_iterate_args args = (map_cb_iterate_args)dest; + if (b->pairs != NULL && b->count > 0) + { + for (pair_iterator = 0; pair_iterator < b->count; ++pair_iterator) + { + pair p = &b->pairs[pair_iterator]; - map_iterate(src, &map_append_cb_iterate, args); + if (map_insert(dest, p->key, p->value) != 0) + { + return 1; + } + } + } + } return 0; } @@ -496,30 +499,29 @@ void map_destroy(map m) free(m); } -map_iterator map_iterator_begin(map m) +void map_iterator_begin(map_iterator it, map m) { - if (m != NULL && m->buckets != NULL && map_size(m) > 0) + if (it != NULL) { - map_iterator it = malloc(sizeof(struct map_iterator_type)); + it->current_bucket = 0; + it->current_pair = 0; - if (it != NULL) + if (m != NULL && m->buckets != NULL && map_size(m) > 0) { it->m = m; - it->current_bucket = 0; - it->current_pair = 0; map_iterator_next(it); - - return it; + } + else + { + it->m = NULL; } } - - return NULL; } -map_key map_iterator_get_key(map_iterator it) +map_key map_iterator_key(map_iterator it) { - if (it != NULL && it->current_bucket < it->m->capacity && it->current_pair > 0) + if (it != NULL && it->m != NULL && it->current_bucket < it->m->capacity && it->current_pair > 0) { return it->m->buckets[it->current_bucket].pairs[it->current_pair - 1].key; } @@ -527,9 +529,9 @@ map_key map_iterator_get_key(map_iterator it) return NULL; } -map_value map_iterator_get_value(map_iterator it) +map_value map_iterator_value(map_iterator it) { - if (it != NULL && it->current_bucket < it->m->capacity && it->current_pair > 0) + if (it != NULL && it->m != NULL && it->current_bucket < it->m->capacity && it->current_pair > 0) { return it->m->buckets[it->current_bucket].pairs[it->current_pair - 1].value; } @@ -539,7 +541,7 @@ map_value map_iterator_get_value(map_iterator it) void map_iterator_next(map_iterator it) { - if (it != NULL) + if (it != NULL && it->m != NULL) { for (; it->current_bucket < it->m->capacity; ++it->current_bucket) { @@ -559,20 +561,18 @@ void map_iterator_next(map_iterator it) } } } + + it->current_pair = 0; } } } -int map_iterator_end(map_iterator *it) +int map_iterator_end(map_iterator it) { - if (it != NULL && *it != NULL) + if (it != NULL && it->m != NULL) { - if ((*it)->current_bucket >= (*it)->m->capacity) + if (it->current_bucket >= it->m->capacity) { - free(*it); - - *it = NULL; - return 0; } diff --git a/source/adt/source/adt_set.c b/source/adt/source/adt_set.c index 2014e56c00..2ffd457172 100644 --- a/source/adt/source/adt_set.c +++ b/source/adt/source/adt_set.c @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,29 +42,6 @@ struct set_type set_cb_compare compare_cb; }; -struct set_iterator_type -{ - set s; - size_t current_bucket; - size_t current_pair; -}; - -struct set_contains_any_cb_iterator_type -{ - set s; - int result; -}; - -struct set_contains_which_cb_iterator_type -{ - set s; - int result; - set_key *key; -}; - -typedef struct set_contains_any_cb_iterator_type *set_contains_any_cb_iterator; -typedef struct set_contains_which_cb_iterator_type *set_contains_which_cb_iterator; - /* -- Methods -- */ set set_create(set_cb_hash hash_cb, set_cb_compare compare_cb) @@ -112,6 +89,8 @@ size_t set_size(set s) return 0; } +/* + static int set_bucket_realloc_iterator(set s, set_key key, set_value value, set_cb_iterate_args args) { set new_set = (set)args; @@ -137,6 +116,41 @@ static int set_bucket_realloc_iterator(set s, set_key key, set_value value, set_ return 1; } +*/ + +static int set_bucket_rehash(set s, set new_set) +{ + size_t bucket_iterator, pair_iterator; + + for (bucket_iterator = 0; bucket_iterator < s->capacity; ++bucket_iterator) + { + bucket b = &s->buckets[bucket_iterator]; + + if (b->pairs != NULL && b->count > 0) + { + for (pair_iterator = 0; pair_iterator < b->count; ++pair_iterator) + { + pair p = &b->pairs[pair_iterator]; + + set_hash h = new_set->hash_cb(p->key); + + size_t index = h % new_set->capacity; + + bucket new_bucket = &new_set->buckets[index]; + + if (bucket_insert(new_bucket, p->key, p->value) != 0) + { + log_write("metacall", LOG_LEVEL_ERROR, "Invalid set bucket realloc insertion"); + return 1; + } + + ++new_set->count; + } + } + } + + return 0; +} static int set_bucket_realloc(set s) { @@ -168,8 +182,10 @@ static int set_bucket_realloc(set s) { size_t iterator; - set_iterate(s, &set_bucket_realloc_iterator, &new_set); + /* Rehash all the elements into the new set */ + set_bucket_rehash(s, &new_set); + /* Destroy all pairs from old set */ for (iterator = 0; iterator < s->capacity; ++iterator) { bucket b = &s->buckets[iterator]; @@ -180,6 +196,7 @@ static int set_bucket_realloc(set s) } } + /* Destroy all buckets from old set */ free(s->buckets); s->capacity = new_set.capacity; @@ -256,9 +273,9 @@ set_value set_get(set s, set_key key) { if (s != NULL && key != NULL) { - set_hash hash = s->hash_cb(key); + set_hash h = s->hash_cb(key); - size_t index = hash % s->capacity; + size_t index = h % s->capacity; bucket b = &s->buckets[index]; @@ -277,9 +294,9 @@ int set_contains(set s, set_key key) { if (s != NULL && key != NULL) { - set_hash hash = s->hash_cb(key); + set_hash h = s->hash_cb(key); - size_t index = hash % s->capacity; + size_t index = h % s->capacity; bucket b = &s->buckets[index]; @@ -294,63 +311,55 @@ int set_contains(set s, set_key key) return 1; } -static int set_contains_any_cb_iterate(set s, set_key key, set_value value, set_cb_iterate_args args) -{ - set_contains_any_cb_iterator iterator = (set_contains_any_cb_iterator)args; - - (void)s; - (void)value; - - iterator->result = set_contains(iterator->s, key); - - /* Stop iteration if we found an element */ - return !iterator->result; -} - int set_contains_any(set dest, set src) { - struct set_contains_any_cb_iterator_type args; - - args.s = dest; - args.result = 1; - - set_iterate(src, &set_contains_any_cb_iterate, (set_cb_iterate_args)&args); - - return args.result; -} - -static int set_contains_which_cb_iterate(set s, set_key key, set_value value, set_cb_iterate_args args) -{ - set_contains_which_cb_iterator iterator = (set_contains_which_cb_iterator)args; + size_t bucket_iterator, pair_iterator; - (void)s; - (void)value; + for (bucket_iterator = 0; bucket_iterator < src->capacity; ++bucket_iterator) + { + bucket b = &src->buckets[bucket_iterator]; - iterator->result = set_contains(iterator->s, key); + if (b->pairs != NULL && b->count > 0) + { + for (pair_iterator = 0; pair_iterator < b->count; ++pair_iterator) + { + pair p = &b->pairs[pair_iterator]; - if (iterator->result == 0) - { - iterator->key = key; + if (set_contains(dest, p->key) == 0) + { + return 0; + } + } + } } - /* Stop iteration if we found an element */ - return !iterator->result; + return 1; } int set_contains_which(set dest, set src, set_key *key) { - struct set_contains_which_cb_iterator_type args; + size_t bucket_iterator, pair_iterator; - args.s = dest; - args.result = 1; - args.key = NULL; + for (bucket_iterator = 0; bucket_iterator < src->capacity; ++bucket_iterator) + { + bucket b = &src->buckets[bucket_iterator]; - set_iterate(src, &set_contains_which_cb_iterate, (set_cb_iterate_args)&args); + if (b->pairs != NULL && b->count > 0) + { + for (pair_iterator = 0; pair_iterator < b->count; ++pair_iterator) + { + pair p = &b->pairs[pair_iterator]; - /* Return which is the duplicated key if any */ - *key = args.key; + if (set_contains(dest, p->key) == 0) + { + *key = p->key; + return 0; + } + } + } + } - return args.result; + return 1; } set_value set_remove(set s, set_key key) @@ -417,40 +426,54 @@ void set_iterate(set s, set_cb_iterate iterate_cb, set_cb_iterate_args args) } } -static int set_append_cb_iterate(set s, set_key key, set_value value, set_cb_iterate_args args) +int set_append(set dest, set src) { - set dest = (set)args; - - (void)s; + size_t bucket_iterator, pair_iterator; - return set_insert(dest, key, value); -} + for (bucket_iterator = 0; bucket_iterator < src->capacity; ++bucket_iterator) + { + bucket b = &src->buckets[bucket_iterator]; -int set_append(set dest, set src) -{ - set_cb_iterate_args args = (set_cb_iterate_args)dest; + if (b->pairs != NULL && b->count > 0) + { + for (pair_iterator = 0; pair_iterator < b->count; ++pair_iterator) + { + pair p = &b->pairs[pair_iterator]; - set_iterate(src, &set_append_cb_iterate, args); + if (set_insert(dest, p->key, p->value) != 0) + { + return 1; + } + } + } + } return 0; } -static int set_disjoint_cb_iterate(set s, set_key key, set_value value, set_cb_iterate_args args) +int set_disjoint(set dest, set src) { - set dest = (set)args; - - set_value deleted = set_remove(dest, key); + size_t bucket_iterator, pair_iterator; - (void)s; + for (bucket_iterator = 0; bucket_iterator < src->capacity; ++bucket_iterator) + { + bucket b = &src->buckets[bucket_iterator]; - return !(deleted == value); -} + if (b->pairs != NULL && b->count > 0) + { + for (pair_iterator = 0; pair_iterator < b->count; ++pair_iterator) + { + pair p = &b->pairs[pair_iterator]; -int set_disjoint(set dest, set src) -{ - set_cb_iterate_args args = (set_cb_iterate_args)dest; + set_value deleted = set_remove(dest, p->key); - set_iterate(src, &set_disjoint_cb_iterate, args); + if (deleted != p->value) + { + return 1; + } + } + } + } return 0; } @@ -520,30 +543,29 @@ void set_destroy(set s) free(s); } -set_iterator set_iterator_begin(set s) +void set_iterator_begin(set_iterator it, set s) { - if (s != NULL && s->buckets != NULL && set_size(s) > 0) + if (it != NULL) { - set_iterator it = malloc(sizeof(struct set_iterator_type)); + it->current_bucket = 0; + it->current_pair = 0; - if (it != NULL) + if (s != NULL && s->buckets != NULL && set_size(s) > 0) { it->s = s; - it->current_bucket = 0; - it->current_pair = 0; set_iterator_next(it); - - return it; + } + else + { + it->s = NULL; } } - - return NULL; } -set_key set_iterator_get_key(set_iterator it) +set_key set_iterator_key(set_iterator it) { - if (it != NULL && it->current_bucket < it->s->capacity && it->current_pair > 0) + if (it != NULL && it->s != NULL && it->current_bucket < it->s->capacity && it->current_pair > 0) { return it->s->buckets[it->current_bucket].pairs[it->current_pair - 1].key; } @@ -551,9 +573,9 @@ set_key set_iterator_get_key(set_iterator it) return NULL; } -set_value set_iterator_get_value(set_iterator it) +set_value set_iterator_value(set_iterator it) { - if (it != NULL && it->current_bucket < it->s->capacity && it->current_pair > 0) + if (it != NULL && it->s != NULL && it->current_bucket < it->s->capacity && it->current_pair > 0) { return it->s->buckets[it->current_bucket].pairs[it->current_pair - 1].value; } @@ -563,7 +585,7 @@ set_value set_iterator_get_value(set_iterator it) void set_iterator_next(set_iterator it) { - if (it != NULL) + if (it != NULL && it->s != NULL) { for (; it->current_bucket < it->s->capacity; ++it->current_bucket) { @@ -582,21 +604,19 @@ void set_iterator_next(set_iterator it) return; } } + + it->current_pair = 0; } } } } -int set_iterator_end(set_iterator *it) +int set_iterator_end(set_iterator it) { - if (it != NULL && *it != NULL) + if (it != NULL && it->s != NULL) { - if ((*it)->current_bucket >= (*it)->s->capacity) + if (it->current_bucket >= it->s->capacity) { - free(*it); - - *it = NULL; - return 0; } diff --git a/source/adt/source/adt_trie.c b/source/adt/source/adt_trie.c index a3790ef3c9..047c20a698 100644 --- a/source/adt/source/adt_trie.c +++ b/source/adt/source/adt_trie.c @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -524,10 +524,11 @@ void trie_node_iterate(trie t, trie_node n, trie_cb_iterate iterate_cb, trie_cb_ if (back->childs != NULL) { - set_iterator it; - for (it = set_iterator_begin(back->childs); set_iterator_end(&it) > 0; set_iterator_next(it)) + struct set_iterator_type it; + + for (set_iterator_begin(&it, back->childs); set_iterator_end(&it) > 0; set_iterator_next(&it)) { - trie_node_ref ref_node = set_iterator_get_value(it); + trie_node_ref ref_node = set_iterator_value(&it); trie_node current_node = &t->node_list[ref_node->index]; @@ -609,11 +610,11 @@ int trie_node_clear(trie t, trie_node n) if (back->childs != NULL) { - set_iterator it; + struct set_iterator_type it; - for (it = set_iterator_begin(back->childs); set_iterator_end(&it) > 0; set_iterator_next(it)) + for (set_iterator_begin(&it, back->childs); set_iterator_end(&it) > 0; set_iterator_next(&it)) { - trie_node_ref ref_node = set_iterator_get_value(it); + trie_node_ref ref_node = set_iterator_value(&it); trie_node current_node = &t->node_list[ref_node->index]; @@ -681,14 +682,13 @@ trie_node trie_node_find(trie t, trie_key key) if (back_ptr != NULL && *back_ptr != NULL) { trie_node back = *back_ptr; - - set_iterator it = NULL; + struct set_iterator_type it; if (back->childs != NULL) { - for (it = set_iterator_begin(back->childs); set_iterator_end(&it) > 0; set_iterator_next(it)) + for (set_iterator_begin(&it, back->childs); set_iterator_end(&it) > 0; set_iterator_next(&it)) { - trie_node_ref ref_node = set_iterator_get_value(it); + trie_node_ref ref_node = set_iterator_value(&it); trie_node current_node = &t->node_list[ref_node->index]; @@ -698,9 +698,10 @@ trie_node trie_node_find(trie t, trie_key key) if (back->key != NULL && t->compare_cb(back->key, key) == 0) { + /* TODO: it may be un-initialized here */ while (set_iterator_end(&it) > 0) { - set_iterator_next(it); + set_iterator_next(&it); } vector_destroy(node_stack); diff --git a/source/adt/source/adt_vector.c b/source/adt/source/adt_vector.c index 462315afe6..0047cc1185 100644 --- a/source/adt/source/adt_vector.c +++ b/source/adt/source/adt_vector.c @@ -2,7 +2,7 @@ * Abstract Data Type Library by Parra Studios * A abstract data type library providing generic containers. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/source/benchmarks/CMakeLists.txt b/source/benchmarks/CMakeLists.txt index 8bf6ce15e8..107a348e81 100644 --- a/source/benchmarks/CMakeLists.txt +++ b/source/benchmarks/CMakeLists.txt @@ -58,6 +58,7 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/b include(CTest) +add_subdirectory(set_bench) add_subdirectory(log_bench) add_subdirectory(metacall_py_c_api_bench) add_subdirectory(metacall_py_call_bench) diff --git a/source/benchmarks/log_bench/CMakeLists.txt b/source/benchmarks/log_bench/CMakeLists.txt index 63f7c901e3..f1ba5575ea 100644 --- a/source/benchmarks/log_bench/CMakeLists.txt +++ b/source/benchmarks/log_bench/CMakeLists.txt @@ -108,7 +108,7 @@ target_compile_options(${target} # Linker options # -target_link_libraries(${target} +target_link_options(${target} PRIVATE ${DEFAULT_LINKER_OPTIONS} ) diff --git a/source/benchmarks/log_bench/source/log_bench.cpp b/source/benchmarks/log_bench/source/log_bench.cpp index 3f41643285..75bdb547bd 100644 --- a/source/benchmarks/log_bench/source/log_bench.cpp +++ b/source/benchmarks/log_bench/source/log_bench.cpp @@ -2,7 +2,7 @@ * MetaCall Library by Parra Studios * A library for providing a foreign function interface calls. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,6 @@ #include #include -#include static int stream_write(void *, const char *, const size_t) { diff --git a/source/benchmarks/metacall_cs_call_bench/CMakeLists.txt b/source/benchmarks/metacall_cs_call_bench/CMakeLists.txt index 618c9a7eec..80db3ce393 100644 --- a/source/benchmarks/metacall_cs_call_bench/CMakeLists.txt +++ b/source/benchmarks/metacall_cs_call_bench/CMakeLists.txt @@ -109,7 +109,7 @@ target_compile_options(${target} # Linker options # -target_link_libraries(${target} +target_link_options(${target} PRIVATE ${DEFAULT_LINKER_OPTIONS} ) diff --git a/source/benchmarks/metacall_cs_call_bench/source/metacall_cs_call_bench.cpp b/source/benchmarks/metacall_cs_call_bench/source/metacall_cs_call_bench.cpp index 1061772b03..179dfaf6c0 100644 --- a/source/benchmarks/metacall_cs_call_bench/source/metacall_cs_call_bench.cpp +++ b/source/benchmarks/metacall_cs_call_bench/source/metacall_cs_call_bench.cpp @@ -2,7 +2,7 @@ * MetaCall Library by Parra Studios * A library for providing a foreign function interface calls. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -186,5 +186,7 @@ int main(int argc, char **argv) ::benchmark::RunSpecifiedBenchmarks(); - return metacall_destroy(); + metacall_destroy(); + + return 0; } diff --git a/source/benchmarks/metacall_node_call_bench/CMakeLists.txt b/source/benchmarks/metacall_node_call_bench/CMakeLists.txt index 37aa304362..16ae8e7684 100644 --- a/source/benchmarks/metacall_node_call_bench/CMakeLists.txt +++ b/source/benchmarks/metacall_node_call_bench/CMakeLists.txt @@ -109,7 +109,7 @@ target_compile_options(${target} # Linker options # -target_link_libraries(${target} +target_link_options(${target} PRIVATE ${DEFAULT_LINKER_OPTIONS} ) diff --git a/source/benchmarks/metacall_node_call_bench/source/metacall_node_call_bench.cpp b/source/benchmarks/metacall_node_call_bench/source/metacall_node_call_bench.cpp index 2dd5fd09c7..16d2c987b5 100644 --- a/source/benchmarks/metacall_node_call_bench/source/metacall_node_call_bench.cpp +++ b/source/benchmarks/metacall_node_call_bench/source/metacall_node_call_bench.cpp @@ -2,7 +2,7 @@ * MetaCall Library by Parra Studios * A library for providing a foreign function interface calls. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -292,5 +292,7 @@ int main(int argc, char **argv) } #endif /* OPTION_BUILD_LOADERS_NODE */ - return metacall_destroy(); + metacall_destroy(); + + return 0; } diff --git a/source/benchmarks/metacall_py_c_api_bench/CMakeLists.txt b/source/benchmarks/metacall_py_c_api_bench/CMakeLists.txt index 45636fb5e3..08605fb08d 100644 --- a/source/benchmarks/metacall_py_c_api_bench/CMakeLists.txt +++ b/source/benchmarks/metacall_py_c_api_bench/CMakeLists.txt @@ -1,3 +1,8 @@ +# Check if this loader is enabled +if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_PY) + return() +endif() + # # External dependencies # @@ -116,7 +121,7 @@ target_compile_options(${target} # Linker options # -target_link_libraries(${target} +target_link_options(${target} PRIVATE ${DEFAULT_LINKER_OPTIONS} ) diff --git a/source/benchmarks/metacall_py_c_api_bench/source/metacall_py_c_api_bench.cpp b/source/benchmarks/metacall_py_c_api_bench/source/metacall_py_c_api_bench.cpp index 421ff1222b..e1db6bb14b 100644 --- a/source/benchmarks/metacall_py_c_api_bench/source/metacall_py_c_api_bench.cpp +++ b/source/benchmarks/metacall_py_c_api_bench/source/metacall_py_c_api_bench.cpp @@ -2,7 +2,7 @@ * MetaCall Library by Parra Studios * A library for providing a foreign function interface calls. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/source/benchmarks/metacall_py_call_bench/CMakeLists.txt b/source/benchmarks/metacall_py_call_bench/CMakeLists.txt index 898bddd699..9ed6744229 100644 --- a/source/benchmarks/metacall_py_call_bench/CMakeLists.txt +++ b/source/benchmarks/metacall_py_call_bench/CMakeLists.txt @@ -109,7 +109,7 @@ target_compile_options(${target} # Linker options # -target_link_libraries(${target} +target_link_options(${target} PRIVATE ${DEFAULT_LINKER_OPTIONS} ) diff --git a/source/benchmarks/metacall_py_call_bench/source/metacall_py_call_bench.cpp b/source/benchmarks/metacall_py_call_bench/source/metacall_py_call_bench.cpp index 4b5717e481..68b0bf5890 100644 --- a/source/benchmarks/metacall_py_call_bench/source/metacall_py_call_bench.cpp +++ b/source/benchmarks/metacall_py_call_bench/source/metacall_py_call_bench.cpp @@ -2,7 +2,7 @@ * MetaCall Library by Parra Studios * A library for providing a foreign function interface calls. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -178,10 +178,7 @@ int main(int argc, char *argv[]) ::benchmark::RunSpecifiedBenchmarks(); ::benchmark::Shutdown(); - if (metacall_destroy() != 0) - { - return 4; - } + metacall_destroy(); return 0; } diff --git a/source/benchmarks/metacall_py_init_bench/CMakeLists.txt b/source/benchmarks/metacall_py_init_bench/CMakeLists.txt index 9933482d18..eb9ecb2c79 100644 --- a/source/benchmarks/metacall_py_init_bench/CMakeLists.txt +++ b/source/benchmarks/metacall_py_init_bench/CMakeLists.txt @@ -109,7 +109,7 @@ target_compile_options(${target} # Linker options # -target_link_libraries(${target} +target_link_options(${target} PRIVATE ${DEFAULT_LINKER_OPTIONS} ) diff --git a/source/benchmarks/metacall_py_init_bench/source/metacall_py_init_bench.cpp b/source/benchmarks/metacall_py_init_bench/source/metacall_py_init_bench.cpp index 7e69f10073..9a1ef4a886 100644 --- a/source/benchmarks/metacall_py_init_bench/source/metacall_py_init_bench.cpp +++ b/source/benchmarks/metacall_py_init_bench/source/metacall_py_init_bench.cpp @@ -2,7 +2,7 @@ * MetaCall Library by Parra Studios * A library for providing a foreign function interface calls. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -130,10 +130,7 @@ BENCHMARK_DEFINE_F(metacall_py_init_bench, destroy) /* Python */ #if defined(OPTION_BUILD_LOADERS_PY) { - if (metacall_destroy() != 0) - { - state.SkipWithError("Error destroying MetaCall"); - } + metacall_destroy(); } #endif /* OPTION_BUILD_LOADERS_PY */ } diff --git a/source/benchmarks/metacall_rb_call_bench/CMakeLists.txt b/source/benchmarks/metacall_rb_call_bench/CMakeLists.txt index 5643afe0b7..4833bad0de 100644 --- a/source/benchmarks/metacall_rb_call_bench/CMakeLists.txt +++ b/source/benchmarks/metacall_rb_call_bench/CMakeLists.txt @@ -109,7 +109,7 @@ target_compile_options(${target} # Linker options # -target_link_libraries(${target} +target_link_options(${target} PRIVATE ${DEFAULT_LINKER_OPTIONS} ) diff --git a/source/benchmarks/metacall_rb_call_bench/source/metacall_rb_call_bench.cpp b/source/benchmarks/metacall_rb_call_bench/source/metacall_rb_call_bench.cpp index 41b3c6b380..4dc75e9424 100644 --- a/source/benchmarks/metacall_rb_call_bench/source/metacall_rb_call_bench.cpp +++ b/source/benchmarks/metacall_rb_call_bench/source/metacall_rb_call_bench.cpp @@ -2,7 +2,7 @@ * MetaCall Library by Parra Studios * A library for providing a foreign function interface calls. * - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -198,10 +198,7 @@ int main(int argc, char *argv[]) ::benchmark::RunSpecifiedBenchmarks(); ::benchmark::Shutdown(); - if (metacall_destroy() != 0) - { - return 4; - } + metacall_destroy(); return 0; } diff --git a/source/benchmarks/set_bench/CMakeLists.txt b/source/benchmarks/set_bench/CMakeLists.txt new file mode 100644 index 0000000000..69630fada5 --- /dev/null +++ b/source/benchmarks/set_bench/CMakeLists.txt @@ -0,0 +1,147 @@ +# +# Executable name and options +# + +# Target name +set(target set-bench) +message(STATUS "Benchmark ${target}") + +# +# Compiler warnings +# + +include(Warnings) + +# +# Compiler security +# + +include(SecurityFlags) + +# +# Sources +# + +set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include/${target}") +set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/source") + +set(sources + ${source_path}/set_bench.cpp +) + +# Group source files +set(header_group "Header Files (API)") +set(source_group "Source Files") +source_group_by_path(${include_path} "\\\\.h$|\\\\.hpp$" + ${header_group} ${headers}) +source_group_by_path(${source_path} "\\\\.cpp$|\\\\.c$|\\\\.h$|\\\\.hpp$" + ${source_group} ${sources}) + +# +# Create executable +# + +# Build executable +add_executable(${target} + ${sources} +) + +# Create namespaced alias +add_executable(${META_PROJECT_NAME}::${target} ALIAS ${target}) + +# +# Project options +# + +set_target_properties(${target} + PROPERTIES + ${DEFAULT_PROJECT_OPTIONS} + FOLDER "${IDE_FOLDER}" +) + +# +# Include directories +# + +target_include_directories(${target} + PRIVATE + ${DEFAULT_INCLUDE_DIRECTORIES} + ${PROJECT_BINARY_DIR}/source/include +) + +# +# Libraries +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LIBRARIES} + + GBench + + ${META_PROJECT_NAME}::version + ${META_PROJECT_NAME}::preprocessor + ${META_PROJECT_NAME}::format + ${META_PROJECT_NAME}::threading + ${META_PROJECT_NAME}::log + ${META_PROJECT_NAME}::adt +) + +# +# Compile definitions +# + +target_compile_definitions(${target} + PRIVATE + ${DEFAULT_COMPILE_DEFINITIONS} +) + +# +# Compile options +# + +target_compile_options(${target} + PRIVATE + ${DEFAULT_COMPILE_OPTIONS} +) + +# +# Linker options +# + +target_link_options(${target} + PRIVATE + ${DEFAULT_LINKER_OPTIONS} +) + +# +# Define test +# + +add_test(NAME ${target} + COMMAND $ + --benchmark_out=${CMAKE_BINARY_DIR}/benchmarks/${target}.json +) + +# +# Define dependencies +# + +add_dependencies(${target} + adt +) + +# +# Define test properties +# + +set_property(TEST ${target} + PROPERTY LABELS ${target} +) + +include(TestEnvironmentVariables) + +test_environment_variables(${target} + "" + ${TESTS_ENVIRONMENT_VARIABLES} +) diff --git a/source/benchmarks/set_bench/source/set_bench.cpp b/source/benchmarks/set_bench/source/set_bench.cpp new file mode 100644 index 0000000000..2129c98b54 --- /dev/null +++ b/source/benchmarks/set_bench/source/set_bench.cpp @@ -0,0 +1,147 @@ +/* + * MetaCall Library by Parra Studios + * A library for providing a foreign function interface calls. + * + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include + +#include +#include + +#define SET_SIZE 1000 +#define ITERATIONS 1000 + +class set_bench : public benchmark::Fixture +{ +public: + void SetUp(benchmark::State &) + { + s = set_create(&hash_callback_ptr, &comparable_callback_ptr); + + keys.reserve(SET_SIZE); + values.reserve(SET_SIZE); + + for (int i = 0; i < SET_SIZE; ++i) + { + keys.push_back(std::to_string(i)); + values.push_back(i); + set_insert(s, (set_key)keys[i].c_str(), &values[i]); + } + } + + void TearDown(benchmark::State &) + { + set_destroy(s); + } + + set s; + std::vector keys; + std::vector values; +}; + +int set_cb_iterate_sum(set s, set_key key, set_value value, set_cb_iterate_args args) +{ + int *i = (int *)value; + uint64_t *sum = (uint64_t *)args; + + (void)s; + (void)key; + + *sum = ((*sum) + (uint64_t)(*i)); + + return 0; +} + +BENCHMARK_DEFINE_F(set_bench, set_iterate) +(benchmark::State &state) +{ + uint64_t sum = 0; + + for (auto _ : state) + { + set_iterate(s, &set_cb_iterate_sum, &sum); + } + + state.SetLabel("Set Benchmark - Iterate Callback"); + state.SetItemsProcessed(SET_SIZE); +} + +BENCHMARK_REGISTER_F(set_bench, set_iterate) + ->Unit(benchmark::kMillisecond) + ->Iterations(ITERATIONS) + ->Repetitions(3); + +/* +BENCHMARK_DEFINE_F(set_bench, set_iterators) +(benchmark::State &state) +{ + uint64_t sum = 0; + + for (auto _ : state) + { + for (set_iterator it = set_iterator_begin(s); set_iterator_end(&it) > 0; set_iterator_next(it)) + { + int *i = (int *)set_iterator_value(it); + + sum += ((uint64_t)(*i)); + } + } + + (void)sum; + + state.SetLabel("Set Benchmark - Iterators"); + state.SetItemsProcessed(SET_SIZE); +} + +BENCHMARK_REGISTER_F(set_bench, set_iterators) + ->Unit(benchmark::kMillisecond) + ->Iterations(ITERATIONS) + ->Repetitions(3); +*/ + +BENCHMARK_DEFINE_F(set_bench, set_iterators_2) +(benchmark::State &state) +{ + uint64_t sum = 0; + + for (auto _ : state) + { + set_iterator_type it; + + for (set_iterator_begin(&it, s); set_iterator_end(&it) > 0; set_iterator_next(&it)) + { + int *i = (int *)set_iterator_value(&it); + + sum += ((uint64_t)(*i)); + } + } + + (void)sum; + + state.SetLabel("Set Benchmark - Iterators 2"); + state.SetItemsProcessed(SET_SIZE); +} + +BENCHMARK_REGISTER_F(set_bench, set_iterators_2) + ->Unit(benchmark::kMillisecond) + ->Iterations(ITERATIONS) + ->Repetitions(3); + +BENCHMARK_MAIN(); diff --git a/source/cli/CMakeLists.txt b/source/cli/CMakeLists.txt index 4f97517286..d6b10bf0dc 100644 --- a/source/cli/CMakeLists.txt +++ b/source/cli/CMakeLists.txt @@ -4,6 +4,12 @@ if(NOT OPTION_BUILD_CLI) return() endif() +# Check if the dependency loaders are enabled +if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_EXT OR NOT OPTION_BUILD_EXTENSIONS OR NOT OPTION_BUILD_LOADERS_NODE) + message(WARNING "The Extension and NodeJS Loaders are a dependency of the CLI, in order to compile the CLI, enable them with -DOPTION_BUILD_LOADERS_EXT=ON -DOPTION_BUILD_LOADERS_NODE=ON") + return() +endif() + # CLI applications add_subdirectory(metacallcli) add_subdirectory(plugins) diff --git a/source/cli/metacallcli/CMakeLists.txt b/source/cli/metacallcli/CMakeLists.txt index 93308ed551..8067b8e620 100644 --- a/source/cli/metacallcli/CMakeLists.txt +++ b/source/cli/metacallcli/CMakeLists.txt @@ -25,22 +25,13 @@ include(SecurityFlags) # set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include/${target}") -set(inline_path "${CMAKE_CURRENT_SOURCE_DIR}/inline/${target}") set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/source") set(headers - ${include_path}/tokenizer.hpp - ${include_path}/parser.hpp ${include_path}/application.hpp ) -set(inline - ${inline_path}/parser.inl -) - set(sources - ${source_path}/tokenizer.cpp - ${source_path}/parser.cpp ${source_path}/application.cpp ${source_path}/main.cpp ) @@ -97,9 +88,6 @@ target_include_directories(${target} ${PROJECT_BINARY_DIR}/source/include ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include - ${PROJECT_BINARY_DIR}/source/inline - ${CMAKE_CURRENT_SOURCE_DIR}/inline - ${CMAKE_CURRENT_BINARY_DIR}/inline ${DEFAULT_INCLUDE_DIRECTORIES} PUBLIC @@ -151,7 +139,7 @@ target_compile_features(${target} # Linker options # -target_link_libraries(${target} +target_link_options(${target} PRIVATE ${DEFAULT_LINKER_OPTIONS} ) @@ -161,18 +149,33 @@ target_link_libraries(${target} # add_loader_dependencies(${target} - node_loader - py_loader - rb_loader - cs_loader - jsm_loader - js_loader - mock_loader c_loader + cob_loader + cs_loader + ext_loader file_loader + java_loader + mock_loader + py_loader + rb_loader + rs_loader + rpc_loader ts_loader + wasm_loader ) +add_dependencies(${target} + node_loader + cli_repl_plugin + cli_core_plugin +) + +if(TARGET cli_cmd_plugin) + add_dependencies(${target} + cli_cmd_plugin + ) +endif() + # # Deployment # @@ -202,10 +205,8 @@ add_test(NAME ${target} COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) -set_property(TEST ${target} - PROPERTY LABELS ${target} -) set_tests_properties(${target} PROPERTIES + LABELS ${target} PASS_REGULAR_EXPRESSION "function three_str\\(a_str, b_str, c_str\\)" ) test_environment_variables(${target} @@ -230,11 +231,9 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_NODE AND OPTION_BUILD_SCRIPTS A COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-node.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-node - PROPERTY LABELS ${target}-node - ) set_tests_properties(${target}-node PROPERTIES - PASS_REGULAR_EXPRESSION "700.0" + LABELS ${target}-node + PASS_REGULAR_EXPRESSION "4001534" ) test_environment_variables(${target}-node "" @@ -245,10 +244,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_NODE AND OPTION_BUILD_SCRIPTS A COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-node-port-py.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-node-port-py - PROPERTY LABELS ${target}-node-port-py - ) set_tests_properties(${target}-node-port-py PROPERTIES + LABELS ${target}-node-port-py PASS_REGULAR_EXPRESSION "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) test_environment_variables(${target}-node-port-py @@ -275,10 +272,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_NODE AND OPTION_BUILD_SCRIPTS A COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-node-null.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-node-null - PROPERTY LABELS ${target}-node-null - ) set_tests_properties(${target}-node-null PROPERTIES + LABELS ${target}-node-null PASS_REGULAR_EXPRESSION "Hello 342521512461246!" ) test_environment_variables(${target}-node-null @@ -290,10 +285,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_NODE AND OPTION_BUILD_SCRIPTS A COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-node-null-empty.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-node-null-empty - PROPERTY LABELS ${target}-node-null-empty - ) set_tests_properties(${target}-node-null-empty PROPERTIES + LABELS ${target}-node-null-empty PASS_REGULAR_EXPRESSION "Hello 342521512461246!" ) test_environment_variables(${target}-node-null-empty @@ -305,10 +298,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_NODE AND OPTION_BUILD_SCRIPTS A COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-node-null-undefined.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-node-null-undefined - PROPERTY LABELS ${target}-node-null-undefined - ) set_tests_properties(${target}-node-null-undefined PROPERTIES + LABELS ${target}-node-null-undefined PASS_REGULAR_EXPRESSION "(null)" ) test_environment_variables(${target}-node-null-undefined @@ -321,10 +312,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_NODE AND OPTION_BUILD_SCRIPTS A COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-py-port.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-py-port - PROPERTY LABELS ${target}-py-port - ) set_tests_properties(${target}-py-port PROPERTIES + LABELS ${target}-py-port PASS_REGULAR_EXPRESSION "1234" ) test_environment_variables(${target}-py-port @@ -337,10 +326,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_NODE AND OPTION_BUILD_SCRIPTS A COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-py-port-rb.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-py-port-rb - PROPERTY LABELS ${target}-py-port-rb - ) set_tests_properties(${target}-py-port-rb PROPERTIES + LABELS ${target}-py-port-rb PASS_REGULAR_EXPRESSION "0123456789ABCDEFasd" ) test_environment_variables(${target}-py-port-rb @@ -356,10 +343,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_FILE AND OPTION_BUILD_SCRIPTS A COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-file.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-file - PROPERTY LABELS ${target}-file - ) set_tests_properties(${target}-file PROPERTIES + LABELS ${target}-file PASS_REGULAR_EXPRESSION "${LOADER_SCRIPT_PATH}/template.html" ) test_environment_variables(${target}-file @@ -370,11 +355,9 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_FILE AND OPTION_BUILD_SCRIPTS A COMMAND $ this-does-not-exist WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-file-fail - PROPERTY LABELS ${target}-file-fail - ) set_tests_properties(${target}-file-fail PROPERTIES - PASS_REGULAR_EXPRESSION "Script \\(this-does-not-exist\\) load error in loader \\(file\\)" + LABELS ${target}-file-fail + PASS_REGULAR_EXPRESSION "Error: Failed to load script 'this-does-not-exist' with loader 'file'" ) test_environment_variables(${target}-file-fail "" @@ -387,10 +370,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_PY) COMMAND $ test.py WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-py-naming - PROPERTY LABELS ${target}-py-naming - ) set_tests_properties(${target}-py-naming PROPERTIES + LABELS ${target}-py-naming PASS_REGULAR_EXPRESSION "Test: 66673332" ) test_environment_variables(${target}-py-naming @@ -401,10 +382,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_PY) COMMAND $ cli-test-argv.py WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-py-argv - PROPERTY LABELS ${target}-py-argv - ) set_tests_properties(${target}-py-argv PROPERTIES + LABELS ${target}-py-argv PASS_REGULAR_EXPRESSION "Test: cli-test-argv.py" ) test_environment_variables(${target}-py-argv @@ -415,10 +394,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_PY) COMMAND $ cli-test-main.py WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-py-main - PROPERTY LABELS ${target}-py-main - ) set_tests_properties(${target}-py-main PROPERTIES + LABELS ${target}-py-main PASS_REGULAR_EXPRESSION "Test: 1234567890abcd" ) test_environment_variables(${target}-py-main @@ -429,10 +406,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_PY) COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-py-exception.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - set_property(TEST ${target}-py-exception - PROPERTY LABELS ${target}-py-exception - ) set_tests_properties(${target}-py-exception PROPERTIES + LABELS ${target}-py-exception PASS_REGULAR_EXPRESSION "66" ) test_environment_variables(${target}-py-exception @@ -441,16 +416,29 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_PY) ) endif() +if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_RB) + add_test(NAME ${target}-rb-simplest + COMMAND $ simplest.rb + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + set_tests_properties(${target}-rb-simplest PROPERTIES + LABELS ${target}-rb-simplest + PASS_REGULAR_EXPRESSION "Hello from Ruby" + ) + test_environment_variables(${target}-rb-simplest + "" + ${TESTS_ENVIRONMENT_VARIABLES} + ) +endif() + if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_TS AND OPTION_BUILD_SCRIPTS AND OPTION_BUILD_SCRIPTS_TS) add_test(NAME ${target}-ts COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-ts.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${LOADER_SCRIPT_PATH}/typedfunc ) - set_property(TEST ${target}-ts - PROPERTY LABELS ${target}-ts - ) set_tests_properties(${target}-ts PROPERTIES - PASS_REGULAR_EXPRESSION "9.0" + LABELS ${target}-ts + PASS_REGULAR_EXPRESSION "51354" ) test_environment_variables(${target}-ts "" @@ -460,10 +448,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_TS AND OPTION_BUILD_SCRIPTS AND COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-tsx-templating.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${LOADER_SCRIPT_PATH}/templating ) - set_property(TEST ${target}-tsx-templating - PROPERTY LABELS ${target}-tsx-templating - ) set_tests_properties(${target}-tsx-templating PROPERTIES + LABELS ${target}-tsx-templating PASS_REGULAR_EXPRESSION "Hello metaprogrammer" ) test_environment_variables(${target}-tsx-templating @@ -497,10 +483,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_TS AND OPTION_BUILD_SCRIPTS AND COMMAND $ loopfail.tsx WORKING_DIRECTORY ${LOADER_SCRIPT_PATH}/loopfail ) - set_property(TEST ${target}-tsx-loop-fail - PROPERTY LABELS ${target}-tsx-loop-fail - ) set_tests_properties(${target}-tsx-loop-fail PROPERTIES + LABELS ${target}-tsx-loop-fail PASS_REGULAR_EXPRESSION "Error: Cannot find module 'yeet-oof/whatever'" ) test_environment_variables(${target}-tsx-loop-fail @@ -514,10 +498,8 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_TS AND OPTION_BUILD_SCRIPTS AND COMMAND ${CMAKE_COMMAND} -D "EXECUTABLE=$" -D "INPUT=${TEST_COMMAND_INPUT}-py-tsx.txt" -P ${TEST_COMMAND_RUNNER} WORKING_DIRECTORY ${LOADER_SCRIPT_PATH}/templating ) - set_property(TEST ${target}-py-tsx - PROPERTY LABELS ${target}-py-tsx - ) set_tests_properties(${target}-py-tsx PROPERTIES + LABELS ${target}-py-tsx PASS_REGULAR_EXPRESSION "Hello World" ) test_environment_variables(${target}-py-tsx @@ -530,3 +512,20 @@ if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_TS AND OPTION_BUILD_SCRIPTS AND ) endif() endif() + +if(OPTION_BUILD_LOADERS AND OPTION_BUILD_LOADERS_EXT AND OPTION_BUILD_EXTENSIONS AND OPTION_BUILD_LOADERS_NODE AND OPTION_BUILD_LOADERS_PY AND OPTION_BUILD_PLUGINS_SANDBOX AND PROJECT_OS_FAMILY STREQUAL unix AND TARGET cli_sandbox_plugin) + if(NOT OPTION_BUILD_THREAD_SANITIZER AND NOT OPTION_BUILD_ADDRESS_SANITIZER) + add_test(NAME ${target}-cmd-sandboxing + COMMAND ${CMAKE_COMMAND} -E env $ --sandboxing --disable_time time.py + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + set_tests_properties(${target}-cmd-sandboxing PROPERTIES + LABELS ${target}-cmd-sandboxing + WILL_FAIL TRUE + ) + test_environment_variables(${target}-cmd-sandboxing + "" + ${TESTS_ENVIRONMENT_VARIABLES} + ) + endif() +endif() diff --git a/source/cli/metacallcli/include/metacallcli/application.hpp b/source/cli/metacallcli/include/metacallcli/application.hpp index b66316214f..c2e7863a8e 100644 --- a/source/cli/metacallcli/include/metacallcli/application.hpp +++ b/source/cli/metacallcli/include/metacallcli/application.hpp @@ -1,6 +1,6 @@ /* * MetaCall Command Line Interface by Parra Studios - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * A command line interface example as metacall wrapper. * @@ -23,15 +23,6 @@ namespace metacallcli { -/* -- Forward Declarations -- */ - -class tokenizer; - -class parser; -class parser_parameter; - -class application; - /* -- Class Definition -- */ /** @@ -41,10 +32,6 @@ class application; class application { public: - /* -- Public Type Definitions -- */ - - typedef bool (*command_callback)(application &, tokenizer &); - /* -- Public Methods -- */ /** @@ -65,248 +52,87 @@ class application */ ~application(void); - /** - * @brief - * Application script loader - * - * @param[in] tag - * Loader tag reference - * - * @param[in] script - * Reference to script name - * - * @return - * Return true on success, false otherwhise - */ - bool load(const std::string &tag, const std::string &script); - - /** - * @brief - * Application script loader from memory - * - * @param[in] tag - * Loader tag reference - * - * @param[in] script - * Script code - * - * @return - * Return true on success, false otherwhise - */ - bool load_from_memory(const std::string &tag, const std::string &script); - - /** - * @brief - * Application script clearer - * - * @param[in] tag - * Loader tag reference - * - * @param[in] script - * Reference to script name - * - * @return - * Return true on success, false otherwhise - */ - bool clear(const std::string &tag, const std::string &script); - /** * @brief * Application main entry point */ void run(void); - /** - * @brief - * Shutdown main application loop - */ - void shutdown(void); - - /** - * @brief - * Debug command line string - * - * @param[in] key - * Name of the command line option - * - * @param[in] t - * Tokenizer wrapper of input command - */ - void command_debug(const std::string &key, const tokenizer &t); +protected: + /* -- Protected Methods -- */ /** * @brief - * Show inspect information - * - * @param[in] str - * Serialized inspect data - * - * @param[in] size - * Size in bytes of str string - * - * @param[in] size - * Size in bytes of str string - * - * @param[in] allocator - * Pointer to the allocator to be used in deserialization + * Initialize the REPL */ - void command_inspect(const char *str, size_t size, void *allocator); + void repl(); /** * @brief - * Create a new value from arguments with parser @p + * Initialize the CMD * - * @param[in] p - * Parser which points to the current iterator of the string + * @param[in] arguments + * Vector of strings containing all the arguments from argv * * @return - * Return a new value instanced if argument was correct + * Return true if the load was successful, false otherwise */ - void *argument_parse(parser_parameter &p); + bool cmd(std::vector &arguments); /** * @brief - * Adapts metacallv from string @name and vector @args - * - * @param[in] name - * String object of function name + * Fallback argument parser * - * @param[in] args - * Vector pointing to arguments + * @param[in] arguments + * Vector of strings containing all the arguments from argv * - * @return - * Return a new value instanced if argument was correct with the result of the call */ - void *metacallv_adaptor(const std::string &name, const std::vector &args); + void arguments_parse(std::vector &arguments); /** * @brief - * Adapts metacallfs from string @name and array string @args - * - * @param[in] name - * String object of function name + * Load all plugins from a subfolder @path * - * @param[in] args - * String representing an array to be deserialized + * @param[in] path + * Subpath where the plugins are located * - * @param[in] allocator - * Pointer to the allocator to be used in deserialization + * @param[out] handle + * Pointer to the handle containing of the loaded scripts * * @return - * Return a new value instanced if argument was correct with the result of the call - */ - void *metacallfs_adaptor(const std::string &name, const std::string &args, void *allocator); - - /** - * @brief - * Adapts metacallfs_await from string @name and array string @args - * - * @param[in] name - * String object of function name + * Return true if the load was successful, false otherwise * - * @param[in] args - * String representing an array to be deserialized - * - * @param[in] allocator - * Pointer to the allocator to be used in deserialization - * - * @return - * Return a new value instanced if argument was correct with the result of the call */ - void *metacallfs_await_adaptor(const std::string &name, const std::string &args, void *allocator); - -protected: - /* -- Protected Definitions -- */ - - static const size_t arguments_str_size; - - /* -- Protected Methods -- */ + bool load_path(const char *path, void **handle); /** * @brief * Execute a command with string parameters * - * @param[in out] t - * Tokenizer wrapper of input command + * @param[inout] tokens + * Value of type array containing all the tokens of the input command + * + * @return + * Return result of the command execution */ - void execute(tokenizer &t); + void *execute(void *tokens); /** * @brief - * Defines a new command with a callback handler - * - * @param[in] key - * Name of the command line option + * Check if a value is an exception or throwable, then prints it. + * The method always destroys the value @v * - * @param[in] command_cb - * Handler will be raised on @key command entered + * @param[inout] v + * Value to be checked against and destroyed */ - void define(const char *key, command_callback command_cb); + void check_for_exception(void *v); private: - /* -- Private Type Definitions -- */ - - typedef std::vector arg_list; - - typedef std::vector script_list; - - typedef std::unordered_map command_table; - - /* -- Private Class Definition -- */ - - class parameter_iterator - { - public: - /* -- Public Methods -- */ - - /** - * @brief - * Initialize parameter iterator - * - * @param[in] app - * Reference to the application - */ - parameter_iterator(application &app); - - /** - * @brief - * Parameter iterator class destructor - */ - ~parameter_iterator(); - - /** - * @brief - * Operator callback for iteration - * - * @param[in] parameter - * Current parameter being iterated - */ - void operator()(const char *parameter); - - /** - * @brief - * Assignement operator for parameter iterator - * - * @return - * Returns a reference to itself - */ - parameter_iterator &operator=(const parameter_iterator &) = delete; - - private: - /* -- Private Member Data -- */ - - application &app; /**< Reference to the application */ - }; - /* -- Private Member Data -- */ - bool exit_condition; /**< Condition for main loop */ - void *plugin_cli_handle; /**< Handle containing all loaded plugins */ - arg_list arguments; /**< Vector containing a list of arguments */ - script_list scripts; /**< Vector containing a list of script names */ - command_table commands; /**< Hash table from command strings to command handlers */ - std::mutex await_mutex; /**< Mutex for blocking the REPL until await is resolved */ - std::condition_variable await_cond; /**< Condition to be fired once await method is resolved or rejected */ + void *plugin_cli_handle; /**< Handle containing all loaded plugins for CLI */ + void *plugin_repl_handle; /**< Handle containing all loaded plugins for REPL */ + void *plugin_cmd_handle; /**< Handle containing all loaded plugins for CMD */ }; } /* namespace metacallcli */ diff --git a/source/cli/metacallcli/include/metacallcli/parser.hpp b/source/cli/metacallcli/include/metacallcli/parser.hpp deleted file mode 100644 index 5fdba85f81..0000000000 --- a/source/cli/metacallcli/include/metacallcli/parser.hpp +++ /dev/null @@ -1,231 +0,0 @@ -/* - * MetaCall Command Line Interface by Parra Studios - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia - * - * A command line interface example as metacall wrapper. - * - */ - -#ifndef METACALL_CLI_PARSER_HPP -#define METACALL_CLI_PARSER_HPP 1 - -/* -- Headers -- */ - -#include - -#include "tokenizer.hpp" - -#include - -/* -- Namespace -- */ - -namespace metacallcli -{ -/* -- Forward Declarations -- */ - -class tokenizer; - -class parser; - -/* -- Class Definition -- */ - -/** -* @brief -* Simple parser utility -*/ -class parser -{ -public: - /* -- Public Methods -- */ - - /** - * @brief - * Parser class constructor - * - * @param[in] it - * Tokenizer iterator reference - */ - parser(const tokenizer::iterator &it); - - /** - * @brief - * Parser class destructor - */ - ~parser(void); - - /** - * @brief - * Check if current token is a defined type @T - * - * @param[template] T - * Type of value to check against token - * - * @return - * True if type @T is equivalent to current token - */ - template bool is(void); - - /** - * @brief - * Return current token transformed to type @T - * - * @param[template] T - * Type of value to check against token - * - * @return - * A copy of the value transformed to given type @T - */ - template T to(void); - - /** - * @brief - * Assignement operator for parser - * - * @return - * Returns a reference to itself - */ - parser &operator=(const parser &) = delete; - -protected: - /* -- Private Member Data -- */ - - const tokenizer::iterator ⁢ /**< Tokenizer iterator reference */ -}; - -/** -* @brief -* Custom parser utility for parameters -*/ -class parser_parameter : public parser -{ -public: - /* -- Public Methods -- */ - - /** - * @brief - * Parser class constructor - * - * @param[in] it - * Tokenizer iterator reference - */ - parser_parameter(const tokenizer::iterator &it); - - /** - * @brief - * Parser class destructor - */ - ~parser_parameter(void); - - /** - * @brief - * Check if current token is a defined type @T - * - * @param[template] T - * Type of value to check against token - * - * @return - * True if type @T is equivalent to current token - */ - template bool is(void); - - /** - * @brief - * Return current token transformed to type @T - * - * @param[template] T - * Type of value to check against token - * - * @return - * A copy of the value transformed to given type @T - */ - template T to(void); - - /** - * @brief - * Assignement operator for parser - * - * @return - * Returns a reference to itself - */ - parser_parameter &operator=(const parser_parameter &) = delete; -}; - -/** -* @brief -* Check if current token is a custom quoted char ('') -* -* @return -* True if current token is a custom quoted char -*/ -template <> bool parser_parameter::is(void); - -/** -* @brief -* Check if current token is a custom long ending with (L) -* -* @return -* True if current token is a custom long -*/ -template <> bool parser_parameter::is(void); - -/** -* @brief -* Check if current token is a custom float ending with (f) -* -* @return -* True if current token is a custom float -*/ -template <> bool parser_parameter::is(void); - -/** -* @brief -* Check if current token is a custom quoted string ("") -* -* @return -* True if current token is a custom quoted string -*/ -template <> bool parser_parameter::is(void); - -/** -* @brief -* Return current token transformed from custom quoted char ('') -* -* @return -* A copy of the value transformed to char -*/ -template <> char parser_parameter::to(void); - -/** -* @brief -* Return current token transformed from custom long ending with (L) -* -* @return -* A copy of the value transformed to long -*/ -template <> long parser_parameter::to(void); - -/** -* @brief -* Return current token transformed from custom float ending with (f) -* -* @return -* A copy of the value transformed to float -*/ -template <> float parser_parameter::to(void); - -/** -* @brief -* Return current token transformed from custom quoted string ('') -* -* @return -* A copy of the value transformed to string -*/ -template <> std::string parser_parameter::to(void); - -} /* namespace metacallcli */ - -/* -- Template Implementation -- */ - -#include - -#endif /* METACALL_CLI_PARSER_HPP */ diff --git a/source/cli/metacallcli/include/metacallcli/tokenizer.hpp b/source/cli/metacallcli/include/metacallcli/tokenizer.hpp deleted file mode 100644 index 71f6d2be62..0000000000 --- a/source/cli/metacallcli/include/metacallcli/tokenizer.hpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - * MetaCall Command Line Interface by Parra Studios - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia - * - * A command line interface example as metacall wrapper. - * - */ - -#ifndef METACALL_CLI_TOKENIZER_HPP -#define METACALL_CLI_TOKENIZER_HPP 1 - -/* -- Headers -- */ - -#include - -#include -#include -#include - -/* -- Namespace -- */ - -namespace metacallcli -{ -/* -- Forward Declarations -- */ - -class tokenizer; - -/* -- Class Definition -- */ - -/** -* @brief -* String tokenizer utility -*/ -class tokenizer -{ -public: - /* -- Public Methods -- */ - - /** - * @brief - * Tokenizer constructor with default delimiters - * - * @param[in] str - * String to be tokenized - */ - tokenizer(const std::string &str); - - /** - * @brief - * Tokenizer constructor with custom @delimiters - * - * @param[in] str - * String to be tokenized - * - * @param[in] delimiters - * Delimiters will be used to tokenize the string @str - */ - tokenizer(const std::string &str, const std::string &delimiters); - - /** - * @brief - * Tokenizer class destructor - */ - ~tokenizer(void); - - /** - * @brief - * Set custom tokenizer delimiters - * - * @param[in] del - * Delimiters will be used to tokenize the string - */ - void delimit(const std::string &del); - - /* -- Public Class Definition -- */ - - /** - * @brief - * String tokenizer iterator - */ - class iterator : public std::iterator< - std::input_iterator_tag, - size_t, - size_t, - const size_t *, - const std::string &> - { - public: - /* -- Public Methods -- */ - - /** - * @brief - * Tokenizer iterator constructor - * - * @param[in] t - * Reference to tokenizer - * - * @param[in] begin - * Initial iterator position - */ - explicit iterator(const tokenizer &t, size_t begin = 0); - - /** - * @brief - * Tokenizer iterator increment operator - * - * @return - * Return a reference to itself - */ - iterator &operator++(void); - - /** - * @brief - * Tokenizer iterator increment operator - * - * @return - * Return a copy of itself - */ - iterator operator++(int); - - /** - * @brief - * Tokenizer iterator equality operator - * - * @param[in] other - * Reference to iterator to be compared against - * - * @return - * Return true if @other iterator points to the same @str and @offset - */ - bool operator==(iterator other) const; - - /** - * @brief - * Tokenizer iterator inequality operator - * - * @param[in] other - * Reference to iterator to be compared against - * - * @return - * Return true if @other iterator points to different @str or @offset - */ - bool operator!=(iterator other) const; - - /** - * @brief - * Tokenizer iterator dereferencing operator - * - * @return - * Return a constant string reference to the current token - */ - reference operator*(void) const; - - /** - * @brief - * Tokenizer iterator current position - * - * @return - * Return current value of @offset - */ - size_t position(void) const; - - /** - * @brief - * Tokenizer iterator escape trailing characters - * - * @param[in] characters - * Reference to list of characters to be escaped - * - * @return - * Return a constant string reference to the current token - */ - reference escape(const std::string &characters); - - /** - * @brief - * Assignment operator for tokenizer iterator - * - * @return - * Returns a reference to itself - */ - iterator &operator=(const iterator &) = delete; - - private: - /* -- Private Member Data -- */ - - const tokenizer &t; /**< Reference to tokenizer */ - - size_t offset; /**< Current position over iteration */ - - std::string token; /**< Current token */ - }; - - /** - * @brief - * Begin iterator operation - * - * @return - * Returns a iterator pointing to the beginning of @str - */ - iterator begin(void) const; - - /** - * @brief - * End iterator operation - * - * @return - * Returns a iterator pointing to the end of @str - */ - iterator end(void) const; - - /** - * @brief - * Assignement operator for tokenizer - * - * @return - * Returns a reference to itself - */ - tokenizer &operator=(const tokenizer &) = delete; - -protected: - /* -- Protected Definitions -- */ - - static const std::string default_delimiters; - -private: - /* -- Private Member Data -- */ - - const std::string str; /**< String to be tokenized */ - - std::string delimiters; /**< Current string token delimiters */ -}; - -} /* namespace metacallcli */ - -#endif /* METACALL_CLI_TOKENIZER_HPP */ diff --git a/source/cli/metacallcli/inline/metacallcli/parser.inl b/source/cli/metacallcli/inline/metacallcli/parser.inl deleted file mode 100644 index 7df9787414..0000000000 --- a/source/cli/metacallcli/inline/metacallcli/parser.inl +++ /dev/null @@ -1,60 +0,0 @@ -/* - * MetaCall Command Line Interface by Parra Studios - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia - * - * A command line interface example as metacall wrapper. - * - */ - -/* -- Headers -- */ - -#include -#include - -/* -- Namespace -- */ - -namespace metacallcli -{ -/* -- Methods -- */ - -template bool parser::is() -{ - std::stringstream str_stream(*it); - - T t; - - return (str_stream >> t && !str_stream.ignore()); -} - -template T parser::to() -{ - std::stringstream str_stream(*it); - - T t; - - str_stream >> t; - - return t; -} - -template bool parser_parameter::is() -{ - std::stringstream str_stream(*it); - - T t; - - return (str_stream >> std::noskipws >> t && !str_stream.ignore()); -} - -template T parser_parameter::to() -{ - std::stringstream str_stream(*it); - - T t; - - str_stream >> std::noskipws >> t; - - return t; -} - -} /* namespace metacallcli */ diff --git a/source/cli/metacallcli/source/application.cpp b/source/cli/metacallcli/source/application.cpp index 33a1b5f876..098f639006 100644 --- a/source/cli/metacallcli/source/application.cpp +++ b/source/cli/metacallcli/source/application.cpp @@ -1,6 +1,6 @@ /* * MetaCall Command Line Interface by Parra Studios - * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia * * A command line interface example as metacall wrapper. * @@ -9,8 +9,6 @@ /* -- Headers -- */ #include -#include -#include #if defined __has_include #if __has_include() @@ -30,509 +28,288 @@ namespace fs = std::experimental::filesystem; #include #include -/* TODO: Windows special characters not working properly */ -/* Set UTF-16 mode for stdout in Windows for the lambda character */ -/* -#if defined(WIN32) || defined(_WIN32) -# include -# include -# include -#endif -*/ - -#include - /* -- Namespace Declarations -- */ using namespace metacallcli; -/* -- Private Methods -- */ +/* -- Private Data -- */ -bool command_cb_help(application & /*app*/, tokenizer & /*t*/) -{ - std::cout << "MetaCall Command Line Interface by Parra Studios" << std::endl; - std::cout << "Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia " << std::endl; - std::cout << std::endl - << "A command line interface for MetaCall Core" << std::endl; - - /* Command list */ - std::cout << std::endl - << "Command list:" << std::endl - << std::endl; - - /* Load command */ - std::cout << "\t┌────────────────────────────────────────────────────────────────────────────────────────┐" << std::endl; - std::cout << "\t│ Load a script from file into MetaCall │" << std::endl; - std::cout << "\t│────────────────────────────────────────────────────────────────────────────────────────│" << std::endl; - std::cout << "\t│ Usage: │" << std::endl; - std::cout << "\t│ load ... │" << std::endl; - std::cout << "\t│ : identifier to the type of script │" << std::endl; - std::cout << "\t│ options : │" << std::endl; - std::cout << "\t│ mock - Mock (for testing purposes) │" << std::endl; - std::cout << "\t│ py - Python │" << std::endl; - std::cout << "\t│ node - NodeJS │" << std::endl; - std::cout << "\t│ rb - Ruby │" << std::endl; - std::cout << "\t│ cs - C# NetCore │" << std::endl; - std::cout << "\t│ cob - Cobol │" << std::endl; - std::cout << "\t│ ts - TypeScript │" << std::endl; - std::cout << "\t│ js - V8 JavaScript Engine │" << std::endl; - std::cout << "\t│ file - Files (for handling file systems) │" << std::endl; - std::cout << "\t│ ... : relative or absolute path to the script(s) │" << std::endl; - std::cout << "\t│ │" << std::endl; - std::cout << "\t│ Example: │" << std::endl; - std::cout << "\t│ load node concat.js │" << std::endl; - std::cout << "\t│ load py example.py │" << std::endl; - std::cout << "\t│ load rb hello.rb │" << std::endl; - std::cout << "\t│ │" << std::endl; - std::cout << "\t│ Result: │" << std::endl; - std::cout << "\t│ Script (concat.js) loaded correctly │" << std::endl; - std::cout << "\t└────────────────────────────────────────────────────────────────────────────────────────┘" << std::endl - << std::endl; - - /* Inspect command */ - std::cout << "\t┌────────────────────────────────────────────────────────────────────────────────────────┐" << std::endl; - std::cout << "\t│ Show all runtimes, modules and functions (with their signature) loaded into MetaCall │" << std::endl; - std::cout << "\t│────────────────────────────────────────────────────────────────────────────────────────│" << std::endl; - std::cout << "\t│ Usage: │" << std::endl; - std::cout << "\t│ inspect │" << std::endl; - std::cout << "\t│ │" << std::endl; - std::cout << "\t│ Example: │" << std::endl; - std::cout << "\t│ inspect │" << std::endl; - std::cout << "\t│ │" << std::endl; - std::cout << "\t│ Result: │" << std::endl; - std::cout << "\t│ runtime node { │" << std::endl; - std::cout << "\t│ module concat { │" << std::endl; - std::cout << "\t│ function concat(left, right) │" << std::endl; - std::cout << "\t│ } │" << std::endl; - std::cout << "\t│ } │" << std::endl; - std::cout << "\t└────────────────────────────────────────────────────────────────────────────────────────┘" << std::endl - << std::endl; - - /* Eval command */ - std::cout << "\t┌────────────────────────────────────────────────────────────────────────────────────────┐" << std::endl; - std::cout << "\t│ Evaluate a code snippet with the specified runtime tag │" << std::endl; - std::cout << "\t│────────────────────────────────────────────────────────────────────────────────────────│" << std::endl; - std::cout << "\t│ Usage: │" << std::endl; - std::cout << "\t│ eval