Initial support for custom build rules in makefiles

This commit is contained in:
Jason Perkins 2012-06-29 09:05:20 -04:00
parent 6df59080eb
commit 2dd8552258
4 changed files with 168 additions and 43 deletions

View File

@ -179,22 +179,60 @@
local tr = project.getsourcetree(prj)
premake.tree.traverse(tr, {
onleaf = function(node, depth)
if path.iscppfile(node.abspath) then
local objectname = project.getfileobject(prj, node.abspath)
_p('$(OBJDIR)/%s.o: %s', make.esc(objectname), make.esc(node.relpath))
_p('\t@echo $(notdir $<)')
cpp.buildcommand(prj)
elseif path.isresourcefile(node.abspath) then
local objectname = project.getfileobject(prj, node.abspath)
_p('$(OBJDIR)/%s.res: %s', make.esc(objectname), make.esc(node.relpath))
_p('\t@echo $(notdir $<)')
_p('\t$(SILENT) $(RESCOMP) $< -O coff -o "$@" $(RESFLAGS)')
-- check to see if this file has custom rules
local rules
for cfg in project.eachconfig(prj) do
local filecfg = config.getfileconfig(cfg, node.abspath)
if filecfg and filecfg.buildrule then
rules = true
break
end
end
-- if it has custom rules, need to break them out
-- into individual configurations
if rules then
cpp.customfilerules(prj, node)
else
cpp.standardfilerules(prj, node)
end
end
})
_p('')
end
function cpp.standardfilerules(prj, node)
-- C/C++ file
if path.iscppfile(node.abspath) then
local objectname = project.getfileobject(prj, node.abspath)
_p('$(OBJDIR)/%s.o: %s', make.esc(objectname), make.esc(node.relpath))
_p('\t@echo $(notdir $<)')
cpp.buildcommand(prj)
-- resource file
elseif path.isresourcefile(node.abspath) then
local objectname = project.getfileobject(prj, node.abspath)
_p('$(OBJDIR)/%s.res: %s', make.esc(objectname), make.esc(node.relpath))
_p('\t@echo $(notdir $<)')
_p('\t$(SILENT) $(RESCOMP) $< -O coff -o "$@" $(RESFLAGS)')
end
end
function cpp.customfilerules(prj, node)
for cfg in project.eachconfig(prj) do
local filecfg = config.getfileconfig(cfg, node.abspath)
local rule = filecfg.buildrule
_p('ifeq ($(config),%s)', make.esc(cfg.shortname))
_p('%s: %s', make.esc(rule.outputs[1]), make.esc(filecfg.relpath))
_p('\t@echo "%s"', rule.description)
for _, cmd in ipairs(rule.commands) do
_p('\t$(SILENT) %s', cmd)
end
_p('endif')
end
end
--
-- Compile flags
@ -261,53 +299,72 @@
local tr = project.getsourcetree(prj)
premake.tree.traverse(tr, {
onleaf = function(node, depth)
-- identify the file type
local kind
if path.iscppfile(node.abspath) then
kind = "objects"
elseif path.isresourcefile(node.abspath) then
kind = "resources"
end
-- skip files that aren't compiled
if not kind then
return
end
-- assign a unique object file name to avoid collisions from
-- files at different folder levels with the same name
local objectname = project.getfileobject(prj, node.abspath)
-- see what set of configurations contains this file
local inallcfgs = true
-- figure out what configurations contain this file, and
-- if it uses custom build rules
local inall = true
local custom = false
for cfg in project.eachconfig(prj) do
local filecfg = config.getfileconfig(cfg, node.abspath)
incfg[cfg] = (filecfg ~= nil)
if not filecfg then
inallcfgs = false
if filecfg then
incfg[cfg] = filecfg
custom = (filecfg.buildrule ~= nil)
else
inall = false
end
end
-- if this file exists in all configurations, write it to
-- the project's list of files, else add to specific cfgs
if inallcfgs then
table.insert(root[kind], objectname)
if not custom then
-- identify the file type
local kind
if path.iscppfile(node.abspath) then
kind = "objects"
elseif path.isresourcefile(node.abspath) then
kind = "resources"
end
-- skip files that aren't compiled
if not custom and not kind then
return
end
-- assign a unique object file name to avoid collisions
local objectname = project.getfileobject(prj, node.abspath)
objectname = "$(OBJDIR)/" .. objectname .. iif(kind == "objects", ".o", ".res")
-- if this file exists in all configurations, write it to
-- the project's list of files, else add to specific cfgs
if inall then
table.insert(root[kind], objectname)
else
for cfg in project.eachconfig(prj) do
if incfg[cfg] then
table.insert(configs[cfg][kind], objectname)
end
end
end
else
for cfg in project.eachconfig(prj) do
if incfg[cfg] then
table.insert(configs[cfg][kind], objectname)
local filecfg = incfg[cfg]
if filecfg then
-- if the custom build outputs an object file, add it to
-- the link step automatically to match Visual Studio
local output = filecfg.buildrule.outputs[1]
if path.isobjectfile(output) then
table.insert(configs[cfg].objects, output)
end
end
end
end
end
})
-- now I can write out the lists, project level first...
function listobjects(var, list, ext)
function listobjects(var, list)
_p('%s \\', var)
for _, objectname in ipairs(list) do
_p('\t$(OBJDIR)/%s.%s \\', make.esc(objectname), ext)
_p('\t%s \\', make.esc(objectname))
end
_p('')
end
@ -321,10 +378,10 @@
if #files.objects > 0 or #files.resources > 0 then
_p('ifeq ($(config),%s)', make.esc(cfg.shortname))
if #files.objects > 0 then
listobjects(' OBJECTS +=', files.objects, 'o')
listobjects(' OBJECTS +=', files.objects)
end
if #files.resources > 0 then
listobjects(' RESOURCES +=', files.resources, 'res')
listobjects(' RESOURCES +=', files.resources)
end
_p('endif')
_p('')

