Skip to content
Open
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
72 changes: 69 additions & 3 deletions src/base/os.lua
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,22 @@
end
end

---
-- Attempt to locate and return the path to a header file.
--
-- Searches the same well-known system locations as os.findlib(), but replaces any /lib or /bin
-- components with /include, and also searches in additional headerdirs provided by the caller.
--
-- @param headerpath
-- A partial header file path.
-- @param headerdirs
-- Optional; a string or table of additional paths.
-- If an input is an absolute path, it will be searched directly.
-- If an input is a relative path, it will be treated as is, relative to the current working directory.
-- @return
-- The full path to the directory containing the headerpath if found; `nil` otherwise.
---
function os.findheader(headerpath, headerdirs)
-- headerpath: a partial header file path
-- headerdirs: additional header search paths

local paths = get_library_search_path()

-- replace all /lib and /bin by /include
Expand All @@ -165,6 +177,60 @@
return result
end

---
-- Attempt to locate and return the path to a header file under additional subdirectories.
--
-- Searches the same well-known system locations as os.findheader(), but appends additional
-- subdirectory paths provided by the caller to the system search paths before searching.
--
-- @param headerpath
-- A partial header file path.
-- @param additionalpaths
-- Required; a string or table of additional paths.
-- If an input is an absolute path, it will be searched directly.
-- If an input is a relative path, it will be appended to each system search path separately.
-- If an input is an empty string, the system search paths will be searched (path.join returns the original path).
-- @return
-- The full path to the directory containing the headerpath if found; `nil` otherwise.
---
function os.findsubdirheader(headerpath, additionalpaths)
if additionalpaths == nil then
error("os.findsubdirheader: additionalpaths is required", 2)
end

local paths = get_library_search_path()

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

local userpaths = {}

if type(additionalpaths) == "string" then
userpaths = { additionalpaths }
elseif type(additionalpaths) == "table" then
userpaths = additionalpaths
end

if #userpaths > 0 then
local basepaths = paths
local newpaths = {}
for _, userpath in ipairs(userpaths) do
if path.isabsolute(userpath) then
-- absolute path: search directly, same as os.findheader
table.insert(newpaths, userpath)
else
for _, p in ipairs(basepaths) do
table.insert(newpaths, path.join(p, userpath))
end
end
end
paths = newpaths
end

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

--
-- Retrieve the current target operating system ID string.
--
Expand Down
29 changes: 29 additions & 0 deletions tests/base/test_os.lua
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,35 @@
os.findheader("test.h", path.getabsolute("folder/subfolder/include")))
end

function suite.findsubdirheader_provided_relative()
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/testlib"), os.findsubdirheader("testlib2.h", "testlib"))

os.getenv = os_getenv
end

function suite.findsubdirheader_failure()
test.isfalse(os.findsubdirheader("Knights/who/say/Ni.hpp", "nonexistent"))
end

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

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

-- "testlib" finds testlib2.h; "" allows test.h to be found in the base include dir
test.isequal(path.getabsolute("folder/subfolder/include/testlib"), os.findsubdirheader("testlib2.h", {"testlib", ""}))
test.isequal(path.getabsolute("folder/subfolder/include"), os.findsubdirheader("test.h", {"testlib", ""}))

os.getenv = os_getenv
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") })
Expand Down
1 change: 1 addition & 0 deletions tests/folder/subfolder/include/testlib/testlib2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Only used for presence in tests
15 changes: 14 additions & 1 deletion website/docs/os/os.findheader.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,28 @@ p = os.findheader("headerfile" [, additionalpaths])

`headerfile` is a file name or a the end of a file path to locate.

`additionalpaths` is a string or a table of one or more additional search path.
`additionalpaths` is a string or a table of one or more additional search path. Absolute paths are searched directly; relative paths are treated as is, relative to the current working directory.

### Return Value ###

The path containing the header file, if found. Otherwise, nil.

### Example ###

``` lua
os.findheader("stdlib.h") -- e.g. /usr/include
os.findheader("freetype2/ft2build.h") -- e.g. /usr/include
os.findheader("ft2build.h", {"/usr/local/include/freetype2", "/usr/include/freetype2"}) -- e.g. /usr/include/freetype2
```

### Remarks ###
`os.findheader` mostly use the same paths as [[os.findlib]] but replace `/lib` by `/include`.

### Availability ###

Premake 5.0 or later.

### See Also ###

* [os.findsubdirheader](os.findsubdirheader.md)
* [os.findlib](os.findlib.md)
41 changes: 41 additions & 0 deletions website/docs/os/os.findsubdirheader.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Scan the well-known system locations looking for a header file, with support for subdirectory paths.

```lua
p = os.findsubdirheader("headerfile", additionalpaths)
```

### Parameters ###

`headerfile` is a file name or the end of a file path to locate.

`additionalpaths` is a required string or table of one or more subdirectory paths:

- **Relative paths** are joined with every default include search path (cross-join); only the resulting subdirectories are searched.
- **Absolute paths** are searched directly, acting the same behaviour of [[os.findheader]].
- **Empty string `""`** is treated as a path segment that resolves to the base include path itself, so it can be mixed with other entries (e.g. `{"freetype2", ""}` searches both `<base>/freetype2` and `<base>`).

### Return Value ###

The path containing the header file, if found. Otherwise, nil.

### Example ###

``` lua
os.findsubdirheader("ft2build.h", "freetype2") -- e.g. /usr/include/freetype2
os.findsubdirheader("gl.h", {"OpenGL", "GL"}) -- e.g. /usr/include/GL
os.findsubdirheader("ft2build.h", "/your/path/to/freetype2") -- e.g. /your/path/to/freetype2
```

### Remarks ###
Unlike [[os.findheader]], relative paths in `additionalpaths` are resolved against each default search path, allowing discovery of headers in named subdirectories without requiring an absolute path. **Only** the specified subdirectories are searched, unless `additionalpaths` contains an empty string.

`os.findsubdirheader` uses the same base paths as [[os.findheader]], which mostly uses the same paths as [[os.findlib]] but replace `/lib` by `/include`.

### Availability ###

Premake 5.0 or later.

### See Also ###

* [os.findheader](os.findheader.md)
* [os.findlib](os.findlib.md)
1 change: 1 addition & 0 deletions website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ module.exports = {
'os/os.execute',
'os/os.executef',
'os/os.findheader',
'os/os.findsubdirheader',
'os/os.findlib',
'os/os.get',
'os/os.getcwd',
Expand Down
Loading