Skip to content

Commit

Permalink
Move linking code to it's own file
Browse files Browse the repository at this point in the history
  • Loading branch information
vchuravy committed Oct 19, 2022
1 parent 83ef0ee commit d3f0340
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 104 deletions.
1 change: 1 addition & 0 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ include("threadcall.jl")
include("uuid.jl")
include("pkgid.jl")
include("toml_parser.jl")
include("linking.jl")
include("loading.jl")

# misc useful functions & macros
Expand Down
154 changes: 154 additions & 0 deletions base/linking.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
module Linking

# inlined LLD_jll
# These get calculated in __init__()
const PATH = Ref("")
const LIBPATH = Ref("")
const PATH_list = String[]
const LIBPATH_list = String[]
const lld_path = Ref{String}()
const lld_exe = Sys.iswindows() ? "lld.exe" : "lld"

if Sys.iswindows()
const LIBPATH_env = "PATH"
const LIBPATH_default = ""
const pathsep = ';'
elseif Sys.isapple()
const LIBPATH_env = "DYLD_FALLBACK_LIBRARY_PATH"
const LIBPATH_default = "~/lib:/usr/local/lib:/lib:/usr/lib"
const pathsep = ':'
else
const LIBPATH_env = "LD_LIBRARY_PATH"
const LIBPATH_default = ""
const pathsep = ':'
end

function adjust_ENV!(env::Dict, PATH::String, LIBPATH::String, adjust_PATH::Bool, adjust_LIBPATH::Bool)
if adjust_LIBPATH
LIBPATH_base = get(env, LIBPATH_env, expanduser(LIBPATH_default))
if !isempty(LIBPATH_base)
env[LIBPATH_env] = string(LIBPATH, pathsep, LIBPATH_base)
else
env[LIBPATH_env] = LIBPATH
end
end
if adjust_PATH && (LIBPATH_env != "PATH" || !adjust_LIBPATH)
if adjust_PATH
if !isempty(get(env, "PATH", ""))
env["PATH"] = string(PATH, pathsep, env["PATH"])
else
env["PATH"] = PATH
end
end
end
return env
end

function __init__()
# Prefer our own bundled lld, but if we don't have one, pick it up off of the PATH
# If this is an in-tree build, `lld` will live in `tools`. Otherwise, it'll be in `libexec`
for bundled_lld_path in (joinpath(Sys.BINDIR, Base.LIBEXECDIR, lld_exe),
joinpath(Sys.BINDIR, "..", "tools", lld_exe),
joinpath(Sys.BINDIR, lld_exe))
if isfile(bundled_lld_path)
lld_path[] = abspath(bundled_lld_path)
return
end
end
lld_path[] = something(Sys.which(lld_exe), lld_exe)
PATH[] = dirname(lld_path[])
if Sys.iswindows()
# On windows, the dynamic libraries (.dll) are in Sys.BINDIR ("usr\\bin")
append!(LIBPATH_list, [joinpath(Sys.BINDIR, Base.LIBDIR, "julia"), Sys.BINDIR])
else
append!(LIBPATH_list, [joinpath(Sys.BINDIR, Base.LIBDIR, "julia"), joinpath(Sys.BINDIR, Base.LIBDIR)])
end
LIBPATH[] = join(LIBPATH_list, pathsep)
return
end

function lld(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true)
env = adjust_ENV!(copy(ENV), PATH[], LIBPATH[], adjust_PATH, adjust_LIBPATH)
return Cmd(Cmd([lld_path[]]); env)
end

function ld()
default_args = ``
@static if Sys.iswindows()
flavor = "link"
elseif Sys.isapple()
flavor = "darwin"
arch = Sys.ARCH == :aarch64 ? :arm64 : Sys.ARCH
# TODO: gently handle failure in `xcrun`/`sw_vers` (command not found, garbage being
# returned, etc...). We probably also want to provide ways to override platform
# version and SDK, for when we build the release binaries.
sysroot = readchomp(`xcrun --sdk macosx --show-sdk-path`)
platform_version = readchomp(`sw_vers -productVersion`)
platform_sdk = readchomp(`xcrun --show-sdk-version`)
default_args = `-arch $arch -syslibroot $(sysroot) -lSystem -platform_version macos $(platform_version) $(platform_sdk)`
else
flavor = "gnu"
end

`$(lld()) -flavor $flavor $default_args`
end

const WHOLE_ARCHIVE = if Sys.isapple()
`-all_load`
elseif Sys.iswindows()
`/WHOLEARCHIVE`
else
`--whole-archive`
end

const NO_WHOLE_ARCHIVE = if Sys.isapple() || Sys.iswindows()
``
else
`--no-whole-archive`
end

const SHARED = if Sys.isapple()
`-dylib`
elseif Sys.iswindows()
`/DLL`
else
`-shared`
end

function libdir(path)
@static if Sys.iswindows()
`/LIBPATH:$(path)`
else
`-L$(path)`
end
end

