Skip to content

Fix findlib and findheader on windows #2442

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

Merged
merged 2 commits into from
Mar 15, 2025
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
76 changes: 23 additions & 53 deletions src/base/os.lua
Original file line number Diff line number Diff line change
Expand Up @@ -63,44 +63,31 @@
end

local function get_library_search_path()
local path
if os.istarget("windows") then
path = os.getenv("PATH") or ""
return (os.getenv("PATH") or ""):explode(";")
elseif os.istarget("haiku") then
path = os.getenv("LIBRARY_PATH") or ""
return (os.getenv("LIBRARY_PATH") or ""):explode(":")
else
local paths
if os.istarget("darwin") then
path = os.getenv("DYLD_LIBRARY_PATH") or ""
paths = (os.getenv("DYLD_LIBRARY_PATH") or ""):explode(":")
else
path = os.getenv("LD_LIBRARY_PATH") or ""
paths = (os.getenv("LD_LIBRARY_PATH") or ""):explode(":")

for _, prefix in ipairs({"", "/opt"}) do
local conf_file = prefix .. "/etc/ld.so.conf"
if os.isfile(conf_file) then
for _, v in ipairs(parse_ld_so_conf(conf_file)) do
if (#path > 0) then
path = path .. ":" .. v
else
path = v
end
end
paths = table.join(paths, parse_ld_so_conf(conf_file))
end
end
end

path = path or ""
local archpath = "/lib:/usr/lib:/usr/local/lib"
local archpaths = {"/lib", "/usr/lib", "/usr/local/lib"}
if os.is64bit() and not (os.istarget("darwin")) then
archpath = "/lib64:/usr/lib64/:usr/local/lib64" .. ":" .. archpath
end
if (#path > 0) then
path = path .. ":" .. archpath
else
path = archpath
archpaths = table.join({"/lib64", "/usr/lib64/", "usr/local/lib64"}, archpaths)
end
return table.join(paths, archpaths)
end

return path
end


Expand All @@ -123,7 +110,7 @@
-- The full path to the library if found; `nil` otherwise.
---
function os.findlib(libname, libdirs)
local path = get_library_search_path()
local paths = get_library_search_path()
local formats

-- assemble a search path, depending on the platform
Expand All @@ -141,25 +128,17 @@
table.insert(formats, "%s")
end

local userpath = ""
local userpaths = {}

if type(libdirs) == "string" then
userpath = libdirs
userpaths = {libdirs}
elseif type(libdirs) == "table" then
userpath = table.implode(libdirs, "", "", ":")
userpaths = libdirs
end

if (#userpath > 0) then
if (#path > 0) then
path = userpath .. ":" .. path
else
path = userpath
end
end

paths = table.join(userpaths, paths)
for _, fmt in ipairs(formats) do
local name = string.format(fmt, libname)
local result = os.pathsearch(name, path)
local result = os.pathsearch(name, table.unpack(paths))
if result then return result end
end
end
Expand All @@ -168,30 +147,21 @@
-- headerpath: a partial header file path
-- headerdirs: additional header search paths

local path = get_library_search_path()
local paths = get_library_search_path()

-- replace all /lib by /include
path = path .. ':'
path = path:gsub ('/lib[0-9]*([:/])', '/include%1')
path = path:sub (1, #path - 1)
-- replace all /lib and /bin by /include
paths = table.translate(paths, function (path) return path:gsub('[/\\]lib[0-9]*', '/include'):gsub('[/\\]bin', '/include') end)

local userpath = ""
local userpaths = {}

if type(headerdirs) == "string" then
userpath = headerdirs
userpaths = { headerdirs }
elseif type(headerdirs) == "table" then
userpath = table.implode(headerdirs, "", "", ":")
end

if (#userpath > 0) then
if (#path > 0) then
path = userpath .. ":" .. path
else
path = userpath
end
userpaths = headerdirs
end
paths = table.join(userpaths, paths)

local result = os.pathsearch (headerpath, path)
local result = os.pathsearch (headerpath, table.unpack(paths))
return result
end

Expand Down
59 changes: 59 additions & 0 deletions tests/base/test_os.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,29 @@
os.chdir(cwd)
end

local function create_mock_os_getenv(map)
return function (key) return map[key] end
end

local function get_LD_PATH_variable_name()
if os.istarget("windows") then
return 'PATH'
elseif os.istarget("haiku") then
return 'LIBRARY_PATH'
elseif os.istarget("darwin") then
return 'DYLD_LIBRARY_PATH'
else
return 'LD_LIBRARY_PATH'
end
end

local function get_surrounded_env_path(dir)
if os.istarget("windows") then
return "c:\\anyPath;" .. path.getabsolute(dir) .. ";c:\\otherpath"
else
return "/any_path:" .. path.getabsolute(dir) .. ":/other_path"
end
end

--
-- os.findlib() tests
Expand Down Expand Up @@ -50,6 +73,20 @@
test.isfalse(os.findlib("NoSuchLibraryAsThisOneHere"))
end

function suite.findlib_provided()
test.isequal(path.getabsolute("folder/subfolder/lib"),
os.findlib("test", path.getabsolute("folder/subfolder/lib")))
end

function suite.findlib_frompath()
local os_getenv = os.getenv
os.getenv = create_mock_os_getenv({ [get_LD_PATH_variable_name()] = get_surrounded_env_path("folder/subfolder/lib") })

test.isequal(path.getabsolute("folder/subfolder/lib"), os.findlib("test"))

os.getenv = os_getenv
end

function suite.findheader_stdheaders()
if not os.istarget("windows") and not os.istarget("macosx") then
test.istrue(os.findheader("stdlib.h"))
Expand All @@ -60,6 +97,28 @@
test.isfalse(os.findheader("Knights/who/say/Ni.hpp"))
end

function suite.findheader_provided()
test.isequal(path.getabsolute("folder/subfolder/include"),
os.findheader("test.h", path.getabsolute("folder/subfolder/include")))
end

function suite.findheader_frompath_lib()
local os_getenv = os.getenv
os.getenv = create_mock_os_getenv({ [get_LD_PATH_variable_name()] = get_surrounded_env_path("folder/subfolder/lib") })

test.isequal(path.getabsolute("folder/subfolder/include"), os.findheader("test.h"))

os.getenv = os_getenv
end

function suite.findheader_frompath_bin()
local os_getenv = os.getenv
os.getenv = create_mock_os_getenv({ [get_LD_PATH_variable_name()] = get_surrounded_env_path("folder/subfolder/bin") })

test.isequal(path.getabsolute("folder/subfolder/include"), os.findheader("test.h"))

os.getenv = os_getenv
end

--
-- os.isfile() tests
Expand Down
1 change: 1 addition & 0 deletions tests/folder/subfolder/include/test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Only used for presence in tests
1 change: 1 addition & 0 deletions tests/folder/subfolder/lib/test.dll
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Only used for presence in tests
1 change: 1 addition & 0 deletions tests/folder/subfolder/lib/test.dylib
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Only used for presence in tests
1 change: 1 addition & 0 deletions tests/folder/subfolder/lib/test.so
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Only used for presence in tests
Loading