123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- --
- -- gmake2.lua
- -- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
- --
- local p = premake
- local project = p.project
- p.modules.gmake2 = {}
- p.modules.gmake2._VERSION = p._VERSION
- local gmake2 = p.modules.gmake2
- --
- -- Write out the default configuration rule for a workspace or project.
- --
- -- @param target
- -- The workspace or project object for which a makefile is being generated.
- --
- function gmake2.defaultconfig(target)
- -- find the right configuration iterator function for this object
- local eachconfig = iif(target.project, project.eachconfig, p.workspace.eachconfig)
- local defaultconfig = nil
- -- find the right default configuration platform, grab first configuration that matches
- if target.defaultplatform then
- for cfg in eachconfig(target) do
- if cfg.platform == target.defaultplatform then
- defaultconfig = cfg
- break
- end
- end
- end
- -- grab the first configuration and write the block
- if not defaultconfig then
- local iter = eachconfig(target)
- defaultconfig = iter()
- end
- if defaultconfig then
- _p('ifndef config')
- _x(' config=%s', defaultconfig.shortname)
- _p('endif')
- _p('')
- end
- end
- ---
- -- Escape a string so it can be written to a makefile.
- ---
- function gmake2.esc(value)
- result = value:gsub("\\", "\\\\")
- result = result:gsub("\"", "\\\"")
- result = result:gsub(" ", "\\ ")
- result = result:gsub("%(", "\\(")
- result = result:gsub("%)", "\\)")
- -- leave $(...) shell replacement sequences alone
- result = result:gsub("$\\%((.-)\\%)", "$(%1)")
- return result
- end
- --
- -- Get the makefile file name for a workspace or a project. If this object is the
- -- only one writing to a location then I can use "Makefile". If more than one object
- -- writes to the same location I use name + ".make" to keep it unique.
- --
- function gmake2.getmakefilename(this, searchprjs)
- local count = 0
- for wks in p.global.eachWorkspace() do
- if wks.location == this.location then
- count = count + 1
- end
- if searchprjs then
- for _, prj in ipairs(wks.projects) do
- if prj.location == this.location then
- count = count + 1
- end
- end
- end
- end
- if count == 1 then
- return "Makefile"
- else
- return ".make"
- end
- end
- --
- -- Output a makefile header.
- --
- -- @param target
- -- The workspace or project object for which the makefile is being generated.
- --
- function gmake2.header(target)
- local kind = iif(target.project, "project", "workspace")
- _p('# %s %s makefile autogenerated by Premake', p.action.current().shortname, kind)
- _p('')
- gmake2.defaultconfig(target)
- _p('ifndef verbose')
- _p(' SILENT = @')
- _p('endif')
- _p('')
- end
- --
- -- Rules for file ops based on the shell type. Can't use defines and $@ because
- -- it screws up the escaping of spaces and parethesis (anyone know a fix?)
- --
- function gmake2.mkdir(dirname)
- _p('ifeq (posix,$(SHELLTYPE))')
- _p('\t$(SILENT) mkdir -p %s', dirname)
- _p('else')
- _p('\t$(SILENT) mkdir $(subst /,\\\\,%s)', dirname)
- _p('endif')
- end
- function gmake2.mkdirRules(dirname)
- _p('%s:', dirname)
- _p('\t@echo Creating %s', dirname)
- gmake2.mkdir(dirname)
- _p('')
- end
- --
- -- Format a list of values to be safely written as part of a variable assignment.
- --
- function gmake2.list(value, quoted)
- quoted = false
- if #value > 0 then
- if quoted then
- local result = ""
- for _, v in ipairs (value) do
- if #result then
- result = result .. " "
- end
- result = result .. p.quoted(v)
- end
- return result
- else
- return " " .. table.concat(value, " ")
- end
- else
- return ""
- end
- end
- --
- -- Convert an arbitrary string (project name) to a make variable name.
- --
- function gmake2.tovar(value)
- value = value:gsub("[ -]", "_")
- value = value:gsub("[()]", "")
- return value
- end
- function gmake2.getToolSet(cfg)
- local default = iif(cfg.system == p.MACOSX, "clang", "gcc")
- local toolset = p.tools[_OPTIONS.cc or cfg.toolset or default]
- if not toolset then
- error("Invalid toolset '" .. cfg.toolset .. "'")
- end
- return toolset
- end
- function gmake2.outputSection(prj, callback)
- local root = {}
- for cfg in project.eachconfig(prj) do
- -- identify the toolset used by this configurations (would be nicer if
- -- this were computed and stored with the configuration up front)
- local toolset = gmake2.getToolSet(cfg)
- local settings = {}
- local funcs = callback(cfg)
- for i = 1, #funcs do
- local c = p.capture(function ()
- funcs[i](cfg, toolset)
- end)
- if #c > 0 then
- table.insert(settings, c)
- end
- end
- if not root.settings then
- root.settings = table.arraycopy(settings)
- else
- root.settings = table.intersect(root.settings, settings)
- end
- root[cfg] = settings
- end
- if #root.settings > 0 then
- for _, v in ipairs(root.settings) do
- p.outln(v)
- end
- p.outln('')
- end
- local first = true
- for cfg in project.eachconfig(prj) do
- local settings = table.difference(root[cfg], root.settings)
- if #settings > 0 then
- if first then
- _x('ifeq ($(config),%s)', cfg.shortname)
- first = false
- else
- _x('else ifeq ($(config),%s)', cfg.shortname)
- end
- for k, v in ipairs(settings) do
- p.outln(v)
- end
- _p('')
- end
- end
- if not first then
- p.outln('endif')
- p.outln('')
- end
- end
- -- convert a rule property into a string
- ---------------------------------------------------------------------------
- --
- -- Handlers for the individual makefile elements that can be shared
- -- between the different language projects.
- --
- ---------------------------------------------------------------------------
- function gmake2.phonyRules(prj)
- _p('.PHONY: clean prebuild')
- _p('')
- end
- function gmake2.shellType()
- _p('SHELLTYPE := posix')
- _p('ifeq (.exe,$(findstring .exe,$(ComSpec)))')
- _p('\tSHELLTYPE := msdos')
- _p('endif')
- _p('')
- end
- function gmake2.target(cfg, toolset)
- p.outln('TARGETDIR = ' .. project.getrelative(cfg.project, cfg.buildtarget.directory))
- p.outln('TARGET = $(TARGETDIR)/' .. cfg.buildtarget.name)
- end
- function gmake2.objdir(cfg, toolset)
- p.outln('OBJDIR = ' .. project.getrelative(cfg.project, cfg.objdir))
- end
- function gmake2.settings(cfg, toolset)
- if #cfg.makesettings > 0 then
- for _, value in ipairs(cfg.makesettings) do
- p.outln(value)
- end
- end
- local value = toolset.getmakesettings(cfg)
- if value then
- p.outln(value)
- end
- end
- function gmake2.buildCmds(cfg, event)
- _p('define %sCMDS', event:upper())
- local steps = cfg[event .. "commands"]
- local msg = cfg[event .. "message"]
- if #steps > 0 then
- steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location)
- msg = msg or string.format("Running %s commands", event)
- _p('\t@echo %s', msg)
- _p('\t%s', table.implode(steps, "", "", "\n\t"))
- end
- _p('endef')
- end
- function gmake2.preBuildCmds(cfg, toolset)
- gmake2.buildCmds(cfg, "prebuild")
- end
- function gmake2.preLinkCmds(cfg, toolset)
- gmake2.buildCmds(cfg, "prelink")
- end
- function gmake2.postBuildCmds(cfg, toolset)
- gmake2.buildCmds(cfg, "postbuild")
- end
- function gmake2.targetDirRules(cfg, toolset)
- gmake2.mkdirRules("$(TARGETDIR)")
- end
- function gmake2.objDirRules(cfg, toolset)
- gmake2.mkdirRules("$(OBJDIR)")
- end
- function gmake2.preBuildRules(cfg, toolset)
- _p('prebuild: | $(OBJDIR)')
- _p('\t$(PREBUILDCMDS)')
- _p('')
- end
- include("gmake2_cpp.lua")
- include("gmake2_csharp.lua")
- include("gmake2_makefile.lua")
- include("gmake2_utility.lua")
- include("gmake2_workspace.lua")
- return gmake2
|