Skip to content

Conversation

@RubMaker
Copy link

  • Before adding new features and new modules, please go to issues to submit the relevant feature description first.
  • Write good commit messages and use the same coding conventions as the rest of the project.
  • Please commit code to dev branch and we will merge into master branch in feature
  • Ensure your edited codes with four spaces instead of TAB.

  • 增加新特性和新模块之前,请先到issues提交相关特性说明,经过讨论评估确认后,再进行相应的代码提交,避免做无用工作。
  • 编写友好可读的提交信息,并使用与工程代码相同的代码规范,代码请用4个空格字符代替tab缩进。
  • 请提交代码到dev分支,如果通过,我们会在特定时间合并到master分支上。
  • 为了规范化提交日志的格式,commit消息,不要用中文,请用英文描述。

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @RubMaker, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the NSIS packaging plugin by introducing comprehensive support for Qt application deployment. It automates the process of collecting and including Qt runtime dependencies, either by utilizing the windeployqt tool for smart deployment or falling back to a manual, version-aware inclusion of core Qt libraries and plugins. This ensures that generated NSIS installers for Qt projects are self-contained and functional, while also improving the uninstallation process with dedicated Qt-related cleanup.

Highlights

  • Automatic Qt Dependency Deployment: The NSIS packaging plugin now automatically detects Qt projects and includes necessary Qt runtime dependencies in the installer.
  • windeployqt Integration: The plugin leverages the windeployqt tool for intelligent and comprehensive collection of Qt application dependencies, including handling QML projects.
  • Manual Qt Deployment Fallback: If windeployqt is unavailable or fails, a robust manual deployment mechanism is provided to include essential Qt DLLs and plugins based on the project's linked libraries and Qt version.
  • Enhanced Uninstaller Cleanup: The uninstaller now includes specific commands to clean up Qt-related files and directories, such as plugins and qt.conf, ensuring a more thorough uninstall process.
  • Improved Directory Removal: A new _safe_rmdir function has been introduced to provide more reliable directory removal on Windows, addressing potential issues with locked files during cleanup operations.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds support for packaging Qt applications with NSIS. It introduces several new helper functions to detect Qt projects, find windeployqt, and deploy Qt dependencies. The changes are comprehensive, but there are several areas for improvement regarding code clarity, resource management, and correctness. I've found a critical bug related to premature cleanup of temporary files, some resource leaks, and inconsistencies in install/uninstall logic. I've also suggested several refactorings to improve code quality and maintainability.

print("Generated", #nsis_commands, "NSIS commands for Qt deployment")

-- Clean up temporary deployment directory
_safe_rmdir(deploy_dir)
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The temporary deployment directory deploy_dir is removed at the end of _deploy_qt_dependencies. However, the nsis_commands returned by this function contain absolute paths to files within deploy_dir. These files are needed by makensis later, but they will have been deleted by this point. This will cause the packaging to fail. The cleanup of deploy_dir should be deferred until after makensis has finished running.

print("Removing existing temporary directory:", deploy_dir)
_safe_rmdir(deploy_dir)
-- Wait a bit to ensure directory is removed
os.sleep(100)
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Using os.sleep() to wait for a directory to be removed is unreliable and can introduce race conditions. The _safe_rmdir function should be synchronous and guarantee the directory is removed before it returns. If there are still issues, the problem might be in _safe_rmdir or the underlying OS commands, and that should be investigated instead of using a sleep. Please remove this line.

[Paths]
Plugins = .
]]
local qt_conf_file = os.tmpfile() .. ".conf"
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 temporary file qt_conf_file created with os.tmpfile() is not deleted, leading to a resource leak on the build machine. This file needs to exist when makensis runs, so it should be cleaned up afterwards. A similar issue exists in the manual deployment fallback on line 581. A possible solution is to return the temporary file path and clean it up in a higher-level function after packaging is complete.

