premake-core icon indicating copy to clipboard operation
premake-core copied to clipboard

Support files at solution scope

Open TurkeyMan opened this issue 6 years ago • 25 comments

Support adding files at solution scope (in VS). No build action is performed on such a file, and as such, this shouldn't affect gmake/etc.

Useful for .editorconfig, .natvis files, etc.

TurkeyMan avatar Apr 17 '18 23:04 TurkeyMan

This page describes the process for adding natvis files manually in Visual Studio: https://msdn.microsoft.com/en-us/library/jj620914.aspx

erincatto avatar Apr 18 '18 18:04 erincatto

This works and add both files to each projects.

workspace "Solution"

	configurations { "Release", "Debug" }
	platforms { "x64", "x32" }

	files {
		"test.natvis",
		"config.editorconfig"
	}

	project "Project"

		kind 		"ConsoleApp"
		language	"C++"
		uuid		"00000000-0000-0000-0000-000000000000"

		files { "project/main.c" }


	project "otherProject"

		kind 		"ConsoleApp"
		language	"C++"
		uuid		"00000000-0000-0000-0000-000000000001"

		files { "otherProject/main2.c" }

If you encounter an issue with this, can you post an example that does not work as expected?

tdesveauxPKFX avatar Apr 18 '18 19:04 tdesveauxPKFX

Yes, that is what I have been doing. Visual Studio also supports adding files at the solution scope. The page I linked above shows the process for adding a natvis file at solution scope and you will see those files are listed in the .sln text in a "Solution Item" folder. This is a nicer way to display these files that have solution level scope.

erincatto avatar Apr 18 '18 21:04 erincatto

Indeed, that would be useful.

Do you know if natvis informations from a solution level file are added to the pdb when building a c++ project as they are when the file is at project level?

I quickly looked into it and this is what Visual Studio expect:

Project("{00000000-0000-0000-0000-000000000000}") = "SolutionFolderName", "SolutionFolderName", "{00000000-0000-0000-0000-000000000000}"
	ProjectSection(SolutionItems) = preProject
		PathTo\file.natvis = PathTo\file.natvis
	EndProjectSection
EndProject

SolutionFolderName can either be a solution folder or a project. However, if it is a project, the file will appear in the next solution folder found for some reason.

The ProjectSection block must be in a Project block, so you can't have a file at solution root.

There might be more to it but this would be a good start I think.

Implementation should be here.

Baking process should be modified too I assume but I am not familiar with this part.

tdesveauxPKFX avatar Apr 19 '18 09:04 tdesveauxPKFX

this might not be so easy using the standard files api, since those are automatically merged down into the project and configs... To support this, we might have to add a new workspacefiles api or something like that, that is explicitly bound to the workspace scope.

the alternative would be to create a dummy project like this:

project 'workspaceitems'
     kind 'workspaceitems'

    files { '**.natvis' }

that would at least isolate the files, or you could even make a new container type.

solutionitems 'foobar'
     files { '**.natvis' }

that would in turn allow us to limit the api's callable inside of that scope. The best part about this particular solution, is that you can add files to the solutionitems at any time, without having to manually exit the project scope and go back into the workspace scope, using the project(nil) pattern. And, the 'name' of the solutionitems container could basically be the folder to put the files in.

tvandijck avatar Apr 21 '18 17:04 tvandijck

I like the idea of a new API, workspacefiles is perfect in my eyes. I would like to be able to specify a workspace file from a project, "this project adds these workspace files" - at work, we have multiple teams consuming each others libraries, and having to manually maintain the "workspace files" at the workspace level would be awful.

samsinsane avatar Apr 22 '18 13:04 samsinsane

Curious…if you could specify the workspace level files using files(), maybe like (addressing the comment from @samsinsane):

project "MyProject"
    files { ... } -- project level files

project "*"  -- selects workspace scope, if you haven't seen it before
    files { ... } -- workspace level files

…would that be preferable to workspacefiles()? I kind of feel like it would be, even though it would be a PITA the way to code is now.

starkos avatar Apr 25 '18 16:04 starkos

@starkos I have not seen that before, that's a thing? That's pretty strange but cool, and I'd rather use that than expect someone to figure out how to get workspacefiles to work. Thanks!

samsinsane avatar Apr 26 '18 09:04 samsinsane

The problem with:

project "*"  -- selects workspace scope, if you haven't seen it before
    files { ... } 

is that while it adds the file at workspace scope, baking puts them simply in the project anyway. This is a supported workflow, and it's used.. So if you wanted to support "workspace" specific files using that API, you would break something that currently allows you to add a file to all projects. You can't have both.

If you want both, you need a new API...

personally, I like the

solutionitems 'foobar'
     files { '**.natvis' }

the best, over a single workspacefiles API. You can make it show up as a separate folder "foobar", containing the files you selected, and the vpaths API could work inside that container too, allowing further categorization of those files.

tvandijck avatar Apr 26 '18 09:04 tvandijck

The problem with ... is that while it adds the file at workspace scope, baking puts them simply in the project anyway.

That's right. I was just asking, for academic purposes, if it was possible, which would people prefer.

starkos avatar Apr 26 '18 15:04 starkos

I'm motivated by both angles... what are some use cases for regular files calls at workspace scope? I am tilted slightly in favour of "make files at workspace scope just work if the action can express it" rather than adding a new API. I think intuition would have basically anyone call files at workspace scope. What are some legit reasons people call files at workspace scope currently? I've never done it in any script I've ever written...

