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
32 changes: 13 additions & 19 deletions .github/workflows/cbake-sysroots.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
name: cbake sysroots
on: workflow_dispatch
on:
workflow_dispatch:
inputs:
armv7_only:
description: Build only the Ubuntu 18.04 and Alpine 3.17 ARMv7 compatibility sysroots
required: false
default: false
type: boolean
jobs:
build:
name: cbake sysroot [${{matrix.distro}}-${{matrix.arch}}]
runs-on: ${{matrix.runner}}
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
arch: [ amd64, arm64 ]
distro:
- ubuntu-18.04
- ubuntu-20.04
- ubuntu-22.04
- ubuntu-24.04
- debian-10
- debian-11
- debian-12
- rhel8
- rhel9
- alpine-3.17
- alpine-3.21

include:
- os: linux
runner: ubuntu-22.04
arch: ${{ fromJSON(inputs.armv7_only && '["arm"]' || '["amd64", "arm64"]') }}
distro: ${{ fromJSON(inputs.armv7_only && '["ubuntu-18.04", "alpine-3.17"]' || '["ubuntu-18.04", "ubuntu-20.04", "ubuntu-22.04", "ubuntu-24.04", "debian-10", "debian-11", "debian-12", "rhel8", "rhel9", "alpine-3.17", "alpine-3.21"]') }}
include: ${{ fromJSON(inputs.armv7_only && '[]' || '[{"distro":"ubuntu-18.04","arch":"arm"},{"distro":"alpine-3.17","arch":"arm"}]') }}

steps:
- name: Check out ${{ github.repository }}
Expand All @@ -50,3 +43,4 @@ jobs:
with:
name: ${{matrix.distro}}-${{matrix.arch}}-sysroot
path: packages/${{matrix.distro}}-${{matrix.arch}}-sysroot.tar.xz
if-no-files-found: error
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ You can also use the command wrapper:

## Supported Linux sysroot recipes

The GitHub Actions matrix currently builds each recipe for `amd64` and `arm64`:
The GitHub Actions matrix builds every recipe for `amd64` and `arm64`. It also builds the fixed ARMv7 compatibility baselines below with the `arm` label. `arm` is intentionally aligned with the `linux-arm` and `linux-musl-arm` runtime identifiers; CBake maps it to Docker buildx platform `linux/arm/v7`.

| Family | Recipes |
| --- | --- |
Expand All @@ -76,6 +76,13 @@ The GitHub Actions matrix currently builds each recipe for `amd64` and `arm64`:
| RHEL | `rhel8`, `rhel9` |
| Alpine | `alpine-3.17`, `alpine-3.21` |

| Compatibility baseline | Archive | Imported sysroot | GCC and Clang target | GCC target directory |
| --- | --- | --- | --- | --- |
| Ubuntu 18.04 (glibc) | `ubuntu-18.04-arm-sysroot.tar.xz` | `sysroots\ubuntu-18.04-arm` | `arm-linux-gnueabihf` | `usr\lib\gcc\arm-linux-gnueabihf\<gcc-version>` |
| Alpine 3.17 (musl) | `alpine-3.17-arm-sysroot.tar.xz` | `sysroots\alpine-3.17-arm` | `armv7-alpine-linux-musleabihf` | `usr\lib\gcc\armv7-alpine-linux-musleabihf\<gcc-version>` |

Import either archive with `Import-CBakeSysroot -Distro '<distro-version>' -Arch 'arm'`. Set `SYSROOT_NAME` to the imported directory name (for example, `ubuntu-18.04-arm`). The Linux toolchain finds the target triple from its `usr\lib\gcc\<target>\<gcc-version>` layout and applies `-march=armv7-a` for this architecture.

