-- -- gmake.lua -- Define the makefile action(s). -- Copyright (c) 2002-2015 Jason Perkins and the Premake project -- local p = premake p.modules.gmake = {} p.modules.gmake._VERSION = p._VERSION -- for backwards compatibility. p.make = p.modules.gmake local make = p.make local project = p.project -- -- 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 make.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 make.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 make.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 make.header(target) local kind = iif(target.project, "project", "workspace") _p('# %s %s makefile autogenerated by Premake', p.action.current().shortname, kind) _p('') if kind == "workspace" then local haspch = false for _, prj in ipairs(target.projects) do for cfg in project.eachconfig(prj) do if cfg.pchheader then haspch = true end end end if haspch then _p('.NOTPARALLEL:') _p('') end end make.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 make.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 make.mkdirRules(dirname) _p('%s:', dirname) _p('\t@echo Creating %s', dirname) make.mkdir(dirname) _p('') end -- -- Format a list of values to be safely written as part of a variable assignment. -- function make.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 make.tovar(value) value = value:gsub("[ -]", "_") value = value:gsub("[()]", "") return value end --------------------------------------------------------------------------- -- -- Handlers for the individual makefile elements that can be shared -- between the different language projects. -- --------------------------------------------------------------------------- function make.objdir(cfg) _x(' OBJDIR = %s', p.esc(project.getrelative(cfg.project, cfg.objdir))) end function make.objDirRules(prj) make.mkdirRules("$(OBJDIR)") end function make.phonyRules(prj) _p('.PHONY: clean prebuild prelink') _p('') end function make.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 make.preBuildCmds(cfg, toolset) make.buildCmds(cfg, "prebuild") end function make.preBuildRules(prj) _p('prebuild:') _p('\t$(PREBUILDCMDS)') _p('') end function make.preLinkCmds(cfg, toolset) make.buildCmds(cfg, "prelink") end function make.preLinkRules(prj) _p('prelink:') _p('\t$(PRELINKCMDS)') _p('') end function make.postBuildCmds(cfg, toolset) make.buildCmds(cfg, "postbuild") end function make.settings(cfg, toolset) if #cfg.makesettings > 0 then for _, value in ipairs(cfg.makesettings) do _p(value) end end local value = toolset.getmakesettings(cfg) if value then _p(value) end end function make.shellType() _p('SHELLTYPE := posix') _p('ifeq (.exe,$(findstring .exe,$(ComSpec)))') _p('\tSHELLTYPE := msdos') _p('endif') _p('') end function make.target(cfg) _x(' TARGETDIR = %s', project.getrelative(cfg.project, cfg.buildtarget.directory)) _x(' TARGET = $(TARGETDIR)/%s', cfg.buildtarget.name) end function make.targetDirRules(prj) make.mkdirRules("$(TARGETDIR)") end include("gmake_cpp.lua") include("gmake_csharp.lua") include("gmake_makefile.lua") include("gmake_utility.lua") include("gmake_workspace.lua") return p.modules.gmake