Skip to content
Open
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
58 changes: 47 additions & 11 deletions xmake/rules/c++/modules/clang/support.lua
Original file line number Diff line number Diff line change
Expand Up @@ -243,25 +243,61 @@ function get_clang_scan_deps(target)
return clang_scan_deps or nil
end

function get_stdmodules(target)
function parse_link_files(filepath)
if not os.islink(filepath) then
return filepath
end
local target = os.readlink(filepath)
if path.is_absolute(target) then
return target
end
return path.join(path.directory(filepath), target)
end

function get_original_file(filepath)
while os.islink(filepath) do
filepath = parse_link_files(filepath)
end
return filepath
end
Comment on lines +246 to +262
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The new functions parse_link_files and get_original_file are only used within this file. It's good practice to declare them as local to limit their scope and avoid polluting the module's global namespace.

local function parse_link_files(filepath)
    if not os.islink(filepath) then
        return filepath
    end
    local target = os.readlink(filepath)
    if path.is_absolute(target) then
        return target
    end
    return path.join(path.directory(filepath), target)
end

local function get_original_file(filepath)
    while os.islink(filepath) do
        filepath = parse_link_files(filepath)
    end
    return filepath
end


function get_stdmodules(target)
local cpplib = get_cpplibrary_name(target)
if cpplib then
if cpplib == "c++" then
-- libc++ module is found by parsing libc++.modules.json
local modules_json_path = _get_std_module_manifest_path(target)
if modules_json_path then
local modules_json = json.decode(io.readfile(modules_json_path))
if modules_json and modules_json.modules and #modules_json.modules > 0 then
local std_module_directory = path.directory(modules_json.modules[1]["source-path"])
if not path.is_absolute(std_module_directory) then
std_module_directory = path.join(path.directory(modules_json_path), std_module_directory)
end
if os.isdir(std_module_directory) then
return {path.normalize(path.join(std_module_directory, "std.cppm")), path.normalize(path.join(std_module_directory, "std.compat.cppm"))}
end
if not modules_json_path then
wprint("libc++.modules.json not found! maybe try to add --sdk=<PATH/TO/LLVM> or install libc++")
return
end
local modules_json = json.decode(io.readfile(modules_json_path))
if not (modules_json and modules_json.modules and #modules_json.modules > 0) then
wprint("libc++.modules.json is invalid! path: %s", path.normalize(modules_json_path))
return
end
local std_module_directory = path.directory(modules_json.modules[1]["source-path"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The code does not check if modules_json.modules[1]["source-path"] exists before using it. If it's nil, path.directory(nil) will be called, which becomes path.directory("nil") and returns . This would lead to incorrect path resolution. It's safer to check for the existence of "source-path" and print a warning if it's missing.

            local source_path = modules_json.modules[1]["source-path"]
            if not source_path then
                wprint("source-path not found in libc++.modules.json: %s", path.normalize(modules_json_path))
                return
            end
            local std_module_directory = path.directory(source_path)

-- check absolute path first
if path.is_absolute(std_module_directory) then
if os.isdir(std_module_directory) then
return {path.normalize(path.join(std_module_directory, "std.cppm")), path.normalize(path.join(std_module_directory, "std.compat.cppm"))}
else
wprint("std module directory not found: %s which defined in %s", path.normalize(std_module_directory), path.normalize(modules_json_path))
return
end
end
-- otherwise try to resolve relative path
local try_std_module_directory
-- first try the directory relative to libc++.modules.json
try_std_module_directory = path.join(path.directory(modules_json_path), std_module_directory)
if os.isdir(try_std_module_directory) then
return {path.normalize(path.join(try_std_module_directory, "std.cppm")), path.normalize(path.join(try_std_module_directory, "std.compat.cppm"))}
end
-- then try the directory relative to clang bin directory
try_std_module_directory = path.join(path.directory(get_original_file(get_clang_path(target))), std_module_directory)
if os.isdir(try_std_module_directory) then
return {path.normalize(path.join(try_std_module_directory, "std.cppm")), path.normalize(path.join(try_std_module_directory, "std.compat.cppm"))}
end
Comment on lines +297 to +300
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

get_clang_path(target) can return nil, which would cause get_original_file(nil) to be called. This will likely lead to a runtime error. You should check if get_clang_path returns a valid path before using it.

            local clang_path = get_clang_path(target)
            if clang_path then
                try_std_module_directory = path.join(path.directory(get_original_file(clang_path)), std_module_directory)
                if os.isdir(try_std_module_directory) then
                    return {path.normalize(path.join(try_std_module_directory, "std.cppm")), path.normalize(path.join(try_std_module_directory, "std.compat.cppm"))}
                end
            end

elseif cpplib == "stdc++" then
-- dont be greedy and don't enable stdc++ std module support for llvm < 19
local clang_version = get_clang_version(target)
Expand Down
Loading