Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help with Alpine build/packaging #52279

Closed
strophy opened this issue Nov 23, 2023 · 17 comments
Closed

Help with Alpine build/packaging #52279

strophy opened this issue Nov 23, 2023 · 17 comments

Comments

@strophy
Copy link

strophy commented Nov 23, 2023

I'm trying to learn Alpine packaging and picked Julia after seeing the package request here. Julia 0.6.2 was last packaged for Alpine around 5 years ago, so I have this old APKBUILD file to work from: https://gitlab.alpinelinux.org/alpine/aports/-/tree/v3.18.4/unmaintained/julia

My approach is to start more or less from scratch, bump all versions and start trying to run the build, applying fixes from the old APKBUILD if they still seem relevant. Partial work is here: https://gitlab.alpinelinux.org/strophy/aports/-/blob/testing/julia/testing/julia/APKBUILD

I'm running into the following issue at the moment:

make[1]: Entering directory '/home/builder/package/src/julia-1.9.4/deps'
Warning: git information unavailable; versioning information limited
/home/builder/package/src/julia-1.9.4/deps/tools/jldownload /home/builder/package/src/julia-1.9.4/deps/srccache/CompilerSupportLibraries.v1.0.5+0.x86_64-linux-musl-libgfortran5.tar.gz https://github.com/JuliaBinaryWrappers/CompilerSupportLibraries_jll.jl/releases/download/CompilerSupportLibraries-v1.0.5+0/CompilerSupportLibraries.v1.0.5.x86_64-linux-musl-libgfortran5.tar.gz
/home/builder/package/src/julia-1.9.4/deps/tools/jldownload /home/builder/package/src/julia-1.9.4/deps/srccache/LibUV.v2.0.1+13.x86_64-linux-musl.tar.gz https://github.com/JuliaBinaryWrappers/LibUV_jll.jl/releases/download/LibUV-v2.0.1+13/LibUV.v2.0.1.x86_64-linux-musl.tar.gz
!!! Downloading of https://github.com/JuliaBinaryWrappers/CompilerSupportLibraries_jll.jl/releases/download/CompilerSupportLibraries-v1.0.5+0/CompilerSupportLibraries.v1.0.5.x86_64-linux-musl-libgfortran5.tar.gz to /home/builder/package/src/julia-1.9.4/deps/srccache/CompilerSupportLibraries.v1.0.5+0.x86_64-linux-musl-libgfortran5.tar.gz disabled !!!
Abuild should not fetch any files in the build phase.
Add all the needed files to the APKBUILD's source=.
make[1]: *** [/home/builder/package/src/julia-1.9.4/deps/csl.mk:106: /home/builder/package/src/julia-1.9.4/deps/srccache/CompilerSupportLibraries.v1.0.5+0.x86_64-linux-musl-libgfortran5.tar.gz] Error 1

Can someone help me understand the difference between gfortran and libgfortran which already exist as Alpine packages with v13.2.1, and libgfortran5, libgfortran4 and libgfortran3 available from https://github.com/JuliaBinaryWrappers/CompilerSupportLibraries_jll.jl/releases ? I don't see an option like USE_SYSTEM_GFORTRAN which exists for other packages where we should try and use the system dependency. Why does it still attempt this download, even if the package is already available as a local system dependency?

For libuv, why is the latest version at https://github.com/JuliaLang/libuv 1.44.2 but https://github.com/JuliaBinaryWrappers/LibUV_jll.jl offers 2.0.1?

The previous maintainer of this package seemed very determined not to allow jldownload to download anything during the build process, is this still a practical approach to packaging Julia?

@LilithHafner
Copy link
Member

Does this command

curl -fsSL https://install.julialang.org | sh

work on Alpine?

I would recommend adding juliaup (the Julia version multiplexer) as an Alpine package under the user-facing name "Julia". This is how it's done on Windows.

Historically, distribution-packaged Julia builds have been buggy and out of date, and issues due to unofficial binaries tend not to receive as much community support.

By giving users access to juliaup instead of Julia itself, users can manage their version of Julia themselves (including access to all historical versions since 1.0 and opt-in access to prereleases) without waiting for the distro-packaged version to be updated.

@strophy
Copy link
Author

strophy commented Nov 23, 2023

