Open TurkeyMan opened 6 years ago
This page describes the process for adding natvis files manually in Visual Studio: https://msdn.microsoft.com/en-us/library/jj620914.aspx
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?
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.
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.
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.
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.
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 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!
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.
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.
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...
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?
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.
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.
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
?
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,
vpaths
.I still think a 'workspaceitems' container would be the most elegant.
workspaceitems 'foobar'
files { '**.lua' }
vpaths { ['Premake Scripts/*'] = '**.lua' }
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?
+1
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",
}
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",
}
},
}
Did this get anywhere? Would love to have my natvis added to my premake generated .sln
I don't think this has gone anywhere. You should able to apply natvis at the project scope, though.
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```
As I didn't really like either of the solutions above, I decided to take my own stab at this :)
Long but worth it, I think the end result is the most intuitive.
require("vstudio")
premake.api.register {
name = "solutionitems",
scope = "workspace",
kind = "table",
}
function recursiveSolutionItemsProject(wks, tbl)
for _, file in pairs(tbl) do
if type(_) ~= "number" then
local name = _
local tbl = file
premake.push('Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "'..name..'", "'..name..'", "{' .. os.uuid("Solution Items:"..wks.name..":"..name) .. '}"')
premake.push("ProjectSection(SolutionItems) = preProject")
local children = false
for _, file in pairs(file) do
if type(_) == "number" and type(file) == "string" then
for _, file in ipairs(os.matchfiles(file)) do
file = path.rebase(file, ".", wks.location)
premake.w(file.." = "..file)
end
end
if type(_) ~= "number" then
children = true
end
end
premake.pop("EndProjectSection")
premake.pop("EndProject")
if children then
recursiveSolutionItemsProject(wks, tbl)
end
end
end
end
premake.override(premake.vstudio.sln2005, "projects", function(base, wks)
if wks.solutionitems and #wks.solutionitems > 0 then
-- root level
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 pairs(wks.solutionitems) do
if type(_) == "number" and type(file) == "string" then
for _, file in ipairs(os.matchfiles(file)) do
file = path.rebase(file, ".", wks.location)
premake.w(file.." = "..file)
end
end
end
premake.pop("EndProjectSection")
premake.pop("EndProject")
-- subprojects
recursiveSolutionItemsProject(wks, wks.solutionitems)
end
base(wks)
end)
function recursiveSolutionItemsNestedProjectLines(wks, parent, tbl)
local parent_uuid
if parent == "Solution Items" then
parent_uuid = os.uuid("Solution Items:"..wks.name)
else
parent_uuid = os.uuid("Solution Items:"..wks.name..":"..parent)
end
for _, file in pairs(tbl) do
if type(_) ~= "number" then
local name = _
local new_tbl = file
project_uuid = os.uuid("Solution Items:"..wks.name..":"..name)
premake.w("{%s} = {%s}", project_uuid, parent_uuid)
--print("child:", name, "parent:", parent)
recursiveSolutionItemsNestedProjectLines(wks, name, new_tbl)
end
end
end
premake.override(premake.vstudio.sln2005, "nestedProjects", function(base, wks)
premake.push("GlobalSection(NestedProjects) = preSolution")
-- base copy-paste START
local tr = premake.workspace.grouptree(wks)
if premake.tree.hasbranches(tr) then
premake.tree.traverse(tr, {
onnode = function(n)
if n.parent.uuid then
premake.w("{%s} = {%s}", (n.project or n).uuid, n.parent.uuid)
end
end
})
end
-- base copy-paste END
-- our START
parent = "Solution Items"
recursiveSolutionItemsNestedProjectLines(wks, parent, wks.solutionitems)
-- our END
premake.pop("EndGlobalSection")
end)
Usage:
workspace "launcher"
solutionitems {
"./README.md",
["GitHub"] = {
"./.github/dependabot.yml",
["workflows"] = {
"./.github/workflows/**.yml",
}
},
["Premake"] = {
"./premake5.lua",
["Deps"] = {
"./deps/premake/**.lua"
}
},
}
Effect:
PS: don't listen to the person above me, both of the previous snippets still work on premake5 (well on 5.0.0-beta2 at least...)
@p0358 Ye, the code looks a bit huge but it works exactly like I need. Thank You for 100% work code, it's rare when you can just copy the code and it works with zero changes and hours of edition :)
And btw, if someone like me likes when main premake5.lua
script has minimum of code lines you can simply paste all this code inside external script and then just include("script.lua")
and problem solved.
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.