To add a distribution, create a new directory under `recipes\` with a Dockerfile and update the workflow matrix if CI should build it.

## Cross-compile a CMake project for Linux
Expand Down Expand Up @@ -103,7 +110,7 @@ Use the target-specific files in `cmake\` when building for non-Linux platforms:
| --- | --- |
| Android | `android-arm.toolchain.cmake`, `android-arm64.toolchain.cmake`, `android-x86.toolchain.cmake`, `android-x86_64.toolchain.cmake` |
| iOS | `ios-arm.toolchain.cmake`, `ios-arm64.toolchain.cmake`, `ios-armv7.toolchain.cmake`, `ios-x86_64.toolchain.cmake` |
| Linux | `linux-amd64.toolchain.cmake`, `linux-arm64.toolchain.cmake`, `linux.toolchain.cmake` |
| Linux | `linux-amd64.toolchain.cmake`, `linux-arm.toolchain.cmake`, `linux-arm64.toolchain.cmake`, `linux.toolchain.cmake` |
| Windows | `windows-x86.toolchain.cmake`, `windows-x64.toolchain.cmake`, `windows-arm64.toolchain.cmake` |

Example:
Expand Down
2 changes: 2 additions & 0 deletions build.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env pwsh

$ErrorActionPreference = 'Stop'

if (-Not (Test-Path Env:CBAKE_HOME)) {
$Env:CBAKE_HOME = $PSScriptRoot
}
Expand Down
45 changes: 31 additions & 14 deletions cbake.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,24 @@ function Convert-CBakeSymbolicLinks() {
[string] $RootPath
)

$ReparsePoints = Get-ChildItem $RootPath -Recurse |
$ReparsePoints = Get-ChildItem -LiteralPath $RootPath -Recurse |
Where-Object { $_.Attributes -band [IO.FileAttributes]::ReparsePoint }
$AbsSymlinks = $ReparsePoints | Where-Object { $_.LinkTarget.StartsWith('/') }
$AbsSymlinks = $ReparsePoints | Where-Object {
-not [string]::IsNullOrEmpty($_.LinkTarget) -and $_.LinkTarget.StartsWith('/')
}
$AbsSymlinks | ForEach-Object {
$Source = $_.FullName
$Directory = $_.Directory
$Target = Join-Path $RootPath $_.LinkTarget
if (Test-Path $Target) {
Push-Location
Set-Location $Directory
$Target = Resolve-Path -Path $Target -Relative
Remove-Item $Source | Out-Null
New-Item -ItemType SymbolicLink -Path $Source -Target $Target | Out-Null
Pop-Location
$Directory = [IO.Path]::GetDirectoryName($Source)
$IsDirectory = $_.PSIsContainer
$Target = Join-Path $RootPath $_.LinkTarget.TrimStart('/')
if (Test-Path -LiteralPath $Target) {
$RelativeTarget = [IO.Path]::GetRelativePath($Directory, $Target)
Remove-Item -LiteralPath $Source | Out-Null
if ($IsDirectory) {
[IO.Directory]::CreateSymbolicLink($Source, $RelativeTarget) | Out-Null
} else {
[IO.File]::CreateSymbolicLink($Source, $RelativeTarget) | Out-Null
}
} else {
Remove-Item -LiteralPath $Source -ErrorAction 'SilentlyContinue' | Out-Null
}
Expand All @@ -33,7 +37,7 @@ function Remove-CBakeSymbolicLinks() {
[string] $RootPath
)

$ReparsePoints = Get-ChildItem $RootPath -Recurse |
$ReparsePoints = Get-ChildItem -LiteralPath $RootPath -Recurse |
Where-Object { $_.Attributes -band [IO.FileAttributes]::ReparsePoint }
$ReparsePoints | ForEach-Object {
$Source = $_.FullName
Expand Down Expand Up @@ -102,7 +106,7 @@ function Remove-CBakeExcludedFiles() {

$ExcludeDirs | ForEach-Object {
$ExcludeDir = Join-Path $RootPath $_.TrimStart('/', '\')
Remove-Item -Path $ExcludeDir -Recurse -Force -ErrorAction 'SilentlyContinue' | Out-Null
Remove-Item -LiteralPath $ExcludeDir -Recurse -Force -ErrorAction 'SilentlyContinue' | Out-Null
}
}

Expand Down Expand Up @@ -185,6 +189,19 @@ function Import-CBakeSysroot {
Invoke-CBakeNativeCommand -FilePath 'tar' -ArgumentList @('xf', $PackageFile, '-C', $SysrootsPath)
}

function Get-CBakeDockerPlatform {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string] $Arch
)

switch ($Arch) {
'arm' { 'linux/arm/v7' }
default { "linux/$Arch" }
}
}

function New-CBakeSysroot {
param(
[Parameter(Mandatory = $true)]
Expand Down Expand Up @@ -214,7 +231,7 @@ function New-CBakeSysroot {
$params = @('buildx',
'build', '.',
'-t', "$distro-$arch-sysroot",
'--platform', "linux/$arch",
'--platform', (Get-CBakeDockerPlatform $Arch),
'-o', "type=tar,dest=$ContainerTarFile")
Invoke-CBakeNativeCommand -FilePath 'docker' -ArgumentList $Params
New-Item -Path $ExportPath -ItemType Directory -ErrorAction 'SilentlyContinue' | Out-Null
Expand Down
4 changes: 4 additions & 0 deletions cmake/linux-arm.toolchain.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
set(CMAKE_SYSTEM_PROCESSOR armv7l)
set(CMAKE_SIZEOF_VOID_P 4)

include("${CMAKE_CURRENT_LIST_DIR}/linux.toolchain.cmake")
3 changes: 3 additions & 0 deletions cmake/linux.toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ if((SYSROOT_ARCH STREQUAL "amd64") OR (SYSROOT_ARCH STREQUAL "x86_64"))
set(CMAKE_SYSTEM_PROCESSOR "x86_64")
elseif((SYSROOT_ARCH STREQUAL "arm64") OR (SYSROOT_ARCH STREQUAL "aarch64"))
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
elseif((SYSROOT_ARCH STREQUAL "arm") OR (SYSROOT_ARCH STREQUAL "armv7"))
set(CMAKE_SYSTEM_PROCESSOR "armv7l")
set(CROSS_MACHINE_FLAGS "-march=armv7-a")
else()
message(FATAL_ERROR "Unknown sysroot architecture: ${SYSROOT_ARCH}")
endif()
Expand Down
116 changes: 116 additions & 0 deletions tests/CBake.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,22 @@ Describe 'Get-CBakePath' {
}
}

Describe 'Convert-CBakeSymbolicLinks' {
It 'converts absolute symlinks to relative targets with wildcard characters in their names' {
$RootPath = Join-Path $TestDrive 'sysroot'
$TargetPath = Join-Path $RootPath 'target'
$SourcePath = Join-Path $RootPath 'link[arm]'
New-Item -Path $TargetPath -ItemType Directory -Force | Out-Null
[IO.Directory]::CreateSymbolicLink($SourcePath, '/target') | Out-Null

Convert-CBakeSymbolicLinks $RootPath

$Link = Get-Item -LiteralPath $SourcePath
$Link.LinkTarget | Should -Be 'target'
$Link.ResolveLinkTarget($true).FullName | Should -Be $TargetPath
}
}

Describe 'Remove-CBakeExcludedFiles' {
It 'removes excluded directories from the provided root path' {
$RootPath = Join-Path $TestDrive 'sysroot'
Expand All @@ -70,6 +86,16 @@ Describe 'Remove-CBakeExcludedFiles' {
Test-Path $ExcludedPath | Should -BeFalse
Test-Path $KeptPath | Should -BeTrue
}

It 'handles wildcard characters in the provided root path literally' {
$RootPath = Join-Path $TestDrive 'sysroot[arm]'
$ExcludedPath = Join-Path $RootPath 'usr\bin'
New-Item -Path $ExcludedPath -ItemType Directory -Force | Out-Null

Remove-CBakeExcludedFiles $RootPath

Test-Path -LiteralPath $ExcludedPath | Should -BeFalse
}
}

Describe 'Invoke-CBakeNativeCommand' {
Expand Down Expand Up @@ -113,13 +139,28 @@ Describe 'Import-CBakeSysroot' {
$ArgumentList[3] -eq $script:SysrootsPath
}
}

It 'uses the ARMv7 compatibility-baseline archive name' {
$PackageFile = Join-Path $script:PackagesPath 'alpine-3.17-arm-sysroot.tar.xz'
New-Item -Path $PackageFile -ItemType File -Force | Out-Null
Mock -ModuleName cbake Invoke-CBakeNativeCommand {}

Import-CBakeSysroot -Distro 'alpine-3.17' -Arch 'arm'

Should -Invoke -CommandName Invoke-CBakeNativeCommand -ModuleName cbake -Exactly -Times 1 -ParameterFilter {
$FilePath -eq 'tar' -and
$ArgumentList[1] -eq $PackageFile -and
$ArgumentList[3] -eq $script:SysrootsPath
}
}
}

Describe 'New-CBakeSysroot' {
BeforeEach {
$script:RecipesPath = Join-Path $TestDrive 'recipes'
$script:PackagesPath = Join-Path $TestDrive 'packages'
New-Item -Path (Join-Path $script:RecipesPath 'ubuntu-24.04') -ItemType Directory -Force | Out-Null
New-Item -Path (Join-Path $script:RecipesPath 'ubuntu-18.04') -ItemType Directory -Force | Out-Null
New-Item -Path $script:PackagesPath -ItemType Directory -Force | Out-Null

$Env:CBAKE_RECIPES_DIR = $script:RecipesPath
Expand Down Expand Up @@ -152,6 +193,25 @@ Describe 'New-CBakeSysroot' {
Should -Invoke -CommandName Optimize-CBakeSysroot -ModuleName cbake -Exactly -Times 1
}

It 'maps the ARM compatibility label to the ARMv7 Docker platform' {
$PackageFile = Join-Path $script:PackagesPath 'ubuntu-18.04-arm-sysroot.tar.xz'
Mock -ModuleName cbake Invoke-CBakeNativeCommand {}
Mock -ModuleName cbake Optimize-CBakeSysroot {}

New-CBakeSysroot -Distro 'ubuntu-18.04' -Arch 'arm'

Should -Invoke -CommandName Invoke-CBakeNativeCommand -ModuleName cbake -Exactly -Times 1 -ParameterFilter {
$FilePath -eq 'docker' -and
$ArgumentList -contains 'linux/arm/v7' -and
$ArgumentList -contains 'type=tar,dest=ubuntu-18.04-arm.tar'
}
Should -Invoke -CommandName Invoke-CBakeNativeCommand -ModuleName cbake -Exactly -Times 1 -ParameterFilter {
$FilePath -eq 'tar' -and
$ArgumentList[0] -eq 'cfJ' -and
$ArgumentList[1] -eq $PackageFile
}
}

It 'restores the caller location when a checked native command fails' {
$StartingLocation = (Get-Location).ProviderPath
Mock -ModuleName cbake Invoke-CBakeNativeCommand {
Expand All @@ -163,4 +223,60 @@ Describe 'New-CBakeSysroot' {
(Get-Location).ProviderPath | Should -Be $StartingLocation
}
}

Describe 'Linux ARMv7 toolchains' {
It 'defines an ARMv7 Linux entry point and ARMv7 compiler flags' {
$LinuxToolchain = Get-Content (Join-Path $script:RepoRoot 'cmake\linux.toolchain.cmake') -Raw
$LinuxArmToolchain = Join-Path $script:RepoRoot 'cmake\linux-arm.toolchain.cmake'

Test-Path $LinuxArmToolchain | Should -BeTrue
Get-Content $LinuxArmToolchain -Raw | Should -Match 'set\(CMAKE_SYSTEM_PROCESSOR armv7l\)'
$LinuxToolchain | Should -Match 'SYSROOT_ARCH STREQUAL "arm"'
$LinuxToolchain | Should -Match 'set\(CROSS_MACHINE_FLAGS "-march=armv7-a"\)'
}

It 'derives the ARMv7 target from the <SysrootName> GCC layout' -TestCases @(
@{
SysrootName = 'ubuntu-18.04-arm'
Target = 'arm-linux-gnueabihf'
},
@{
SysrootName = 'alpine-3.17-arm'
Target = 'armv7-alpine-linux-musleabihf'
}
) {
param($SysrootName, $Target)

$SysrootPath = Join-Path $TestDrive $SysrootName
$LLVMPath = Join-Path $TestDrive 'llvm'
$CMakeScriptPath = Join-Path $TestDrive 'verify-armv7.cmake'
New-Item -ItemType Directory -Force -Path (Join-Path $SysrootPath "usr\lib\gcc\$Target\12"), $LLVMPath | Out-Null

$CMakeScript = @'
set(SYSROOT_NAME "__SYSROOT_NAME__")
set(CMAKE_SYSROOT "__SYSROOT_PATH__")
set(LLVM_PREFIX "__LLVM_PATH__")
include("__TOOLCHAIN_PATH__")
if(NOT CMAKE_C_COMPILER_TARGET STREQUAL "__TARGET__")
message(FATAL_ERROR "Unexpected compiler target: ${CMAKE_C_COMPILER_TARGET}")
endif()
if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
message(FATAL_ERROR "Unexpected system processor: ${CMAKE_SYSTEM_PROCESSOR}")
endif()
string(FIND "${CMAKE_C_FLAGS}" "-march=armv7-a" ARMV7_FLAG_INDEX)
if(ARMV7_FLAG_INDEX EQUAL -1)
message(FATAL_ERROR "ARMv7 compiler flag is missing")
endif()
'@
$CMakeScript = $CMakeScript.Replace('__SYSROOT_NAME__', $SysrootName).
Replace('__SYSROOT_PATH__', $SysrootPath.Replace('\', '/')).
Replace('__LLVM_PATH__', $LLVMPath.Replace('\', '/')).
Replace('__TOOLCHAIN_PATH__', (Join-Path $script:RepoRoot 'cmake\linux.toolchain.cmake').Replace('\', '/')).
Replace('__TARGET__', $Target)
Set-Content -Path $CMakeScriptPath -Value $CMakeScript -NoNewline

& cmake -P $CMakeScriptPath | Out-Null
$LASTEXITCODE | Should -Be 0
}
}
}
Loading