--
-- gmake_workspace.lua
-- Generate a workspace-level makefile.
-- (c) 2016-2017 Jess Perkins, Blizzard Entertainment and the Premake project
--

	local p = premake
	local gmake = p.modules.gmake

	local tree    = p.tree
	local project = p.project

--
-- Generate a GNU make "workspace" makefile, with support for the new platforms API.
--

	function gmake.generate_workspace(wks)
		p.eol("\n")

		gmake.header(wks)

		gmake.configmap(wks)
		gmake.projects(wks)

		gmake.workspacePhonyRule(wks)
		gmake.groupRules(wks)

		gmake.projectrules(wks)
		gmake.cleanrules(wks)
		gmake.helprule(wks)
	end


--
-- Write out the workspace's configuration map, which maps workspace
-- level configurations to the project level equivalents.
--

	function gmake.configmap(wks)
		local first = true
		for cfg in p.workspace.eachconfig(wks) do
			if first then
				_p('ifeq ($(config),%s)', cfg.shortname)
				first = false
			else
				_p('else ifeq ($(config),%s)', cfg.shortname)
			end

			for prj in p.workspace.eachproject(wks) do
				local prjcfg = project.getconfig(prj, cfg.buildcfg, cfg.platform)
				if prjcfg then
					_p('  %s_config = %s', gmake.tovar(prj.name), prjcfg.shortname)
				end
			end

			_p('')
		end

		if not first then
			_p('else')
			_p('  $(error "invalid configuration $(config)")')
			_p('endif')
			_p('')
		end
	end


--
-- Write out the rules for the `make clean` action.
--

	function gmake.cleanrules(wks)
		_p('clean:')
		for prj in p.workspace.eachproject(wks) do
			local prjpath = p.filename(prj, gmake.getmakefilename(prj, true))
			local prjdir = path.getdirectory(path.getrelative(wks.location, prjpath))
			local prjname = path.getname(prjpath)
			_x(1,'@${MAKE} --no-print-directory -C %s -f %s clean', prjdir, prjname)
		end
		_p('')
	end


--
-- Write out the make file help rule and configurations list.
--

	function gmake.helprule(wks)
		_p('help:')
		_p(1,'@echo "Usage: make [config=name] [target]"')
		_p(1,'@echo ""')
		_p(1,'@echo "CONFIGURATIONS:"')

		for cfg in p.workspace.eachconfig(wks) do
			_x(1, '@echo "  %s"', cfg.shortname)
		end

		_p(1,'@echo ""')

		_p(1,'@echo "TARGETS:"')
		_p(1,'@echo "   all (default)"')
		_p(1,'@echo "   clean"')

		for prj in p.workspace.eachproject(wks) do
			_p(1,'@echo "   %s"', prj.name)
		end

		_p(1,'@echo ""')
		_p(1,'@echo "For more information, see https://github.com/premake/premake-core/wiki"')
	end


--
-- Write out the list of projects that comprise the workspace.
--

	function gmake.projects(wks)
		_p('PROJECTS := %s', table.concat(p.esc(table.extract(wks.projects, "name")), " "))
		_p('')
	end

--
-- Write out the workspace PHONY rule
--

	function gmake.workspacePhonyRule(wks)
		local groups = {}
		local tr = p.workspace.grouptree(wks)
		tree.traverse(tr, {
			onbranch = function(n)
				table.insert(groups, p.esc(n.path))
			end
		})

		_p('.PHONY: all clean help $(PROJECTS) ' .. table.implode(groups, '', '', ' '))
		_p('')
		_p('all: $(PROJECTS)')
		_p('')
	end

--
-- Write out the phony rules representing project groups
--
	function gmake.groupRules(wks)
		-- Transform workspace groups into target aggregate
		local tr = p.workspace.grouptree(wks)
		tree.traverse(tr, {
			onbranch = function(n)
				local rule = p.esc(n.path) .. ":"
				local projectTargets = {}
				local groupTargets = {}
				for i, c in pairs(n.children)
				do
					if type(i) == "string"
					then
						if c.project
						then
							table.insert(projectTargets, c.name)
						else
							table.insert(groupTargets, c.path)
						end
					end
				end
				if #groupTargets > 0 then
					table.sort(groupTargets)
					rule = rule .. " " .. table.concat(groupTargets, " ")
				end
				if #projectTargets > 0 then
					table.sort(projectTargets)
					rule = rule .. " " .. table.concat(projectTargets, " ")
				end
				_p(rule)
				_p('')
			end
		})
	end

--
-- Write out the rules to build each of the workspace's projects.
--

	function gmake.projectrules(wks)
		for prj in p.workspace.eachproject(wks) do
			local deps = project.getdependencies(prj)
			deps = table.extract(deps, "name")

			_p('%s:%s', p.esc(prj.name), gmake.list(p.esc(deps)))

			local cfgvar = gmake.tovar(prj.name)
			_p('ifneq (,$(%s_config))', cfgvar)

			_p(1,'@echo "==== Building %s ($(%s_config)) ===="', prj.name, cfgvar)

			local prjpath = p.filename(prj, gmake.getmakefilename(prj, true))
			local prjdir = path.getdirectory(path.getrelative(wks.location, prjpath))
			local prjname = path.getname(prjpath)

			_x(1,'@${MAKE} --no-print-directory -C %s -f %s config=$(%s_config)', prjdir, prjname, cfgvar)

			_p('endif')
			_p('')
		end
	end