Thanks for the quick response @LilithHafner!

The command you provided fails immediately on Alpine with:

$ curl -fsSL https://install.julialang.org | sh

info: downloading installer
ps: unrecognized option: p
BusyBox v1.36.1 (2023-08-16 10:24:53 UTC) multi-call binary.

Usage: ps [-o COL1,COL2=HEADER] [-T]

Show list of processes

	-o COL1,COL2=HEADER	Select columns for display
	-T			Show threads
Error: To install Julia in non-interactive mode pass the -y parameter.

juliaup would need to be patched to work with the very minimal version of ps provided by BusyBox (related issue) but there will likely be more errors after this one. In general Alpine focuses on highly space efficient packaging, and I suspect juliaup would not be using local system dependencies but instead downloading or building its own versions, which goes against the Alpine philosophy. This is why I think it is worth picking up maintenance of the Alpine package again.

I was looking at how the julia:alpine3.18 Docker image is built here, could you maybe point me towards how the binary used there built for release? Would be interesting to see if any shared system deps are assumed for that build.

@PallHaraldsson
Copy link
Contributor

PallHaraldsson commented Nov 23, 2023

It seems to me that toybox, the BusyBox replacement, has ps -p so you could try that. Toybox is not just for Android, though Android is a major user of it.

I realize it's not the default (why not?), I'm not sure if you can switch or have both available. It's the default here:

https://www.glaucuslinux.org

I had not heard of that, you might first try it there, I'm not sure, it seems Alpine-based or at least similar.

@LilithHafner
Copy link
Member

I could definitely be overlooking something, but on my system juliaup's julia installs are about half the size of built from source installs:

x@x temp % git clone https://github.com/JuliaLang/julia ; cd julia ; git checkout 8e5136fa2979885081cd502d2210633dff1d2a1a; make -j 4; rm -rf .git; du -hd0
...
1.0G    .
x@x julia % du -hd0 /Users/x/.julia/juliaup/julia-1.9.4+0.aarch64.apple.darwin14
422M    /Users/x/.julia/juliaup/julia-1.9.4+0.aarch64.apple.darwin14

@davidanthoff suggested a fix for the issue you linked—I imagine that making the PR he recommended would be a good way to avoid the ps problem entirely.

@davidanthoff
Copy link
Contributor

So, I'm strongly in favor of packaging Juliaup as "julia", as @LilithHafner suggests. That is where we are generally going, i.e. the whole version multiplexing story of Juliaup is soon going to be considered a "default" part of Julia.

Maybe the right approach to do this is actually add build recipe for Juliaup to Apline? I.e. don't try the curl download thing, but instead just clone https://github.com/julialang/juliaup, and then build using Rust?

@strophy
Copy link
Author

strophy commented Nov 28, 2023

Thanks @LilithHafner and @davidanthoff I'm open to pursuing the juliaup approach to packaging Julia on Alpine. This approach is notably different to how other languages are installed on Alpine, so I have asked Alpine maintainers for their opinion on this here. I attempted to build juliaup under Alpine and failed, so I have opened an issue here. Looking forward to continuing to work on this.

@strophy
Copy link
Author

strophy commented Nov 28, 2023

@LilithHafner it looks like your size comparison above is using the default Makefile, but the APKBUILD I shared above uses a custom Makefile like this:

cat > Make.user <<-EOF
	prefix=/usr
	libexecdir=/usr/lib
	sysconfdir=/etc
	DESTDIR="$pkgdir"
	LIBBLAS=-lopenblas
	LIBBLASNAME=libopenblas
	LIBLAPACK=-lopenblas
	LIBLAPACKNAME=libopenblas
	LLVM_CONFIG=/usr/lib/llvm$_llvm_ver/bin/llvm-config
	LLVM_VER=$_llvm_ver
	NO_GIT=1
	USE_LLVM_SHLIB=1
	USE_SYSTEM_ARPACK=1
	USE_SYSTEM_BLAS=1
	USE_SYSTEM_CURL=1
	USE_SYSTEM_DSFMT=1
	USE_SYSTEM_FFTW=1
	USE_SYSTEM_GMP=1
	USE_SYSTEM_LAPACK=1
	USE_SYSTEM_LIBBLASTRAMPOLINE=1
	USE_SYSTEM_LIBGIT2=1
	USE_SYSTEM_LIBM=1
	USE_SYSTEM_LIBSSH2=1
	USE_SYSTEM_LIBUNWIND=1
	USE_SYSTEM_LIBUV=0
	USE_SYSTEM_LLVM=1
	USE_SYSTEM_MBEDTLS=1
	USE_SYSTEM_MPFR=1
	USE_SYSTEM_OPENLIBM=1
	USE_SYSTEM_OPENSPECFUN=1
	USE_SYSTEM_PATCHELF=1
	USE_SYSTEM_PCRE=1
	USE_SYSTEM_SUITESPARSE=1
	USE_SYSTEM_UTF8PROC=1
	VERBOSE=1