function output(path)
@static if Sys.isapple()
`-o $(path)`
elseif Sys.iswindows()
`/OUT:$(path)`
else
`--output=$(path)`
end
end

function l(path)
@static if Sys.iswindows()
path
else
"-l$path"
end
end

is_debug() = ccall(:jl_is_debugbuild, Cint, ()) == 1

function link_image(path, out, internal_stderr::IO = stderr, internal_stdout::IO = stdout)
LIBDIR = libdir(joinpath(Sys.BINDIR, "..", "lib"))
libs = is_debug() ? ("julia-debug", "julia-internal-debug") : ("julia", "julia-internal")
LIBS = map(l, libs)

run(`$(ld()) $SHARED $(output(out)) $WHOLE_ARCHIVE $path $NO_WHOLE_ARCHIVE $LIBDIR $LIBS`,
Base.DevNull(), internal_stdout, internal_stderr)
end
end # module Linking
105 changes: 1 addition & 104 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1753,110 +1753,7 @@ end

const MAX_NUM_PRECOMPILE_FILES = Ref(10)

module Linking

const lld_path = Ref{String}()
const lld_exe = Sys.iswindows() ? "lld.exe" : "lld"

function __init__()
# Prefer our own bundled lld, but if we don't have one, pick it up off of the PATH
# If this is an in-tree build, `lld` will live in `tools`. Otherwise, it'll be in `libexec`
for bundled_lld_path in (joinpath(Sys.BINDIR, Base.LIBEXECDIR, lld_exe),
joinpath(Sys.BINDIR, "..", "tools", lld_exe),
joinpath(Sys.BINDIR, lld_exe))
if isfile(bundled_lld_path)
lld_path[] = abspath(bundled_lld_path)
return
end
end
lld_path[] = something(Sys.which(lld_exe), lld_exe)
return
end

function lld()
return Cmd([lld_path[]])
end

function ld()
default_args = ``
@static if Sys.iswindows()
flavor = "link"
elseif Sys.isapple()
flavor = "darwin"
arch = Sys.ARCH == :aarch64 ? :arm64 : Sys.ARCH
# TODO: gently handle failure in `xcrun`/`sw_vers` (command not found, garbage being
# returned, etc...). We probably also want to provide ways to override platform
# version and SDK, for when we build the release binaries.
sysroot = readchomp(`xcrun --sdk macosx --show-sdk-path`)
platform_version = readchomp(`sw_vers -productVersion`)
platform_sdk = readchomp(`xcrun --show-sdk-version`)
default_args = `-arch $arch -syslibroot $(sysroot) -lSystem -platform_version macos $(platform_version) $(platform_sdk)`
else
flavor = "gnu"
end

`$(lld()) -flavor $flavor $default_args`
end

const WHOLE_ARCHIVE = if Sys.isapple()
`-all_load`
elseif Sys.iswindows()
`/WHOLEARCHIVE`
else
`--whole-archive`
end

const NO_WHOLE_ARCHIVE = if Sys.isapple() || Sys.iswindows()
``
else
`--no-whole-archive`
end

const SHARED = if Sys.isapple()
`-dylib`
elseif Sys.iswindows()
`/DLL`
else
`-shared`
end

function libdir(path)
@static if Sys.iswindows()
`/LIBPATH:$(path)`
else
`-L$(path)`
end
end

function output(path)
@static if Sys.isapple()
`-o $(path)`
elseif Sys.iswindows()
`/OUT:$(path)`
else
`--output=$(path)`
end
end

function l(path)
@static if Sys.iswindows()
path
else
"-l$path"
end
end

is_debug() = ccall(:jl_is_debugbuild, Cint, ()) == 1

function link_jilib(path, out, internal_stderr::IO = stderr, internal_stdout::IO = stdout)
LIBDIR = libdir(joinpath(Sys.BINDIR, "..", "lib"))
libs = is_debug() ? ("julia-debug", "julia-internal-debug") : ("julia", "julia-internal")
LIBS = map(l, libs)

run(`$(ld()) $SHARED $(output(out)) $WHOLE_ARCHIVE $path $NO_WHOLE_ARCHIVE $LIBDIR $LIBS`,
Base.DevNull(), internal_stdout, internal_stderr)
end
end # module Linking

function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, internal_stdout::IO = stdout,
keep_loaded_modules::Bool = true)
Expand Down Expand Up @@ -1892,7 +1789,7 @@ function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, in
p = create_expr_cache(pkg, path, tmppath, tmppath_o, concrete_deps, internal_stderr, internal_stdout)
if success(p)
# Run linker over tmppath_o
Linking.link_jilib(tmppath_o, tmppath_so)
Linking.link_image(tmppath_o, tmppath_so)

# Read preferences hash back from .ji file (we can't precompute because
# we don't actually know what the list of compile-time preferences are without compiling)
Expand Down

0 comments on commit d3f0340

Please sign in to comment.