Path tokens in non-path fields (like custom build commands) are not expanded to project-relative paths

This commit is contained in:
Jason Perkins 2013-04-17 11:54:07 -04:00
parent 0cd9bac896
commit b59850dd1b
8 changed files with 106 additions and 39 deletions

View File

@ -457,8 +457,8 @@
local commands = table.concat(filecfg.buildcommands,'\r\n')
_p(3,'<Command %s>%s</Command>', condition, premake.esc(commands))
local outputs = table.concat(filecfg.buildoutputs, ' ')
_p(3,'<Outputs %s>%s</Outputs>', condition, premake.esc(outputs))
local outputs = project.getrelative(prj, filecfg.buildoutputs)
vc2010.element(3, "Outputs", condition, '%s', table.concat(outputs, " "))
end
end

View File

@ -40,6 +40,14 @@
ctx._filename = { filename } or {}
ctx.terms = {}
-- This base directory is used when expanding path tokens encountered
-- in non-path value; such values will be made relative to this value
-- so the resulting projects will only contain relative paths. It is
-- expected that the creator of the context will set this value using
-- the setbasedir() function.
ctx._basedir = os.getcwd()
-- when a missing field is requested, fetch it from my config
-- set, and then cache the value for future lookups
setmetatable(ctx, context.__mt)
@ -82,6 +90,26 @@
end
--
-- Sets the base directory for path token expansion in non-path fields; such
-- values will be made relative to this path.
--
-- @param ctx
-- The context in which to set the value.
-- @param basedir
-- The new base directory for path token expansion. This should be
-- provided as an absolute path. This may be left nil to simply fetch
-- the current base directory.
-- @return
-- The context's base directory.
--
function context.basedir(ctx, basedir)
ctx._basedir = basedir or ctx._basedir
return ctx._basedir
end
--
-- Compiles the context for better performance. The list of context terms
-- becomes locked down; any subsequent changes are ignored.
@ -130,8 +158,8 @@
local field = premake.fields[key]
if field and field.tokens then
local kind = field.kind
local ispath = kind:startswith("path") or kind:startswith("mixed")
value = premake.detoken.expand(value, ctx.environ, ispath)
local ispath = kind:startswith("path") or kind:startswith("file") or kind:startswith("mixed")
value = premake.detoken.expand(value, ctx.environ, ispath, ctx._basedir)
end
-- store the result for later lookups

View File

@ -3,7 +3,7 @@
--
-- Expands tokens.
--
-- Copyright (c) 2011-2012 Jason Perkins and the Premake project
-- Copyright (c) 2011-2013 Jason Perkins and the Premake project
--
premake.detoken = {}
@ -22,11 +22,14 @@
-- @param ispath
-- If true, the value treated as a file system path, and checks will be made
-- for nested absolute paths from expanded tokens.
-- @param basedir
-- If provided, path tokens encountered in non-path fields (where the ispath
-- parameter is set to false) will be made relative to this location.
-- @return
-- The value with any contained tokens expanded.
--
function detoken.expand(value, environ, ispath)
function detoken.expand(value, environ, ispath, basedir)
-- enable access to the global environment
setmetatable(environ, {__index = _G})
@ -36,20 +39,42 @@
if not func then
return nil, err
end
-- give the function access to the project objects
setfenv(func, environ)
-- run it and return the result
local result = func() or ""
-- if I'm replacing within a path value, and the replacement is
-- itself and absolute path, insert a marker at the start of it.
-- This will be my clue later to trim the path here.
if ispath and path.isabsolute(result) then
-- If the result is an absolute path, and it is being inserted into
-- a path value, place a special marker at the start of it. After
-- all results have been processed, I can look for these markers to
-- find the last absolute path expanded.
--
-- Example: the value "/home/user/myprj/%{cfg.objdir}" expands to:
-- "/home/user/myprj//home/user/myprj/obj/Debug".
--
-- By inserting a marker this becomes:
-- "/home/user/myprj/[\0]/home/user/myprj/obj/Debug".
--
-- I can now trim everything before the marker to get the right
-- result, which should always be the last absolute path specified:
-- "/home/user/myprj/obj/Debug"
local isAbs = path.isabsolute(result)
if isAbs and ispath then
result = "\0" .. result
end
-- If the result is an absolute path, and it is being inserted into
-- a NON-path value, I need to make it relative to the project that
-- will contain it. Otherwise I ended up with an absolute path in
-- the generated project, and it can no longer be moved around.
if isAbs and not ispath and basedir then
result = path.getrelative(basedir, result)
end
return result
end
@ -64,7 +89,7 @@
return result
end)
until count == 0
-- if a path, look for a split out embedded absolute paths
if ispath then
local i, j
@ -75,7 +100,7 @@
end
until not i
end
return value
end
@ -89,7 +114,7 @@
return expandvalue(value)
end
end
return recurse(value)
end