Comment on lines +698 to +711
-- Add version-specific cleanup
if is_qt6 then
table.insert(qt_cleanup_commands, '${unRMFileIfExists} "$InstDir\\bin\\Qt6Core.dll"')
table.insert(qt_cleanup_commands, '${unRMFileIfExists} "$InstDir\\bin\\Qt6Gui.dll"')
table.insert(qt_cleanup_commands, '${unRMFileIfExists} "$InstDir\\bin\\Qt6Widgets.dll"')
table.insert(qt_cleanup_commands, '${unRMFileIfExists} "$InstDir\\bin\\Qt6Network.dll"')
table.insert(qt_cleanup_commands, '${unRMFileIfExists} "$InstDir\\bin\\Qt6Sql.dll"')
else
table.insert(qt_cleanup_commands, '${unRMFileIfExists} "$InstDir\\bin\\Qt5Core.dll"')
table.insert(qt_cleanup_commands, '${unRMFileIfExists} "$InstDir\\bin\\Qt5Gui.dll"')
table.insert(qt_cleanup_commands, '${unRMFileIfExists} "$InstDir\\bin\\Qt5Widgets.dll"')
table.insert(qt_cleanup_commands, '${unRMFileIfExists} "$InstDir\\bin\\Qt5Network.dll"')
table.insert(qt_cleanup_commands, '${unRMFileIfExists} "$InstDir\\bin\\Qt5Sql.dll"')
end
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 list of Qt DLLs to be removed by the uninstaller is incomplete. The manual deployment logic in _get_qt_deployment_commands can deploy many other libraries (e.g., for XML, PrintSupport, Multimedia, OpenGL, SVG, QML/Quick) which are not cleaned up here. This will leave files behind after uninstallation. The cleanup logic should be made consistent with the deployment logic to ensure a clean uninstall.

Comment on lines +237 to +238
path.join("build", plat, "release", package:name() .. ".exe"),
path.join("build", "release", package:name() .. ".exe"),
Copy link
Contributor

Choose a reason for hiding this comment

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

high

There is a duplicated path in the possible_paths table. This is likely a copy-paste error and should be removed.

        path.join("build", "release", package:name() .. ".exe"),

Comment on lines +60 to +102
local function _safe_rmdir(dir)
if not os.isdir(dir) then
return true
end

-- Try multiple methods to remove directory
local ok = false

-- Method 1: Use os.tryrm first
ok = os.tryrm(dir)
if ok then
print("Successfully removed directory using os.tryrm:", dir)
return true
end

-- Method 2: Try Windows rmdir command
if is_host("windows") then
print("Trying Windows rmdir command for:", dir)
local ok2 = try { function()
os.vrunv("cmd", {"/c", "rmdir", "/s", "/q", path.translate(dir)})
return true
end }
if ok2 then
print("Successfully removed directory using rmdir:", dir)
return true
end
end

-- Method 3: Try PowerShell Remove-Item
if is_host("windows") then
print("Trying PowerShell Remove-Item for:", dir)
local ok3 = try { function()
os.vrunv("powershell", {"-Command", "Remove-Item -Recurse -Force '" .. dir .. "'"})
return true
end }
if ok3 then
print("Successfully removed directory using PowerShell:", dir)
return true
end
end

return false
end
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This function contains several print statements which seem to be for debugging. In xmake, it's better to use dprint for debug messages. Also, the ok variable is declared but its value is not used after being initialized, making it redundant. The logic can be simplified by removing it and returning directly after a successful removal attempt.


-- Add Qt deployment commands if this is a Qt project
if _is_qt_project(package) then
print("Adding Qt deployment commands to installer")
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This print statement should be cprint to follow xmake's logging conventions for user-facing information.

        cprint("Adding Qt deployment commands to installer")


-- Add Qt cleanup commands if this is a Qt project
if _is_qt_project(package) then
print("Adding Qt cleanup commands to uninstaller")
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This print statement should be cprint to follow xmake's logging conventions for user-facing information.

        cprint("Adding Qt cleanup commands to uninstaller")

if links then
for _, link in ipairs(links) do
if link:lower():find("qt") then
print("Qt project detected via link:", link)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This print statement and others in this function (lines 187, 204, 211) seem to be for debugging. It's better to use dprint for debug messages in xmake, so they only appear in verbose mode.

                dprint("Qt project detected via link: %s", link)

Comment on lines +850 to +857
-- check if this is a Qt project
local is_qt = _is_qt_project(package)
if is_qt then
cprint("Detected Qt project - using windeployqt for proper dependency deployment")

-- Check for windeployqt availability
local windeployqt = _get_windeployqt()
end
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 call to _get_windeployqt() here is redundant. The returned windeployqt variable is not used, and _get_windeployqt() is already called inside _get_qt_deployment_commands when it's needed. This block of code can be removed to avoid the unnecessary check.

@A2va A2va mentioned this pull request Sep 19, 2025
@RubMaker RubMaker closed this Sep 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant