Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork8.5k
Fix "Argument list too long" error in qstr generation for large projects#18328
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:master
Are you sure you want to change the base?
Conversation
0bb4f97 to5b602f5Comparegithub-actionsbot commentedOct 26, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Code size report: |
codecovbot commentedOct 26, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@## master #18328 +/- ##======================================= Coverage 98.38% 98.38% ======================================= Files 171 171 Lines 22297 22297 ======================================= Hits 21936 21936 Misses 361 361 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Sounds like the most straight-forward solution. Do we also need to do this for cmake and msbuild?
Also, I'm wondering why are we parsing LVGL for qstrs? Usually we put 3rd party libraries somewhere where they don't get added toSRC_QSTR so that we don't waste time parsing them since they don't contain any MicroPython code.
py/mkrules.mk Outdated
| $(HEADER_BUILD)/qstr.i.last:$(SRC_QSTR)$(QSTR_GLOBAL_DEPENDENCIES) |$(QSTR_GLOBAL_REQUIREMENTS) | ||
| $(ECHO)"GEN$@" | ||
| $(Q)$(PYTHON)$(PY_SRC)/makeqstrdefs.py pp$(CPP) output$(HEADER_BUILD)/qstr.i.last cflags$(QSTR_GEN_CFLAGS) cxxflags$(QSTR_GEN_CXXFLAGS) sources$^ dependencies$(QSTR_GLOBAL_DEPENDENCIES) changed_sources$? | ||
| $(Q)rm -f$(HEADER_BUILD)/qstr_sources.txt&&\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Do we really need the&& \ here? IIRC, running the recipe will already check each line for failure and stop.
py/mkrules.mk Outdated
| $(Q)$(PYTHON)$(PY_SRC)/makeqstrdefs.py pp$(CPP) output$(HEADER_BUILD)/qstr.i.last cflags$(QSTR_GEN_CFLAGS) cxxflags$(QSTR_GEN_CXXFLAGS) sources$^ dependencies$(QSTR_GLOBAL_DEPENDENCIES) changed_sources$? | ||
| $(Q)rm -f$(HEADER_BUILD)/qstr_sources.txt&&\ | ||
| forsrcin $^;doecho"$$src">>$(HEADER_BUILD)/qstr_sources.txt;done&&\ | ||
| $(PYTHON)$(PY_SRC)/makeqstrdefs.py pp$(CPP) output$(HEADER_BUILD)/qstr.i.last cflags$(QSTR_GEN_CFLAGS) cxxflags$(QSTR_GEN_CXXFLAGS) sources @$(HEADER_BUILD)/qstr_sources.txt dependencies$(QSTR_GLOBAL_DEPENDENCIES) changed_sources$? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Should we split this us into two recipes now that there is an intermediate file generated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I'm open to direction here, though my feeling is you split to avoid the time re-processing a file. Considering this is just the file list I can't imagine splitting would speed it up in a measurable way, it just adds a few extra lines to the makefile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I just mentioned it because I've had make get confused from intermediate files before. It's been too long though that I don't remember the details. Might be OK here since the file gets completely recreated each time the recipe runs.
py/makeqstrdefs.py Outdated
| # Support response files (starting with @) to avoid argument list too long errors | ||
| ifarg.startswith("@")andos.path.isfile(arg[1:]): | ||
| withopen(arg[1:],"r")asf: | ||
| named_args[current_tok].extend(f.read().split()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I guess this means that all file names are stored in a single line? It could be nice for troubleshooting purposes to put each file on a separate line to make it easier to read if someone ever needs to take a peek at it.
andrewleechOct 26, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actually they are already one file per line but I'll make it a bit more explicit / clearer.
I initially wasn't going to submit this change at all until I figured out whether it was needed, or I just had a bug in my makefile.
Then I figured that having the listing in a fine would be the easiest way to diagnose the issue and that it could also be helpful for others.
andrewleech commentedOct 26, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Oh yes they certainly would need the same change. Update: msbuild shouldn't be affected, it uses a different approach where files are individually preprocessed then the outputs contatenated by custom C# task
The parsing isn't (intended to be) lvgl itself but the user C module wrappers, including support libraries and to a limited extent some examples. I do still need to debug the build scripts a bit more to check if there is indeed much more being added to the qstr list than needed; having them in a file was going to make that easier I figured. The makefile snippet for the user C module includes some wildcard entries as the module itself involves a level of auto generated code / files. Regardless I'm honestly not sure how close to an arg limit a "normal" micropython build is to know if this change is really necessary, or if there's just a bug in my user C module makefile. |
38d5b09 to1213627CompareSupport response files in makeqstrdefs.py to handle builds with largenumbers of source files. This prevents shell argument limit exceedederrors during the qstr preprocessing step.Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
1213627 to66ec367Compare
Uh oh!
There was an error while loading.Please reload this page.
Problem
When building MicroPython projects with a large number of source files, the qstr generation step fails with shell errors like:
This occurs because the
makeqstrdefs.pyscript receives all source file paths as command-line arguments, which can exceed the shell'sARG_MAXlimit. This issue was first encountered when including large user C modules like LVGL, which adds 1200+ files to the qstr scanning list.The
ARG_MAXlimit varies significantly between systems:The issue manifests during the qstr preprocessing step in
py/mkrules.mkwhen generating$(HEADER_BUILD)/qstr.i.last.Solution
This PR implements support for response files (argument files) in the qstr generation toolchain. Response files allow passing the large file list via a file instead of on the command line, completely avoiding ARG_MAX limitations for the problematic argument.
Changes
py/mkrules.mk: Modified the qstr generation rule to write only the source file list to a temporary file (
qstr_sources.txt). All other arguments (CPP, flags, dependencies) remain as command-line arguments.py/mkrules.cmake: Modified to write the semicolon-separated source list to a file at configure time. This avoids passing the huge list as command-line arguments to any build-time process.
py/makeqstrdefs.py: Enhanced the argument parser to detect and read response files when an argument starts with
@. The parser now handles both newline-separated format (from Make builds) and semicolon-separated format (from CMake builds).Implementation Details
@(e.g.,sources @qstr_sources.txt)Testing
This fix has been tested with:
Related Issues
This addresses build failures in projects with extensive use of external libraries, particularly those using LVGL bindings or other large codebases that push against shell argument limits.