Skip to content

Linux GCC/Clang Qt6.7 TinyDrivers #102

Linux GCC/Clang Qt6.7 TinyDrivers

Linux GCC/Clang Qt6.7 TinyDrivers #102

# MySQL
# ---
# Forces TLS connections with the caching_sha2_password and certificate validation, also validates
# certificate's CN for issuer and subject.
# ccache
# ---
# Uses /ccache_drivers folder and the compressed cache size is 1.8G (after whole workflow finishes)
name: Linux GCC/Clang Qt6.7 TinyDrivers
# Invoke manually from the command-line using the gh command, eg.:
# gh workflow run --ref silverqx-develop
# The reason for this is that I have 2 self-hosted runners on one PC (one for Linux and other for
# Windows) and I'm not able to serialize all these workflows and because of that I would have to
# decrease parallel and it would take hours to finish, so all Linux workflows must be invoked
# manually.
on: workflow_dispatch
concurrency:
group: tinyorm-linux
# I will not remove the build folders before a job execution it's not necessary and
# it will be faster this way. I can still remove them manually if needed or
# if something goes wrong.
jobs:
build:
name: cmake build / ctest
# Self-hosted runner is Fedora 40
runs-on: [ self-hosted, linux ]
env:
# Settings (constant variables)
TINY_QT_VERSION: 6.7.2
TINY_QT_SPEC: linux_gcc_64
# Don't use more than 3 cores, I also saw blue screen with zram :/
# Currenlty using 16G swap file to be safe
TINY_PARALLEL_GCC: 3
TINY_PARALLEL_CLANG: 8
# State variables
TINY_VCPKG_NEEDS_UPGRADE: false
strategy:
matrix:
lto: [ OFF ]
drivers-type: [ Shared, Loadable, Static ]
build-type:
- key: debug
name: Debug
- key: release
name: Release
compiler:
- key: clang
name: clang18
command: clang++-18
linker-command: ld.lld
- key: gcc
name: gcc14
command: g++-14
linker-command: ld
include:
- lto: ON
drivers-type: Loadable
build-type:
key: release
name: Release
compiler:
key: clang
name: clang18
command: clang++-18
linker-command: ld.lld
- lto: ON
drivers-type: Loadable
build-type:
key: release
name: Release
compiler:
key: gcc
name: gcc14
command: g++-14
linker-command: ld
steps:
- uses: actions/checkout@v4
with:
path: main
- name: TinyORM prepare environment
run: |
runnerWorkPath=$(realpath "$RUNNER_WORKSPACE/..")
echo "TinyRunnerWorkPath=$runnerWorkPath" >> $GITHUB_ENV
# Parallel gcc to 3 and Clang to 8 is maximum what my computer allows but I decided to use
# the different strategy, I will use the on: workflow_dispatch for all self-hosted actions
# and these workflows are invoked automatically one from other:
# gh workflow run --ref silverqx-develop
# --
# For gcc14 with the parallel 4 I saw 15.1GB maximum memory usage out of 15.6GB and that is
# very close to the edge, so I have to decrease it to 3 (also saw the blue screen on Fedora
# with zram only without the swap file).
# For clang18 it was ~11.6 out of 15.6GB so parallel 8 is ok.
[[ '${{ matrix.compiler.key }}' == 'gcc' ]] && parallel=$TINY_PARALLEL_GCC || \
parallel=$TINY_PARALLEL_CLANG
echo "TinyParallel=$parallel" >> $GITHUB_ENV
echo "TinyParallelVcpkg=$(nproc)" >> $GITHUB_ENV
tinyormPath=$(realpath ./main)
echo "TinyORMPath=$tinyormPath" >> $GITHUB_ENV
tinyormBuildName='TinyDrivers-${{ matrix.compiler.name }}-${{ matrix.drivers-type }}-${{ matrix.build-type.key }}'
[[ '${{ matrix.lto }}' == 'ON' ]] && tinyormBuildName="$tinyormBuildName-lto"
echo "TinyORMBuildName=$tinyormBuildName" >> $GITHUB_ENV
tinyormBuildTree="$RUNNER_WORKSPACE/TinyORM-builds-cmake/build-$tinyormBuildName"
echo "TinyORMBuildTree=$tinyormBuildTree" >> $GITHUB_ENV
# Remove all before the first _ character eg. linux_gcc_64 -> gcc_64
echo "TinyQtSpecPlain=${TINY_QT_SPEC#*_}" >> $GITHUB_ENV
- name: MySQL service check status
run: |
mysqladmin --password="$DB_MYSQL_PASSWORD" ping
env:
DB_MYSQL_PASSWORD: ${{ secrets.DB_MYSQL_PASSWORD_SELF }}
- name: Print MySQL database version
run: |
mysql --version
# lukka/get-cmake@latest needed because of Fedora
- name: CMake and Ninja install latest versions
uses: lukka/get-cmake@latest
with:
useLocalCache: true
useCloudCache: false
# Don't use the default CCACHE_DIR path on self-hosted runners
- name: Ccache prepare environment
run: |
ccacheDirPath="$RUNNER_WORKSPACE/ccache_drivers"
echo "CCACHE_DIR=$ccacheDirPath" >> $GITHUB_ENV
# I'm managing the ccache configuration manually on self-hosted runners using the ccache.conf
# because it's used by more actions.
- name: Ccache print version and configuration
run: |
echo '::group::Print version'
ccache --version
echo '::endgroup::'
echo '::group::Print ccache config'
ccache --show-config
echo '::endgroup::'
# Don't define VCPKG_DEFAULT_BINARY_CACHE as Linux VM image is strictly for GH actions use only
- name: vcpkg prepare environment
run: |
echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV
echo 'VCPKG_DEFAULT_TRIPLET=x64-linux-dynamic' >> $GITHUB_ENV
echo "VCPKG_MAX_CONCURRENCY=$TinyParallelVcpkg" >> $GITHUB_ENV
- name: vcpkg needs upgrade? (once per day)
run: |
vcpkgUpgradedAtFilepath="$RUNNER_WORKSPACE/.vcpkg_upgraded_at"
if [ ! -f "$vcpkgUpgradedAtFilepath" ] || [ ! -r "$vcpkgUpgradedAtFilepath" ] || \
! read datePreviousUpgradeRaw < "$vcpkgUpgradedAtFilepath"
then
echo 'TINY_VCPKG_NEEDS_UPGRADE=true' >> $GITHUB_ENV
exit 0
fi
datePreviousUpgrade=$(date --date="$datePreviousUpgradeRaw" +%s)
if [ $? -ne 0 ] || [ -z "$datePreviousUpgrade" ]; then
echo "Parsing the '.vcpkg_upgraded_at' failed." >&2
exit 1
fi
dateToday=$(date --date=$(date +%Y-%m-%d) +%s)
if [ "$datePreviousUpgrade" -lt "$dateToday" ]; then
echo 'TINY_VCPKG_NEEDS_UPGRADE=true' >> $GITHUB_ENV
fi
- name: vcpkg upgrade repository (latest version)
if: env.TINY_VCPKG_NEEDS_UPGRADE == 'true'
run: |
cd "$VCPKG_INSTALLATION_ROOT"
git switch master
git fetch --tags origin
git reset --hard origin/master
./bootstrap-vcpkg.sh
date +%Y-%m-%d > "$RUNNER_WORKSPACE/.vcpkg_upgraded_at"
- name: Qt v${{ env.TINY_QT_VERSION }} prepare environment
run: |
echo "/opt/Qt/$TINY_QT_VERSION/$TinyQtSpecPlain/bin" >> $GITHUB_PATH
echo "LD_LIBRARY_PATH=/opt/Qt/$TINY_QT_VERSION/$TinyQtSpecPlain/lib${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" >> $GITHUB_ENV
- name: Compiler print version (${{ matrix.compiler.command }})
run: |
${{ matrix.compiler.command }} --version
- name: Linker print version (${{ matrix.compiler.linker-command }})
run: |
${{ matrix.compiler.linker-command }} --version
- name: CMake print version
run: |
cmake --version
- name: Ninja print version
run: |
ninja --version
- name: vcpkg print version
run: |
vcpkg --version
- name: Qt print version
run: |
qmake -query QT_VERSION
- name: Ccache clear statistics
run: |
ccache --zero-stats
# BUILD_TREE_DEPLOY isn't needed because CMake forces linker to write absolute paths to exe, but
# I enable it anyway to test this feature.
# CMAKE_DISABLE_PRECOMPILE_HEADERS=ON is correct as we need to test missing #include-s.
- name: TinyORM cmake configure (${{ env.TinyORMBuildName }})
working-directory: ${{ env.TinyORMPath }}
run: >-
cmake --log-level=DEBUG --log-context
-S .
-B "$TinyORMBuildTree"
-G Ninja
-D CMAKE_CXX_COMPILER_LAUNCHER:FILEPATH=ccache
-D CMAKE_CXX_COMPILER:FILEPATH=${{ matrix.compiler.command }}
-D CMAKE_TOOLCHAIN_FILE:FILEPATH="$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"
-D CMAKE_DISABLE_PRECOMPILE_HEADERS:BOOL=ON
-D CMAKE_EXPORT_PACKAGE_REGISTRY:BOOL=OFF
-D CMAKE_BUILD_TYPE:STRING=${{ matrix.build-type.name }}
-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF
-D CMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=${{ matrix.lto }}
-D VCPKG_APPLOCAL_DEPS:BOOL=OFF
-D VERBOSE_CONFIGURE:BOOL=ON
-D BUILD_TREE_DEPLOY:BOOL=ON
-D STRICT_MODE:BOOL=ON
-D MYSQL_PING:BOOL=ON
-D BUILD_TESTS:BOOL=ON
-D ORM:BOOL=ON
-D TOM:BOOL=ON
-D TOM_EXAMPLE:BOOL=ON
-D BUILD_DRIVERS:BOOL=ON
-D DRIVERS_TYPE:STRING=${{ matrix.drivers-type }}
- name: TinyORM cmake build ✨ (${{ env.TinyORMBuildName }})
working-directory: ${{ env.TinyORMBuildTree }}
run: |
cmake --build . --target all --parallel $TinyParallel
- name: Ccache print statistics
run: |
ccache --show-stats --verbose
- name: libTinyOrm print .comment section
working-directory: ${{ env.TinyORMBuildTree }}
run: >-
[[ '${{ matrix.build-type.key }}' == 'debug' ]] &&
tinyLibTinyOrm='libTinyOrmd.so' ||
tinyLibTinyOrm='libTinyOrm.so'
readelf --string-dump .comment "./$tinyLibTinyOrm"
- name: TinyORM add on the $LD_LIBRARY_PATH
run: |
echo "LD_LIBRARY_PATH=$TinyORMBuildTree${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" >> $env:GITHUB_ENV
# Used migrate:fresh instead (is safer)
- name: Create and Seed tables for unit tests 🎉
working-directory: ${{ env.TinyORMBuildTree }}/tests/testdata_tom
run: |
./tom_testdata migrate:fresh --database=tinyorm_testdata_tom_mysql --seed --no-ansi
env:
DB_MYSQL_CHARSET: ${{ secrets.DB_MYSQL_CHARSET }}
DB_MYSQL_COLLATION: ${{ secrets.DB_MYSQL_COLLATION }}
DB_MYSQL_DATABASE: ${{ secrets.DB_MYSQL_DATABASE }}
DB_MYSQL_HOST: ${{ secrets.DB_MYSQL_HOST_SELF }}
DB_MYSQL_PASSWORD: ${{ secrets.DB_MYSQL_PASSWORD_SELF }}
DB_MYSQL_SSL_CA: ${{ secrets.DB_MYSQL_DATA_SELF_LINUX }}/ca.pem
DB_MYSQL_SSL_CERT: ${{ secrets.DB_MYSQL_DATA_SELF_LINUX }}/client-cert.pem
DB_MYSQL_SSL_KEY: ${{ secrets.DB_MYSQL_DATA_SELF_LINUX }}/client-key.pem
DB_MYSQL_SSL_MODE: ${{ secrets.DB_MYSQL_SSL_MODE }}
DB_MYSQL_USERNAME: ${{ secrets.DB_MYSQL_USERNAME_SELF }}
TOM_TESTDATA_ENV: ${{ vars.TOM_TESTDATA_ENV }}
- name: TinyORM execute ctest 🔥
working-directory: ${{ env.TinyORMBuildTree }}
run: |
ctest --output-on-failure --parallel 16
env:
DB_MYSQL_CHARSET: ${{ secrets.DB_MYSQL_CHARSET }}
DB_MYSQL_COLLATION: ${{ secrets.DB_MYSQL_COLLATION }}
DB_MYSQL_DATABASE: ${{ secrets.DB_MYSQL_DATABASE }}
DB_MYSQL_HOST: ${{ secrets.DB_MYSQL_HOST_SELF }}
DB_MYSQL_PASSWORD: ${{ secrets.DB_MYSQL_PASSWORD_SELF }}
DB_MYSQL_SSL_CA: ${{ secrets.DB_MYSQL_DATA_SELF_LINUX }}/ca.pem
DB_MYSQL_SSL_CERT: ${{ secrets.DB_MYSQL_DATA_SELF_LINUX }}/client-cert.pem
DB_MYSQL_SSL_KEY: ${{ secrets.DB_MYSQL_DATA_SELF_LINUX }}/client-key.pem
DB_MYSQL_SSL_MODE: ${{ secrets.DB_MYSQL_SSL_MODE }}
DB_MYSQL_USERNAME: ${{ secrets.DB_MYSQL_USERNAME_SELF }}
TOM_TESTS_ENV: ${{ vars.TOM_TESTS_ENV }}
- name: Tom example test some commands (MySQL) 🚀
working-directory: ${{ env.TinyORMBuildTree }}/examples/tom
run: |
./tom migrate:fresh --database=tinyorm_tom_mysql --seed --no-ansi
./tom migrate:uninstall --reset --database=tinyorm_tom_mysql --no-ansi
./tom migrate:install --database=tinyorm_tom_mysql --no-ansi
./tom migrate --database=tinyorm_tom_mysql --seed --no-ansi
./tom migrate:status --database=tinyorm_tom_mysql --no-ansi
./tom migrate:refresh --database=tinyorm_tom_mysql --seed --no-ansi
./tom migrate:reset --database=tinyorm_tom_mysql --no-ansi
./tom migrate:uninstall --database=tinyorm_tom_mysql --no-ansi
# Restore my development environment
./tom migrate --database=tinyorm_tom_mysql --seed --no-ansi
env:
DB_MYSQL_CHARSET: ${{ secrets.DB_MYSQL_CHARSET }}
DB_MYSQL_COLLATION: ${{ secrets.DB_MYSQL_COLLATION }}
DB_MYSQL_DATABASE: ${{ secrets.DB_MYSQL_DATABASE }}
DB_MYSQL_HOST: ${{ secrets.DB_MYSQL_HOST_SELF }}
DB_MYSQL_PASSWORD: ${{ secrets.DB_MYSQL_PASSWORD_SELF }}
DB_MYSQL_SSL_CA: ${{ secrets.DB_MYSQL_DATA_SELF_LINUX }}/ca.pem
DB_MYSQL_SSL_CERT: ${{ secrets.DB_MYSQL_DATA_SELF_LINUX }}/client-cert.pem
DB_MYSQL_SSL_KEY: ${{ secrets.DB_MYSQL_DATA_SELF_LINUX }}/client-key.pem
DB_MYSQL_SSL_MODE: ${{ secrets.DB_MYSQL_SSL_MODE }}
DB_MYSQL_USERNAME: ${{ secrets.DB_MYSQL_USERNAME_SELF }}
TOM_EXAMPLE_ENV: ${{ vars.TOM_EXAMPLE_ENV }}
# The tom_testdata will be needed in vcpkg-linux-drivers.yml so we need to copy this executable,
# the reason for this is to always have the latest tom_testdata and to avoid manual rebuilds if
# any shared library is updated on which the tom_testdata depends to avoid crashes.
- name: Install tom_testdata for vcpkg-linux-drivers.yml
if: matrix.compiler.key == 'gcc' && matrix.drivers-type == 'Static' && matrix.build-type.key == 'release'
working-directory: ${{ env.TinyORMBuildTree }}/tests/testdata_tom
run: |
mkdir -p "$RUNNER_WORKSPACE/.local/bin"
cp --force --target-directory="$RUNNER_WORKSPACE/.local/bin" ./tom_testdata
# The reason for this is the concurrency:group: can contain only two in_progress workflows,
# one will be in_progress and the second will be queued (waiting until the first finish),
# and all others will be canceled.
# Jobs are run randomly! They are sorted from 0 to strategy.job-total - 1 in GitHub UI, so
# the first job has index 0, the second job has index 1, ...
# Execute the next workflow inly if it's active and isn't disabled (disabled_manually state).
# Also, if the step fails due to any error, continue (eg. network unreachable or similar).
- name: Run vcpkg-linux.yml workflow
continue-on-error: true
if: strategy.job-index == 0
working-directory: ${{ env.TinyORMPath }}
run: |
workflowState=$(gh workflow list --all --json path,state \
--jq '.[] | select (.path | endswith("/vcpkg-linux.yml")) | .state')
if [ $? -eq 0 ] && [[ "$workflowState" == 'active' ]]; then
gh workflow run vcpkg-linux.yml --ref "$GITHUB_REF_NAME"
fi
env:
GH_TOKEN: ${{ github.token }}
- name: Cancel vcpkg-linux.yml workflow (on failure)
if: ${{ failure() }}
working-directory: ${{ env.TinyORMPath }}
run: |
databaseId=$(gh run list --workflow vcpkg-linux.yml --event workflow_dispatch \
--json databaseId,conclusion,status \
--jq '.[] | select (.status == "pending") | select (.conclusion == "") | .databaseId')
if [ $? -eq 0 ] && [[ "$databaseId" != "" && "$databaseId" =~ ^[0-9]+$ ]] &&
[ $databaseId -gt 0 ]
then
gh run cancel $databaseId
fi
env:
GH_TOKEN: ${{ github.token }}