TurkeyMan avatar May 05 '18 04:05 TurkeyMan

I totally understand Tom's argument, but I wonder if the use case we'd be sacrificing is worth the subversion of intuition. Which is more useful?

TurkeyMan avatar May 05 '18 04:05 TurkeyMan

I found some other use cases that would make this nice to have: Doxyfile, .gitignore, premake5.lua, etc. This seems like a generally useful feature.

erincatto avatar May 06 '18 20:05 erincatto

I think @TurkeyMan is asking if there is any use case where you would call files() at the workspace scope, but not want those files to appear in the workspace if the tool supports it. I can't think of any, myself.

starkos avatar May 08 '18 23:05 starkos

I can't think of any either.

I do like the solutionitems container proposed by @tvandijck, this would leave the possibility to add files at workspace scope that are inherited by projects. Or we could use group?

tdesveauxPKFX avatar May 11 '18 20:05 tdesveauxPKFX

I'm concerned about separating the files() call at workspace scope. For one, it would require special casing that API in the context code. But more importantly, you would have to introduce a secondairy API to allow grouping. In projects we have vpath to allow grouping of files in folders, but at the workspace scope you can't do that, because that would then require you to also special case the vpaths API, which you can't do, because that is 100% certainly an API that is used at workspace scope but is assumed to apply to all projects. (in Heroes of the Storms & Starcraft2 for sure, because I wrote that).

So personally,

  • I don't like special casing a single API to not merge down.
  • and I want grouping of files in solution folders, so I need vpaths.

I still think a 'workspaceitems' container would be the most elegant.

workspaceitems 'foobar'
    files { '**.lua' }
    vpaths { ['Premake Scripts/*'] = '**.lua' }

tvandijck avatar May 11 '18 20:05 tvandijck

Yeah, I'm feeling Tom's suggestion. making a distinct container for workspace items feels okay. What are the semantics of that API? Is it mutually exclusive with project? Does calling workspaceitems or project cancel the other out?

TurkeyMan avatar Jun 07 '18 18:06 TurkeyMan

+1

andrewbhamilton avatar Jul 09 '18 19:07 andrewbhamilton

Heres a premake override you can paste in to your premake5.lua file for anyone who still want this.

require('vstudio')
premake.api.register {
  name = "workspace_files",
  scope = "workspace",
  kind = "list:string",
}

premake.override(premake.vstudio.sln2005, "projects", function(base, wks)
  if wks.workspace_files and #wks.workspace_files > 0 then
    premake.push('Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{' .. os.uuid("Solution Items:"..wks.name) .. '}"')
    premake.push("ProjectSection(SolutionItems) = preProject")
    for _, file in ipairs(wks.workspace_files) do
      file = path.rebase(file, ".", wks.location)
      premake.w(file.." = "..file)
    end
    premake.pop("EndProjectSection")
    premake.pop("EndProject")
  end
  base(wks)
end)

You can just use it like this

workspace "test"
    workspace_files {
        ".editorconfig",
    }

fsfod avatar Nov 25 '18 06:11 fsfod

Expanded @fsfod 's solution to include n number of solution folders for n number of files.

require('vstudio')
premake.api.register {
  name = "solutionitems",
  scope = "workspace",
  kind = "list:keyed:list:string",
}

premake.override(premake.vstudio.sln2005, "projects", function(base, wks)
    for _, folder in ipairs(wks.solutionitems) do
      for name, files in pairs(folder) do
        premake.push('Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "'..name..'", "'..name..'", "{' .. os.uuid("Solution Items:"..wks.name) .. '}"')
        premake.push("ProjectSection(SolutionItems) = preProject")
        for _, file in ipairs(files) do
          file = path.rebase(file, ".", wks.location)
          premake.w(file.." = "..file)
        end
        premake.pop("EndProjectSection")
        premake.pop("EndProject")
      end
    end
  base(wks)
end)

You can just use it like this

  solutionitems {
    { ["doc"] = { 
        "README.md",
        "SomeOther.md",
      } 
    },
    { ["foobar"] = { 
        "hello.md",
      } 
    },
    { ["stuff"] = { 
        "1.md",
        "2.md",
        "3.md",
      } 
    },
  }

nikitabuyevich avatar Jul 03 '20 00:07 nikitabuyevich

Did this get anywhere? Would love to have my natvis added to my premake generated .sln

vikhik avatar Aug 19 '22 00:08 vikhik

I don't think this has gone anywhere. You should able to apply natvis at the project scope, though.

nickclark2016 avatar Aug 19 '22 01:08 nickclark2016

For the next person. I couldn't get the above snippets working with latest (I'm also relatively new to modern premake).

But this does work, at the project scope, and keeps generating the vs filters properly for other source files (e.g. my natvis are in /Third-Party/** and my other projects are in /%{prj.name}/Source/**

function usesMyLib()
    language "C++"
    files { "%{prj.name}/**.h", "%{prj.name}/**.c", "%{prj.name}/**.cpp", "**.natvis" }
    local projname = project().name
    vpaths { 
        ["__Natvis"] = "**.natvis",
        ["*"] = projname.."/Source/**"
    }
    includedirs {"./MyLib/Public" }
end```

vikhik avatar Aug 19 '22 04:08 vikhik