EOF

Do you think this could be affecting the size of the build, or why is the juliaup-installed version so much smaller? Can anyone point me to the steps used to create the pre-built binaries that juliaup installs? Could you maybe try and run your build again using external dependencies and see what size the resulting binary comes out as?

@vchuravy
Copy link
Sponsor Member

This approach is notably different to how other languages are installed on Alpine,

Looks like folks to the same with rust? https://pkgs.alpinelinux.org/package/edge/community/x86_64/rustup

USE_SYSTEM_LLVM=1

Note that we decidedly warn against this and do not provide support for this configuration.

@LilithHafner
Copy link
Member

With that makefile I got this

x@x julia % cat Make.user 
prefix=/usr
libexecdir=/usr/lib
sysconfdir=/etc
DESTDIR=""
LIBBLAS=-lopenblas
LIBBLASNAME=libopenblas
LIBLAPACK=-lopenblas
LIBLAPACKNAME=libopenblas
LLVM_CONFIG=/usr/lib/llvm/bin/llvm-config
LLVM_VER=
NO_GIT=1
USE_LLVM_SHLIB=1
USE_SYSTEM_ARPACK=1
USE_SYSTEM_BLAS=1
USE_SYSTEM_CURL=1
USE_SYSTEM_DSFMT=1
USE_SYSTEM_FFTW=1
USE_SYSTEM_GMP=1
USE_SYSTEM_LAPACK=1
USE_SYSTEM_LIBBLASTRAMPOLINE=1
USE_SYSTEM_LIBGIT2=1
USE_SYSTEM_LIBM=1
USE_SYSTEM_LIBSSH2=1
USE_SYSTEM_LIBUNWIND=1
USE_SYSTEM_LIBUV=0
USE_SYSTEM_LLVM=1
USE_SYSTEM_MBEDTLS=1
USE_SYSTEM_MPFR=1
USE_SYSTEM_OPENLIBM=1
USE_SYSTEM_OPENSPECFUN=1
USE_SYSTEM_PATCHELF=1
USE_SYSTEM_PCRE=1
USE_SYSTEM_SUITESPARSE=1
USE_SYSTEM_UTF8PROC=1
VERBOSE=1
x@x julia % make -j4
/Users/x/.julia/dev/julia/deps/tools/jldownload /Users/x/.julia/dev/julia/deps/srccache/llvm-julia-15.0.7-9.tar.gz https://api.github.com/repos/JuliaLang/llvm-project/tarball/julia-15.0.7-9
/Users/x/.julia/dev/julia/deps/tools/jldownload /Users/x/.julia/dev/julia/deps/srccache/lapack-3.9.0.tgz https://www.netlib.org/lapack/lapack-3.9.0.tgz
clang -mmacosx-version-min=11.0 -mcpu=native -integrated-as -Wall -O3   -fPIC -shared /Users/x/.julia/dev/julia/deps/gfortblas.c -o scratch/libgfortblas.dylib -pipe \
                                -Wl,-reexport_framework,Accelerate -Wl,-alias_list,/Users/x/.julia/dev/julia/deps/gfortblas.alias