View File

@ -132,6 +132,10 @@
})
setmetatable(sln, getmetatable(result))
-- Specify the solution's file system location; when path tokens are
-- expanded in solution values, they will be made relative to this path.
context.basedir(ctx, project.getlocation(sln))
-- bake all of the projects in the list, and store that result
local projects = {}

View File

@ -263,6 +263,13 @@
filecfg.config = cfg
filecfg.project = cfg.project
-- Set the context's base directory the project's file system
-- location. Any path tokens which are expanded in non-path fields
-- (such as the custom build commands) will be made relative to
-- this path, ensuring a portable generated project.
context.basedir(filecfg, project.getlocation(cfg.project))
-- and cache the result
cfg.files[filename] = filecfg
end

View File

@ -123,6 +123,12 @@
})
setmetatable(prj, getmetatable(result))
-- Set the context's base directory the project's file system
-- location. Any path tokens which are expanded in non-path fields
-- are made relative to this, ensuring a portable generated project.
context.basedir(ctx, project.getlocation(prj))
-- bake all configurations contained by the project
local configs = {}
for _, pairing in ipairs(result._cfglist) do
@ -285,24 +291,8 @@
cfg.solution = prj.solution
cfg.project = prj
cfg.context = ctx
environ.cfg = cfg
-- File this under "too clever by half": I want path tokens (targetdir, etc.)
-- to expand to relative paths, so they can be used in custom build rules and
-- other places where it would be impractical to detect and convert them. So
-- create a proxy object with an attached metatable that converts path fields
-- on the fly as they are requested.
local proxy = {}
setmetatable(proxy, {
__index = function(proxy, key)
local field = premake.fields[key]
if field and field.kind == "path" then
return premake5.project.getrelative(cfg.project, cfg[key])
end
return cfg[key]
end,
})
environ.cfg = proxy
-- TODO: HACK, TRANSITIONAL, REMOVE: pass requests for missing values

View File

@ -285,7 +285,7 @@
function suite.customBuildTool_onBuildRuleWithTokens()
files { "hello.x" }
objdir "../../../tmp"
objdir "../tmp/%{cfg.name}"
configuration "**.x"
buildmessage "Compiling $(InputFile)"
buildcommands {
@ -303,8 +303,8 @@
>
<Tool
Name="VCCustomBuildTool"
CommandLine="cxc -c hello.x -o obj/Debug/hello.xo&#x0D;&#x0A;c2o -c obj/Debug/hello.xo -o obj/Debug/hello.obj"
Outputs="obj/Debug/hello.obj"
CommandLine="cxc -c hello.x -o ../tmp/Debug/hello.xo&#x0D;&#x0A;c2o -c ../tmp/Debug/hello.xo -o ../tmp/Debug/hello.obj"
Outputs="../tmp/Debug/hello.obj"
/>
</FileConfiguration>
]]

View File

@ -4,8 +4,7 @@
-- Copyright (c) 2011-2012 Jason Perkins and the Premake project
--
T.detoken = {}
local suite = T.detoken
local suite = test.declare("detoken")
local detoken = premake.detoken
@ -66,12 +65,25 @@
--
function suite.canExpandToAbsPath()
environ.cfg = { basedir=os.getcwd() }
environ.cfg = { basedir = os.getcwd() }
x = detoken.expand("bin/debug/%{cfg.basedir}", environ, true)
test.isequal(os.getcwd(), x)
end
--
-- If a non-path field contains a token that expands to a path, that
-- path should be converted to a relative value.
--
function suite.canExpandToRelPath()
local cwd = os.getcwd()
environ.cfg = { basedir = path.getdirectory(cwd) }
x = detoken.expand("cd %{cfg.basedir}", environ, false, cwd)
test.isequal("cd ..", x)
end
--
-- If the value being expanded is a table, iterate over all of its values.
--
@ -80,3 +92,4 @@
x = detoken.expand({ "A%{1}", "B%{2}", "C%{3}" }, environ)
test.isequal({ "A1", "B2", "C3" }, x)
end