Repository: mesonbuild/meson

Issue:
Cannot pass extra_c_flags to hotdoc.generate_doc()
It is not possible to pass `extra_c_flags` to HotDoc using the Meson `hotdoc` module. 

###### Steps to reproduce:

```sh

touch index.md
echo index.md > sitemap.txt
cat > meson.build <<EOF
project('test', 'c')
hotdoc = import('hotdoc')
assert(hotdoc.has_extensions('c-extension'), 'No HotDoc c-extension?')
docs = hotdoc.generate_doc('test', project_version: '1',
	index: 'index.md', sitemap: 'sitemap.txt',
	extra_c_flags: ['-DBUILDING_DOCS=1'])
EOF
meson build
```

##### Expected Outcome

The generated JSON configuration file for HotDoc contains the `-DBUILDING_DOCS=1` flag to be passed to the compiler:

```json
{
  "extra_c_flags": [
    "-DBUILDING_DOCS=1"
  ],
  ...
}
```

##### Actual Outcome

During configuration, Meson will exit with an error return code, the logged output is:

```
% meson build
The Meson build system
Version: 0.51.1
Source dir: /home/aperez/test
Build dir: /home/aperez/test/b
Build type: native build
Project name: test
Project version: undefined
C compiler for the build machine: ccache cc (gcc 9.1.0 "cc (GCC) 9.1.0")
C compiler for the host machine: ccache cc (gcc 9.1.0 "cc (GCC) 9.1.0")
Build machine cpu family: x86_64
Build machine cpu: x86_64
Program hotdoc found: YES (/usr/bin/hotdoc)
Extension 'c-extension'... FOUND.
Extension 'gi-extension'... FOUND.
Generating Hotdoc configuration for:  test
usage: meson [--extra-extension-path EXTRA_EXTENSION_PATH]
             [--conf-file CONF_FILE] [--output-conf-file OUTPUT_CONF_FILE]
             [--init-dir INIT_DIR] [--version] [--makefile-path]
             [--get-conf-key GET_CONF_KEY] [--get-conf-path GET_CONF_PATH]
             [--get-private-folder] [--has-extension HAS_EXTENSIONS]
             [--list-extensions] [-] [--disable-incremental-build] [--verbose]
             [--fatal-warnings] [--gtk-doc-remove-xml] [--gtk-doc-escape-html]
             [--gdbus-codegen-sources GDBUS_CODEGEN_SOURCES [GDBUS_CODEGEN_SOURCES ...]]
             [--html-theme HTML_THEME] [--html-extra-theme HTML_EXTRA_THEME]
             [--html-add-anchors] [--html-number-headings]
             [--project-name PROJECT_NAME] [--project-version PROJECT_VERSION]
             [-i INDEX] [--sitemap SITEMAP]
             [--include-paths INCLUDE_PATHS [INCLUDE_PATHS ...]]
             [--extra-assets EXTRA_ASSETS] [--dry]
             [--deps-file-dest DEPS_FILE_DEST]
             [--deps-file-target DEPS_FILE_TARGET] [-o OUTPUT]
             [--disable-syntax-highlighting]
             [--multiple-choice-tags TAG_PROTOTYPES [TAG_PROTOTYPES ...]]
             [--choices-blacklist CHOICES_BLACKLIST [CHOICES_BLACKLIST ...]]
             [--devhelp-activate] [--default-license DEFAULT_LICENSE]
             [--default-code-samples-license DEFAULT_CODE_SAMPLES_LICENSE]
             [--authors-hold-copyright AUTHORS_HOLD_COPYRIGHT]
             [--git-upload-local-repo GIT_UPLOAD_LOCAL_REPO]
             [--git-upload-repository GIT_UPLOAD_REPOSITORY]
             [--git-upload-remote-branch GIT_UPLOAD_REMOTE_BRANCH]
             [--git-upload-commit-message GIT_UPLOAD_COMMIT_MESSAGE]
             [--git-upload-copy-only] [--git-upload]
             [--edit-on-github-repository EDIT_ON_GITHUB_REPOSITORY]
             [--edit-on-github-branch EDIT_ON_GITHUB_BRANCH]
             [--dbus-index DBUS_INDEX] [--dbus-smart-index]
             [--dbus-sources DBUS_SOURCES [DBUS_SOURCES ...]]
             [--dbus-source-filters DBUS_SOURCE_FILTERS [DBUS_SOURCE_FILTERS ...]]
             [--c-index C_INDEX] [--c-smart-index]
             [--c-sources C_SOURCES [C_SOURCES ...]]
             [--c-source-filters C_SOURCE_FILTERS [C_SOURCE_FILTERS ...]]
             [--c-source-roots C_SOURCE_ROOTS [C_SOURCE_ROOTS ...]]
             [--c-include-directories C_INCLUDE_DIRECTORIES [C_INCLUDE_DIRECTORIES ...]]
             [--pkg-config-packages PKG_CONFIG_PACKAGES [PKG_CONFIG_PACKAGES ...]]
             [--extra-c-flags EXTRA_C_FLAGS [EXTRA_C_FLAGS ...]]
             [--gi-index GI_INDEX] [--gi-smart-index]
             [--gi-sources GI_SOURCES [GI_SOURCES ...]]
             [--gi-c-sources GI_C_SOURCES [GI_C_SOURCES ...]]
             [--gi-c-source-filters GI_C_SOURCE_FILTERS [GI_C_SOURCE_FILTERS ...]]
             [--gi-c-source-roots GI_C_SOURCE_ROOTS [GI_C_SOURCE_ROOTS ...]]
             [--languages [LANGUAGES [LANGUAGES ...]]]
             [{run,conf,init,help}]
meson: error: argument --extra-c-flags: expected at least one argument
%
```



