Repository: mesonbuild/meson

Issue:
custom_target: install: true always enables build_by_default even when explicitly disabled
With Meson 0.47.2 it seems a custom_target with install set to true will always override build_by_default. Which means it's not possible to have an optional target that can also be installed.

Minimal repro:

```
project('test')
custom_target('test_bug',
	command: ['echo', 'executed'],
	output: '.',
	install: true,
	install_dir: '/tmp',
	build_by_default: false)
```

```
$ ninja -C build
ninja: Entering directory `build'
[1/1] Generating test_bug with a custom command.
executed
```

with install: false:

```
$ ninja -C build
ninja: Entering directory `build'
ninja: no work to do.
```


Discussion:

Resolving patch:
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -778,7 +778,7 @@ def get_build_by_default_targets(self):
         result = OrderedDict()
         # Get all build and custom targets that must be built by default
         for name, t in self.build.get_targets().items():
-            if t.build_by_default or t.install:
+            if t.build_by_default:
                 result[name] = t
         # Get all targets used as test executables and arguments. These must
         # also be built by default. XXX: Sometime in the future these should be
@@ -1039,7 +1039,8 @@ def generate_target_install(self, d):
                 if num_outdirs == 1 and num_out > 1:
                     for output in t.get_outputs():
                         f = os.path.join(self.get_target_dir(t), output)
-                        i = TargetInstallData(f, outdirs[0], {}, False, {}, None, install_mode)
+                        i = TargetInstallData(f, outdirs[0], {}, False, {}, None, install_mode,
+                                              optional=not t.build_by_default)
                         d.targets.append(i)
                 else:
                     for output, outdir in zip(t.get_outputs(), outdirs):
@@ -1047,7 +1048,8 @@ def generate_target_install(self, d):
                         if outdir is False:
                             continue
                         f = os.path.join(self.get_target_dir(t), output)
-                        i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode)
+                        i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode,
+                                              optional=not t.build_by_default)
                         d.targets.append(i)
 
     def generate_custom_install_script(self, d):
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -404,6 +404,11 @@ def process_kwargs(self, kwargs):
             self.build_by_default = kwargs['build_by_default']
             if not isinstance(self.build_by_default, bool):
                 raise InvalidArguments('build_by_default must be a boolean value.')
+        elif kwargs.get('install', False):
+            # For backward compatibility, if build_by_default is not explicitly
+            # set, use the value of 'install' if it's enabled.
+            self.build_by_default = True
+
         self.option_overrides = self.parse_overrides(kwargs)
 
     def parse_overrides(self, kwargs):


Test patch:
diff --git a/test cases/common/209 custom target build by default/docgen.py b/test cases/common/209 custom target build by default/docgen.py
new file mode 100644
--- /dev/null
+++ b/test cases/common/209 custom target build by default/docgen.py	
@@ -0,0 +1,12 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+
+out = sys.argv[1]
+
+os.mkdir(out)
+
+for name in ('a', 'b', 'c'):
+    with open(os.path.join(out, name + '.txt'), 'w') as f:
+        f.write(name)
diff --git a/test cases/common/209 custom target build by default/installed_files.txt b/test cases/common/209 custom target build by default/installed_files.txt
new file mode 100644
diff --git a/test cases/common/209 custom target build by default/meson.build b/test cases/common/209 custom target build by default/meson.build
new file mode 100644
--- /dev/null
+++ b/test cases/common/209 custom target build by default/meson.build	
@@ -0,0 +1,10 @@
+project('custom-target-dir-install', 'c')
+
+docgen = find_program('docgen.py')
+
+custom_target('docgen',
+  output : 'html',
+  command : [docgen, '@OUTPUT@'],
+  install : true,
+  build_by_default : false,
+  install_dir : join_paths(get_option('datadir'), 'doc/testpkgname'))