/Users/x/.julia/dev/julia/deps/tools/jldownload /Users/x/.julia/dev/julia/deps/srccache/SuiteSparse-7.2.1.tar.gz https://github.com/DrTimothyAldenDavis/SuiteSparse/archive/v7.2.1.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Uplo a % Total    % Received % Xferd  Averaged    T o% Total    % Received % Xferd  Average Speed    TSpieme    Time     Tiemde    Cutrarle nt
   T i m       e      T i m e      TimSpent    Left  Speed
  0     0    0     0                    Dload  Upload   Tota e 0l    Cur r e  nSt
    0           p  0         e nt    Left  Speed
   0             Dlo a        0 - -d:   -Up-l0:oad - -  T-o-t:a-l- : - -S p-e-n:t- - : - -L e f t    0Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0/Users/x/.julia/dev/julia/deps/gfortblas.c:46:7: error: conflicting types for 'sasum_'
float sasum_(int *N, float *SX, int *INCX) {
      ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/vecLib.framework/Headers/fortran_blas.h:33:8: note: previous declaration is here
double sasum_(int *n, float *sx, int *incx)
       ^
/Users/x/.julia/dev/julia/deps/gfortblas.c:49:7: error: conflicting types for 'scasum_'
float scasum_(int *N, void *SX, int *INCX) {
      ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/vecLib.framework/Headers/fortran_blas.h:39:8: note: previous declaration is here
double scasum_(int *n, void *cx, int *incx)
       ^
/Users/x/.julia/dev/julia/deps/gfortblas.c:52:7: error: conflicting types for 'scnrm2_'
float scnrm2_(int *N, void *X, int *INCX) {
      ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/vecLib.framework/Headers/fortran_blas.h:131:8: note: previous declaration is here
double scnrm2_(int *n, void *cx, int *incx)
       ^
/Users/x/.julia/dev/julia/deps/gfortblas.c:55:7: error: conflicting types for 'sdot_'
float sdot_(int *N, float *SX, int *INCX, float *SY, int *INCY) {
      ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/vecLib.framework/Headers/fortran_blas.h:85:8: note: previous declaration is here
double sdot_(int *n,
       ^
/Users/x/.julia/dev/julia/deps/gfortblas.c:58:7: error: conflicting types for 'sdsdot_'
float sdsdot_(int *N, float *SB, float *SX, int *INCX, float *SY, int *INCY) {
      ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/vecLib.framework/Headers/fortran_blas.h:95:8: note: previous declaration is here
double sdsdot_(int *n, float *sb,
       ^
/Users/x/.julia/dev/julia/deps/gfortblas.c:61:7: error: conflicting types for 'snrm2_'
float snrm2_(int *N, float *X, int *INCX) {
      ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/vecLib.framework/Headers/fortran_blas.h:125:8: note: previous declaration is here
double snrm2_(int *n, float *x, int *incx)
       ^
/Users/x/.julia/dev/julia/deps/gfortblas.c:70:15: error: conflicting types for 'cdotc_'
complex float cdotc_(int *N, void *CX, int *INCX, void *CY, int *INCY) {
              ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/vecLib.framework/Headers/fortran_blas.h:105:6: note: previous declaration is here
void cdotc_(void * ret_val, int *n,
     ^
/Users/x/.julia/dev/julia/deps/gfortblas.c:75:15: error: conflicting types for 'cdotu_'
complex float cdotu_(int *N, void *CX, int *INCX, void *CY, int *INCY) {
              ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/vecLib.framework/Headers/fortran_blas.h:115:6: note: previous declaration is here
void cdotu_(void * ret_val, int *n,
     ^
/Users/x/.julia/dev/julia/deps/gfortblas.c:80:16: error: conflicting types for 'zdotc_'
complex double zdotc_(int *N, void *CX, int *INCX, void *CY, int *INCY) {
               ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/vecLib.framework/Headers/fortran_blas.h:110:6: note: previous declaration is here
void zdotc_(void * ret_val, int *n,
     ^
/Users/x/.julia/dev/julia/deps/gfortblas.c:85:16: error: conflicting types for 'zdotu_'
complex double zdotu_(int *N, void *CX, int *INCX, void *CY, int *INCY) {
               ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/vecLib.framework/Headers/fortran_blas.h:120:6: note: previous declaration is here
void zdotu_(void * ret_val, int *n,
     ^
10 errors generated.
make[1]: *** [scratch/libgfortblas.dylib] Error 1
make[1]: *** Waiting for unfinished jobs....
100   429  100   429    0     0    578      0 --:--:-- --:--:-- --:--:--   583
100   423  100   423    0     0    490      0 --:--:-- --:--:-- --:--:--   494
100   425  100   425    0     0    202      0  0:00:02  0:00:02 --:--:--   203
100 9128k  100 9128k    0     0  4223k      0  0:00:02  0:00:02 --:--:-- 8991k
100  158M  100  158M    0     0  8177k      0  0:00:19  0:00:19 --:--:-- 7645k
100 62.3M  100 62.3M    0     0  2722k      0  0:00:23  0:00:23 --:--:-- 9921k
make: *** [julia-deps] Error 2

@LilithHafner
Copy link
Member

To add some explanation for the opposition to USE_SYSTEM_LLVM=1, we have pretty tight integration with LLVM which includes both

  • Pinning it to a specific version
  • Vendoring certain patches

If you upstream all the Julia-specific patches into LLVM and there is some way of specifying a specific LLVM version dependency, then I imagine this could work. Though that would be a lot of work and there may be other significant obstacles I'm not thinking of atm.

@strophy
Copy link
Author

strophy commented Nov 28, 2023

@vchuravy That is the rustup package, not rust. I believe @davidanthoff was suggesting to build and execute juliaup tool and then package the resulting Julia installation under the Alpine package name julia. Whatever the package ends up being named, let's try and get an installation working and tested using the juliaup method first.

@LilithHafner Thanks, I saw that a custom LLVM is necessary and tested (but didn't push) an APKBUILD that downloads and uses https://github.com/JuliaLang/llvm-project . I also saw the following note at https://docs.julialang.org/en/v1/devdocs/build/build/#LLVM

Using an unpatched or different version of LLVM will result in errors and/or poor performance. Though Julia can be built with newer LLVM versions, support for this should be regarded as experimental and not suitable for packaging.

Could you provide more detail on these caveats? It looks like this passage was written almost 6 years ago when LLVM 5 was the current version, has the situation changed since with e.g. LLVM 17? There is some interesting discussion around this where devs are discussing how package maintainers should handle these deps in the PR that added the text above over at #25912

@vchuravy
Copy link
Sponsor Member

under the Alpine package name

If you use juliaup or julia as a package name that doesn't matter. I would call it juliaup.

has the situation changed since with e.g. LLVM 17?

The situation is fundamentally unchanged. Julia versions and LLVM versions are tightly coupled, and while we have upstreamed many of our patches we also find ever more that we need to temporarily carry.

If someone encounters an issue we will ask where they obtained Julia from and ask them to reproduce the issue with an official build. This prevents duplicated work from having to debug the same issue multiple times.

Archlinux had to include a disclaimer https://wiki.archlinux.org/title/Julia because we kept running into this situation multiple times.

As a note a second dependency where this holds true is libuv.

@strophy
Copy link
Author

strophy commented Nov 28, 2023

Thanks, I'm now fully convinced packaging juliaup is the right way forwards here. I ran into a lot of trouble trying to build juliaup with Rust installed using apk add rust, and the solution was to apk add rustup and then use rustup to install Rust, so the irony is not lost on me, it certainly does seem like best practice to install this way. And packaging juliaup should be considerably easier 😄

My issue is now that juliaup doesn't seem able to install musl builds, I opened another issue here.

@strophy
Copy link
Author

strophy commented Nov 28, 2023

https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/56206

cargo test currently failing in CI due to juliaup incorrectly installing GNU binaries.

@StefanKarpinski
Copy link
Sponsor Member

If you use juliaup or julia as a package name that doesn't matter. I would call it juliaup.

Personally, I would prefer if distros all packaged juliaup under the name julia because that's what people know that they want "Hey, I want to use Julia, is there a julia package? Oh yeah, there is, cool, let me install it." If the juliaup package is called julia then they install that and have a working, current julia (hopefully). The fact that they can also manage Julia versions with the juliaup command is sort of a footnote from their perspective. This perspective is very much forward looking to a time when juliaup is the say to install and manage Julia, but that's where we're going, so that's how I would suggest doing this.

@davidanthoff
Copy link
Contributor

Very much agree with @StefanKarpinski! On Windows that is how things are already, "Julia" in the Windows Store is really Juliaup.

@vtjnash
Copy link
Sponsor Member

vtjnash commented Feb 10, 2024

This appears to be more of a discourse discussion than an issue currently

@vtjnash vtjnash closed this as completed Feb 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants