diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 401e807..b30038f 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -62,6 +62,8 @@ jobs: uses: julia-actions/julia-runtest@v1 with: depwarn: error + env: + NORMALIZ_JL_CXX_COVERAGE: ${{ matrix.cxx-coverage == true && 'true' || 'false' }} - name: "Run doctests" if: ${{ matrix.julia-version == '1.10' }} run: | @@ -85,11 +87,12 @@ jobs: gcovr \ --root "$PWD" \ --filter deps/src/normaliz.cpp \ - --gcov-object-directory deps/src/build \ + --gcov-object-directory deps/build-* \ --exclude-throw-branches \ --xml-pretty \ --output coverage.xml \ - --print-summary + --print-summary \ + deps/build-* - name: "Upload coverage data to Codecov" continue-on-error: true uses: codecov/codecov-action@v6 diff --git a/.gitignore b/.gitignore index 2c2710b..62e3e1f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ Manifest.toml /deps/build.log +/deps/build-*/ /deps/Normaliz/ /deps/src/build/ /docs/build/ diff --git a/Project.toml b/Project.toml index e524814..e2bc52d 100644 --- a/Project.toml +++ b/Project.toml @@ -8,6 +8,7 @@ CxxWrap = "1f15a43c-97ca-5a2a-ae31-89f07a497df4" Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Nemo = "2edaba10-b0f1-5616-af89-8c11ac63239a" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce" normaliz_jll = "6690c6e9-4e12-53b8-b8fd-4bffaef8839f" [compat] @@ -17,6 +18,7 @@ CxxWrap = "0.17" Libdl = "1.10" Nemo = "0.50, 0.51, 0.52, 0.53, 0.54, 0.55" Pkg = "1.10" +SHA = "0.7" normaliz_jll = "300.1100.100" [extras] diff --git a/deps/build.jl b/deps/build.jl deleted file mode 100644 index 9f0af59..0000000 --- a/deps/build.jl +++ /dev/null @@ -1,78 +0,0 @@ -using CxxWrap -import CMake_jll -using Pkg.Artifacts - -using normaliz_jll - -# Parse some basic command-line arguments -const verbose = "--verbose" in ARGS -const cxx_coverage = - lowercase(get(ENV, "NORMALIZ_JL_CXX_COVERAGE", "false")) in - ("1", "true", "yes", "on") - -jlcxx_cmake_dir = joinpath(CxxWrap.prefix_path(), "lib", "cmake", "JlCxx") -julia_exec = joinpath(Sys.BINDIR, Base.julia_exename()) - -function jll_artifact_dir(the_jll::Module) - artifacts_toml = joinpath(dirname(dirname(Base.pathof(the_jll))), "StdlibArtifacts.toml") - - # If this file exists, it's a stdlib JLL and we must download the artifact ourselves - if isfile(artifacts_toml) - # the artifact name is always equal to the module name minus the "_jll" suffix - name = replace(string(nameof(the_jll)), "_jll" => "") - meta = artifact_meta(name, artifacts_toml) - hash = Base.SHA1(meta["git-tree-sha1"]) - if !artifact_exists(hash) - dl_info = first(meta["download"]) - download_artifact(hash, dl_info["url"], dl_info["sha256"]) - end - return artifact_path(hash) - end - - # Otherwise, we can just use the artifact directory given to us by GMP_jll - return the_jll.find_artifact_dir() -end - -cd(joinpath(@__DIR__, "src")) -builddir = "build" - -# delete any previous build, so we rebuild from scratch -rm(builddir; force=true, recursive=true) - -@static if Sys.isbsd() - using normaliz_jll.LLVMOpenMP_jll - libomp_path = normaliz_jll.LLVMOpenMP_jll.get_libomp_path() -else - using normaliz_jll.CompilerSupportLibraries_jll - libomp_path = normaliz_jll.CompilerSupportLibraries_jll.get_libgomp_path() -end - -CMake_jll.cmake() do exe - run(`$exe - -DJulia_EXECUTABLE=$julia_exec - -DJlCxx_DIR=$jlcxx_cmake_dir - -DCMAKE_BUILD_TYPE=$(cxx_coverage ? "Debug" : "Release") - -DNORMALIZ_JULIA_ENABLE_COVERAGE=$(cxx_coverage ? "ON" : "OFF") - -Dnormaliz_prefix=$(jll_artifact_dir(normaliz_jll)) - -Dgmp_prefix=$(jll_artifact_dir(normaliz_jll.GMP_jll)) - -Dmpfr_prefix=$(jll_artifact_dir(normaliz_jll.MPFR_jll)) - -Dnauty_prefix=$(jll_artifact_dir(normaliz_jll.nauty_jll)) - -Dflint_prefix=$(jll_artifact_dir(normaliz_jll.FLINT_jll)) - -Dlibnormaliz_path=$(normaliz_jll.get_libnormaliz_path()) - -Dlibgmp_path=$(normaliz_jll.GMP_jll.get_libgmp_path()) - -Dlibgmpxx_path=$(normaliz_jll.GMP_jll.get_libgmpxx_path()) - -Dlibmpfr_path=$(normaliz_jll.MPFR_jll.get_libmpfr_path()) - -Dlibnauty_path=$(normaliz_jll.nauty_jll.get_libnauty_path()) - -Dlibflint_path=$(normaliz_jll.FLINT_jll.get_libflint_path()) - -Dlibomp_path=$libomp_path - -B $(builddir) - -S . - `) - - run(`$exe - --build $(builddir) - --config $(cxx_coverage ? "Debug" : "Release") - -- - -j$(div(Sys.CPU_THREADS,2)) - `) -end diff --git a/src/Normaliz.jl b/src/Normaliz.jl index ecb776d..b21c119 100644 --- a/src/Normaliz.jl +++ b/src/Normaliz.jl @@ -1,14 +1,13 @@ module Normaliz -import Libdl -import normaliz_jll - using CxxWrap export Cone export computed_cone_properties, cone_property, is_computed, known_cone_properties -get_libnormaliz_julia_path() = joinpath(@__DIR__, "..", "deps", "src", "build", "lib", "libnormaliz_julia.$(Libdl.dlext)") +include("setup.jl") + +get_libnormaliz_julia_path() = Setup.locate_libnormaliz_julia() @wrapmodule(get_libnormaliz_julia_path, :define_module_normaliz) function __init__() diff --git a/src/setup.jl b/src/setup.jl new file mode 100644 index 0000000..3d06953 --- /dev/null +++ b/src/setup.jl @@ -0,0 +1,157 @@ +module Setup + +import CMake_jll +import CxxWrap +import Libdl +import Pkg +import Pkg.Artifacts +import SHA +import normaliz_jll + +function enabled(envvar::String) + return lowercase(get(ENV, envvar, "false")) in ("1", "true", "yes", "on") +end + +cxx_coverage_enabled() = enabled("NORMALIZ_JL_CXX_COVERAGE") + +function jll_artifact_dir(the_jll::Module) + artifacts_toml = + joinpath(dirname(dirname(Base.pathof(the_jll))), "StdlibArtifacts.toml") + + if isfile(artifacts_toml) + name = replace(string(nameof(the_jll)), "_jll" => "") + meta = Pkg.Artifacts.artifact_meta(name, artifacts_toml) + hash = Base.SHA1(meta["git-tree-sha1"]) + if !Pkg.Artifacts.artifact_exists(hash) + dl_info = first(meta["download"]) + Pkg.Artifacts.download_artifact(hash, dl_info["url"], dl_info["sha256"]) + end + return Pkg.Artifacts.artifact_path(hash) + end + + return the_jll.find_artifact_dir() +end + +function libomp_path() + @static if Sys.isbsd() + return normaliz_jll.LLVMOpenMP_jll.get_libomp_path() + else + return normaliz_jll.CompilerSupportLibraries_jll.get_libgomp_path() + end +end + +function source_files(srcdir::String) + files = String[] + for (root, dirs, filenames) in walkdir(srcdir) + filter!(dirs) do dir + return !(dir == "build" || startswith(dir, "build-")) + end + for filename in filenames + push!(files, relpath(joinpath(root, filename), srcdir)) + end + end + return sort!(files) +end + +function source_hash(srcdir::String) + buf = IOBuffer() + for file in source_files(srcdir) + write(buf, file) + write(buf, '\0') + write(buf, read(joinpath(srcdir, file))) + write(buf, '\0') + end + return bytes2hex(SHA.sha1(take!(buf))) +end + +function build_key(srcdir::String) + jlcxx_cmake_dir = joinpath(CxxWrap.prefix_path(), "lib", "cmake", "JlCxx") + julia_exec = joinpath(Sys.BINDIR, Base.julia_exename()) + coverage = cxx_coverage_enabled() + entries = [ + "source_hash=$(source_hash(srcdir))", + "julia_version=$(VERSION)", + "host_triplet=$(Base.BinaryPlatforms.host_triplet())", + "julia_exec=$(julia_exec)", + "jlcxx_cmake_dir=$(jlcxx_cmake_dir)", + "coverage=$(coverage)", + "normaliz_prefix=$(jll_artifact_dir(normaliz_jll))", + "gmp_prefix=$(jll_artifact_dir(normaliz_jll.GMP_jll))", + "mpfr_prefix=$(jll_artifact_dir(normaliz_jll.MPFR_jll))", + "nauty_prefix=$(jll_artifact_dir(normaliz_jll.nauty_jll))", + "flint_prefix=$(jll_artifact_dir(normaliz_jll.FLINT_jll))", + "libnormaliz_path=$(normaliz_jll.get_libnormaliz_path())", + "libgmp_path=$(normaliz_jll.GMP_jll.get_libgmp_path())", + "libgmpxx_path=$(normaliz_jll.GMP_jll.get_libgmpxx_path())", + "libmpfr_path=$(normaliz_jll.MPFR_jll.get_libmpfr_path())", + "libnauty_path=$(normaliz_jll.nauty_jll.get_libnauty_path())", + "libflint_path=$(normaliz_jll.FLINT_jll.get_libflint_path())", + "libomp_path=$(libomp_path())", + ] + return join(entries, "\n") * "\n" +end + +function cached_library(lib_path::String, key_path::String, key::String) + return isfile(lib_path) && isfile(key_path) && read(key_path, String) == key +end + +function build_libnormaliz_julia(builddir::String, srcdir::String, key::String) + @info "Compiling libnormaliz_julia" + + jlcxx_cmake_dir = joinpath(CxxWrap.prefix_path(), "lib", "cmake", "JlCxx") + julia_exec = joinpath(Sys.BINDIR, Base.julia_exename()) + coverage = cxx_coverage_enabled() + + rm(builddir; force=true, recursive=true) + + cmake = CMake_jll.cmake() + withenv("JULIA_LOAD_PATH" => nothing) do + run(`$cmake + -DJulia_EXECUTABLE=$julia_exec + -DJlCxx_DIR=$jlcxx_cmake_dir + -DCMAKE_BUILD_TYPE=$(coverage ? "Debug" : "Release") + -DNORMALIZ_JULIA_ENABLE_COVERAGE=$(coverage ? "ON" : "OFF") + -Dnormaliz_prefix=$(jll_artifact_dir(normaliz_jll)) + -Dgmp_prefix=$(jll_artifact_dir(normaliz_jll.GMP_jll)) + -Dmpfr_prefix=$(jll_artifact_dir(normaliz_jll.MPFR_jll)) + -Dnauty_prefix=$(jll_artifact_dir(normaliz_jll.nauty_jll)) + -Dflint_prefix=$(jll_artifact_dir(normaliz_jll.FLINT_jll)) + -Dlibnormaliz_path=$(normaliz_jll.get_libnormaliz_path()) + -Dlibgmp_path=$(normaliz_jll.GMP_jll.get_libgmp_path()) + -Dlibgmpxx_path=$(normaliz_jll.GMP_jll.get_libgmpxx_path()) + -Dlibmpfr_path=$(normaliz_jll.MPFR_jll.get_libmpfr_path()) + -Dlibnauty_path=$(normaliz_jll.nauty_jll.get_libnauty_path()) + -Dlibflint_path=$(normaliz_jll.FLINT_jll.get_libflint_path()) + -Dlibomp_path=$(libomp_path()) + -B $builddir + -S $srcdir + `) + + run(`$cmake + --build $builddir + --config $(coverage ? "Debug" : "Release") + -- + -j$(max(1, div(Sys.CPU_THREADS, 2))) + `) + end + + key_path = joinpath(builddir, "lib", "libnormaliz_julia.buildinfo") + write(key_path, key) +end + +function locate_libnormaliz_julia() + depsdir = abspath(joinpath(@__DIR__, "..", "deps")) + srcdir = joinpath(depsdir, "src") + builddir = joinpath(depsdir, "build-$VERSION") + lib_path = joinpath(builddir, "lib", "libnormaliz_julia.$(Libdl.dlext)") + key_path = joinpath(builddir, "lib", "libnormaliz_julia.buildinfo") + key = build_key(srcdir) + + cached_library(lib_path, key_path, key) && return lib_path + + build_libnormaliz_julia(builddir, srcdir, key) + + return lib_path +end + +end