Discussion:
This looks like some kind of quoting issue in the way Meson is invoking HotDoc. In order to successfully pass compiler flags which themselves start with a dash (`-`), I need to do this when invoking HotDoc:

```sh
hotdoc --extra-c-flags=-DBUILDING_DOCS=1 ...
```

instead of:

```sh
hotdoc --extra-c-flags -DBUILDING_DOCS=1 ...
```

I suppose that Meson is using the second form, because that produces the same error message logged when running `meson build` to configure the project. 

@aperezdc , sorry for not seeing this issue earlier, this is related to https://stackoverflow.com/questions/16174992/cant-get-argparse-to-read-quoted-string-with-dashes-in-it and the same workaround can be used, simply prefix your dashed flags with a space, eg:

```
extra_c_flags: [' -DBUILDING_DOCS=1', ' -Dfoo=bar']
```

should work just fine :)

Resolving patch:
diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py
--- a/mesonbuild/modules/hotdoc.py
+++ b/mesonbuild/modules/hotdoc.py
@@ -81,12 +81,28 @@ def set_arg_value(self, option, value):
         elif isinstance(value, list):
             # Do not do anything on empty lists
             if value:
+                # https://bugs.python.org/issue9334 (from 2010 :( )
+                # The syntax with nargs=+ is inherently ambiguous
+                # A workaround for this case is to simply prefix with a space
+                # every value starting with a dash
+                escaped_value = []
+                for e in value:
+                    if isinstance(e, str) and e.startswith('-'):
+                        escaped_value += [' %s' % e]
+                    else:
+                        escaped_value += [e]
                 if option:
-                    self.cmd.extend([option] + value)
+                    self.cmd.extend([option] + escaped_value)
                 else:
-                    self.cmd.extend(value)
+                    self.cmd.extend(escaped_value)
         else:
-            self.cmd.extend([option, value])
+            # argparse gets confused if value(s) start with a dash.
+            # When an option expects a single value, the unambiguous way
+            # to specify it is with =
+            if isinstance(value, str):
+                self.cmd.extend(['%s=%s' % (option, value)])
+            else:
+                self.cmd.extend([option, value])
 
     def check_extra_arg_type(self, arg, value):
         value = getattr(value, 'held_object', value)


Test patch: