diff --git a/README.md b/README.md index 6cdec081..332585d3 100644 --- a/README.md +++ b/README.md @@ -37,10 +37,35 @@ Free Gurobi licenses are available for [academics and students](https://www.guro ## Installation -First, obtain a license of Gurobi and install Gurobi solver. +To use Gurobi, you need a license. To install the license, first obtain a key +from [gurobi.com](https://www.gurobi.com), then run: +```julia +import Pkg +Pkg.add("Gurobi_jll") +import Gurobi_jll +# Replace the contents xxxxx with your actual key +key = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +run(`$(Gurobi_jll.grbgetkey()) $key`) +``` -Then, set the `GUROBI_HOME` environment variable as appropriate and run -`Pkg.add("Gurobi")`: +### Default installation + +Install Gurobi as follows: +```julia +import Pkg +Pkg.add("Gurobi") +``` + +In addition to installing the Gurobi.jl package, this will also download and +install the Gurobi binaries from [Gurobi_jll.jl](https://github.com/jump-dev/Gurobi_jll.jl). +You do not need to install Gurobi separately. + +### Manual installation + +To opt-out of using the Gurobi_jll binaries, set the `GUROBI_HOME` environment +variable to point to your local installation and set the +`GUROBI_JL_USE_GUROBI_JLL` environment variable to `"false"`, then run +`Pkg.add` and `Pkg.build`: ```julia # On Windows, this might be @@ -48,20 +73,15 @@ ENV["GUROBI_HOME"] = "C:\\Program Files\\gurobi1100\\win64" # ... or perhaps ... ENV["GUROBI_HOME"] = "C:\\gurobi1100\\win64" # On Mac, this might be -ENV["GUROBI_HOME"] = "/Library/gurobi1100/mac64" +ENV["GUROBI_HOME"] = "/Library/gurobi1100/macos_universal2" + +# Opt-out of using Gurobi_jll +ENV["GUROBI_JL_USE_GUROBI_JLL"] = "false" import Pkg Pkg.add("Gurobi") +Pkg.build("Gurobi") ``` -**Note: your path may differ. Check which folder you installed Gurobi in, and -update the path accordingly.** - -By default, building Gurobi.jl will fail if the Gurobi library is not found. -This may not be desirable in certain cases, for example when part of a package's -test suite uses Gurobi as an optional test dependency, but Gurobi cannot be -installed on a CI server running the test suite. To support this use case, the -`GUROBI_JL_SKIP_LIB_CHECK` environment variable may be set (to any value) to -make Gurobi.jl installable (but not usable). ## Use with JuMP diff --git a/deps/build.jl b/deps/build.jl index 4c9171f1..32f0d519 100644 --- a/deps/build.jl +++ b/deps/build.jl @@ -13,13 +13,17 @@ if isfile(DEPS_FILE) end if Int === Int32 - error("Gurobi.jl does not support 32-bit Julia. Please install a 64-bit Julia.") + error( + "Gurobi.jl does not support 32-bit Julia. Please install a 64-bit Julia.", + ) end function write_depsfile(path) open(DEPS_FILE, "w") do io println(io, "const libgurobi = \"$(escape_string(path))\"") + return end + return end const ALIASES = [ @@ -30,35 +34,33 @@ const ALIASES = [ "gurobi90" ] -paths_to_try = copy(ALIASES) - -for a in ALIASES - if haskey(ENV, "GUROBI_HOME") - if Sys.isunix() - push!(paths_to_try, joinpath(ENV["GUROBI_HOME"], "lib", string("lib", a, ".so"))) - end - if Sys.iswindows() - push!(paths_to_try, joinpath(ENV["GUROBI_HOME"], "bin", string(a, ".", Libdl.dlext))) +function _try_local_install() + paths_to_try = copy(ALIASES) + for a in ALIASES + root = get(ENV, "GUROBI_HOME", nothing) + if root !== nothing + if Sys.isunix() + push!(paths_to_try, joinpath(root, "lib", "lib$a.so"),) + end + if Sys.iswindows() + push!(paths_to_try, joinpath(root, "bin", "$a.$(Libdl.dlext)")) + end + if Sys.isapple() + push!(paths_to_try, joinpath(root, "lib", "lib$a.dylib")) + end end - if Sys.isapple() - push!(paths_to_try, joinpath(ENV["GUROBI_HOME"], "lib", string("lib", a, ".dylib"))) + if Sys.isapple() # gurobi uses .so on OS X for some reason + push!(paths_to_try, string("lib$a.so")) + push!(paths_to_try, string("lib$a.dylib")) end end - # gurobi uses .so on OS X for some reason - if Sys.isapple() - push!(paths_to_try, string("lib$a.so")) - push!(paths_to_try, string("lib$a.dylib")) - end -end - -found = false -for l in paths_to_try - d = Libdl.dlopen_e(l) - if d != C_NULL - global found = true - write_depsfile(l) - break + for l in paths_to_try + if Libdl.dlopen_e(l) != C_NULL + write_depsfile(l) + return true + end end + return false end function _print_GUROBI_HOME_help() @@ -164,6 +166,13 @@ function diagnose_gurobi_install() _print_GUROBI_HOME_help() end end + return error( + """ + Unable to locate Gurobi installation. If the advice above did not help, + open an issue at https://github.com/jump-dev/Gurobi.jl and post the full + print-out of this diagnostic attempt. + """, + ) end if haskey(ENV, "GUROBI_JL_SKIP_LIB_CHECK") @@ -172,19 +181,19 @@ if haskey(ENV, "GUROBI_JL_SKIP_LIB_CHECK") elseif get(ENV, "JULIA_REGISTRYCI_AUTOMERGE", "false") == "true" # We write a fake depsfile so Gurobi.jl is loadable but not usable. write_depsfile("__skipped_installation__") -elseif !found && (Sys.islinux() || Sys.isapple() || Sys.iswindows()) - if haskey(ENV, "WLSLICENSE") +elseif get(ENV, "GUROBI_JL_USE_GUROBI_JLL", "true") == "false" + # The user has asked to avoid Gurobi_jll + found = _try_local_install() + if !found + diagnose_gurobi_install() + end +else + # We're using the artifact + if haskey(ENV, "WLSLICENSE") # This is used by CI home = Sys.iswindows() ? ENV["USERPROFILE"] : ENV["HOME"] write(joinpath(home, "gurobi.lic"), ENV["WLSLICENSE"]) end open(DEPS_FILE, "w") do io println(io, "# No libgurobi constant; we're using the Artifact.") end -elseif !found - diagnose_gurobi_install() - error(""" - Unable to locate Gurobi installation. If the advice above did not help, - open an issue at https://github.com/jump-dev/Gurobi.jl and post the full - print-out of this diagnostic attempt. - """) end diff --git a/src/Gurobi.jl b/src/Gurobi.jl index 101b28d9..95909e9e 100644 --- a/src/Gurobi.jl +++ b/src/Gurobi.jl @@ -17,10 +17,10 @@ elseif Sys.islinux() || Sys.isapple() || Sys.iswindows() import Gurobi_jll const libgurobi = Gurobi_jll.libgurobi else - error(""" - Gurobi not properly installed. Please run Pkg.build(\"Gurobi\"). For - more information go to https://github.com/jump-dev/Gurobi.jl - """) + error( + "Unsupported platform: Use a manual installation by setting " * + "`GUROBI_JL_USE_GUROBI_JLL` to false. See the README for details.", + ) end const _GUROBI_VERSION = if libgurobi == "__skipped_installation__"