View File

@ -274,6 +274,7 @@
fcfg.vpath = fcfg.relpath
end
fcfg.name = path.getname(filename)
fcfg.basename = path.getbasename(filename)
fcfg.path = fcfg.relpath

View File

@ -43,3 +43,36 @@ $(OBJDIR)/hello1.o: src/hello.cpp
]]
end
--
-- If a custom build rule is supplied, it should be used.
--
function suite.customBuildRule()
files { "hello.x" }
configuration "**.x"
buildrule {
description = "Compiling %{file.name}",
commands = {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
},
outputs = { "%{cfg.objdir}/%{file.basename}.obj" }
}
prepare()
test.capture [[
ifeq ($(config),debug)
obj/Debug/hello.obj: hello.x
@echo "Compiling hello.x"
$(SILENT) cxc -c "hello.x" -o "obj/Debug/hello.xo"
$(SILENT) c2o -c "obj/Debug/hello.xo" -o "obj/Debug/hello.obj"
endif
ifeq ($(config),release)
obj/Release/hello.obj: hello.x
@echo "Compiling hello.x"
$(SILENT) cxc -c "hello.x" -o "obj/Release/hello.xo"
$(SILENT) c2o -c "obj/Release/hello.xo" -o "obj/Release/hello.obj"
endif
]]
end

View File

@ -112,3 +112,37 @@ RESOURCES := \
]]
end
--
-- If a custom rule builds to an object file, include it in the
-- link automatically to match the behavior of Visual Studio
--
function suite.customBuildRule()
files { "hello.x" }
configuration "**.x"
buildrule {
description = "Compiling %{file.name}",
commands = {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
},
outputs = { "%{cfg.objdir}/%{file.basename}.obj" }
}
prepare()
test.capture [[
OBJECTS := \
RESOURCES := \
ifeq ($(config),debug)
OBJECTS += \
obj/Debug/hello.obj \
endif
]]
end