Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## Unreleased
* Added option `lib` to JuliaCall. Setting this will skip the discovery subprocess.
* Bug fixes.

## 0.9.34 (2026-05-18)
Expand Down
1 change: 1 addition & 0 deletions docs/src/juliacall.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ be configured in two ways:
| `-X juliacall-heap-size-hint=<N>` | `PYTHON_JULIACALL_HEAP_SIZE_HINT=<N>` | Hint for initial heap size in bytes. |
| `-X juliacall-exe=<file>` | `PYTHON_JULIACALL_EXE=<file>` | Path to Julia binary to use (overrides JuliaPkg). |
| `-X juliacall-project=<dir>` | `PYTHON_JULIACALL_PROJECT=<dir>` | Path to the Julia project to use (overrides JuliaPkg). |
| `-X juliacall-lib=<file>` | `PYTHON_JULIACALL_LIB=<file>` | Path to libjulia. Set to skip the relatively slow discovery process. |
| `-X juliacall-trace-compile=<stderr\|name>` | `PYTHON_JULIACALL_TRACE_COMPILE=<stderr\|name>` | Print precompile statements. |
| `-X juliacall-trace-compile-timing` | `PYTHON_JULIACALL_TRACE_COMPILE_TIMING=<yes\|no>` | Include timings with precompile statements. |

Expand Down
44 changes: 25 additions & 19 deletions pysrc/juliacall/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,39 +179,45 @@ def args_from_config(config):
CONFIG['opt_handle_signals'] = choice('handle_signals', ['yes', 'no'])[0]
CONFIG['opt_startup_file'] = choice('startup_file', ['yes', 'no'])[0]
CONFIG['opt_heap_size_hint'] = option('heap_size_hint')[0]
CONFIG['project'] = path_option('project', check_exists=True)[0]
CONFIG['exepath'] = executable_option('exe')[0]
CONFIG['project'] = project = path_option('project', check_exists=True)[0]
CONFIG['libpath'] = libpath = path_option('lib', check_exists=True)[0]
CONFIG['exepath'] = exepath = executable_option('exe')[0]

# Stop if we already initialised
if CONFIG['inited']:
return

have_exepath = CONFIG['exepath'] is not None
have_project = CONFIG['project'] is not None
if have_exepath and have_project:
if (exepath is None) and (bindir is not None):
# if bindir is set then set exepath={bindir}/julia
CONFIG['exepath'] = exepath = os.path.join(bindir, 'julia.exe' if os.name == 'nt' else 'julia')
if (exepath is not None) and (project is not None):
pass
elif (not have_exepath) and (not have_project):
elif (exepath is None) and (project is None):
# we don't import this at the top level because it is not required when
# juliacall is loaded by PythonCall and won't be available, or if both
# `exepath` and `project` are set by the user.
import juliapkg

# Find the Julia executable and project
CONFIG['exepath'] = juliapkg.executable()
CONFIG['project'] = juliapkg.project()
CONFIG['exepath'] = exepath = juliapkg.executable()
CONFIG['project'] = project = juliapkg.project()
else:
raise Exception("Both PYTHON_JULIACALL_PROJECT and PYTHON_JULIACALL_EXE must be set together, not only one of them.")

exepath = CONFIG['exepath']
project = CONFIG['project']

# Find the Julia library
cmd = [exepath, '--project='+project, '--startup-file=no', '-O0', '--compile=min',
'-e', 'import Libdl; print(abspath(Libdl.dlpath("libjulia")), "\\0", Sys.BINDIR)']
libpath, default_bindir = subprocess.run(cmd, check=True, capture_output=True, encoding='utf8').stdout.split('\0')
if (libpath is not None) and (exepath is None):
raise Exception("PYTHON_JULIACALL_EXE is required if PYTHON_JULIACALL_LIB is set.")

# Find the Julia library, if not specified.
if libpath is None:
cmd = [exepath, '--project='+project, '--startup-file=no', '-O0', '--compile=min',
'-e', 'import Libdl; print(abspath(Libdl.dlpath("libjulia")), "\\0", Sys.BINDIR)']
libpath, found_bindir = subprocess.run(cmd, check=True, capture_output=True, encoding='utf8').stdout.split('\0')
CONFIG['libpath'] = libpath
if bindir is None:
CONFIG['bindir'] = bindir = found_bindir
if bindir is None:
bindir = os.path.dirname(exepath)
assert os.path.exists(libpath)
assert os.path.exists(default_bindir)
CONFIG['libpath'] = libpath
assert os.path.exists(bindir)

# Add the Julia library directory to the PATH on Windows so Julia's system libraries can
# be found. They are normally found because they are in the same directory as julia.exe,
Expand Down Expand Up @@ -242,7 +248,7 @@ def args_from_config(config):
jl_init.argtypes = [c.c_char_p, c.c_char_p]
jl_init.restype = None
jl_init(
(default_bindir if bindir is None else bindir).encode('utf8'),
None if bindir is None else bindir.encode('utf8'),
None if sysimg is None else sysimg.encode('utf8'),
)

Expand Down
Loading