Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic library loader: search in -L directories before default ones #13069

Merged
merged 2 commits into from
Feb 14, 2023
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
5 changes: 5 additions & 0 deletions spec/compiler/loader/msvc_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ describe Crystal::Loader do
loader.search_paths.should eq [%q(C:\foo\bar), "baz"]
end

it "prepends directory paths before default search paths" do
loader = Crystal::Loader.parse(%w(/LIBPATH:foo /LIBPATH:bar), search_paths: %w(baz quux))
loader.search_paths.should eq %w(foo bar baz quux)
end

it "parses file paths" do
expect_raises(Crystal::Loader::LoadError, "cannot find foobar.lib") do
Crystal::Loader.parse(["foobar.lib"], search_paths: [] of String)
Expand Down
5 changes: 5 additions & 0 deletions spec/compiler/loader/unix_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ describe Crystal::Loader do
loader.search_paths.should eq ["/foo/bar/baz", "qux"]
end

it "prepends directory paths before default search paths" do
loader = Crystal::Loader.parse(%w(-Lfoo -Lbar), search_paths: %w(baz quux))
loader.search_paths.should eq %w(foo bar baz quux)
end

it "parses static" do
expect_raises(Crystal::Loader::LoadError, "static libraries are not supported by Crystal's runtime loader") do
Crystal::Loader.parse(["-static"], search_paths: [] of String)
Expand Down
9 changes: 7 additions & 2 deletions src/compiler/crystal/loader/msvc.cr
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ class Crystal::Loader
libnames = [] of String
file_paths = [] of String

# NOTE: `/LIBPATH` overrides the default paths, not the other way round
# NOTE: `/LIBPATH`s are prepended before the default paths:
# (https://docs.microsoft.com/en-us/cpp/build/reference/libpath-additional-libpath)
#
# > ... The linker will first search in the path specified by this option,
# > and then search in the path specified in the LIB environment variable.
extra_search_paths = [] of String

args.each do |arg|
Expand All @@ -35,8 +38,10 @@ class Crystal::Loader
end
end

search_paths = extra_search_paths + search_paths

begin
self.new(extra_search_paths + search_paths, libnames, file_paths)
self.new(search_paths, libnames, file_paths)
rescue exc : LoadError
exc.args = args
exc.search_paths = search_paths
Expand Down
18 changes: 17 additions & 1 deletion src/compiler/crystal/loader/unix.cr
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,24 @@ class Crystal::Loader
libnames = [] of String
file_paths = [] of String

# `man ld(1)` on Linux:
#
# > -L searchdir
# > ... The directories are searched in the order in which they are
# specified on the command line. Directories specified on the command line
# are searched before the default directories.
#
# `man ld(1)` on macOS:
#
# > -Ldir
# > ... Directories specified with -L are searched in the order they appear
# > on the command line and before the default search path...
extra_search_paths = [] of String

# OptionParser removes items from the args array, so we dup it here in order to produce a meaningful error message.
OptionParser.parse(args.dup) do |parser|
parser.on("-L DIRECTORY", "--library-path DIRECTORY", "Add DIRECTORY to library search path") do |directory|
search_paths << directory
extra_search_paths << directory
end
parser.on("-l LIBNAME", "--library LIBNAME", "Search for library LIBNAME") do |libname|
libnames << libname
Expand All @@ -56,6 +70,8 @@ class Crystal::Loader
end
end

search_paths = extra_search_paths + search_paths

begin
self.new(search_paths, libnames, file_paths)
rescue exc : LoadError
Expand Down