Skip to content

Commit c67ccbe

Browse files
authored
[Runner] Move target wrappers to /opt/bin/$(triplet(platform)) (#82)
* [Runner] Move target wrappers to `/opt/bin/$(triplet(platform))` This allows us to better discriminate between the wrappers for the host and those for the target, important when the two platforms are similar (e.g., they differ only by the C++ string ABI). * Generate CMake and Meson toolchain files
1 parent dd4e519 commit c67ccbe

File tree

10 files changed

+300
-83
lines changed

10 files changed

+300
-83
lines changed

src/BinaryBuilderBase.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ include("Products.jl")
3333
include("Platforms.jl")
3434

3535
include("Runner.jl")
36+
include("BuildToolchains.jl")
3637
include("Rootfs.jl")
3738
include("squashfs_utils.jl")
3839
include("UserNSRunner.jl")

src/BuildToolchains.jl

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
abstract type AbstractBuildToolchain{C} end
2+
3+
struct CMake{C} <: AbstractBuildToolchain{C} end
4+
struct Meson{C} <: AbstractBuildToolchain{C} end
5+
6+
c_compiler(::AbstractBuildToolchain{:clang}) = "clang"
7+
cxx_compiler(::AbstractBuildToolchain{:clang}) = "clang++"
8+
c_compiler(::AbstractBuildToolchain{:gcc}) = "gcc"
9+
cxx_compiler(::AbstractBuildToolchain{:gcc}) = "g++"
10+
fortran_compiler(::AbstractBuildToolchain) = "gfortran"
11+
12+
function cmake_arch(p::AbstractPlatform)
13+
if arch(p) == "powerpc64le"
14+
return "ppc64le"
15+
else
16+
return arch(p)
17+
end
18+
end
19+
20+
function cmake_os(p::AbstractPlatform)
21+
if Sys.islinux(p)
22+
return "Linux"
23+
elseif Sys.isfreebsd(p)
24+
return "FreeBSD"
25+
elseif Sys.isapple(p)
26+
return "Darwin"
27+
elseif Sys.iswindows(p)
28+
return "Windows"
29+
end
30+
end
31+
32+
function toolchain_file(bt::CMake, p::AbstractPlatform)
33+
target = triplet(p)
34+
aatarget = aatriplet(p)
35+
36+
if Sys.isapple(p)
37+
darwin_ver = something(os_version(p), v"14.5.0")
38+
maj_ver = darwin_ver.major
39+
min_ver = darwin_ver.minor
40+
return """
41+
# CMake toolchain file for $(c_compiler(bt)) running on $(target)
42+
set(CMAKE_SYSTEM_NAME $(cmake_os(p)))
43+
set(CMAKE_SYSTEM_PROCESSOR $(cmake_arch(p)))
44+
set(CMAKE_SYSTEM_VERSION $(maj_ver).$(min_ver))
45+
set(DARWIN_MAJOR_VERSION $(maj_ver))
46+
set(DARWIN_MINOR_VERSION $(min_ver))
47+
48+
# Enable rpath support
49+
set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
50+
51+
set(CMAKE_SYSROOT /opt/$(aatarget)/$(aatarget)/sys-root)
52+
set(CMAKE_SYSTEM_FRAMEWORK_PATH
53+
\${CMAKE_SYSROOT}/System/Library/Frameworks
54+
\${CMAKE_SYSROOT}/System/Library/PrivateFrameworks
55+
)
56+
set(CMAKE_INSTALL_PREFIX \$ENV{prefix})
57+
58+
set(CMAKE_C_COMPILER /opt/bin/$(target)/$(c_compiler(bt)))
59+
set(CMAKE_CXX_COMPILER /opt/bin/$(target)/$(cxx_compiler(bt)))
60+
set(CMAKE_Fortran_COMPILER /opt/bin/$(target)/$(fortran_compiler(bt)))
61+
62+
set(CMAKE_LINKER /opt/bin/$(target)/$(aatarget)-ld)
63+
set(CMAKE_OBJCOPY /opt/bin/$(target)/$(aatarget)-objcopy)
64+
65+
set(CMAKE_AR /opt/bin/$(target)/$(aatarget)-ar)
66+
set(CMAKE_NM /opt/bin/$(target)/$(aatarget)-nm)
67+
set(CMAKE_RANLIB /opt/bin/$(target)/$(aatarget)-ranlib)
68+
69+
if( \$ENV{CC} MATCHES ccache )
70+
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
71+
endif()
72+
"""
73+
else
74+
return """
75+
# CMake toolchain file for $(c_compiler(bt)) running on $(target)
76+
set(CMAKE_SYSTEM_NAME $(cmake_os(p)))
77+
set(CMAKE_SYSTEM_PROCESSOR $(cmake_arch(p)))
78+
79+
set(CMAKE_SYSROOT /opt/$(aatarget)/$(aatarget)/sys-root/)
80+
set(CMAKE_INSTALL_PREFIX \$ENV{prefix})
81+
82+
set(CMAKE_C_COMPILER /opt/bin/$(target)/$(c_compiler(bt)))
83+
set(CMAKE_CXX_COMPILER /opt/bin/$(target)/$(cxx_compiler(bt)))
84+
set(CMAKE_Fortran_COMPILER /opt/bin/$(target)/$(fortran_compiler(bt)))
85+
86+
set(CMAKE_LINKER /opt/bin/$(target)/$(aatarget)-ld)
87+
set(CMAKE_OBJCOPY /opt/bin/$(target)/$(aatarget)-objcopy)
88+
89+
set(CMAKE_AR /opt/bin/$(target)/$(aatarget)-ar)
90+
set(CMAKE_NM /opt/bin/$(target)/$(aatarget)-nm)
91+
set(CMAKE_RANLIB /opt/bin/$(target)/$(aatarget)-ranlib)
92+
93+
if( \$ENV{CC} MATCHES ccache )
94+
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
95+
endif()
96+
"""
97+
end
98+
end
99+
100+
function meson_c_link_args(p::AbstractPlatform)
101+
if arch(p) == "powerpc64le" && Sys.islinux(p)
102+
return "'-Wl,-rpath-link,/workspace/destdir/lib64'"
103+
else
104+
return ""
105+
end
106+
end
107+
meson_cxx_link_args(p::AbstractPlatform) = meson_c_link_args(p)
108+
meson_fortran_link_args(p::AbstractPlatform) = meson_c_link_args(p)
109+
110+
# We can run native programs only on
111+
# * i686-linux-gnu
112+
# * x86_64-linux-gnu
113+
# * x86_64-linux-musl
114+
function meson_is_foreign(p::AbstractPlatform)
115+
if Sys.islinux(p) && proc_family(p) == "intel" && (libc(p) == "glibc" || (libc(p) == "musl" && arch(p) == "x86_64"))
116+
# Better to explicitly return the string we expect rather than
117+
# relying on the representation of the boolean values (even though
118+
# the result is the same)
119+
return "false"
120+
else
121+
return "true"
122+
end
123+
end
124+
125+
# https://mesonbuild.com/Reference-tables.html#operating-system-names
126+
meson_system(p::AbstractPlatform) = lowercase(cmake_os(p))
127+
128+
# https://github.com/mesonbuild/meson/blob/6e39dcad2fbd8d1c739e262b0e7b7d901cf1ce08/mesonbuild/environment.py#L412-L440
129+
meson_cpu(p::AbstractPlatform) = cmake_arch(p)
130+
131+
# https://mesonbuild.com/Reference-tables.html#cpu-families
132+
function meson_cpu_family(p::AbstractPlatform)
133+
if arch(p) == "powerpc64le"
134+
return "ppc64"
135+
elseif arch(p) == "i686"
136+
return "x86"
137+
elseif arch(p) == "x86_64"
138+
return "x86_64"
139+
elseif arch(p) == "aarch64"
140+
return "aarch64"
141+
elseif startswith(arch(p), "arm")
142+
return "arm"
143+
end
144+
end
145+
146+
function toolchain_file(bt::Meson, p::AbstractPlatform)
147+
target = triplet(p)
148+
aatarget = aatriplet(p)
149+
150+
return """
151+
[binaries]
152+
c = '/opt/bin/$(target)/$(aatarget)-$(c_compiler(bt))'
153+
cpp = '/opt/bin/$(target)/$(aatarget)-$(c_compiler(bt))'
154+
fortran = '/opt/bin/$(target)/$(aatarget)-$(fortran_compiler(bt))'
155+
objc = '/opt/bin/$(target)/$(aatarget)-objc'
156+
ar = '/opt/bin/$(target)/$(aatarget)-ar'
157+
ld = '/opt/bin/$(target)/$(aatarget)-ld'
158+
nm = '/opt/bin/$(target)/$(aatarget)-nm'
159+
strip = '/opt/bin/$(target)/$(aatarget)-strip'
160+
pkgconfig = '/usr/bin/pkg-config'
161+
162+
[properties]
163+
c_args = []
164+
cpp_args = []
165+
fortran_args = []
166+
c_link_args = [$(meson_c_link_args(p))]
167+
cpp_link_args = [$(meson_cxx_link_args(p))]
168+
fortran_link_args = [$(meson_fortran_link_args(p))]
169+
needs_exe_wrapper = $(meson_is_foreign(p))
170+
171+
[build_machine]
172+
system = 'linux'
173+
cpu_family = 'x86_64'
174+
cpu = 'x86_64'
175+
endian = 'little'
176+
177+
[host_machine]
178+
system = '$(meson_system(p))'
179+
cpu_family = '$(meson_cpu_family(p))'
180+
cpu = '$(meson_cpu(p))'
181+
endian = 'little'
182+
183+
[paths]
184+
prefix = '/workspace/destdir'
185+
"""
186+
end
187+
188+
function generate_toolchain_files!(platform::AbstractPlatform;
189+
toolchains_path::AbstractString,
190+
host_platform::AbstractPlatform = default_host_platform,
191+
)
192+
193+
# Generate the files fot bot the host and the target platforms
194+
for p in unique((platform, host_platform))
195+
dir = joinpath(toolchains_path, triplet(p))
196+
mkpath(dir)
197+
198+
write(joinpath(dir, "$(aatriplet(p))_clang.cmake"), toolchain_file(CMake{:clang}(), p))
199+
write(joinpath(dir, "$(aatriplet(p))_gcc.cmake"), toolchain_file(CMake{:gcc}(), p))
200+
write(joinpath(dir, "$(aatriplet(p))_clang.meson"), toolchain_file(Meson{:clang}(), p))
201+
write(joinpath(dir, "$(aatriplet(p))_gcc.meson"), toolchain_file(Meson{:gcc}(), p))
202+
203+
# On FreeBSD and MacOS we actually want to default to clang, otherwise gcc
204+
if Sys.isbsd(p)
205+
symlink("$(aatriplet(p))_clang.cmake", joinpath(dir, "$(aatriplet(p)).cmake"))
206+
symlink("$(aatriplet(p))_clang.meson", joinpath(dir, "$(aatriplet(p)).meson"))
207+
else
208+
symlink("$(aatriplet(p))_gcc.cmake", joinpath(dir, "$(aatriplet(p)).cmake"))
209+
symlink("$(aatriplet(p))_gcc.meson", joinpath(dir, "$(aatriplet(p)).meson"))
210+
end
211+
end
212+
end

src/DockerRunner.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ function DockerRunner(workspace_root::String;
7474
extra_env=Dict{String, String}(),
7575
verbose::Bool = false,
7676
compiler_wrapper_path::String = mktempdir(),
77+
toolchains_path::String = mktempdir(),
7778
src_name::AbstractString = "",
7879
shards = nothing,
7980
kwargs...)
@@ -91,6 +92,10 @@ function DockerRunner(workspace_root::String;
9192
generate_compiler_wrappers!(platform; bin_path=compiler_wrapper_path, extract_kwargs(kwargs, (:compilers,:allow_unsafe_flags,:lock_microarchitecture))...)
9293
push!(workspaces, compiler_wrapper_path => "/opt/bin")
9394

95+
# Generate CMake and Meson files
96+
generate_toolchain_files!(platform; toolchains_path=toolchains_path)
97+
push!(workspaces, toolchains_path => "/opt/toolchains")
98+
9499
# the workspace_root is always a workspace, and we always mount it first
95100
insert!(workspaces, 1, workspace_root => "/workspace")
96101

src/Rootfs.jl

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct CompilerShard
1515
# Things like Platform("x86_64", "windows"; libgfortran_version=v"3")
1616
target::Union{Nothing,Platform}
1717

18-
# Usually `Platform("x86_64", "linux"; libc="musl")`
18+
# Usually `default_host_platform`
1919
host::AbstractPlatform
2020

2121
# :unpacked or :squashfs. Possibly more in the future.
@@ -332,9 +332,8 @@ function macos_sdk_already_installed()
332332
css = all_compiler_shards()
333333
macos_artifact_names = artifact_name.(filter(cs -> cs.target !== nothing && Sys.isapple(cs.target), css))
334334

335-
host_platform = Platform("x86_64", "linux"; libc="musl")
336335
artifacts_toml = joinpath(dirname(@__DIR__), "Artifacts.toml")
337-
macos_artifact_hashes = artifact_hash.(macos_artifact_names, artifacts_toml; platform=host_platform)
336+
macos_artifact_hashes = artifact_hash.(macos_artifact_names, artifacts_toml; platform=default_host_platform)
338337

339338
# Return `true` if _any_ of these artifacts exist on-disk:
340339
return any(artifact_exists.(macos_artifact_hashes))
@@ -497,9 +496,6 @@ function choose_shards(p::AbstractPlatform;
497496
preferred_llvm_version::VersionNumber = getversion(LLVM_builds[end]),
498497
)
499498

500-
# Our host platform is x86_64-linux-musl
501-
host_platform = Platform("x86_64", "linux"; libc="musl")
502-
503499
function find_shard(name, version, archive_type; target = nothing)
504500
# Ugly hack alert! Because GCC 11 has somehow broken C++, we pair GCC 9 with GCC 11 on MacOS
505501
if name == "GCCBootstrap" && version.major == 11 && target !== nothing && Sys.islinux(target)
@@ -531,7 +527,7 @@ function choose_shards(p::AbstractPlatform;
531527

532528
# Ugly hack alert! We disable this check because we don't even ship a GCC 11 build
533529
# for the host platform because it's prerelease and broken.
534-
#if !shard_exists("GCCBootstrap", getversion(GCC_build), archive_type; target=host_platform)
530+
#if !shard_exists("GCCBootstrap", getversion(GCC_build), archive_type; target=default_host_platform)
535531
# return false
536532
#end
537533
return true
@@ -566,19 +562,19 @@ function choose_shards(p::AbstractPlatform;
566562
find_shard("RustToolchain", Rust_build, archive_type; target=p),
567563
])
568564

569-
if !platforms_match(p, host_platform)
565+
if !platforms_match(p, default_host_platform)
570566
# In case we need to bootstrap stuff and we bootstrap it for the actual host platform
571-
push!(shards, find_shard("RustToolchain", Rust_build, archive_type; target=host_platform))
567+
push!(shards, find_shard("RustToolchain", Rust_build, archive_type; target=default_host_platform))
572568
end
573569
end
574570

575571
if :rust in compilers || :c in compilers
576572
# If we're not building for the host platform, then add host shard for host tools
577573
# This is necessary for both rust and c compilers
578-
if !platforms_match(p, host_platform)
574+
if !platforms_match(p, default_host_platform)
579575
append!(shards, [
580-
find_shard("PlatformSupport", ps_build, archive_type; target=host_platform),
581-
find_shard("GCCBootstrap", GCC_build, archive_type; target=host_platform),
576+
find_shard("PlatformSupport", ps_build, archive_type; target=default_host_platform),
577+
find_shard("GCCBootstrap", GCC_build, archive_type; target=default_host_platform),
582578
])
583579
end
584580
end
@@ -606,7 +602,7 @@ function choose_shards(p::AbstractPlatform;
606602
end
607603

608604
# XXX: we want AnyPlatform to look like `x86_64-linux-musl` in the build environment.
609-
choose_shards(::AnyPlatform; kwargs...) = choose_shards(Platform("x86_64", "linux"; libc="musl"); kwargs...)
605+
choose_shards(::AnyPlatform; kwargs...) = choose_shards(default_host_platform; kwargs...)
610606

611607
"""
612608
supported_platforms(;exclude::Union{Vector{<:Platform},Function}=x->false)
@@ -874,7 +870,7 @@ function download_all_artifacts(; verbose::Bool = false)
874870
artifacts_toml;
875871
include_lazy=true,
876872
verbose=verbose,
877-
platform=Platform("x86_64", "linux"; libc="musl"),
873+
platform=default_host_platform,
878874
)
879875
end
880876

0 commit comments

Comments
 (0)