diff --git a/src/Runner.jl b/src/Runner.jl index 5701a407f..e1cf62a34 100644 --- a/src/Runner.jl +++ b/src/Runner.jl @@ -33,7 +33,7 @@ exeext(p::Union{Linux,FreeBSD,MacOS}) = "" exeext(p::Platform) = error("Unknown exeext for platform $(p)") """ - generate_compiler_wrappers(p::Platform, bin_path::AbstractString) + generate_compiler_wrappers!(p::Platform, bin_path::AbstractString) We generate a set of compiler wrapper scripts within our build environment to force all build systems to honor the necessary sets of compiler flags to build for our systems. @@ -61,6 +61,32 @@ function generate_compiler_wrappers!(platform::Platform; bin_path::AbstractStrin host_target = aatriplet(host_platform) rust_target = aatriplet(rust_platform) + + # If the ABI-agnostic triplets of the target and the host platform are the + # same, then we have to be very careful: we can't have distinct wrappers, so + # we have to be sure that their ABIs are consistent, in particular that + # we're correctly writing the wrappers for the target platform. In + # particular, what we care about with regard to the wrappers is the C++ + # string ABI. We have the following situations: + # * they are equal: this is fine + # * they're different and the host has a prefernce for the C++ string ABI: + # we can't deal with this situation as the host wrappers will be always + # overwritten, then error out + # * in all other cases we don't do anything here but later below we'll let + # the host wrappers to be overwritten by the wrappers for the target + if target == host_target + target_cxxabi = compiler_abi(platform).cxxstring_abi + host_cxxabi = compiler_abi(host_platform).cxxstring_abi + if target_cxxabi !== host_cxxabi + if host_cxxabi !== nothing + # This is a very unlikely situation as ideally the host + # shouldn't have particular preferences for the ABI, thus in + # practice we shouldn't never reach this. + error("Incompatible C++ string ABIs between the host and target platforms") + end + end + end + # If we should use ccache, prepend this to every compiler invocation ccache = use_ccache ? "ccache" : "" @@ -73,7 +99,7 @@ function generate_compiler_wrappers!(platform::Platform; bin_path::AbstractStrin unsafe_flags = String[]) write(io, """ #!/bin/bash - # This compiler wrapper script brought into existence by `generate_compiler_wrappers()` + # This compiler wrapper script brought into existence by `generate_compiler_wrappers!()` if [ "x\${SUPER_VERBOSE}" = "x" ]; then vrun() { "\$@"; } @@ -308,8 +334,11 @@ function generate_compiler_wrappers!(platform::Platform; bin_path::AbstractStrin chmod(joinpath(bin_path, fname), 0o775) end - ## Generate compiler wrappers for both our target and our host - for p in unique((platform, host_platform)) + ## Generate compiler wrappers for both our host and our target. In + ## particular, we write the wrapper for the target after those for the host, + ## to override host-specific ABI in case this is incompatible with that of + ## the target + for p in unique((host_platform, platform)) t = aatriplet(p) # Generate `:c` compilers diff --git a/test/basic.jl b/test/basic.jl index 7aa09ffe5..3ec892470 100644 --- a/test/basic.jl +++ b/test/basic.jl @@ -1,6 +1,6 @@ ## Basic tests for simple utilities within BB using BinaryBuilder, Test, Pkg -using BinaryBuilder: preferred_runner, resolve_jlls, CompilerShard, preferred_libgfortran_version, preferred_cxxstring_abi, gcc_version, available_gcc_builds, getversion +using BinaryBuilder: preferred_runner, resolve_jlls, CompilerShard, preferred_libgfortran_version, preferred_cxxstring_abi, gcc_version, available_gcc_builds, getversion, generate_compiler_wrappers! @testset "File Collection" begin temp_prefix() do prefix @@ -358,4 +358,54 @@ end cabi = CompilerABI(cabi; libstdcxx_version=v"3.4.23") @test gcc_version(cabi, available_gcc_builds) == [v"7.1.0"] end + + @testset "Compiler wrappers" begin + platform = Linux(:x86_64, libc=:musl) + mktempdir() do bin_path + generate_compiler_wrappers!(platform; bin_path = bin_path) + # Make sure the C++ string ABI is not set + @test !occursin("-D_GLIBCXX_USE_CXX11_ABI", read(joinpath(bin_path, "gcc"), String)) + # Make sure gfortran doesn't uses ccache when BinaryBuilder.use_ccache is true + BinaryBuilder.use_ccache && @test !occursin("ccache", read(joinpath(bin_path, "gfortran"), String)) + end + platform = Linux(:x86_64, libc=:musl, compiler_abi=CompilerABI(cxxstring_abi=:cxx03)) + mktempdir() do bin_path + generate_compiler_wrappers!(platform; bin_path = bin_path) + gcc = read(joinpath(bin_path, "gcc"), String) + # Make sure the C++ string ABI is set as expected + @test occursin("-D_GLIBCXX_USE_CXX11_ABI=0", gcc) + # Make sure the unsafe flags check is there + @test occursin("You used one or more of the unsafe flags", gcc) + end + platform = Linux(:x86_64, libc=:musl, compiler_abi=CompilerABI(cxxstring_abi=:cxx11)) + mktempdir() do bin_path + generate_compiler_wrappers!(platform; bin_path = bin_path, allow_unsafe_flags = true) + gcc = read(joinpath(bin_path, "gcc"), String) + # Make sure the C++ string ABI is set as expected + @test occursin("-D_GLIBCXX_USE_CXX11_ABI=1", gcc) + # Make sure the unsafe flags check is not there in this case + @test !occursin("You used one or more of the unsafe flags", gcc) + end + platform = FreeBSD(:x86_64) + mktempdir() do bin_path + generate_compiler_wrappers!(platform; bin_path = bin_path, compilers = [:c, :rust, :go]) + clang = read(joinpath(bin_path, "clang"), String) + # Check link flags + @test occursin("-L/opt/$(triplet(platform))/$(triplet(platform))/lib", clang) + @test occursin("fuse-ld=$(triplet(platform))", clang) + # Other compilers + @test occursin("GOOS=\"freebsd\"", read(joinpath(bin_path, "go"), String)) + @test occursin("--target=x86_64-unknown-freebsd", read(joinpath(bin_path, "rustc"), String)) + end + platform = Linux(:x86_64, libc=:musl, compiler_abi=CompilerABI(cxxstring_abi=:cxx03)) + host_platform = Linux(:x86_64, libc=:musl, compiler_abi=CompilerABI(cxxstring_abi=:cxx11)) + mktempdir() do bin_path + @test_throws ErrorException generate_compiler_wrappers!(platform; bin_path = bin_path, host_platform = host_platform) + end + platform = Linux(:x86_64, libc=:musl) + host_platform = Linux(:x86_64, libc=:musl, compiler_abi=CompilerABI(cxxstring_abi=:cxx03)) + mktempdir() do bin_path + @test_throws ErrorException generate_compiler_wrappers!(platform; bin_path = bin_path, host_platform = host_platform) + end + end end