Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 76 additions & 13 deletions .github/workflows/cpp-ci-serial-programs-base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,32 @@ jobs:
- name: Set variables
shell: bash
run: |
if [[ "${{inputs.compiler}}" == "clang" ]]; then
if [[ "${{inputs.os}}" == windows* ]]; then
CMAKE_ADDITIONAL_FLAGS="-T ClangCL"
elif [[ "${{inputs.os}}" == ubuntu* ]]; then
CMAKE_ADDITIONAL_FLAGS="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=RelWithDebInfo"
BUILD_PARALLEL=10
if [[ "${{inputs.os}}" == windows* ]]; then
# Build with Ninja: ccache can't wrap the compiler under the Visual Studio generator.
# "Ninja Multi-Config" keeps Visual Studio's output layout (bin/RelWithDebInfo/).
# ccache also can't cache /FAs listings, so turn them off.
# CI needs no debug info, so keep RelWithDebInfo's optimization but leave out its
# debug info: with policy CMP0141, an empty CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
# drops /Zi, and linking without /debug writes no PDB. Release builds made outside
# CI keep their debug info.
echo "CMAKE_GENERATOR=Ninja Multi-Config" >> $GITHUB_ENV
CMAKE_ADDITIONAL_FLAGS="-DCMAKE_POLICY_DEFAULT_CMP0141=NEW -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT= -DCMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO=/INCREMENTAL:NO -DPA_ASSEMBLY_LISTINGS=OFF"
if [[ "${{inputs.compiler}}" == "clang" ]]; then
CMAKE_ADDITIONAL_FLAGS="$CMAKE_ADDITIONAL_FLAGS -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl"
else
CMAKE_ADDITIONAL_FLAGS="$CMAKE_ADDITIONAL_FLAGS -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl"
fi
# Visual Studio ran about one compile per core (/MP). Keep Ninja near that instead of
# 10 at once, so memory use stays close to what the runner handled before.
BUILD_PARALLEL=$(( $(nproc) + 2 ))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is okay to be merged as is. We may want to come back to profile this to see if there is a reason to have this additional parallel limit.

elif [[ "${{inputs.compiler}}" == "clang" && "${{inputs.os}}" == ubuntu* ]]; then
# RelWithDebInfo's -O2 without its -g: CI doesn't use the debug info.
CMAKE_ADDITIONAL_FLAGS="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=RelWithDebInfo '-DCMAKE_C_FLAGS_RELWITHDEBINFO=-O2 -DNDEBUG' '-DCMAKE_CXX_FLAGS_RELWITHDEBINFO=-O2 -DNDEBUG'"
fi
if [[ "${{inputs.os}}" != windows* ]]; then
CMAKE_ADDITIONAL_FLAGS="$CMAKE_ADDITIONAL_FLAGS -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
fi
CMAKE_ADDITIONAL_FLAGS="$CMAKE_ADDITIONAL_FLAGS -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
echo "CMAKE_ADDITIONAL_FLAGS=$CMAKE_ADDITIONAL_FLAGS" >> $GITHUB_ENV
echo "BUILD_PARALLEL=$BUILD_PARALLEL" >> $GITHUB_ENV

if [[ "${{inputs.os}}" == windows* ]]; then
UPLOAD_FOLDER="Arduino-Source/SerialPrograms/bin/RelWithDebInfo"
Expand Down Expand Up @@ -125,26 +140,70 @@ jobs:
# CMake quietly builds without Discord integration when it can't find DPP, so check here.
pkg-config --exact-version=10.1.5 dpp

