diff --git a/.github/julia/build_tarballs.jl b/.github/julia/build_tarballs.jl new file mode 100644 index 00000000..259649e1 --- /dev/null +++ b/.github/julia/build_tarballs.jl @@ -0,0 +1,115 @@ +using BinaryBuilder, Pkg + +haskey(ENV, "UNO_RELEASE") || error("The environment variable UNO_RELEASE is not defined.") +haskey(ENV, "UNO_COMMIT") || error("The environment variable UNO_COMMIT is not defined.") + +name = "Uno" +version = VersionNumber(ENV["UNO_RELEASE"]) + +# Collection of sources required to complete build +sources = [ + GitSource("https://github.com/cvanaret/Uno.git", ENV["UNO_COMMIT"]) +] + +# Bash recipe for building across all platforms +script = raw""" +# Export dependencies +mkdir ${prefix}/deps +cd ${libdir} +for file in $(ls .); do + if [[ -f $file ]]; then + if [[ -z $(ls -la $file | grep 'artifacts') ]]; then + cp -P ${file} ${prefix}/deps/${file} + else + cp -L ${file} ${prefix}/deps/${file} + fi + fi +done +cd ${prefix} +cp -rL share/licenses deps/licenses +chmod -R u=rwx deps +tar -czvf deps.tar.gz deps +rm -r deps + +# Compile Uno +cd $WORKSPACE/srcdir/Uno +mkdir -p build +cd build + +if [[ "${target}" == *apple* ]] || [[ "${target}" == *freebsd* ]]; then + OMP=omp +else + OMP=gomp +fi + +# FortranCInterface_VERIFY fails on macOS, but it's not actually needed for the current build +sed -i 's/FortranCInterface_VERIFY(CXX)/# FortranCInterface_VERIFY(CXX)/g' ../CMakeLists.txt + +cmake \ + -DCMAKE_INSTALL_PREFIX=${prefix} \ + -DCMAKE_PREFIX_PATH=${libdir} \ + -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TARGET_TOOLCHAIN} \ + -DCMAKE_BUILD_TYPE=Release \ + -DAMPLSOLVER=${libdir}/libasl.${dlext} \ + -DHSL=${libdir}/libhsl.${dlext} \ + -DMUMPS_INCLUDE_DIR=${includedir} \ + -DMETIS_INCLUDE_DIR=${includedir} \ + -DMUMPS_LIBRARY="${libdir}/libdmumps.${dlext}" \ + -DMUMPS_COMMON_LIBRARY="${libdir}/libmumps_common.${dlext}" \ + -DMUMPS_PORD_LIBRARY="${libdir}/libpord.${dlext}" \ + -DMUMPS_MPISEQ_LIBRARY="${libdir}/libmpiseq.${dlext}" \ + -DBLAS_LIBRARIES="${libdir}/libopenblas.${dlext}" \ + -DLAPACK_LIBRARIES="${libdir}/libopenblas.${dlext}" \ + .. + +make -j${nproc} + +# Uno does not support `make install`. Manually copy for now. +install -v -m 755 "uno_ampl${exeext}" -t "${bindir}" + +# Currently, Uno does not provide a shared library. This may be useful in the future once it has a C API. +# We just check that we can generate it, but we don't include it in the tarballs. +${CXX} -shared $(flagon -Wl,--whole-archive) libuno.a $(flagon -Wl,--no-whole-archive) -o libuno.${dlext} -L${libdir} -l${OMP} -lopenblas -ldmumps -lmetis -lhsl +cp libuno.a ${prefix}/lib/libuno.a +cp libuno.${dlext} "${libdir}/libuno.${dlext} +""" + +# These are the platforms we will build for by default, unless further +# platforms are passed in on the command line +platforms = supported_platforms() +platforms = expand_gfortran_versions(platforms) + +# The products that we will ensure are always built +products = [ + ExecutableProduct("uno_ampl", :amplexe), + LibraryProduct("libuno", :libuno), + FileProduct("lib/libuno.a", :libuno_a), +] + +# Dependencies that must be installed before this package can be built +dependencies = [ + Dependency(PackageSpec(name="HSL_jll", uuid="017b0a0e-03f4-516a-9b91-836bbd1904dd")), + Dependency(PackageSpec(name="METIS_jll", uuid="d00139f3-1899-568f-a2f0-47f597d42d70")), + Dependency(PackageSpec(name="ASL_jll", uuid="ae81ac8f-d209-56e5-92de-9978fef736f9"), compat="0.1.3"), + # Most recent version compiled with OpenBLAS and not LBT + Dependency(PackageSpec(name="MUMPS_seq_jll", uuid="d7ed1dd3-d0ae-5e8e-bfb4-87a502085b8d"), compat="=5.4.1"), + Dependency(PackageSpec(name="OpenBLAS32_jll", uuid="656ef2d0-ae68-5445-9ca0-591084a874a2")), + # For OpenMP we use libomp from `LLVMOpenMP_jll` where we use LLVM as compiler (BSD systems), + # and libgomp from `CompilerSupportLibraries_jll` everywhere else. + Dependency(PackageSpec(name="CompilerSupportLibraries_jll", uuid="e66e0078-7015-5450-92f7-15fbd957f2ae"); platforms=filter(!Sys.isbsd, platforms)), + Dependency(PackageSpec(name="LLVMOpenMP_jll", uuid="1d63c593-3942-5779-bab2-d838dc0a180e"); platforms=filter(Sys.isbsd, platforms)), + HostBuildDependency(PackageSpec(name="CMake_jll", uuid="3f4e10e2-61f2-5801-8945-23b9d642d0e6")), +] + +build_tarballs( + ARGS, + name, + version, + sources, + script, + platforms, + products, + dependencies; + julia_compat = "1.6", + preferred_gcc_version = v"10.2.0", +) diff --git a/.github/julia/generate_binaries.jl b/.github/julia/generate_binaries.jl new file mode 100644 index 00000000..1ae86b1e --- /dev/null +++ b/.github/julia/generate_binaries.jl @@ -0,0 +1,92 @@ +# Version +haskey(ENV, "UNO_RELEASE") || error("The environment variable UNO_RELEASE is not defined.") +version = VersionNumber(ENV["UNO_RELEASE"]) +version2 = ENV["UNO_RELEASE"] +package = "Uno" + +platforms = [ + ("aarch64-apple-darwin-libgfortran5" , "lib", "dylib"), +# ("aarch64-linux-gnu-libgfortran3" , "lib", "so" ), +# ("aarch64-linux-gnu-libgfortran4" , "lib", "so" ), +# ("aarch64-linux-gnu-libgfortran5" , "lib", "so" ), +# ("aarch64-linux-musl-libgfortran3" , "lib", "so" ), +# ("aarch64-linux-musl-libgfortran4" , "lib", "so" ), +# ("aarch64-linux-musl-libgfortran5" , "lib", "so" ), +# ("powerpc64le-linux-gnu-libgfortran3" , "lib", "so" ), +# ("powerpc64le-linux-gnu-libgfortran4" , "lib", "so" ), +# ("powerpc64le-linux-gnu-libgfortran5" , "lib", "so" ), +# ("x86_64-apple-darwin-libgfortran3" , "lib", "dylib"), +# ("x86_64-apple-darwin-libgfortran4" , "lib", "dylib"), + ("x86_64-apple-darwin-libgfortran5" , "lib", "dylib"), +# ("x86_64-linux-gnu-libgfortran3" , "lib", "so" ), +# ("x86_64-linux-gnu-libgfortran4" , "lib", "so" ), + ("x86_64-linux-gnu-libgfortran5" , "lib", "so" ), +# ("x86_64-linux-musl-libgfortran3" , "lib", "so" ), +# ("x86_64-linux-musl-libgfortran4" , "lib", "so" ), +# ("x86_64-linux-musl-libgfortran5" , "lib", "so" ), +# ("x86_64-unknown-freebsd-libgfortran3", "lib", "so" ), +# ("x86_64-unknown-freebsd-libgfortran4", "lib", "so" ), +# ("x86_64-unknown-freebsd-libgfortran5", "lib", "so" ), +# ("x86_64-w64-mingw32-libgfortran3" , "bin", "dll" ), +# ("x86_64-w64-mingw32-libgfortran4" , "bin", "dll" ), + ("x86_64-w64-mingw32-libgfortran5" , "bin", "dll" ), +] + + +for (platform, libdir, ext) in platforms + + tarball_name = "$package.v$version.$platform.tar.gz" + + if isfile("products/$(tarball_name)") + # Unzip the tarball generated by BinaryBuilder.jl + isdir("products/$platform") && rm("products/$platform", recursive=true) + mkdir("products/$platform") + run(`tar -xzf products/$(tarball_name) -C products/$platform`) + + if isfile("products/$platform/deps.tar.gz") + # Unzip the tarball of the dependencies + run(`tar -xzf products/$platform/deps.tar.gz -C products/$platform`) + + # Copy the license of each dependency + for folder in readdir("products/$platform/deps/licenses") + cp("products/$platform/deps/licenses/$folder", "products/$platform/share/licenses/$folder") + end + rm("products/$platform/deps/licenses", recursive=true) + + # Copy the shared library of each dependency + for file in readdir("products/$platform/deps") + cp("products/$platform/deps/$file", "products/$platform/$libdir/$file") + end + + # Remove the folder used to unzip the tarball of the dependencies + rm("products/$platform/deps", recursive=true) + rm("products/$platform/deps.tar.gz", recursive=true) + + # Create the archives *_binaries + isfile("$(package)_binaries.$version2.$platform.tar.gz") && rm("$(package)_binaries.$version2.$platform.tar.gz") + isfile("$(package)_binaries.$version2.$platform.zip") && rm("$(package)_binaries.$version2.$platform.zip") + cd("products/$platform") + + # Create a folder with the version number of the package + mkdir("$(package)_binaries.$version2") + for folder in ("share", "modules", "lib", "bin") + cp(folder, "$(package)_binaries.$version2/$folder") + end + + cd("$(package)_binaries.$version2") + if ext == "dll" + run(`zip -r --symlinks ../../../$(package)_binaries.$version2.$platform.zip share modules lib bin`) + else + run(`tar -czf ../../../$(package)_binaries.$version2.$platform.tar.gz share modules lib bin`) + end + cd("../../..") + + # Remove the folder used to unzip the tarball generated by BinaryBuilder.jl + rm("products/$platform", recursive=true) + else + @warn("The tarball deps.tar.gz is missing in $(tarball_name)!") + end + else + @warn("The tarball for the platform $platform was not generated!") + end +end diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..c0ceb88a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,93 @@ +name: Release +on: + push: + # Sequence of patterns matched against refs/tags + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v2023.11.15 +jobs: + build: + name: Uno -- Release ${{ github.ref_name }} + runs-on: ubuntu-latest + steps: + - name: Checkout Uno + uses: actions/checkout@v4 + - name: Install Julia + uses: julia-actions/setup-julia@v2 + with: + version: "1.7" + arch: x64 + - name: Set the environment variables BINARYBUILDER_AUTOMATIC_APPLE, UNO_RELEASE, UNO_COMMIT + shell: bash + run: | + echo "BINARYBUILDER_AUTOMATIC_APPLE=true" >> $GITHUB_ENV + echo "UNO_RELEASE=${{ github.ref_name }}" >> $GITHUB_ENV + echo "UNO_COMMIT=${{ github.sha }}" >> $GITHUB_ENV + - name: Cross-compilation of Uno -- x86_64-linux-gnu-libgfortran5 + run: | + julia --color=yes -e 'using Pkg; Pkg.add("BinaryBuilder")' + julia --color=yes .github/julia/build_tarballs.jl x86_64-linux-gnu-libgfortran5 --verbose + rm -r ~/.julia + - name: Cross-compilation of Uno -- x86_64-w64-mingw32-libgfortran5 + run: | + julia --color=yes -e 'using Pkg; Pkg.add("BinaryBuilder")' + julia --color=yes .github/julia/build_tarballs.jl x86_64-w64-mingw32-libgfortran5 --verbose + rm -r ~/.julia + - name: Cross-compilation of Uno -- x86_64-apple-darwin-libgfortran5 + run: | + julia --color=yes -e 'using Pkg; Pkg.add("BinaryBuilder")' + julia --color=yes .github/julia/build_tarballs.jl x86_64-apple-darwin-libgfortran5 --verbose + rm -r ~/.julia + - name: Cross-compilation of Uno -- aarch64-apple-darwin-libgfortran5 + run: | + julia --color=yes -e 'using Pkg; Pkg.add("BinaryBuilder")' + julia --color=yes .github/julia/build_tarballs.jl aarch64-apple-darwin-libgfortran5 --verbose + rm -r ~/.julia + - name: Generate the binaries + run: julia --color=yes .github/julia/generate_binaries.jl + - name: Create a new release + uses: actions/create-release@v1 + id: create_release + with: + draft: false + prerelease: false + release_name: ${{ github.ref_name }} + tag_name: ${{ github.ref_name }} + body: + env: + GITHUB_TOKEN: ${{ github.token }} + - name: upload Linux artifact + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./Uno_binaries.${{ github.ref_name }}.x86_64-linux-gnu-libgfortran5.tar.gz + asset_name: Uno.${{ github.ref_name }}.linux.tar.gz + asset_content_type: application/gzip + - name: upload Mac (Intel) artifact + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./Uno_binaries.${{ github.ref_name }}.x86_64-apple-darwin-libgfortran5.tar.gz + asset_name: Uno.${{ github.ref_name }}.mac-intel.tar.gz + asset_content_type: application/gzip + - name: upload Mac (ARM) artifact + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./Uno_binaries.${{ github.ref_name }}.aarch64-apple-darwin-libgfortran5.tar.gz + asset_name: Uno.${{ github.ref_name }}.mac-arm.tar.gz + asset_content_type: application/gzip + - name: upload Windows artifact + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./Uno_binaries.${{ github.ref_name }}.x86_64-w64-mingw32-libgfortran5.zip + asset_name: Uno.${{ github.ref_name }}.windows.zip + asset_content_type: application/zip