From 822ee5f77d2d348a6a3a14e06adb6758da310cf5 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Thu, 18 Jun 2026 06:40:59 -0400 Subject: [PATCH 1/2] Fix-up / Add i686 support --- Artifacts.toml | 2 +- src/abi_export.jl | 5 +++-- src/julia-config.jl | 18 ++++++++++++++++++ src/linking.jl | 6 ++++++ test/cli.jl | 8 ++++---- test/programatic.jl | 12 ++++++------ test/runtests.jl | 2 ++ test/trimming.jl | 4 ++-- test/utils.jl | 1 + 9 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 test/utils.jl diff --git a/Artifacts.toml b/Artifacts.toml index 9874561..e29c356 100644 --- a/Artifacts.toml +++ b/Artifacts.toml @@ -10,7 +10,7 @@ lazy = true [[mingw-w64]] arch = "i686" -git-tree-sha1 = "76b9f278e7de1d7dfdfe3a786afbe9c1e29003ea" +git-tree-sha1 = "85a99abd904b7d85813340fa459899f61fe2e9cc" os = "windows" lazy = true diff --git a/src/abi_export.jl b/src/abi_export.jl index d99ead5..3c218c0 100644 --- a/src/abi_export.jl +++ b/src/abi_export.jl @@ -103,9 +103,10 @@ function emit_struct_info!(ctx::TypeEmitter, @nospecialize(dt::DataType); indent indented_println(" \"size\": ", Core.sizeof(dt), ",") indented_println(" \"alignment\": ", Base.datatype_alignment(dt), ",") indented_println(" \"fields\": [") - for i = 1:Base.datatype_nfields(dt) + nfields = Int(Base.datatype_nfields(dt)) + for i = 1:nfields emit_field_info!(ctx, dt, i; indent = indent + 4) - println(ctx.io, i == Base.datatype_nfields(dt) ? "" : ",") + println(ctx.io, i == nfields ? "" : ",") end indented_println(" ]") print(ctx.io, " " ^ indent, "}") diff --git a/src/julia-config.jl b/src/julia-config.jl index 3d47cf4..2cda94b 100755 --- a/src/julia-config.jl +++ b/src/julia-config.jl @@ -45,9 +45,20 @@ function includeDir() return abspath(Sys.BINDIR, Base.INCLUDEDIR, "julia") end +function march_flags() + if Sys.ARCH === :i686 + return "-m32 -march=pentium4" + end + return "" +end + function ldflags(; framework::Bool=false) framework && return "-F$(shell_escape(frameworkDir()))" fl = "-L$(shell_escape(libDir()))" + march = march_flags() + if !isempty(march) + fl = march * " " * fl + end if Sys.iswindows() fl = fl * " -Wl,--stack,8388608" elseif !Sys.isapple() @@ -89,6 +100,13 @@ end function cflags(; framework::Bool=false) flags = IOBuffer() print(flags, "-std=gnu11") + march = march_flags() + if !isempty(march) + print(flags, " ", march) + end + if Sys.ARCH === :i686 + print(flags, " -Wno-psabi") + end if framework include = shell_escape(frameworkDir()) print(flags, " -F", include) diff --git a/src/linking.jl b/src/linking.jl index 1bd1587..0c754df 100644 --- a/src/linking.jl +++ b/src/linking.jl @@ -134,6 +134,12 @@ function link_products(recipe::LinkRecipe) end # Link in the whole archive and user-provided objects, then undo WHOLE_ARCHIVE cmd2 = `$cmd2 -Wl,$(Base.Linking.WHOLE_ARCHIVE) $(image_recipe.img_path) $(image_recipe.extra_objects) -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` + if Sys.ARCH === :i686 + # On 32-bit x86, Julia's 64-bit atomics require libatomic + cmd2 = `$cmd2 -latomic` + # On 32-bit x86, float math (e.g. floorf) can become a libcall to libm + cmd2 = `$cmd2 -lm` + end # Platform-specific linker flags lib_name = basename(recipe.outname) if Sys.iswindows() diff --git a/test/cli.jl b/test/cli.jl index 7397006..fdfe7da 100644 --- a/test/cli.jl +++ b/test/cli.jl @@ -76,20 +76,20 @@ end CVector_Float32 = abi["types"][findfirst(type["name"] == "CVector{Float32}" for type in abi["types"])] @test length(CVector_Float32["fields"]) == 2 @test CVector_Float32["fields"][1]["offset"] == 0 - @test CVector_Float32["fields"][2]["offset"] == 8 + @test CVector_Float32["fields"][2]["offset"] == sizeof(UInt) @test abi["types"][CVector_Float32["fields"][1]["type_id"]]["name"] == "Int32" @test abi["types"][CVector_Float32["fields"][2]["type_id"]]["name"] == "Ptr{Float32}" - @test CVector_Float32["size"] == 16 + @test CVector_Float32["size"] == sizeof(UInt) * 2 # `CVectorPair{Float32}` should have been exported with the correct info @test any(Bool[type["name"] == "CVectorPair{Float32}" for type in abi["types"]]) CVectorPair_Float32 = abi["types"][findfirst(type["name"] == "CVectorPair{Float32}" for type in abi["types"])] @test length(CVectorPair_Float32["fields"]) == 2 @test CVectorPair_Float32["fields"][1]["offset"] == 0 - @test CVectorPair_Float32["fields"][2]["offset"] == 16 + @test CVectorPair_Float32["fields"][2]["offset"] == sizeof(UInt) * 2 @test abi["types"][CVectorPair_Float32["fields"][1]["type_id"]]["name"] == "CVector{Float32}" @test abi["types"][CVectorPair_Float32["fields"][2]["type_id"]]["name"] == "CVector{Float32}" - @test CVectorPair_Float32["size"] == 32 + @test CVectorPair_Float32["size"] == sizeof(UInt) * 4 # `CTree{Float64}` should have been exported with the correct info @test any(Bool[type["name"] == "CTree{Float64}" for type in abi["types"]]) diff --git a/test/programatic.jl b/test/programatic.jl index edc2f6c..de7acac 100644 --- a/test/programatic.jl +++ b/test/programatic.jl @@ -34,9 +34,9 @@ cc = something(Sys.which("cc"), Sys.which("clang")) cc === nothing && error("C compiler not found") if Sys.islinux() - run(`$cc -o $exe $csrc -ldl`) + run(`$cc $(cflags()) -o $exe $csrc -ldl`) else - run(`$cc -o $exe $csrc`) + run(`$cc $(cflags()) -o $exe $csrc`) end run(`$exe $libpath`) end @@ -87,9 +87,9 @@ cc = something(Sys.which("cc"), Sys.which("clang")) cc === nothing && error("C compiler not found") if Sys.islinux() - run(`$cc -o $exe $csrc -ldl`) + run(`$cc $(cflags()) -o $exe $csrc -ldl`) else - run(`$cc -o $exe $csrc`) + run(`$cc $(cflags()) -o $exe $csrc`) end run(`$exe $libpath`) end @@ -483,9 +483,9 @@ end exe = joinpath(bindir, Sys.iswindows() ? "ctest_jloptions.exe" : "ctest_jloptions") cc = JuliaC.get_compiler_cmd() if Sys.islinux() - run(`$cc -o $exe $csrc -ldl`) + run(`$cc $(cflags()) -o $exe $csrc -ldl`) else - run(`$cc -o $exe $csrc`) + run(`$cc $(cflags()) -o $exe $csrc`) end out = read(`$exe $libpath`, String) diff --git a/test/runtests.jl b/test/runtests.jl index 05ed726..987454e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,6 +9,8 @@ const TEST_SRC = joinpath(TEST_PROJ, "src", "test.jl") const TEST_LIB_PROJ = abspath(joinpath(@__DIR__, "lib_project")) const TEST_LIB_SRC = joinpath(TEST_LIB_PROJ, "src", "libtest.jl") +include("utils.jl") + include("programatic.jl") include("cli.jl") include("trimming.jl") diff --git a/test/trimming.jl b/test/trimming.jl index 5897b2e..c63ee36 100644 --- a/test/trimming.jl +++ b/test/trimming.jl @@ -99,9 +99,9 @@ end cc = JuliaC.get_compiler_cmd() if Sys.islinux() - run(`$cc -o $exe $csrc -ldl`) + run(`$cc $(cflags()) -o $exe $csrc -ldl`) else - run(`$cc -o $exe $csrc`) + run(`$cc $(cflags()) -o $exe $csrc`) end # Run the C application diff --git a/test/utils.jl b/test/utils.jl new file mode 100644 index 0000000..f5d4626 --- /dev/null +++ b/test/utils.jl @@ -0,0 +1 @@ +cflags() = Base.shell_split(JuliaC.JuliaConfig.march_flags()) From 72a5307e8b6e982e859303842f4e6e0033724581 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Thu, 18 Jun 2026 06:46:58 -0400 Subject: [PATCH 2/2] Add 32-bit CI coverage --- .github/workflows/ci.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f433e8..5ca4e26 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,12 +35,29 @@ jobs: - os: macos-latest arch: aarch64 version: 'nightly' + - os: ubuntu-latest + arch: x86 + version: '1' + - os: ubuntu-latest + arch: x86 + version: 'pre' + - os: ubuntu-latest + arch: x86 + version: 'nightly' + - os: windows-latest + arch: x86 + version: '1' steps: - uses: actions/checkout@v6 - uses: julia-actions/setup-julia@v3 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} + - name: Install 32-bit cross toolchain + if: ${{ runner.os == 'Linux' && matrix.arch == 'x86' }} + run: | + sudo apt-get update + sudo apt-get install -y gcc-multilib - uses: julia-actions/cache@v3 - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1