diff --git a/docs/reference/gobject/glib-mkenums.xml b/docs/reference/gobject/glib-mkenums.xml index 2573bb3e9..84023e9b1 100644 --- a/docs/reference/gobject/glib-mkenums.xml +++ b/docs/reference/gobject/glib-mkenums.xml @@ -375,6 +375,15 @@ Write output to FILE instead of stdout. + + + +When passed as the sole argument, read and parse the actual arguments from +RSPFILE. Useful on systems with a low command-line length +limit. For example, Windows has a limit of 8191 characters. + + + diff --git a/gobject/glib-mkenums.in b/gobject/glib-mkenums.in index 985edd2f7..91ad77942 100755 --- a/gobject/glib-mkenums.in +++ b/gobject/glib-mkenums.in @@ -69,6 +69,29 @@ def print_info(msg): print_color(msg, color=Color.GREEN, prefix='INFO') +def get_rspfile_args(rspfile): + ''' + Response files are useful on Windows where there is a command-line character + limit of 8191 because when passing sources as arguments to glib-mkenums this + limit can be exceeded in large codebases. + + There is no specification for response files and each tool that supports it + generally writes them out in slightly different ways, but some sources are: + https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-response-files + https://docs.microsoft.com/en-us/windows/desktop/midl/the-response-file-command + ''' + import shlex + if not os.path.isfile(rspfile): + sys.exit('Response file {!r} does not exist'.format(rspfile)) + try: + with open(rspfile, 'r') as f: + cmdline = f.read() + except OSError as e: + sys.exit('Response file {!r} could not be read: {}' + .format(rspfile, e.strerror)) + return shlex.split(cmdline) + + def write_output(output): global output_stream print(output, file=output_stream) @@ -326,9 +349,17 @@ parser.add_argument('--output', default=None, dest='output') parser.add_argument('--version', '-v', default=False, action='store_true', dest='version', help='Print version information') parser.add_argument('args', nargs='*', - help='Input files') + help='One or more input files, or a single argument @rspfile_path ' + 'pointing to a file that contains the actual arguments') -options = parser.parse_args() +# Support reading an rspfile of the form @filename which contains the args +# to be parsed +if len(sys.argv) == 2 and sys.argv[1].startswith('@'): + args = get_rspfile_args(sys.argv[1][1:]) +else: + args = sys.argv[1:] + +options = parser.parse_args(args) if options.version: print(VERSION_STR) diff --git a/gobject/tests/mkenums.py b/gobject/tests/mkenums.py index bb5443394..d18536b13 100644 --- a/gobject/tests/mkenums.py +++ b/gobject/tests/mkenums.py @@ -45,6 +45,7 @@ class TestMkenums(unittest.TestCase): parsing and generation code out into a library and unit test that, and convert this test to just check command line behaviour. """ + rspfile = False def setUp(self): self.timeout_seconds = 10 # seconds per test @@ -57,12 +58,25 @@ class TestMkenums(unittest.TestCase): 'glib-mkenums') else: self.__mkenums = os.path.join('/', 'usr', 'bin', 'glib-mkenums') - print('mkenums:', self.__mkenums) + print('rspfile: {}, mkenums:'.format(self.rspfile), self.__mkenums) def tearDown(self): self.tmpdir.cleanup() + def _write_rspfile(self, argv): + import shlex + with tempfile.NamedTemporaryFile(dir=self.tmpdir.name, mode='w', + delete=False) as f: + contents = ' '.join([shlex.quote(arg) for arg in argv]) + print('Response file contains:', contents) + f.write(contents) + f.flush() + return f.name + def runMkenums(self, *args): + if self.rspfile: + rspfile = self._write_rspfile(args) + args = ['@' + rspfile] argv = [self.__mkenums] argv.extend(args) print('Running:', argv) @@ -448,5 +462,10 @@ comment: {standard_bottom_comment} '''.format(**result.subs).strip(), result.out) +class TestRspMkenums(TestMkenums): + '''Run all tests again in @rspfile mode''' + rspfile = True + + if __name__ == '__main__': unittest.main(testRunner=taptestrunner.TAPTestRunner())