# Ninja needs the MSVC build environment (cl and link on PATH, INCLUDE, LIB, ...), which the
# Visual Studio generator set up by itself. Run vcvars64.bat from the newest Visual Studio,
# the one that generator used, and pass every variable it adds or changes to later steps.
- name: Set up MSVC environment (Windows)
if: startsWith(inputs.os, 'windows')
shell: pwsh
run: |
$vs = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
$vcvars = cmd /c "`"$vs\VC\Auxiliary\Build\vcvars64.bat`" >nul && set"
if ($LASTEXITCODE -ne 0) {
throw "vcvars64.bat failed with exit code $LASTEXITCODE"
}
foreach ($line in $vcvars) {
# Skip anything that isn't a NAME=value line.
if ($line -notmatch '^([^=]+)=(.*)$') {
continue
}
$name = $Matches[1]
$value = $Matches[2]
if ($name -eq 'Path' -and '${{inputs.compiler}}' -eq 'clang') {
# Find Visual Studio's own clang-cl, the one its ClangCL toolset used, before any
# other LLVM install on the runner.
$value = "$vs\VC\Tools\Llvm\x64\bin;$value"
}
if ([Environment]::GetEnvironmentVariable($name) -ne $value) {
"$name=$value" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
[Environment]::SetEnvironmentVariable($name, $value)
}
}
if (-not (Get-Command cl -ErrorAction SilentlyContinue)) {
throw "cl.exe isn't on PATH after vcvars64.bat"
}
Get-Command cl, link, clang-cl, ninja, cmake -ErrorAction SilentlyContinue | Format-Table Name, Version, Source -AutoSize

# Keep compiler outputs between runs, so a build only recompiles what a change affects.
# Only pushes to main save the cache: every PR restores main's latest one, and PR runs don't
# fill the repo's 10 GB cache quota with entries that no other run can read.
# Not used on Windows: ccache can't cache MSVC builds that write debug info to a PDB (/Zi).
# max-size is only a cap: evict-old-files drops everything this build didn't use, so each
# saved cache is about one build's worth.
# On Windows, install the action's own ccache: the runner's Strawberry Perl puts an older
# ccache (4.9.1) on PATH, which the default install: detect would use instead.
- name: Set up ccache
if: ${{!startsWith(inputs.os, 'windows')}}
uses: hendrikmuhs/ccache-action@v1.2.24
with:
key: ${{inputs.os}}-${{inputs.compiler}}
max-size: 2G
max-size: 5G
evict-old-files: job
save: ${{github.ref == 'refs/heads/main'}}
install: ${{startsWith(inputs.os, 'windows') && 'binary' || 'detect'}}

- name: Generate binaries
env:
# Depend mode: on a cache miss, ccache hashes the include files the compiler reports
# (-MD or /showIncludes) instead of running the preprocessor a second time, which the
# ccache manual says makes a miss much cheaper. In the first runs with ccache, where
# every file missed, compiling took 10-40% longer than before on Linux and macOS, and
# about twice as long on Windows.
CCACHE_DEPEND: 1
run: |
cd Arduino-Source/SerialPrograms
mkdir bin
cd bin
cmake .. -DQT_MAJOR:STRING=6 ${{env.CMAKE_ADDITIONAL_FLAGS}}
cmake --build . --config RelWithDebInfo --parallel 10
cmake --build . --config RelWithDebInfo --parallel ${{env.BUILD_PARALLEL}}

- name: Prepare upload build
if: inputs.upload-build
Expand All @@ -155,12 +214,16 @@ jobs:
echo "https://github.com/${{github.repository_owner}}/Packages/commit/$(git -C Arduino-Source/Packages rev-parse HEAD)"
} > ${{env.UPLOAD_FOLDER}}/version.txt

# Leave out the static libraries, which only the build itself uses. With debug info,
# SerialProgramsLib.lib alone was over 1 GB uncompressed.
- name: Upload Build
uses: actions/upload-artifact@v7
if: inputs.upload-build
with:
name: Serial Programs (os=${{inputs.os}} - compiler=${{inputs.compiler}})
path: ${{env.UPLOAD_FOLDER}}
path: |
${{env.UPLOAD_FOLDER}}
!${{env.UPLOAD_FOLDER}}/*.lib

- name: Upload Executable Only
uses: actions/upload-artifact@v7
Expand Down
20 changes: 18 additions & 2 deletions SerialPrograms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ option(COMMAND_LINE_EXE "Build the optional executable" ON)
# searched for.
option(PA_CORE_ONLY "Build only the GUI-free core (basic microcontroller functions, no Qt, OpenCV, etc.)" OFF)

# With MSVC or clang-cl, write an assembly listing (/FAs) of every source file to
# Assembly/ in the build folder, to check the code the compiler generates, e.g. for
# the SIMD kernels. CI turns this off: ccache can't cache a compile that writes a
# listing, so every file would be recompiled on every run.
option(PA_ASSEMBLY_LISTINGS "Write an assembly listing of every source file to Assembly/ (MSVC and clang-cl only)" ON)

if(PA_CORE_ONLY)
message(STATUS "PA_CORE_ONLY: building only the GUI-free core")
set(CMAKE_AUTOMOC OFF)
Expand Down Expand Up @@ -388,7 +394,15 @@ if (WIN32)
PA_SOCIAL_SDK
)

target_compile_options(SerialProgramsLib PRIVATE /FAs /FaAssembly/ /MP /W4 /WX /external:anglebrackets /external:W0 /utf-8)
if(PA_ASSEMBLY_LISTINGS)
target_compile_options(SerialProgramsLib PRIVATE /FAs /FaAssembly/)
endif()
target_compile_options(SerialProgramsLib PRIVATE /W4 /WX /external:W0 /utf-8)
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# cl only: clang-cl ignores these, and /WX turns its unused-argument warning into an
# error. (Visual Studio's ClangCL toolset never passed them on to clang-cl.)
target_compile_options(SerialProgramsLib PRIVATE /MP /external:anglebrackets)
endif()
target_compile_options(SerialProgramsLib PRIVATE /wd5054) # Deprecated enum arithemtic
target_compile_options(SerialProgramsLib PRIVATE /wd4505) # unreferenced local function has been removed

Expand All @@ -397,7 +411,9 @@ if (WIN32)
set(ARCH_FLAGS_17_Skylake /arch:AVX512)
set(ARCH_FLAGS_19_IceLake /arch:AVX512)

if(CMAKE_GENERATOR_TOOLSET MATCHES "ClangCL")
# clang-cl, whether from Visual Studio's ClangCL toolset (-T ClangCL) or from another
# generator such as Ninja, where CMAKE_GENERATOR_TOOLSET is empty.
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(SerialProgramsLib PRIVATE -Wno-unused-function)
target_compile_options(SerialProgramsLib PRIVATE -march=nehalem)
set(ARCH_FLAGS_09_Nehalem -march=nehalem)
Expand Down
16 changes: 12 additions & 4 deletions SerialPrograms/cmake/CoreLib.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,21 @@ add_library(CoreLib STATIC ${CORE_LIBRARY_SOURCES})
pa_apply_gui_free_target_properties(CoreLib)

if (WIN32)
# /FaAssembly/CoreLib/ writes assembly listings to Assembly/CoreLib/ in the build folder.
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Assembly/CoreLib)
target_compile_options(CoreLib PRIVATE /FAs /FaAssembly/CoreLib/ /MP /W4 /WX /external:anglebrackets /external:W0 /utf-8)
if(PA_ASSEMBLY_LISTINGS) # option defined in CMakeLists.txt
# /FaAssembly/CoreLib/ writes assembly listings to Assembly/CoreLib/ in the build folder.
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Assembly/CoreLib)
target_compile_options(CoreLib PRIVATE /FAs /FaAssembly/CoreLib/)
endif()
target_compile_options(CoreLib PRIVATE /W4 /WX /external:W0 /utf-8)
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# cl only: clang-cl ignores these, and /WX turns its unused-argument warning into an error.
target_compile_options(CoreLib PRIVATE /MP /external:anglebrackets)
endif()
target_compile_options(CoreLib PRIVATE /wd5054) # Deprecated enum arithemtic
target_compile_options(CoreLib PRIVATE /wd4505) # unreferenced local function has been removed

if(CMAKE_GENERATOR_TOOLSET MATCHES "ClangCL")
# clang-cl, from Visual Studio's ClangCL toolset or from another generator such as Ninja.
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(CoreLib PRIVATE -Wno-unused-function)
target_compile_options(CoreLib PRIVATE -march=nehalem)
endif()
Expand Down
Loading