123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787 |
- --
- -- gmake2_cpp.lua
- -- Generate a C/C++ project makefile.
- -- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
- --
- local p = premake
- local gmake2 = p.modules.gmake2
- gmake2.cpp = {}
- local cpp = gmake2.cpp
- local project = p.project
- local config = p.config
- local fileconfig = p.fileconfig
- ---
- -- Add namespace for element definition lists for premake.callarray()
- ---
- cpp.elements = {}
- --
- -- Generate a GNU make C++ project makefile, with support for the new platforms API.
- --
- cpp.elements.makefile = function(prj)
- return {
- gmake2.header,
- gmake2.phonyRules,
- gmake2.shellType,
- cpp.createRuleTable,
- cpp.outputConfigurationSection,
- cpp.outputPerFileConfigurationSection,
- cpp.createFileTable,
- cpp.outputFilesSection,
- cpp.outputRulesSection,
- cpp.outputFileRuleSection,
- cpp.dependencies,
- }
- end
- function cpp.generate(prj)
- p.eol("\n")
- p.callArray(cpp.elements.makefile, prj)
- -- allow the garbage collector to clean things up.
- for cfg in project.eachconfig(prj) do
- cfg._gmake = nil
- end
- prj._gmake = nil
- end
- function cpp.initialize()
- rule 'cpp'
- fileExtension { ".cc", ".cpp", ".cxx", ".mm" }
- buildoutputs { "$(OBJDIR)/%{file.objname}.o" }
- buildmessage '$(notdir $<)'
- buildcommands {'$(CXX) %{premake.modules.gmake2.cpp.fileFlags(cfg, file)} $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"'}
- rule 'cc'
- fileExtension {".c", ".s", ".m"}
- buildoutputs { "$(OBJDIR)/%{file.objname}.o" }
- buildmessage '$(notdir $<)'
- buildcommands {'$(CC) %{premake.modules.gmake2.cpp.fileFlags(cfg, file)} $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"'}
- rule 'resource'
- fileExtension ".rc"
- buildoutputs { "$(OBJDIR)/%{file.objname}.res" }
- buildmessage '$(notdir $<)'
- buildcommands {'$(RESCOMP) $< -O coff -o "$@" $(ALL_RESFLAGS)'}
- global(nil)
- end
- function cpp.createRuleTable(prj)
- local rules = {}
- local function addRule(extension, rule)
- if type(extension) == 'table' then
- for _, value in ipairs(extension) do
- addRule(value, rule)
- end
- else
- rules[extension] = rule
- end
- end
- -- add all rules.
- local usedRules = table.join({'cpp', 'cc', 'resource'}, prj.rules)
- for _, name in ipairs(usedRules) do
- local rule = p.global.getRule(name)
- addRule(rule.fileExtension, rule)
- end
- -- create fileset categories.
- local filesets = {
- ['.o'] = 'OBJECTS',
- ['.obj'] = 'OBJECTS',
- ['.cc'] = 'SOURCES',
- ['.cpp'] = 'SOURCES',
- ['.cxx'] = 'SOURCES',
- ['.mm'] = 'SOURCES',
- ['.c'] = 'SOURCES',
- ['.s'] = 'SOURCES',
- ['.m'] = 'SOURCES',
- ['.rc'] = 'RESOURCES',
- }
- -- cache the result.
- prj._gmake = prj._gmake or {}
- prj._gmake.rules = rules
- prj._gmake.filesets = filesets
- end
- function cpp.createFileTable(prj)
- for cfg in project.eachconfig(prj) do
- cfg._gmake = cfg._gmake or {}
- cfg._gmake.filesets = {}
- cfg._gmake.fileRules = {}
- local files = table.shallowcopy(prj._.files)
- table.foreachi(files, function(node)
- cpp.addFile(cfg, node)
- end)
- for _, f in pairs(cfg._gmake.filesets) do
- table.sort(f)
- end
- cfg._gmake.kinds = table.keys(cfg._gmake.filesets)
- table.sort(cfg._gmake.kinds)
- prj._gmake.kinds = table.join(prj._gmake.kinds or {}, cfg._gmake.kinds)
- end
- -- we need to reassign object sequences if we generated any files.
- if prj.hasGeneratedFiles and p.project.iscpp(prj) then
- p.oven.assignObjectSequences(prj)
- end
- prj._gmake.kinds = table.unique(prj._gmake.kinds)
- table.sort(prj._gmake.kinds)
- end
- function cpp.addFile(cfg, node)
- local filecfg = fileconfig.getconfig(node, cfg)
- if not filecfg or filecfg.flags.ExcludeFromBuild then
- return
- end
- -- skip generated files, since we try to figure it out manually below.
- if node.generated then
- return
- end
- -- process custom build commands.
- if fileconfig.hasCustomBuildRule(filecfg) then
- local env = table.shallowcopy(filecfg.environ)
- env.PathVars = {
- ["file.basename"] = { absolute = false, token = node.basename },
- ["file.abspath"] = { absolute = true, token = node.abspath },
- ["file.relpath"] = { absolute = false, token = node.relpath },
- ["file.name"] = { absolute = false, token = node.name },
- ["file.objname"] = { absolute = false, token = node.objname },
- ["file.path"] = { absolute = true, token = node.path },
- ["file.directory"] = { absolute = true, token = path.getdirectory(node.abspath) },
- ["file.reldirectory"] = { absolute = false, token = path.getdirectory(node.relpath) },
- }
- local shadowContext = p.context.extent(filecfg, env)
- local buildoutputs = p.project.getrelative(cfg.project, shadowContext.buildoutputs)
- if buildoutputs and #buildoutputs > 0 then
- local file = {
- buildoutputs = buildoutputs,
- source = node.relpath,
- buildmessage = shadowContext.buildmessage,
- buildcommands = shadowContext.buildcommands,
- buildinputs = p.project.getrelative(cfg.project, shadowContext.buildinputs)
- }
- table.insert(cfg._gmake.fileRules, file)
- for _, output in ipairs(buildoutputs) do
- cpp.addGeneratedFile(cfg, node, output)
- end
- end
- else
- cpp.addRuleFile(cfg, node)
- end
- end
- function cpp.determineFiletype(cfg, node)
- -- determine which filetype to use
- local filecfg = fileconfig.getconfig(node, cfg)
- local fileext = path.getextension(node.abspath):lower()
- if filecfg and filecfg.compileas then
- if p.languages.isc(filecfg.compileas) then
- fileext = ".c"
- elseif p.languages.iscpp(filecfg.compileas) then
- fileext = ".cpp"
- end
- end
- return fileext;
- end
- function cpp.addGeneratedFile(cfg, source, filename)
- -- mark that we have generated files.
- cfg.project.hasGeneratedFiles = true
- -- add generated file to the project.
- local files = cfg.project._.files
- local node = files[filename]
- if not node then
- node = fileconfig.new(filename, cfg.project)
- files[filename] = node
- table.insert(files, node)
- end
- -- always overwrite the dependency information.
- node.dependsOn = source
- node.generated = true
- -- add to config if not already added.
- if not fileconfig.getconfig(node, cfg) then
- fileconfig.addconfig(node, cfg)
- end
- -- determine which filetype to use
- local fileext = cpp.determineFiletype(cfg, node)
- -- add file to the fileset.
- local filesets = cfg.project._gmake.filesets
- local kind = filesets[fileext] or "CUSTOM"
- -- don't link generated object files automatically if it's explicitly
- -- disabled.
- if path.isobjectfile(filename) and source.linkbuildoutputs == false then
- kind = "CUSTOM"
- end
- local fileset = cfg._gmake.filesets[kind] or {}
- table.insert(fileset, filename)
- cfg._gmake.filesets[kind] = fileset
- local generatedKind = "GENERATED"
- local generatedFileset = cfg._gmake.filesets[generatedKind] or {}
- table.insert(generatedFileset, filename)
- cfg._gmake.filesets[generatedKind] = generatedFileset
- -- recursively setup rules.
- cpp.addRuleFile(cfg, node)
- end
- function cpp.addRuleFile(cfg, node)
- local rules = cfg.project._gmake.rules
- local fileext = cpp.determineFiletype(cfg, node)
- local rule = rules[fileext]
- if rule then
- local filecfg = fileconfig.getconfig(node, cfg)
- local environ = table.shallowcopy(filecfg.environ)
- if rule.propertydefinition then
- p.rule.prepareEnvironment(rule, environ, cfg)
- p.rule.prepareEnvironment(rule, environ, filecfg)
- end
- local shadowContext = p.context.extent(rule, environ)
- local buildoutputs = shadowContext.buildoutputs
- local buildmessage = shadowContext.buildmessage
- local buildcommands = shadowContext.buildcommands
- local buildinputs = shadowContext.buildinputs
- buildoutputs = p.project.getrelative(cfg.project, buildoutputs)
- if buildoutputs and #buildoutputs > 0 then
- local file = {
- buildoutputs = buildoutputs,
- source = node.relpath,
- buildmessage = buildmessage,
- buildcommands = buildcommands,
- buildinputs = buildinputs
- }
- table.insert(cfg._gmake.fileRules, file)
- for _, output in ipairs(buildoutputs) do
- cpp.addGeneratedFile(cfg, node, output)
- end
- end
- end
- end
- --
- -- Write out the settings for a particular configuration.
- --
- cpp.elements.configuration = function(cfg)
- return {
- cpp.tools,
- gmake2.target,
- gmake2.objdir,
- cpp.pch,
- cpp.defines,
- cpp.includes,
- cpp.forceInclude,
- cpp.cppFlags,
- cpp.cFlags,
- cpp.cxxFlags,
- cpp.resFlags,
- cpp.libs,
- cpp.ldDeps,
- cpp.ldFlags,
- cpp.linkCmd,
- cpp.bindirs,
- cpp.exepaths,
- gmake2.settings,
- gmake2.preBuildCmds,
- gmake2.preLinkCmds,
- gmake2.postBuildCmds,
- }
- end
- function cpp.outputConfigurationSection(prj)
- _p('# Configurations')
- _p('# #############################################')
- _p('')
- gmake2.outputSection(prj, cpp.elements.configuration)
- end
- function cpp.tools(cfg, toolset)
- local tool = toolset.gettoolname(cfg, "cc")
- if tool then
- _p('ifeq ($(origin CC), default)')
- _p(' CC = %s', tool)
- _p('endif' )
- end
- tool = toolset.gettoolname(cfg, "cxx")
- if tool then
- _p('ifeq ($(origin CXX), default)')
- _p(' CXX = %s', tool)
- _p('endif' )
- end
- tool = toolset.gettoolname(cfg, "ar")
- if tool then
- _p('ifeq ($(origin AR), default)')
- _p(' AR = %s', tool)
- _p('endif' )
- end
- tool = toolset.gettoolname(cfg, "rc")
- if tool then
- _p('RESCOMP = %s', tool)
- end
- end
- function cpp.pch(cfg, toolset)
- local pch = p.tools.gcc.getpch(cfg)
- -- If there is no header, or if PCH has been disabled, I can early out
- if pch == nil then
- return
- end
- p.outln('PCH = ' .. pch)
- p.outln('PCH_PLACEHOLDER = $(OBJDIR)/$(notdir $(PCH))')
- p.outln('GCH = $(PCH_PLACEHOLDER).gch')
- end
- function cpp.defines(cfg, toolset)
- p.outln('DEFINES +=' .. gmake2.list(table.join(toolset.getdefines(cfg.defines, cfg), toolset.getundefines(cfg.undefines))))
- end
- function cpp.includes(cfg, toolset)
- local includes = toolset.getincludedirs(cfg, cfg.includedirs, cfg.sysincludedirs, cfg.frameworkdirs)
- p.outln('INCLUDES +=' .. gmake2.list(includes))
- end
- function cpp.forceInclude(cfg, toolset)
- local includes = toolset.getforceincludes(cfg)
- p.outln('FORCE_INCLUDE +=' .. gmake2.list(includes))
- end
- function cpp.cppFlags(cfg, toolset)
- local flags = gmake2.list(toolset.getcppflags(cfg))
- p.outln('ALL_CPPFLAGS += $(CPPFLAGS)' .. flags .. ' $(DEFINES) $(INCLUDES)')
- end
- function cpp.cFlags(cfg, toolset)
- local flags = gmake2.list(table.join(toolset.getcflags(cfg), cfg.buildoptions))
- p.outln('ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS)' .. flags)
- end
- function cpp.cxxFlags(cfg, toolset)
- local flags = gmake2.list(table.join(toolset.getcxxflags(cfg), cfg.buildoptions))
- p.outln('ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS)' .. flags)
- end
- function cpp.resFlags(cfg, toolset)
- local resflags = table.join(toolset.getdefines(cfg.resdefines), toolset.getincludedirs(cfg, cfg.resincludedirs), cfg.resoptions)
- p.outln('ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)' .. gmake2.list(resflags))
- end
- function cpp.libs(cfg, toolset)
- local flags = toolset.getlinks(cfg)
- p.outln('LIBS +=' .. gmake2.list(flags, true))
- end
- function cpp.ldDeps(cfg, toolset)
- local deps = config.getlinks(cfg, "siblings", "fullpath")
- p.outln('LDDEPS +=' .. gmake2.list(p.esc(deps)))
- end
- function cpp.ldFlags(cfg, toolset)
- local flags = table.join(toolset.getLibraryDirectories(cfg), toolset.getrunpathdirs(cfg, table.join(cfg.runpathdirs, config.getsiblingtargetdirs(cfg))), toolset.getldflags(cfg), cfg.linkoptions)
- p.outln('ALL_LDFLAGS += $(LDFLAGS)' .. gmake2.list(flags))
- end
- function cpp.linkCmd(cfg, toolset)
- if cfg.kind == p.STATICLIB then
- if cfg.architecture == p.UNIVERSAL then
- p.outln('LINKCMD = libtool -o "$@" $(OBJECTS)')
- else
- p.outln('LINKCMD = $(AR) -rcs "$@" $(OBJECTS)')
- end
- elseif cfg.kind == p.UTILITY then
- -- Empty LINKCMD for Utility (only custom build rules)
- p.outln('LINKCMD =')
- else
- -- this was $(TARGET) $(LDFLAGS) $(OBJECTS)
- -- but had trouble linking to certain static libs; $(OBJECTS) moved up
- -- $(LDFLAGS) moved to end (http://sourceforge.net/p/premake/patches/107/)
- -- $(LIBS) moved to end (http://sourceforge.net/p/premake/bugs/279/)
- local cc = iif(p.languages.isc(cfg.language), "CC", "CXX")
- p.outln('LINKCMD = $(' .. cc .. ') -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)')
- end
- end
- function cpp.bindirs(cfg, toolset)
- local dirs = project.getrelative(cfg.project, cfg.bindirs)
- if #dirs > 0 then
- p.outln('EXECUTABLE_PATHS = "' .. table.concat(dirs, ":") .. '"')
- end
- end
- function cpp.exepaths(cfg, toolset)
- local dirs = project.getrelative(cfg.project, cfg.bindirs)
- if #dirs > 0 then
- p.outln('EXE_PATHS = export PATH=$(EXECUTABLE_PATHS):$$PATH;')
- end
- end
- --
- -- Write out the per file configurations.
- --
- function cpp.outputPerFileConfigurationSection(prj)
- _p('# Per File Configurations')
- _p('# #############################################')
- _p('')
- for cfg in project.eachconfig(prj) do
- table.foreachi(prj._.files, function(node)
- local fcfg = fileconfig.getconfig(node, cfg)
- if fcfg then
- cpp.perFileFlags(cfg, fcfg)
- end
- end)
- end
- _p('')
- end
- function cpp.makeVarName(prj, value, saltValue)
- prj._gmake = prj._gmake or {}
- prj._gmake.varlist = prj._gmake.varlist or {}
- prj._gmake.varlistlength = prj._gmake.varlistlength or 0
- local cache = prj._gmake.varlist
- local length = prj._gmake.varlistlength
- local key = value .. saltValue
- if (cache[key] ~= nil) then
- return cache[key], false
- end
- local var = string.format("PERFILE_FLAGS_%d", length)
- cache[key] = var
- prj._gmake.varlistlength = length + 1
- return var, true
- end
- function cpp.perFileFlags(cfg, fcfg)
- local toolset = gmake2.getToolSet(cfg)
- local isCFile = path.iscfile(fcfg.name)
- local getflags = iif(isCFile, toolset.getcflags, toolset.getcxxflags)
- local value = gmake2.list(table.join(getflags(fcfg), fcfg.buildoptions))
- if fcfg.defines or fcfg.undefines then
- local defs = table.join(toolset.getdefines(fcfg.defines, cfg), toolset.getundefines(fcfg.undefines))
- if #defs > 0 then
- value = value .. gmake2.list(defs)
- end
- end
- if fcfg.includedirs or fcfg.sysincludedirs or fcfg.frameworkdirs then
- local includes = toolset.getincludedirs(cfg, fcfg.includedirs, fcfg.sysincludedirs, fcfg.frameworkdirs)
- if #includes > 0 then
- value = value .. gmake2.list(includes)
- end
- end
- if #value > 0 then
- local newPerFileFlag = false
- fcfg.flagsVariable, newPerFileFlag = cpp.makeVarName(cfg.project, value, iif(isCFile, '_C', '_CPP'))
- if newPerFileFlag then
- if isCFile then
- _p('%s = $(ALL_CFLAGS)%s', fcfg.flagsVariable, value)
- else
- _p('%s = $(ALL_CXXFLAGS)%s', fcfg.flagsVariable, value)
- end
- end
- end
- end
- function cpp.fileFlags(cfg, file)
- local fcfg = fileconfig.getconfig(file, cfg)
- local flags = {}
- if cfg.pchheader and not cfg.flags.NoPCH and (not fcfg or not fcfg.flags.NoPCH) then
- table.insert(flags, "-include $(PCH_PLACEHOLDER)")
- end
- if fcfg and fcfg.flagsVariable then
- table.insert(flags, string.format("$(%s)", fcfg.flagsVariable))
- else
- local fileExt = cpp.determineFiletype(cfg, file)
- if path.iscfile(fileExt) then
- table.insert(flags, "$(ALL_CFLAGS)")
- elseif path.iscppfile(fileExt) then
- table.insert(flags, "$(ALL_CXXFLAGS)")
- end
- end
- return table.concat(flags, ' ')
- end
- --
- -- Write out the file sets.
- --
- cpp.elements.filesets = function(cfg)
- local result = {}
- for _, kind in ipairs(cfg._gmake.kinds) do
- for _, f in ipairs(cfg._gmake.filesets[kind]) do
- table.insert(result, function(cfg, toolset)
- cpp.outputFileset(cfg, kind, f)
- end)
- end
- end
- return result
- end
- function cpp.outputFilesSection(prj)
- _p('# File sets')
- _p('# #############################################')
- _p('')
- for _, kind in ipairs(prj._gmake.kinds) do
- _x('%s :=', kind)
- end
- _x('')
- gmake2.outputSection(prj, cpp.elements.filesets)
- end
- function cpp.outputFileset(cfg, kind, file)
- _x('%s += %s', kind, file)
- end
- --
- -- Write out the targets.
- --
- cpp.elements.rules = function(cfg)
- return {
- cpp.allRules,
- cpp.targetRules,
- gmake2.targetDirRules,
- gmake2.objDirRules,
- cpp.cleanRules,
- gmake2.preBuildRules,
- cpp.customDeps,
- cpp.pchRules,
- }
- end
- function cpp.outputRulesSection(prj)
- _p('# Rules')
- _p('# #############################################')
- _p('')
- gmake2.outputSection(prj, cpp.elements.rules)
- end
- function cpp.allRules(cfg, toolset)
- if cfg.system == p.MACOSX and cfg.kind == p.WINDOWEDAPP then
- _p('all: $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist')
- _p('\t@:')
- _p('')
- _p('$(dir $(TARGETDIR))PkgInfo:')
- _p('$(dir $(TARGETDIR))Info.plist:')
- else
- _p('all: $(TARGET)')
- _p('\t@:')
- end
- _p('')
- end
- function cpp.targetRules(cfg, toolset)
- local targets = ''
- for _, kind in ipairs(cfg._gmake.kinds) do
- if kind ~= 'OBJECTS' and kind ~= 'RESOURCES' then
- targets = targets .. '$(' .. kind .. ') '
- end
- end
- targets = targets .. '$(OBJECTS) $(LDDEPS)'
- if cfg._gmake.filesets['RESOURCES'] then
- targets = targets .. ' $(RESOURCES)'
- end
- _p('$(TARGET): %s | $(TARGETDIR)', targets)
- _p('\t$(PRELINKCMDS)')
- _p('\t@echo Linking %s', cfg.project.name)
- _p('\t$(SILENT) $(LINKCMD)')
- _p('\t$(POSTBUILDCMDS)')
- _p('')
- end
- function cpp.customDeps(cfg, toolset)
- for _, kind in ipairs(cfg._gmake.kinds) do
- if kind == 'CUSTOM' or kind == 'SOURCES' then
- _p('$(%s): | prebuild', kind)
- end
- end
- end
- function cpp.cleanRules(cfg, toolset)
- _p('clean:')
- _p('\t@echo Cleaning %s', cfg.project.name)
- _p('ifeq (posix,$(SHELLTYPE))')
- _p('\t$(SILENT) rm -f $(TARGET)')
- _p('\t$(SILENT) rm -rf $(GENERATED)')
- _p('\t$(SILENT) rm -rf $(OBJDIR)')
- _p('else')
- _p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))')
- _p('\t$(SILENT) if exist $(subst /,\\\\,$(GENERATED)) rmdir /s /q $(subst /,\\\\,$(GENERATED))')
- _p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))')
- _p('endif')
- _p('')
- end
- function cpp.pchRules(cfg, toolset)
- _p('ifneq (,$(PCH))')
- _p('$(OBJECTS): $(GCH) | $(PCH_PLACEHOLDER)')
- _p('$(GCH): $(PCH) | prebuild')
- _p('\t@echo $(notdir $<)')
- local cmd = iif(p.languages.isc(cfg.language), "$(CC) -x c-header $(ALL_CFLAGS)", "$(CXX) -x c++-header $(ALL_CXXFLAGS)")
- _p('\t$(SILENT) %s -o "$@" -MF "$(@:%%.gch=%%.d)" -c "$<"', cmd)
- _p('$(PCH_PLACEHOLDER): $(GCH) | $(OBJDIR)')
- _p('ifeq (posix,$(SHELLTYPE))')
- _p('\t$(SILENT) touch "$@"')
- _p('else')
- _p('\t$(SILENT) echo $null >> "$@"')
- _p('endif')
- _p('else')
- _p('$(OBJECTS): | prebuild')
- _p('endif')
- _p('')
- end
- --
- -- Output the file compile targets.
- --
- cpp.elements.fileRules = function(cfg)
- local funcs = {}
- for _, fileRule in ipairs(cfg._gmake.fileRules) do
- table.insert(funcs, function(cfg, toolset)
- cpp.outputFileRules(cfg, fileRule)
- end)
- end
- return funcs
- end
- function cpp.outputFileRuleSection(prj)
- _p('# File Rules')
- _p('# #############################################')
- _p('')
- gmake2.outputSection(prj, cpp.elements.fileRules)
- end
- function cpp.outputFileRules(cfg, file)
- local dependencies = p.esc(file.source)
- if file.buildinputs and #file.buildinputs > 0 then
- dependencies = dependencies .. " " .. table.concat(p.esc(file.buildinputs), " ")
- end
- _p('%s: %s', file.buildoutputs[1], dependencies)
- if file.buildmessage then
- _p('\t@echo %s', file.buildmessage)
- end
- if file.buildcommands then
- local cmds = os.translateCommandsAndPaths(file.buildcommands, cfg.project.basedir, cfg.project.location)
- for _, cmd in ipairs(cmds) do
- if cfg.bindirs and #cfg.bindirs > 0 then
- _p('\t$(SILENT) $(EXE_PATHS) %s', cmd)
- else
- _p('\t$(SILENT) %s', cmd)
- end
- end
- end
- -- TODO: this is a hack with some imperfect side-effects.
- -- better solution would be to emit a dummy file for the rule, and then outputs depend on it (must clean up dummy in 'clean')
- -- better yet, is to use pattern rules, but we need to detect that all outputs have the same stem
- if #file.buildoutputs > 1 then
- _p('%s: %s', table.concat({ table.unpack(file.buildoutputs, 2) }, ' '), file.buildoutputs[1])
- end
- end
- ---------------------------------------------------------------------------
- --
- -- Handlers for individual makefile elements
- --
- ---------------------------------------------------------------------------
- function cpp.dependencies(prj)
- -- include the dependencies, built by GCC (with the -MMD flag)
- _p('-include $(OBJECTS:%%.o=%%.d)')
- _p('ifneq (,$(PCH))')
- _p(' -include $(PCH_PLACEHOLDER).d')
- _p('endif')
- end
|