Repository: mesonbuild/meson

Issue:
Visual studio default build project
The first declared project in the visual studio solutions file is the "start-up" project, i.e. the default project. Should we have a `BUILD_ALL` project as the default project like cmake has?


Discussion:
Since `msbuild` builds all projects by default and VS has a `Build solution (F7)` which also does that I don't really see a reason to add a `BUILD_ALL` project.

However, it would still be nice to have a main entrypoint project. VS calls it "StartUp Project". You can right click any project and "Set as StartUp Project". This is then the executable that will be run by default with "Start Debugging (F5)". My goal with this issue is that I can do `meson build` and then `F5` immediately in VS and compile/run the correct program every time.

Being able to define a main entrypoint would also allow us to implement something like `meson run` that would run the entrypoint executable.

What would be the preferred way to define such an entrypoint?

```
my_exe = executable(..., project_entrypoint: true)
```

or

```
my_exe = executable(...)
project_entrypoint(my_exe)
```
It seems more reasonable to have this as a visual studio backend option. That way it can be changed without needing to edit build definition files.
So something like:

```
project('my_proj', 'cpp', default_options: ['vs_startup_project=my_exe'])
```
Something like that yes.

Resolving patch:
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -282,7 +282,7 @@ def generate_solution(self, sln_filename, projlist):
                 for dep in all_deps.keys():
                     guid = self.environment.coredata.target_guids[dep]
                     ofile.write('\t\t{%s} = {%s}\n' % (guid, guid))
-                ofile.write('EndProjectSection\n')
+                ofile.write('\tEndProjectSection\n')
                 ofile.write('EndProject\n')
                 for dep, target in recursive_deps.items():
                     if prj[0] in default_projlist:
@@ -345,8 +345,12 @@ def generate_solution(self, sln_filename, projlist):
             ofile.write('EndGlobal\n')
 
     def generate_projects(self):
+        startup_project = self.environment.coredata.backend_options['backend_startup_project'].value
         projlist = []
-        for name, target in self.build.targets.items():
+        startup_idx = 0
+        for (i, (name, target)) in enumerate(self.build.targets.items()):
+            if startup_project and startup_project == target.get_basename():
+                startup_idx = i
             outdir = Path(
                 self.environment.get_build_dir(),
                 self.get_target_dir(target)
@@ -359,6 +363,11 @@ def generate_projects(self):
             proj_uuid = self.environment.coredata.target_guids[name]
             self.gen_vcxproj(target, str(projfile_path), proj_uuid)
             projlist.append((name, relname, proj_uuid))
+
+        # Put the startup project first in the project list
+        if startup_idx:
+            projlist = [projlist[startup_idx]] + projlist[0:startup_idx] + projlist[startup_idx + 1:-1]
+
         return projlist
 
     def split_sources(self, srclist):
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -303,9 +303,19 @@ def init_builtins(self):
 
     def init_backend_options(self, backend_name):
         if backend_name == 'ninja':
-            self.backend_options['backend_max_links'] = UserIntegerOption('backend_max_links',
-                                                                          'Maximum number of linker processes to run or 0 for no limit',
-                                                                          0, None, 0)
+            self.backend_options['backend_max_links'] = \
+                UserIntegerOption(
+                    'backend_max_links',
+                    'Maximum number of linker processes to run or 0 for no '
+                    'limit',
+                    0, None, 0)
+        elif backend_name.startswith('vs'):
+            self.backend_options['backend_startup_project'] = \
+                UserStringOption(
+                    'backend_startup_project',
+                    'Default project to execute in Visual Studio',
+                    '')
+
 
     def get_builtin_option(self, optname):
         if optname in self.builtins:


Test patch: