diff --git a/src/actions/make/_make.lua b/src/actions/make/_make.lua index bca0d277..248c090e 100644 --- a/src/actions/make/_make.lua +++ b/src/actions/make/_make.lua @@ -6,6 +6,7 @@ premake.make = { } local make = premake.make + local solution = premake.solution local project = premake5.project -- @@ -38,7 +39,7 @@ if premake.isdotnetproject(prj) then premake.generate(prj, makefile, make.generate_csharp) else - premake.generate(prj, makefile, make.generate_cpp) + premake.generate(prj, makefile, make.cpp.generate) end end, @@ -53,21 +54,24 @@ -- --- Output the default configuration for a project. --- @return --- True if a default configuration is written, false if the project --- does not contain any supported configurations. +-- Write out the default configuration rule for a solution or project. +-- @param target +-- The solution or project object for which a makefile is being generated. -- - function make.defaultconfig(prj) - -- I don't actually loop, just getting the first config - for cfg in project.eachconfig(prj) do + function make.defaultconfig(target) + -- find the configuration iterator function + local eachconfig = iif(target.project, project.eachconfig, solution.eachconfig) + local iter = eachconfig(target) + + -- grab the first configuration and write the block + local cfg = iter() + if cfg then _p('ifndef config') _p(' config=%s', make.esc(cfg.shortname)) _p('endif') _p('export config') _p('') - return true end end @@ -111,8 +115,8 @@ count = count + 1 end - if (searchprjs) then - for _,prj in ipairs(sln.projects) do + if searchprjs then + for _, prj in ipairs(sln.projects) do if prj.location == this.location then count = count + 1 end diff --git a/src/actions/make/make_cpp.lua b/src/actions/make/make_cpp.lua index 7e242e44..69b6641e 100644 --- a/src/actions/make/make_cpp.lua +++ b/src/actions/make/make_cpp.lua @@ -10,17 +10,179 @@ -- - -- Generate a GNU make C++ project makefile, with support for the new platforms API. - -- + function make.cpp.generate(prj) + --[[ + -- create a shortcut to the compiler interface + local cc = premake.gettool(prj) - function make.generate_cpp(prj) + -- build a list of supported target platforms that also includes a generic build + local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native") + --]] + + cpp.header(prj) + + --[[ + premake.gmake_cpp_header(prj, cc, platforms) + + for _, platform in ipairs(platforms) do + for cfg in premake.eachconfig(prj, platform) do + premake.gmake_cpp_config(cfg, cc) + end + end + + -- list intermediate files + _p('OBJECTS := \\') + for _, file in ipairs(prj.files) do + if path.iscppfile(file) then + _p('\t$(OBJDIR)/%s.o \\', _MAKE.esc(path.getbasename(file))) + end + end + _p('') + + _p('RESOURCES := \\') + for _, file in ipairs(prj.files) do + if path.isresourcefile(file) then + _p('\t$(OBJDIR)/%s.res \\', _MAKE.esc(path.getbasename(file))) + end + end + _p('') + + -- identify the shell type + _p('SHELLTYPE := msdos') + _p('ifeq (,$(ComSpec)$(COMSPEC))') + _p(' SHELLTYPE := posix') + _p('endif') + _p('ifeq (/bin,$(findstring /bin,$(SHELL)))') + _p(' SHELLTYPE := posix') + _p('endif') + _p('') + + -- main build rule(s) + _p('.PHONY: clean prebuild prelink') + _p('') + + if os.is("MacOSX") and prj.kind == "WindowedApp" then + _p('all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist') + else + _p('all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET)') + end + _p('\t@:') + _p('') + + -- target build rule + _p('$(TARGET): $(GCH) $(OBJECTS) $(LDDEPS) $(RESOURCES)') + _p('\t@echo Linking %s', prj.name) + _p('\t$(SILENT) $(LINKCMD)') + _p('\t$(POSTBUILDCMDS)') + _p('') + + -- Create destination directories. Can't use $@ for this because it loses the + -- escaping, causing issues with spaces and parenthesis + _p('$(TARGETDIR):') + premake.make_mkdirrule("$(TARGETDIR)") + + _p('$(OBJDIR):') + premake.make_mkdirrule("$(OBJDIR)") + + -- Mac OS X specific targets + if os.is("MacOSX") and prj.kind == "WindowedApp" then + _p('$(dir $(TARGETDIR))PkgInfo:') + _p('$(dir $(TARGETDIR))Info.plist:') + _p('') + end + + -- clean target + _p('clean:') + _p('\t@echo Cleaning %s', prj.name) + _p('ifeq (posix,$(SHELLTYPE))') + _p('\t$(SILENT) rm -f $(TARGET)') + _p('\t$(SILENT) rm -rf $(OBJDIR)') + _p('else') + _p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))') + _p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))') + _p('endif') + _p('') + + -- custom build step targets + _p('prebuild:') + _p('\t$(PREBUILDCMDS)') + _p('') + + _p('prelink:') + _p('\t$(PRELINKCMDS)') + _p('') + + -- precompiler header rule + cpp.pchrules(prj) + + -- per-file rules + for _, file in ipairs(prj.files) do + if path.iscppfile(file) then + _p('$(OBJDIR)/%s.o: %s', _MAKE.esc(path.getbasename(file)), _MAKE.esc(file)) + _p('\t@echo $(notdir $<)') + cpp.buildcommand(path.iscfile(file)) + elseif (path.getextension(file) == ".rc") then + _p('$(OBJDIR)/%s.res: %s', _MAKE.esc(path.getbasename(file)), _MAKE.esc(file)) + _p('\t@echo $(notdir $<)') + _p('\t$(SILENT) $(RESCOMP) $< -O coff -o "$@" $(RESFLAGS)') + end + end + _p('') + + -- include the dependencies, built by GCC (with the -MMD flag) + _p('-include $(OBJECTS:%%.o=%%.d)') + --]] + print("** Warning: GMake C++ project have not been ported yet") end +-- +-- Write out the C++ makefile header. +-- + + function cpp.header(prj) + -- a little help for the uninitiated + _p('# %s C/C++ project makefile autogenerated by Premake', premake.action.current().shortname) + _p('') + + make.defaultconfig(prj) + + _p('ifndef verbose') + _p(' SILENT = @') + _p('endif') + _p('') + + --[[ + _p('ifndef CC') + _p(' CC = %s', cc.cc) + _p('endif') + _p('') + + _p('ifndef CXX') + _p(' CXX = %s', cc.cxx) + _p('endif') + _p('') + + _p('ifndef AR') + _p(' AR = %s', cc.ar) + _p('endif') + _p('') + + _p('ifndef RESCOMP') + _p(' ifdef WINDRES') + _p(' RESCOMP = $(WINDRES)') + _p(' else') + _p(' RESCOMP = windres') + _p(' endif') + _p('endif') + _p('') + --]] + end + ----------------------------------------------------------------------------- -- Everything below this point is a candidate for deprecation diff --git a/src/actions/make/make_solution.lua b/src/actions/make/make_solution.lua index 6984451b..b63789fe 100644 --- a/src/actions/make/make_solution.lua +++ b/src/actions/make/make_solution.lua @@ -6,6 +6,7 @@ local make = premake.make local solution = premake.solution + local project = premake5.project -- @@ -13,92 +14,37 @@ -- function make.generate_solution(sln) - ---[[ - -- create a shortcut to the compiler interface - local cc = premake[_OPTIONS.cc] - - -- build a list of supported target platforms that also includes a generic build - local platforms = premake.filterplatforms(sln, cc.platforms, "Native") ---]] - -- a little guidance for the uninitiated _p('# %s solution makefile autogenerated by Premake', premake.action.current().shortname) _p('# Type "make help" for usage help') _p('') - -- find and set a default configuration - for prj in solution.eachproject_ng(sln) do - if make.defaultconfig(prj) then - break - end - end - - ---[[ - - -- set a default configuration - _p('ifndef config') - _p(' config=%s', _MAKE.esc(premake.getconfigname(sln.configurations[1], platforms[1], true))) - _p('endif') - _p('export config') - _p('') + make.defaultconfig(sln) + make.projects(sln) - -- list the projects included in the solution - _p('PROJECTS := %s', table.concat(_MAKE.esc(table.extract(sln.projects, "name")), " ")) - _p('') _p('.PHONY: all clean help $(PROJECTS)') _p('') _p('all: $(PROJECTS)') _p('') - -- write the project build rules - for _, prj in ipairs(sln.projects) do - _p('%s: %s', _MAKE.esc(prj.name), table.concat(_MAKE.esc(table.extract(premake.getdependencies(prj), "name")), " ")) - _p('\t@echo "==== Building %s ($(config)) ===="', prj.name) - _p('\t@${MAKE} --no-print-directory -C %s -f %s', _MAKE.esc(path.getrelative(sln.location, prj.location)), _MAKE.esc(make.getmakefilename(prj, true))) - _p('') - end + make.projectrules(sln) + make.cleanrules(sln) + make.helprule(sln) + end - -- clean rules + +-- +-- Write out the rules for the `make clean` action. +-- + + function make.cleanrules(sln) _p('clean:') - for _ ,prj in ipairs(sln.projects) do - _p('\t@${MAKE} --no-print-directory -C %s -f %s clean', _MAKE.esc(path.getrelative(sln.location, prj.location)), _MAKE.esc(make.getmakefilename(prj, true))) + for prj in solution.eachproject_ng(sln) do + local slnpath = solution.getlocation(sln) + local prjpath = path.getrelative(slnpath, project.getlocation(prj)) + _p(1,'@${MAKE} --no-print-directory -C %s -f %s clean', make.esc(prjpath), make.esc(make.getmakefilename(prj, true))) end _p('') ---]] - - make.helprule(sln) - ---[[ - -- help rule - _p('help:') - _p(1,'@echo "Usage: make [config=name] [target]"') - _p(1,'@echo ""') - _p(1,'@echo "CONFIGURATIONS:"') - - local cfgpairs = { } - for _, platform in ipairs(platforms) do - for _, cfgname in ipairs(sln.configurations) do - _p(1,'@echo " %s"', premake.getconfigname(cfgname, platform, true)) - end - end - _p(1,'@echo ""') - - _p(1,'@echo "TARGETS:"') - _p(1,'@echo " all (default)"') - _p(1,'@echo " clean"') - - for _, prj in ipairs(sln.projects) do - _p(1,'@echo " %s"', prj.name) - end - - _p(1,'@echo ""') - _p(1,'@echo "For more information, see http://industriousone.com/premake/quick-start"') - ---]] - - print("** Warning: GMake solutions have not been ported yet") end @@ -117,9 +63,52 @@ end _p(1,'@echo ""') + + _p(1,'@echo "TARGETS:"') + _p(1,'@echo " all (default)"') + _p(1,'@echo " clean"') + + for prj in solution.eachproject_ng(sln) do + _p(1,'@echo " %s"', prj.name) + end + + _p(1,'@echo ""') + _p(1,'@echo "For more information, see http://industriousone.com/premake/quick-start"') end +-- +-- Write out the list of projects that comprise the solution. +-- + + function make.projects(sln) + _p('PROJECTS := %s', table.concat(make.esc(table.extract(sln.projects, "name")), " ")) + _p('') + end + + +-- +-- Write out the rules to build each of the solution's projects. +-- + + function make.projectrules(sln) + for prj in solution.eachproject_ng(sln) do + local deps = project.getdependencies(prj) + deps = table.extract(deps, "name") + _p('%s: %s', make.esc(prj.name), make.esc(table.concat(deps, " "))) + + _p(1,'@echo "==== Building %s ($(config)) ===="', prj.name) + + local slnpath = solution.getlocation(sln) + local prjpath = path.getrelative(slnpath, project.getlocation(prj)) + _p(1,'@${MAKE} --no-print-directory -C %s -f %s', make.esc(prjpath), make.esc(make.getmakefilename(prj, true))) + + _p('') + end + end + + + ----------------------------------------------------------------------------- -- Everything below this point is a candidate for deprecation -----------------------------------------------------------------------------